diff options
author | John W. Linville <linville@tuxdriver.com> | 2013-02-08 13:16:17 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2013-02-08 13:16:17 -0500 |
commit | f5237f278f30a92401539a54f87ee0c717b6f818 (patch) | |
tree | 209d4fd6fb00e660c76ca8ac5d4caed59dbb9957 /drivers | |
parent | b285109dde7b873b5dc671ef1b3ae3090f4bc72f (diff) | |
parent | b26f5f09ebdeb85ab152344cc1d6d484a3ce967d (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem
Diffstat (limited to 'drivers')
211 files changed, 25183 insertions, 2782 deletions
diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h index 04f7c86ea3d8..6f377bd1a6d6 100644 --- a/drivers/bcma/bcma_private.h +++ b/drivers/bcma/bcma_private.h | |||
@@ -47,6 +47,7 @@ int bcma_sprom_get(struct bcma_bus *bus); | |||
47 | /* driver_chipcommon.c */ | 47 | /* driver_chipcommon.c */ |
48 | #ifdef CONFIG_BCMA_DRIVER_MIPS | 48 | #ifdef CONFIG_BCMA_DRIVER_MIPS |
49 | void bcma_chipco_serial_init(struct bcma_drv_cc *cc); | 49 | void bcma_chipco_serial_init(struct bcma_drv_cc *cc); |
50 | extern struct platform_device bcma_pflash_dev; | ||
50 | #endif /* CONFIG_BCMA_DRIVER_MIPS */ | 51 | #endif /* CONFIG_BCMA_DRIVER_MIPS */ |
51 | 52 | ||
52 | /* driver_chipcommon_pmu.c */ | 53 | /* driver_chipcommon_pmu.c */ |
diff --git a/drivers/bcma/driver_chipcommon_nflash.c b/drivers/bcma/driver_chipcommon_nflash.c index 1f0b83e18f68..d4f699aef8c4 100644 --- a/drivers/bcma/driver_chipcommon_nflash.c +++ b/drivers/bcma/driver_chipcommon_nflash.c | |||
@@ -5,11 +5,11 @@ | |||
5 | * Licensed under the GNU/GPL. See COPYING for details. | 5 | * Licensed under the GNU/GPL. See COPYING for details. |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include "bcma_private.h" | ||
9 | |||
8 | #include <linux/platform_device.h> | 10 | #include <linux/platform_device.h> |
9 | #include <linux/bcma/bcma.h> | 11 | #include <linux/bcma/bcma.h> |
10 | 12 | ||
11 | #include "bcma_private.h" | ||
12 | |||
13 | struct platform_device bcma_nflash_dev = { | 13 | struct platform_device bcma_nflash_dev = { |
14 | .name = "bcma_nflash", | 14 | .name = "bcma_nflash", |
15 | .num_resources = 0, | 15 | .num_resources = 0, |
diff --git a/drivers/bcma/driver_chipcommon_sflash.c b/drivers/bcma/driver_chipcommon_sflash.c index 1e694db4532d..e6ed4fe5dced 100644 --- a/drivers/bcma/driver_chipcommon_sflash.c +++ b/drivers/bcma/driver_chipcommon_sflash.c | |||
@@ -5,11 +5,11 @@ | |||
5 | * Licensed under the GNU/GPL. See COPYING for details. | 5 | * Licensed under the GNU/GPL. See COPYING for details. |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include "bcma_private.h" | ||
9 | |||
8 | #include <linux/platform_device.h> | 10 | #include <linux/platform_device.h> |
9 | #include <linux/bcma/bcma.h> | 11 | #include <linux/bcma/bcma.h> |
10 | 12 | ||
11 | #include "bcma_private.h" | ||
12 | |||
13 | static struct resource bcma_sflash_resource = { | 13 | static struct resource bcma_sflash_resource = { |
14 | .name = "bcma_sflash", | 14 | .name = "bcma_sflash", |
15 | .start = BCMA_SOC_FLASH2, | 15 | .start = BCMA_SOC_FLASH2, |
diff --git a/drivers/bcma/driver_gpio.c b/drivers/bcma/driver_gpio.c index 9a6f585da2d9..0b5df538dfd9 100644 --- a/drivers/bcma/driver_gpio.c +++ b/drivers/bcma/driver_gpio.c | |||
@@ -73,6 +73,16 @@ static void bcma_gpio_free(struct gpio_chip *chip, unsigned gpio) | |||
73 | bcma_chipco_gpio_pullup(cc, 1 << gpio, 0); | 73 | bcma_chipco_gpio_pullup(cc, 1 << gpio, 0); |
74 | } | 74 | } |
75 | 75 | ||
76 | static int bcma_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) | ||
77 | { | ||
78 | struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip); | ||
79 | |||
80 | if (cc->core->bus->hosttype == BCMA_HOSTTYPE_SOC) | ||
81 | return bcma_core_irq(cc->core); | ||
82 | else | ||
83 | return -EINVAL; | ||
84 | } | ||
85 | |||
76 | int bcma_gpio_init(struct bcma_drv_cc *cc) | 86 | int bcma_gpio_init(struct bcma_drv_cc *cc) |
77 | { | 87 | { |
78 | struct gpio_chip *chip = &cc->gpio; | 88 | struct gpio_chip *chip = &cc->gpio; |
@@ -85,6 +95,7 @@ int bcma_gpio_init(struct bcma_drv_cc *cc) | |||
85 | chip->set = bcma_gpio_set_value; | 95 | chip->set = bcma_gpio_set_value; |
86 | chip->direction_input = bcma_gpio_direction_input; | 96 | chip->direction_input = bcma_gpio_direction_input; |
87 | chip->direction_output = bcma_gpio_direction_output; | 97 | chip->direction_output = bcma_gpio_direction_output; |
98 | chip->to_irq = bcma_gpio_to_irq; | ||
88 | chip->ngpio = 16; | 99 | chip->ngpio = 16; |
89 | /* There is just one SoC in one device and its GPIO addresses should be | 100 | /* There is just one SoC in one device and its GPIO addresses should be |
90 | * deterministic to address them more easily. The other buses could get | 101 | * deterministic to address them more easily. The other buses could get |
diff --git a/drivers/bcma/driver_mips.c b/drivers/bcma/driver_mips.c index 9fe86ee16c66..9a7f0e3ab5a3 100644 --- a/drivers/bcma/driver_mips.c +++ b/drivers/bcma/driver_mips.c | |||
@@ -14,11 +14,33 @@ | |||
14 | 14 | ||
15 | #include <linux/bcma/bcma.h> | 15 | #include <linux/bcma/bcma.h> |
16 | 16 | ||
17 | #include <linux/mtd/physmap.h> | ||
18 | #include <linux/platform_device.h> | ||
17 | #include <linux/serial.h> | 19 | #include <linux/serial.h> |
18 | #include <linux/serial_core.h> | 20 | #include <linux/serial_core.h> |
19 | #include <linux/serial_reg.h> | 21 | #include <linux/serial_reg.h> |
20 | #include <linux/time.h> | 22 | #include <linux/time.h> |
21 | 23 | ||
24 | static const char *part_probes[] = { "bcm47xxpart", NULL }; | ||
25 | |||
26 | static struct physmap_flash_data bcma_pflash_data = { | ||
27 | .part_probe_types = part_probes, | ||
28 | }; | ||
29 | |||
30 | static struct resource bcma_pflash_resource = { | ||
31 | .name = "bcma_pflash", | ||
32 | .flags = IORESOURCE_MEM, | ||
33 | }; | ||
34 | |||
35 | struct platform_device bcma_pflash_dev = { | ||
36 | .name = "physmap-flash", | ||
37 | .dev = { | ||
38 | .platform_data = &bcma_pflash_data, | ||
39 | }, | ||
40 | .resource = &bcma_pflash_resource, | ||
41 | .num_resources = 1, | ||
42 | }; | ||
43 | |||
22 | /* The 47162a0 hangs when reading MIPS DMP registers registers */ | 44 | /* The 47162a0 hangs when reading MIPS DMP registers registers */ |
23 | static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev) | 45 | static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev) |
24 | { | 46 | { |
@@ -211,6 +233,7 @@ static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore) | |||
211 | { | 233 | { |
212 | struct bcma_bus *bus = mcore->core->bus; | 234 | struct bcma_bus *bus = mcore->core->bus; |
213 | struct bcma_drv_cc *cc = &bus->drv_cc; | 235 | struct bcma_drv_cc *cc = &bus->drv_cc; |
236 | struct bcma_pflash *pflash = &cc->pflash; | ||
214 | 237 | ||
215 | switch (cc->capabilities & BCMA_CC_CAP_FLASHT) { | 238 | switch (cc->capabilities & BCMA_CC_CAP_FLASHT) { |
216 | case BCMA_CC_FLASHT_STSER: | 239 | case BCMA_CC_FLASHT_STSER: |
@@ -220,15 +243,20 @@ static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore) | |||
220 | break; | 243 | break; |
221 | case BCMA_CC_FLASHT_PARA: | 244 | case BCMA_CC_FLASHT_PARA: |
222 | bcma_debug(bus, "Found parallel flash\n"); | 245 | bcma_debug(bus, "Found parallel flash\n"); |
223 | cc->pflash.present = true; | 246 | pflash->present = true; |
224 | cc->pflash.window = BCMA_SOC_FLASH2; | 247 | pflash->window = BCMA_SOC_FLASH2; |
225 | cc->pflash.window_size = BCMA_SOC_FLASH2_SZ; | 248 | pflash->window_size = BCMA_SOC_FLASH2_SZ; |
226 | 249 | ||
227 | if ((bcma_read32(cc->core, BCMA_CC_FLASH_CFG) & | 250 | if ((bcma_read32(cc->core, BCMA_CC_FLASH_CFG) & |
228 | BCMA_CC_FLASH_CFG_DS) == 0) | 251 | BCMA_CC_FLASH_CFG_DS) == 0) |
229 | cc->pflash.buswidth = 1; | 252 | pflash->buswidth = 1; |
230 | else | 253 | else |
231 | cc->pflash.buswidth = 2; | 254 | pflash->buswidth = 2; |
255 | |||
256 | bcma_pflash_data.width = pflash->buswidth; | ||
257 | bcma_pflash_resource.start = pflash->window; | ||
258 | bcma_pflash_resource.end = pflash->window + pflash->window_size; | ||
259 | |||
232 | break; | 260 | break; |
233 | default: | 261 | default: |
234 | bcma_err(bus, "Flash type not supported\n"); | 262 | bcma_err(bus, "Flash type not supported\n"); |
diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c index ff8528925322..6eda7ef0682f 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c | |||
@@ -149,6 +149,14 @@ static int bcma_register_cores(struct bcma_bus *bus) | |||
149 | dev_id++; | 149 | dev_id++; |
150 | } | 150 | } |
151 | 151 | ||
152 | #ifdef CONFIG_BCMA_DRIVER_MIPS | ||
153 | if (bus->drv_cc.pflash.present) { | ||
154 | err = platform_device_register(&bcma_pflash_dev); | ||
155 | if (err) | ||
156 | bcma_err(bus, "Error registering parallel flash\n"); | ||
157 | } | ||
158 | #endif | ||
159 | |||
152 | #ifdef CONFIG_BCMA_SFLASH | 160 | #ifdef CONFIG_BCMA_SFLASH |
153 | if (bus->drv_cc.sflash.present) { | 161 | if (bus->drv_cc.sflash.present) { |
154 | err = platform_device_register(&bcma_sflash_dev); | 162 | err = platform_device_register(&bcma_sflash_dev); |
diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index 7647ed6b73d7..17507dc8a1e7 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig | |||
@@ -58,6 +58,7 @@ config ATH9K_DEBUGFS | |||
58 | bool "Atheros ath9k debugging" | 58 | bool "Atheros ath9k debugging" |
59 | depends on ATH9K | 59 | depends on ATH9K |
60 | select MAC80211_DEBUGFS | 60 | select MAC80211_DEBUGFS |
61 | select RELAY | ||
61 | ---help--- | 62 | ---help--- |
62 | Say Y, if you need access to ath9k's statistics for | 63 | Say Y, if you need access to ath9k's statistics for |
63 | interrupts, rate control, etc. | 64 | interrupts, rate control, etc. |
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index b2d6c18d1678..97c90b21e1cb 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h | |||
@@ -319,6 +319,8 @@ struct ath_rx { | |||
319 | struct ath_rx_edma rx_edma[ATH9K_RX_QUEUE_MAX]; | 319 | struct ath_rx_edma rx_edma[ATH9K_RX_QUEUE_MAX]; |
320 | 320 | ||
321 | struct sk_buff *frag; | 321 | struct sk_buff *frag; |
322 | |||
323 | u32 ampdu_ref; | ||
322 | }; | 324 | }; |
323 | 325 | ||
324 | int ath_startrecv(struct ath_softc *sc); | 326 | int ath_startrecv(struct ath_softc *sc); |
@@ -754,6 +756,7 @@ struct ath_softc { | |||
754 | /* relay(fs) channel for spectral scan */ | 756 | /* relay(fs) channel for spectral scan */ |
755 | struct rchan *rfs_chan_spec_scan; | 757 | struct rchan *rfs_chan_spec_scan; |
756 | enum spectral_mode spectral_mode; | 758 | enum spectral_mode spectral_mode; |
759 | struct ath_spec_scan spec_config; | ||
757 | int scanning; | 760 | int scanning; |
758 | 761 | ||
759 | #ifdef CONFIG_PM_SLEEP | 762 | #ifdef CONFIG_PM_SLEEP |
@@ -863,31 +866,31 @@ static inline u8 spectral_bitmap_weight(u8 *bins) | |||
863 | * interface. | 866 | * interface. |
864 | */ | 867 | */ |
865 | enum ath_fft_sample_type { | 868 | enum ath_fft_sample_type { |
866 | ATH_FFT_SAMPLE_HT20 = 0, | 869 | ATH_FFT_SAMPLE_HT20 = 1, |
867 | }; | 870 | }; |
868 | 871 | ||
869 | struct fft_sample_tlv { | 872 | struct fft_sample_tlv { |
870 | u8 type; /* see ath_fft_sample */ | 873 | u8 type; /* see ath_fft_sample */ |
871 | u16 length; | 874 | __be16 length; |
872 | /* type dependent data follows */ | 875 | /* type dependent data follows */ |
873 | } __packed; | 876 | } __packed; |
874 | 877 | ||
875 | struct fft_sample_ht20 { | 878 | struct fft_sample_ht20 { |
876 | struct fft_sample_tlv tlv; | 879 | struct fft_sample_tlv tlv; |
877 | 880 | ||
878 | u8 __alignment; | 881 | u8 max_exp; |
879 | 882 | ||
880 | u16 freq; | 883 | __be16 freq; |
881 | s8 rssi; | 884 | s8 rssi; |
882 | s8 noise; | 885 | s8 noise; |
883 | 886 | ||
884 | u16 max_magnitude; | 887 | __be16 max_magnitude; |
885 | u8 max_index; | 888 | u8 max_index; |
886 | u8 bitmap_weight; | 889 | u8 bitmap_weight; |
887 | 890 | ||
888 | u64 tsf; | 891 | __be64 tsf; |
889 | 892 | ||
890 | u16 data[SPECTRAL_HT20_NUM_BINS]; | 893 | u8 data[SPECTRAL_HT20_NUM_BINS]; |
891 | } __packed; | 894 | } __packed; |
892 | 895 | ||
893 | void ath9k_tasklet(unsigned long data); | 896 | void ath9k_tasklet(unsigned long data); |
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 6c5d313ebcb7..3714b971d18e 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c | |||
@@ -895,6 +895,7 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf, | |||
895 | RXS_ERR("RX-Bytes-All", rx_bytes_all); | 895 | RXS_ERR("RX-Bytes-All", rx_bytes_all); |
896 | RXS_ERR("RX-Beacons", rx_beacons); | 896 | RXS_ERR("RX-Beacons", rx_beacons); |
897 | RXS_ERR("RX-Frags", rx_frags); | 897 | RXS_ERR("RX-Frags", rx_frags); |
898 | RXS_ERR("RX-Spectral", rx_spectral); | ||
898 | 899 | ||
899 | if (len > size) | 900 | if (len > size) |
900 | len = size; | 901 | len = size; |
@@ -1035,6 +1036,182 @@ static const struct file_operations fops_spec_scan_ctl = { | |||
1035 | .llseek = default_llseek, | 1036 | .llseek = default_llseek, |
1036 | }; | 1037 | }; |
1037 | 1038 | ||
1039 | static ssize_t read_file_spectral_short_repeat(struct file *file, | ||
1040 | char __user *user_buf, | ||
1041 | size_t count, loff_t *ppos) | ||
1042 | { | ||
1043 | struct ath_softc *sc = file->private_data; | ||
1044 | char buf[32]; | ||
1045 | unsigned int len; | ||
1046 | |||
1047 | len = sprintf(buf, "%d\n", sc->spec_config.short_repeat); | ||
1048 | return simple_read_from_buffer(user_buf, count, ppos, buf, len); | ||
1049 | } | ||
1050 | |||
1051 | static ssize_t write_file_spectral_short_repeat(struct file *file, | ||
1052 | const char __user *user_buf, | ||
1053 | size_t count, loff_t *ppos) | ||
1054 | { | ||
1055 | struct ath_softc *sc = file->private_data; | ||
1056 | unsigned long val; | ||
1057 | char buf[32]; | ||
1058 | ssize_t len; | ||
1059 | |||
1060 | len = min(count, sizeof(buf) - 1); | ||
1061 | if (copy_from_user(buf, user_buf, len)) | ||
1062 | return -EFAULT; | ||
1063 | |||
1064 | buf[len] = '\0'; | ||
1065 | if (kstrtoul(buf, 0, &val)) | ||
1066 | return -EINVAL; | ||
1067 | |||
1068 | if (val < 0 || val > 1) | ||
1069 | return -EINVAL; | ||
1070 | |||
1071 | sc->spec_config.short_repeat = val; | ||
1072 | return count; | ||
1073 | } | ||
1074 | |||
1075 | static const struct file_operations fops_spectral_short_repeat = { | ||
1076 | .read = read_file_spectral_short_repeat, | ||
1077 | .write = write_file_spectral_short_repeat, | ||
1078 | .open = simple_open, | ||
1079 | .owner = THIS_MODULE, | ||
1080 | .llseek = default_llseek, | ||
1081 | }; | ||
1082 | |||
1083 | static ssize_t read_file_spectral_count(struct file *file, | ||
1084 | char __user *user_buf, | ||
1085 | size_t count, loff_t *ppos) | ||
1086 | { | ||
1087 | struct ath_softc *sc = file->private_data; | ||
1088 | char buf[32]; | ||
1089 | unsigned int len; | ||
1090 | |||
1091 | len = sprintf(buf, "%d\n", sc->spec_config.count); | ||
1092 | return simple_read_from_buffer(user_buf, count, ppos, buf, len); | ||
1093 | } | ||
1094 | |||
1095 | static ssize_t write_file_spectral_count(struct file *file, | ||
1096 | const char __user *user_buf, | ||
1097 | size_t count, loff_t *ppos) | ||
1098 | { | ||
1099 | struct ath_softc *sc = file->private_data; | ||
1100 | unsigned long val; | ||
1101 | char buf[32]; | ||
1102 | ssize_t len; | ||
1103 | |||
1104 | len = min(count, sizeof(buf) - 1); | ||
1105 | if (copy_from_user(buf, user_buf, len)) | ||
1106 | return -EFAULT; | ||
1107 | |||
1108 | buf[len] = '\0'; | ||
1109 | if (kstrtoul(buf, 0, &val)) | ||
1110 | return -EINVAL; | ||
1111 | |||
1112 | if (val < 0 || val > 255) | ||
1113 | return -EINVAL; | ||
1114 | |||
1115 | sc->spec_config.count = val; | ||
1116 | return count; | ||
1117 | } | ||
1118 | |||
1119 | static const struct file_operations fops_spectral_count = { | ||
1120 | .read = read_file_spectral_count, | ||
1121 | .write = write_file_spectral_count, | ||
1122 | .open = simple_open, | ||
1123 | .owner = THIS_MODULE, | ||
1124 | .llseek = default_llseek, | ||
1125 | }; | ||
1126 | |||
1127 | static ssize_t read_file_spectral_period(struct file *file, | ||
1128 | char __user *user_buf, | ||
1129 | size_t count, loff_t *ppos) | ||
1130 | { | ||
1131 | struct ath_softc *sc = file->private_data; | ||
1132 | char buf[32]; | ||
1133 | unsigned int len; | ||
1134 | |||
1135 | len = sprintf(buf, "%d\n", sc->spec_config.period); | ||
1136 | return simple_read_from_buffer(user_buf, count, ppos, buf, len); | ||
1137 | } | ||
1138 | |||
1139 | static ssize_t write_file_spectral_period(struct file *file, | ||
1140 | const char __user *user_buf, | ||
1141 | size_t count, loff_t *ppos) | ||
1142 | { | ||
1143 | struct ath_softc *sc = file->private_data; | ||
1144 | unsigned long val; | ||
1145 | char buf[32]; | ||
1146 | ssize_t len; | ||
1147 | |||
1148 | len = min(count, sizeof(buf) - 1); | ||
1149 | if (copy_from_user(buf, user_buf, len)) | ||
1150 | return -EFAULT; | ||
1151 | |||
1152 | buf[len] = '\0'; | ||
1153 | if (kstrtoul(buf, 0, &val)) | ||
1154 | return -EINVAL; | ||
1155 | |||
1156 | if (val < 0 || val > 255) | ||
1157 | return -EINVAL; | ||
1158 | |||
1159 | sc->spec_config.period = val; | ||
1160 | return count; | ||
1161 | } | ||
1162 | |||
1163 | static const struct file_operations fops_spectral_period = { | ||
1164 | .read = read_file_spectral_period, | ||
1165 | .write = write_file_spectral_period, | ||
1166 | .open = simple_open, | ||
1167 | .owner = THIS_MODULE, | ||
1168 | .llseek = default_llseek, | ||
1169 | }; | ||
1170 | |||
1171 | static ssize_t read_file_spectral_fft_period(struct file *file, | ||
1172 | char __user *user_buf, | ||
1173 | size_t count, loff_t *ppos) | ||
1174 | { | ||
1175 | struct ath_softc *sc = file->private_data; | ||
1176 | char buf[32]; | ||
1177 | unsigned int len; | ||
1178 | |||
1179 | len = sprintf(buf, "%d\n", sc->spec_config.fft_period); | ||
1180 | return simple_read_from_buffer(user_buf, count, ppos, buf, len); | ||
1181 | } | ||
1182 | |||
1183 | static ssize_t write_file_spectral_fft_period(struct file *file, | ||
1184 | const char __user *user_buf, | ||
1185 | size_t count, loff_t *ppos) | ||
1186 | { | ||
1187 | struct ath_softc *sc = file->private_data; | ||
1188 | unsigned long val; | ||
1189 | char buf[32]; | ||
1190 | ssize_t len; | ||
1191 | |||
1192 | len = min(count, sizeof(buf) - 1); | ||
1193 | if (copy_from_user(buf, user_buf, len)) | ||
1194 | return -EFAULT; | ||
1195 | |||
1196 | buf[len] = '\0'; | ||
1197 | if (kstrtoul(buf, 0, &val)) | ||
1198 | return -EINVAL; | ||
1199 | |||
1200 | if (val < 0 || val > 15) | ||
1201 | return -EINVAL; | ||
1202 | |||
1203 | sc->spec_config.fft_period = val; | ||
1204 | return count; | ||
1205 | } | ||
1206 | |||
1207 | static const struct file_operations fops_spectral_fft_period = { | ||
1208 | .read = read_file_spectral_fft_period, | ||
1209 | .write = write_file_spectral_fft_period, | ||
1210 | .open = simple_open, | ||
1211 | .owner = THIS_MODULE, | ||
1212 | .llseek = default_llseek, | ||
1213 | }; | ||
1214 | |||
1038 | static struct dentry *create_buf_file_handler(const char *filename, | 1215 | static struct dentry *create_buf_file_handler(const char *filename, |
1039 | struct dentry *parent, | 1216 | struct dentry *parent, |
1040 | umode_t mode, | 1217 | umode_t mode, |
@@ -1059,11 +1236,13 @@ static int remove_buf_file_handler(struct dentry *dentry) | |||
1059 | void ath_debug_send_fft_sample(struct ath_softc *sc, | 1236 | void ath_debug_send_fft_sample(struct ath_softc *sc, |
1060 | struct fft_sample_tlv *fft_sample_tlv) | 1237 | struct fft_sample_tlv *fft_sample_tlv) |
1061 | { | 1238 | { |
1239 | int length; | ||
1062 | if (!sc->rfs_chan_spec_scan) | 1240 | if (!sc->rfs_chan_spec_scan) |
1063 | return; | 1241 | return; |
1064 | 1242 | ||
1065 | relay_write(sc->rfs_chan_spec_scan, fft_sample_tlv, | 1243 | length = __be16_to_cpu(fft_sample_tlv->length) + |
1066 | fft_sample_tlv->length + sizeof(*fft_sample_tlv)); | 1244 | sizeof(*fft_sample_tlv); |
1245 | relay_write(sc->rfs_chan_spec_scan, fft_sample_tlv, length); | ||
1067 | } | 1246 | } |
1068 | 1247 | ||
1069 | static struct rchan_callbacks rfs_spec_scan_cb = { | 1248 | static struct rchan_callbacks rfs_spec_scan_cb = { |
@@ -1893,6 +2072,16 @@ int ath9k_init_debug(struct ath_hw *ah) | |||
1893 | debugfs_create_file("spectral_scan_ctl", S_IRUSR | S_IWUSR, | 2072 | debugfs_create_file("spectral_scan_ctl", S_IRUSR | S_IWUSR, |
1894 | sc->debug.debugfs_phy, sc, | 2073 | sc->debug.debugfs_phy, sc, |
1895 | &fops_spec_scan_ctl); | 2074 | &fops_spec_scan_ctl); |
2075 | debugfs_create_file("spectral_short_repeat", S_IRUSR | S_IWUSR, | ||
2076 | sc->debug.debugfs_phy, sc, | ||
2077 | &fops_spectral_short_repeat); | ||
2078 | debugfs_create_file("spectral_count", S_IRUSR | S_IWUSR, | ||
2079 | sc->debug.debugfs_phy, sc, &fops_spectral_count); | ||
2080 | debugfs_create_file("spectral_period", S_IRUSR | S_IWUSR, | ||
2081 | sc->debug.debugfs_phy, sc, &fops_spectral_period); | ||
2082 | debugfs_create_file("spectral_fft_period", S_IRUSR | S_IWUSR, | ||
2083 | sc->debug.debugfs_phy, sc, | ||
2084 | &fops_spectral_fft_period); | ||
1896 | 2085 | ||
1897 | #ifdef CONFIG_ATH9K_MAC_DEBUG | 2086 | #ifdef CONFIG_ATH9K_MAC_DEBUG |
1898 | debugfs_create_file("samples", S_IRUSR, sc->debug.debugfs_phy, sc, | 2087 | debugfs_create_file("samples", S_IRUSR, sc->debug.debugfs_phy, sc, |
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index a22c0d780700..410d6d8f1aa7 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h | |||
@@ -219,6 +219,7 @@ struct ath_tx_stats { | |||
219 | * @rx_too_many_frags_err: Frames dropped due to too-many-frags received. | 219 | * @rx_too_many_frags_err: Frames dropped due to too-many-frags received. |
220 | * @rx_beacons: No. of beacons received. | 220 | * @rx_beacons: No. of beacons received. |
221 | * @rx_frags: No. of rx-fragements received. | 221 | * @rx_frags: No. of rx-fragements received. |
222 | * @rx_spectral: No of spectral packets received. | ||
222 | */ | 223 | */ |
223 | struct ath_rx_stats { | 224 | struct ath_rx_stats { |
224 | u32 rx_pkts_all; | 225 | u32 rx_pkts_all; |
@@ -237,6 +238,7 @@ struct ath_rx_stats { | |||
237 | u32 rx_too_many_frags_err; | 238 | u32 rx_too_many_frags_err; |
238 | u32 rx_beacons; | 239 | u32 rx_beacons; |
239 | u32 rx_frags; | 240 | u32 rx_frags; |
241 | u32 rx_spectral; | ||
240 | }; | 242 | }; |
241 | 243 | ||
242 | struct ath_stats { | 244 | struct ath_stats { |
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 4b1abc7da98c..af932c9444de 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c | |||
@@ -497,6 +497,13 @@ static void ath9k_init_misc(struct ath_softc *sc) | |||
497 | 497 | ||
498 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) | 498 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) |
499 | sc->ant_comb.count = ATH_ANT_DIV_COMB_INIT_COUNT; | 499 | sc->ant_comb.count = ATH_ANT_DIV_COMB_INIT_COUNT; |
500 | |||
501 | sc->spec_config.enabled = 0; | ||
502 | sc->spec_config.short_repeat = true; | ||
503 | sc->spec_config.count = 8; | ||
504 | sc->spec_config.endless = false; | ||
505 | sc->spec_config.period = 0xFF; | ||
506 | sc->spec_config.fft_period = 0xF; | ||
500 | } | 507 | } |
501 | 508 | ||
502 | static void ath9k_eeprom_request_cb(const struct firmware *eeprom_blob, | 509 | static void ath9k_eeprom_request_cb(const struct firmware *eeprom_blob, |
@@ -915,7 +922,7 @@ static void ath9k_deinit_softc(struct ath_softc *sc) | |||
915 | 922 | ||
916 | ath9k_eeprom_release(sc); | 923 | ath9k_eeprom_release(sc); |
917 | 924 | ||
918 | if (sc->rfs_chan_spec_scan) { | 925 | if (config_enabled(CONFIG_ATH9K_DEBUGFS) && sc->rfs_chan_spec_scan) { |
919 | relay_close(sc->rfs_chan_spec_scan); | 926 | relay_close(sc->rfs_chan_spec_scan); |
920 | sc->rfs_chan_spec_scan = NULL; | 927 | sc->rfs_chan_spec_scan = NULL; |
921 | } | 928 | } |
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index b42be910a83d..811007ec07a7 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c | |||
@@ -605,13 +605,13 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, | |||
605 | * reported, then decryption and MIC errors are irrelevant, | 605 | * reported, then decryption and MIC errors are irrelevant, |
606 | * the frame is going to be dropped either way | 606 | * the frame is going to be dropped either way |
607 | */ | 607 | */ |
608 | if (ads.ds_rxstatus8 & AR_CRCErr) | 608 | if (ads.ds_rxstatus8 & AR_PHYErr) { |
609 | rs->rs_status |= ATH9K_RXERR_CRC; | ||
610 | else if (ads.ds_rxstatus8 & AR_PHYErr) { | ||
611 | rs->rs_status |= ATH9K_RXERR_PHY; | 609 | rs->rs_status |= ATH9K_RXERR_PHY; |
612 | phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode); | 610 | phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode); |
613 | rs->rs_phyerr = phyerr; | 611 | rs->rs_phyerr = phyerr; |
614 | } else if (ads.ds_rxstatus8 & AR_DecryptCRCErr) | 612 | } else if (ads.ds_rxstatus8 & AR_CRCErr) |
613 | rs->rs_status |= ATH9K_RXERR_CRC; | ||
614 | else if (ads.ds_rxstatus8 & AR_DecryptCRCErr) | ||
615 | rs->rs_status |= ATH9K_RXERR_DECRYPT; | 615 | rs->rs_status |= ATH9K_RXERR_DECRYPT; |
616 | else if (ads.ds_rxstatus8 & AR_MichaelErr) | 616 | else if (ads.ds_rxstatus8 & AR_MichaelErr) |
617 | rs->rs_status |= ATH9K_RXERR_MIC; | 617 | rs->rs_status |= ATH9K_RXERR_MIC; |
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 4b72b660f180..5432f1247e2e 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -1099,45 +1099,34 @@ int ath9k_spectral_scan_config(struct ieee80211_hw *hw, | |||
1099 | struct ath_softc *sc = hw->priv; | 1099 | struct ath_softc *sc = hw->priv; |
1100 | struct ath_hw *ah = sc->sc_ah; | 1100 | struct ath_hw *ah = sc->sc_ah; |
1101 | struct ath_common *common = ath9k_hw_common(ah); | 1101 | struct ath_common *common = ath9k_hw_common(ah); |
1102 | struct ath_spec_scan param; | ||
1103 | 1102 | ||
1104 | if (!ath9k_hw_ops(ah)->spectral_scan_trigger) { | 1103 | if (!ath9k_hw_ops(ah)->spectral_scan_trigger) { |
1105 | ath_err(common, "spectrum analyzer not implemented on this hardware\n"); | 1104 | ath_err(common, "spectrum analyzer not implemented on this hardware\n"); |
1106 | return -1; | 1105 | return -1; |
1107 | } | 1106 | } |
1108 | 1107 | ||
1109 | /* NOTE: this will generate a few samples ... | ||
1110 | * | ||
1111 | * TODO: review default parameters, and/or define an interface to set | ||
1112 | * them. | ||
1113 | */ | ||
1114 | param.enabled = 1; | ||
1115 | param.short_repeat = true; | ||
1116 | param.count = 8; | ||
1117 | param.endless = false; | ||
1118 | param.period = 0xFF; | ||
1119 | param.fft_period = 0xF; | ||
1120 | |||
1121 | switch (spectral_mode) { | 1108 | switch (spectral_mode) { |
1122 | case SPECTRAL_DISABLED: | 1109 | case SPECTRAL_DISABLED: |
1123 | param.enabled = 0; | 1110 | sc->spec_config.enabled = 0; |
1124 | break; | 1111 | break; |
1125 | case SPECTRAL_BACKGROUND: | 1112 | case SPECTRAL_BACKGROUND: |
1126 | /* send endless samples. | 1113 | /* send endless samples. |
1127 | * TODO: is this really useful for "background"? | 1114 | * TODO: is this really useful for "background"? |
1128 | */ | 1115 | */ |
1129 | param.endless = 1; | 1116 | sc->spec_config.endless = 1; |
1117 | sc->spec_config.enabled = 1; | ||
1130 | break; | 1118 | break; |
1131 | case SPECTRAL_CHANSCAN: | 1119 | case SPECTRAL_CHANSCAN: |
1132 | break; | ||
1133 | case SPECTRAL_MANUAL: | 1120 | case SPECTRAL_MANUAL: |
1121 | sc->spec_config.endless = 0; | ||
1122 | sc->spec_config.enabled = 1; | ||
1134 | break; | 1123 | break; |
1135 | default: | 1124 | default: |
1136 | return -1; | 1125 | return -1; |
1137 | } | 1126 | } |
1138 | 1127 | ||
1139 | ath9k_ps_wakeup(sc); | 1128 | ath9k_ps_wakeup(sc); |
1140 | ath9k_hw_ops(ah)->spectral_scan_config(ah, ¶m); | 1129 | ath9k_hw_ops(ah)->spectral_scan_config(ah, &sc->spec_config); |
1141 | ath9k_ps_restore(sc); | 1130 | ath9k_ps_restore(sc); |
1142 | 1131 | ||
1143 | sc->spectral_mode = spectral_mode; | 1132 | sc->spectral_mode = spectral_mode; |
diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c index d2074334ec9b..815bee21c19a 100644 --- a/drivers/net/wireless/ath/ath9k/mci.c +++ b/drivers/net/wireless/ath/ath9k/mci.c | |||
@@ -474,8 +474,6 @@ void ath_mci_cleanup(struct ath_softc *sc) | |||
474 | { | 474 | { |
475 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 475 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
476 | struct ath_hw *ah = sc->sc_ah; | 476 | struct ath_hw *ah = sc->sc_ah; |
477 | struct ath_mci_coex *mci = &sc->mci_coex; | ||
478 | struct ath_mci_buf *buf = &mci->sched_buf; | ||
479 | 477 | ||
480 | ar9003_mci_cleanup(ah); | 478 | ar9003_mci_cleanup(ah); |
481 | 479 | ||
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index d7c129bb571b..2d0fd17a1917 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c | |||
@@ -1016,18 +1016,20 @@ static void ath9k_rx_skb_postprocess(struct ath_common *common, | |||
1016 | rxs->flag &= ~RX_FLAG_DECRYPTED; | 1016 | rxs->flag &= ~RX_FLAG_DECRYPTED; |
1017 | } | 1017 | } |
1018 | 1018 | ||
1019 | #ifdef CONFIG_ATH9K_DEBUGFS | ||
1019 | static s8 fix_rssi_inv_only(u8 rssi_val) | 1020 | static s8 fix_rssi_inv_only(u8 rssi_val) |
1020 | { | 1021 | { |
1021 | if (rssi_val == 128) | 1022 | if (rssi_val == 128) |
1022 | rssi_val = 0; | 1023 | rssi_val = 0; |
1023 | return (s8) rssi_val; | 1024 | return (s8) rssi_val; |
1024 | } | 1025 | } |
1026 | #endif | ||
1025 | 1027 | ||
1026 | 1028 | /* returns 1 if this was a spectral frame, even if not handled. */ | |
1027 | static void ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr, | 1029 | static int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr, |
1028 | struct ath_rx_status *rs, u64 tsf) | 1030 | struct ath_rx_status *rs, u64 tsf) |
1029 | { | 1031 | { |
1030 | #ifdef CONFIG_ATH_DEBUG | 1032 | #ifdef CONFIG_ATH9K_DEBUGFS |
1031 | struct ath_hw *ah = sc->sc_ah; | 1033 | struct ath_hw *ah = sc->sc_ah; |
1032 | u8 bins[SPECTRAL_HT20_NUM_BINS]; | 1034 | u8 bins[SPECTRAL_HT20_NUM_BINS]; |
1033 | u8 *vdata = (u8 *)hdr; | 1035 | u8 *vdata = (u8 *)hdr; |
@@ -1035,7 +1037,8 @@ static void ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr, | |||
1035 | struct ath_radar_info *radar_info; | 1037 | struct ath_radar_info *radar_info; |
1036 | struct ath_ht20_mag_info *mag_info; | 1038 | struct ath_ht20_mag_info *mag_info; |
1037 | int len = rs->rs_datalen; | 1039 | int len = rs->rs_datalen; |
1038 | int i, dc_pos; | 1040 | int dc_pos; |
1041 | u16 length, max_magnitude; | ||
1039 | 1042 | ||
1040 | /* AR9280 and before report via ATH9K_PHYERR_RADAR, AR93xx and newer | 1043 | /* AR9280 and before report via ATH9K_PHYERR_RADAR, AR93xx and newer |
1041 | * via ATH9K_PHYERR_SPECTRAL. Haven't seen ATH9K_PHYERR_FALSE_RADAR_EXT | 1044 | * via ATH9K_PHYERR_SPECTRAL. Haven't seen ATH9K_PHYERR_FALSE_RADAR_EXT |
@@ -1044,7 +1047,14 @@ static void ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr, | |||
1044 | if (rs->rs_phyerr != ATH9K_PHYERR_RADAR && | 1047 | if (rs->rs_phyerr != ATH9K_PHYERR_RADAR && |
1045 | rs->rs_phyerr != ATH9K_PHYERR_FALSE_RADAR_EXT && | 1048 | rs->rs_phyerr != ATH9K_PHYERR_FALSE_RADAR_EXT && |
1046 | rs->rs_phyerr != ATH9K_PHYERR_SPECTRAL) | 1049 | rs->rs_phyerr != ATH9K_PHYERR_SPECTRAL) |
1047 | return; | 1050 | return 0; |
1051 | |||
1052 | /* check if spectral scan bit is set. This does not have to be checked | ||
1053 | * if received through a SPECTRAL phy error, but shouldn't hurt. | ||
1054 | */ | ||
1055 | radar_info = ((struct ath_radar_info *)&vdata[len]) - 1; | ||
1056 | if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK)) | ||
1057 | return 0; | ||
1048 | 1058 | ||
1049 | /* Variation in the data length is possible and will be fixed later. | 1059 | /* Variation in the data length is possible and will be fixed later. |
1050 | * Note that we only support HT20 for now. | 1060 | * Note that we only support HT20 for now. |
@@ -1053,19 +1063,13 @@ static void ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr, | |||
1053 | */ | 1063 | */ |
1054 | if ((len > SPECTRAL_HT20_TOTAL_DATA_LEN + 2) || | 1064 | if ((len > SPECTRAL_HT20_TOTAL_DATA_LEN + 2) || |
1055 | (len < SPECTRAL_HT20_TOTAL_DATA_LEN - 1)) | 1065 | (len < SPECTRAL_HT20_TOTAL_DATA_LEN - 1)) |
1056 | return; | 1066 | return 1; |
1057 | |||
1058 | /* check if spectral scan bit is set. This does not have to be checked | ||
1059 | * if received through a SPECTRAL phy error, but shouldn't hurt. | ||
1060 | */ | ||
1061 | radar_info = ((struct ath_radar_info *)&vdata[len]) - 1; | ||
1062 | if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK)) | ||
1063 | return; | ||
1064 | 1067 | ||
1065 | fft_sample.tlv.type = ATH_FFT_SAMPLE_HT20; | 1068 | fft_sample.tlv.type = ATH_FFT_SAMPLE_HT20; |
1066 | fft_sample.tlv.length = sizeof(fft_sample) - sizeof(fft_sample.tlv); | 1069 | length = sizeof(fft_sample) - sizeof(fft_sample.tlv); |
1070 | fft_sample.tlv.length = __cpu_to_be16(length); | ||
1067 | 1071 | ||
1068 | fft_sample.freq = ah->curchan->chan->center_freq; | 1072 | fft_sample.freq = __cpu_to_be16(ah->curchan->chan->center_freq); |
1069 | fft_sample.rssi = fix_rssi_inv_only(rs->rs_rssi_ctl0); | 1073 | fft_sample.rssi = fix_rssi_inv_only(rs->rs_rssi_ctl0); |
1070 | fft_sample.noise = ah->noise; | 1074 | fft_sample.noise = ah->noise; |
1071 | 1075 | ||
@@ -1093,7 +1097,7 @@ static void ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr, | |||
1093 | memcpy(&bins[32], &vdata[33], SPECTRAL_HT20_NUM_BINS - 32); | 1097 | memcpy(&bins[32], &vdata[33], SPECTRAL_HT20_NUM_BINS - 32); |
1094 | break; | 1098 | break; |
1095 | default: | 1099 | default: |
1096 | return; | 1100 | return 1; |
1097 | } | 1101 | } |
1098 | 1102 | ||
1099 | /* DC value (value in the middle) is the blind spot of the spectral | 1103 | /* DC value (value in the middle) is the blind spot of the spectral |
@@ -1105,19 +1109,41 @@ static void ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr, | |||
1105 | /* mag data is at the end of the frame, in front of radar_info */ | 1109 | /* mag data is at the end of the frame, in front of radar_info */ |
1106 | mag_info = ((struct ath_ht20_mag_info *)radar_info) - 1; | 1110 | mag_info = ((struct ath_ht20_mag_info *)radar_info) - 1; |
1107 | 1111 | ||
1108 | /* Apply exponent and grab further auxiliary information. */ | 1112 | /* copy raw bins without scaling them */ |
1109 | for (i = 0; i < SPECTRAL_HT20_NUM_BINS; i++) | 1113 | memcpy(fft_sample.data, bins, SPECTRAL_HT20_NUM_BINS); |
1110 | fft_sample.data[i] = bins[i] << mag_info->max_exp; | 1114 | fft_sample.max_exp = mag_info->max_exp & 0xf; |
1111 | 1115 | ||
1112 | fft_sample.max_magnitude = spectral_max_magnitude(mag_info->all_bins); | 1116 | max_magnitude = spectral_max_magnitude(mag_info->all_bins); |
1117 | fft_sample.max_magnitude = __cpu_to_be16(max_magnitude); | ||
1113 | fft_sample.max_index = spectral_max_index(mag_info->all_bins); | 1118 | fft_sample.max_index = spectral_max_index(mag_info->all_bins); |
1114 | fft_sample.bitmap_weight = spectral_bitmap_weight(mag_info->all_bins); | 1119 | fft_sample.bitmap_weight = spectral_bitmap_weight(mag_info->all_bins); |
1115 | fft_sample.tsf = tsf; | 1120 | fft_sample.tsf = __cpu_to_be64(tsf); |
1116 | 1121 | ||
1117 | ath_debug_send_fft_sample(sc, &fft_sample.tlv); | 1122 | ath_debug_send_fft_sample(sc, &fft_sample.tlv); |
1123 | return 1; | ||
1124 | #else | ||
1125 | return 0; | ||
1118 | #endif | 1126 | #endif |
1119 | } | 1127 | } |
1120 | 1128 | ||
1129 | static void ath9k_apply_ampdu_details(struct ath_softc *sc, | ||
1130 | struct ath_rx_status *rs, struct ieee80211_rx_status *rxs) | ||
1131 | { | ||
1132 | if (rs->rs_isaggr) { | ||
1133 | rxs->flag |= RX_FLAG_AMPDU_DETAILS | RX_FLAG_AMPDU_LAST_KNOWN; | ||
1134 | |||
1135 | rxs->ampdu_reference = sc->rx.ampdu_ref; | ||
1136 | |||
1137 | if (!rs->rs_moreaggr) { | ||
1138 | rxs->flag |= RX_FLAG_AMPDU_IS_LAST; | ||
1139 | sc->rx.ampdu_ref++; | ||
1140 | } | ||
1141 | |||
1142 | if (rs->rs_flags & ATH9K_RX_DELIM_CRC_PRE) | ||
1143 | rxs->flag |= RX_FLAG_AMPDU_DELIM_CRC_ERROR; | ||
1144 | } | ||
1145 | } | ||
1146 | |||
1121 | int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) | 1147 | int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) |
1122 | { | 1148 | { |
1123 | struct ath_buf *bf; | 1149 | struct ath_buf *bf; |
@@ -1202,8 +1228,12 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) | |||
1202 | unlikely(tsf_lower - rs.rs_tstamp > 0x10000000)) | 1228 | unlikely(tsf_lower - rs.rs_tstamp > 0x10000000)) |
1203 | rxs->mactime += 0x100000000ULL; | 1229 | rxs->mactime += 0x100000000ULL; |
1204 | 1230 | ||
1205 | if ((rs.rs_status & ATH9K_RXERR_PHY)) | 1231 | if (rs.rs_status & ATH9K_RXERR_PHY) { |
1206 | ath_process_fft(sc, hdr, &rs, rxs->mactime); | 1232 | if (ath_process_fft(sc, hdr, &rs, rxs->mactime)) { |
1233 | RX_STAT_INC(rx_spectral); | ||
1234 | goto requeue_drop_frag; | ||
1235 | } | ||
1236 | } | ||
1207 | 1237 | ||
1208 | retval = ath9k_rx_skb_preprocess(common, hw, hdr, &rs, | 1238 | retval = ath9k_rx_skb_preprocess(common, hw, hdr, &rs, |
1209 | rxs, &decrypt_error); | 1239 | rxs, &decrypt_error); |
@@ -1320,6 +1350,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) | |||
1320 | if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx == 3) | 1350 | if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx == 3) |
1321 | ath_ant_comb_scan(sc, &rs); | 1351 | ath_ant_comb_scan(sc, &rs); |
1322 | 1352 | ||
1353 | ath9k_apply_ampdu_details(sc, &rs, rxs); | ||
1354 | |||
1323 | ieee80211_rx(hw, skb); | 1355 | ieee80211_rx(hw, skb); |
1324 | 1356 | ||
1325 | requeue_drop_frag: | 1357 | requeue_drop_frag: |
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 116f4e807ae1..002851fceb2f 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c | |||
@@ -204,7 +204,6 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, | |||
204 | break; | 204 | break; |
205 | default: | 205 | default: |
206 | return -EOPNOTSUPP; | 206 | return -EOPNOTSUPP; |
207 | |||
208 | } | 207 | } |
209 | 208 | ||
210 | /* FW don't support scan after connection attempt */ | 209 | /* FW don't support scan after connection attempt */ |
@@ -228,8 +227,8 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, | |||
228 | } | 227 | } |
229 | /* 0-based channel indexes */ | 228 | /* 0-based channel indexes */ |
230 | cmd.cmd.channel_list[cmd.cmd.num_channels++].channel = ch - 1; | 229 | cmd.cmd.channel_list[cmd.cmd.num_channels++].channel = ch - 1; |
231 | wil_dbg(wil, "Scan for ch %d : %d MHz\n", ch, | 230 | wil_dbg_misc(wil, "Scan for ch %d : %d MHz\n", ch, |
232 | request->channels[i]->center_freq); | 231 | request->channels[i]->center_freq); |
233 | } | 232 | } |
234 | 233 | ||
235 | return wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) + | 234 | return wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) + |
@@ -425,8 +424,8 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, | |||
425 | return -EINVAL; | 424 | return -EINVAL; |
426 | } | 425 | } |
427 | 426 | ||
428 | wil_dbg(wil, "AP on Channel %d %d MHz, %s\n", channel->hw_value, | 427 | wil_dbg_misc(wil, "AP on Channel %d %d MHz, %s\n", channel->hw_value, |
429 | channel->center_freq, info->privacy ? "secure" : "open"); | 428 | channel->center_freq, info->privacy ? "secure" : "open"); |
430 | print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET, | 429 | print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET, |
431 | info->ssid, info->ssid_len); | 430 | info->ssid, info->ssid_len); |
432 | 431 | ||
diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index 38049da71049..dc97e7b2609c 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c | |||
@@ -38,7 +38,9 @@ | |||
38 | #define WIL6210_IMC_RX BIT_DMA_EP_RX_ICR_RX_DONE | 38 | #define WIL6210_IMC_RX BIT_DMA_EP_RX_ICR_RX_DONE |
39 | #define WIL6210_IMC_TX (BIT_DMA_EP_TX_ICR_TX_DONE | \ | 39 | #define WIL6210_IMC_TX (BIT_DMA_EP_TX_ICR_TX_DONE | \ |
40 | BIT_DMA_EP_TX_ICR_TX_DONE_N(0)) | 40 | BIT_DMA_EP_TX_ICR_TX_DONE_N(0)) |
41 | #define WIL6210_IMC_MISC (ISR_MISC_FW_READY | ISR_MISC_MBOX_EVT) | 41 | #define WIL6210_IMC_MISC (ISR_MISC_FW_READY | \ |
42 | ISR_MISC_MBOX_EVT | \ | ||
43 | ISR_MISC_FW_ERROR) | ||
42 | 44 | ||
43 | #define WIL6210_IRQ_PSEUDO_MASK (u32)(~(BIT_DMA_PSEUDO_CAUSE_RX | \ | 45 | #define WIL6210_IRQ_PSEUDO_MASK (u32)(~(BIT_DMA_PSEUDO_CAUSE_RX | \ |
44 | BIT_DMA_PSEUDO_CAUSE_TX | \ | 46 | BIT_DMA_PSEUDO_CAUSE_TX | \ |
@@ -50,7 +52,6 @@ | |||
50 | 52 | ||
51 | static inline void wil_icr_clear(u32 x, void __iomem *addr) | 53 | static inline void wil_icr_clear(u32 x, void __iomem *addr) |
52 | { | 54 | { |
53 | |||
54 | } | 55 | } |
55 | #else /* defined(CONFIG_WIL6210_ISR_COR) */ | 56 | #else /* defined(CONFIG_WIL6210_ISR_COR) */ |
56 | /* configure to Write-1-to-Clear mode */ | 57 | /* configure to Write-1-to-Clear mode */ |
@@ -94,7 +95,7 @@ static void wil6210_mask_irq_misc(struct wil6210_priv *wil) | |||
94 | 95 | ||
95 | static void wil6210_mask_irq_pseudo(struct wil6210_priv *wil) | 96 | static void wil6210_mask_irq_pseudo(struct wil6210_priv *wil) |
96 | { | 97 | { |
97 | wil_dbg_IRQ(wil, "%s()\n", __func__); | 98 | wil_dbg_irq(wil, "%s()\n", __func__); |
98 | 99 | ||
99 | iowrite32(WIL6210_IRQ_DISABLE, wil->csr + | 100 | iowrite32(WIL6210_IRQ_DISABLE, wil->csr + |
100 | HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW)); | 101 | HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW)); |
@@ -125,7 +126,7 @@ static void wil6210_unmask_irq_misc(struct wil6210_priv *wil) | |||
125 | 126 | ||
126 | static void wil6210_unmask_irq_pseudo(struct wil6210_priv *wil) | 127 | static void wil6210_unmask_irq_pseudo(struct wil6210_priv *wil) |
127 | { | 128 | { |
128 | wil_dbg_IRQ(wil, "%s()\n", __func__); | 129 | wil_dbg_irq(wil, "%s()\n", __func__); |
129 | 130 | ||
130 | set_bit(wil_status_irqen, &wil->status); | 131 | set_bit(wil_status_irqen, &wil->status); |
131 | 132 | ||
@@ -135,7 +136,7 @@ static void wil6210_unmask_irq_pseudo(struct wil6210_priv *wil) | |||
135 | 136 | ||
136 | void wil6210_disable_irq(struct wil6210_priv *wil) | 137 | void wil6210_disable_irq(struct wil6210_priv *wil) |
137 | { | 138 | { |
138 | wil_dbg_IRQ(wil, "%s()\n", __func__); | 139 | wil_dbg_irq(wil, "%s()\n", __func__); |
139 | 140 | ||
140 | wil6210_mask_irq_tx(wil); | 141 | wil6210_mask_irq_tx(wil); |
141 | wil6210_mask_irq_rx(wil); | 142 | wil6210_mask_irq_rx(wil); |
@@ -145,7 +146,7 @@ void wil6210_disable_irq(struct wil6210_priv *wil) | |||
145 | 146 | ||
146 | void wil6210_enable_irq(struct wil6210_priv *wil) | 147 | void wil6210_enable_irq(struct wil6210_priv *wil) |
147 | { | 148 | { |
148 | wil_dbg_IRQ(wil, "%s()\n", __func__); | 149 | wil_dbg_irq(wil, "%s()\n", __func__); |
149 | 150 | ||
150 | iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_RX_ICR) + | 151 | iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_RX_ICR) + |
151 | offsetof(struct RGF_ICR, ICC)); | 152 | offsetof(struct RGF_ICR, ICC)); |
@@ -167,7 +168,7 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie) | |||
167 | HOSTADDR(RGF_DMA_EP_RX_ICR) + | 168 | HOSTADDR(RGF_DMA_EP_RX_ICR) + |
168 | offsetof(struct RGF_ICR, ICR)); | 169 | offsetof(struct RGF_ICR, ICR)); |
169 | 170 | ||
170 | wil_dbg_IRQ(wil, "ISR RX 0x%08x\n", isr); | 171 | wil_dbg_irq(wil, "ISR RX 0x%08x\n", isr); |
171 | 172 | ||
172 | if (!isr) { | 173 | if (!isr) { |
173 | wil_err(wil, "spurious IRQ: RX\n"); | 174 | wil_err(wil, "spurious IRQ: RX\n"); |
@@ -177,7 +178,7 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie) | |||
177 | wil6210_mask_irq_rx(wil); | 178 | wil6210_mask_irq_rx(wil); |
178 | 179 | ||
179 | if (isr & BIT_DMA_EP_RX_ICR_RX_DONE) { | 180 | if (isr & BIT_DMA_EP_RX_ICR_RX_DONE) { |
180 | wil_dbg_IRQ(wil, "RX done\n"); | 181 | wil_dbg_irq(wil, "RX done\n"); |
181 | isr &= ~BIT_DMA_EP_RX_ICR_RX_DONE; | 182 | isr &= ~BIT_DMA_EP_RX_ICR_RX_DONE; |
182 | wil_rx_handle(wil); | 183 | wil_rx_handle(wil); |
183 | } | 184 | } |
@@ -197,7 +198,7 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie) | |||
197 | HOSTADDR(RGF_DMA_EP_TX_ICR) + | 198 | HOSTADDR(RGF_DMA_EP_TX_ICR) + |
198 | offsetof(struct RGF_ICR, ICR)); | 199 | offsetof(struct RGF_ICR, ICR)); |
199 | 200 | ||
200 | wil_dbg_IRQ(wil, "ISR TX 0x%08x\n", isr); | 201 | wil_dbg_irq(wil, "ISR TX 0x%08x\n", isr); |
201 | 202 | ||
202 | if (!isr) { | 203 | if (!isr) { |
203 | wil_err(wil, "spurious IRQ: TX\n"); | 204 | wil_err(wil, "spurious IRQ: TX\n"); |
@@ -208,13 +209,13 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie) | |||
208 | 209 | ||
209 | if (isr & BIT_DMA_EP_TX_ICR_TX_DONE) { | 210 | if (isr & BIT_DMA_EP_TX_ICR_TX_DONE) { |
210 | uint i; | 211 | uint i; |
211 | wil_dbg_IRQ(wil, "TX done\n"); | 212 | wil_dbg_irq(wil, "TX done\n"); |
212 | isr &= ~BIT_DMA_EP_TX_ICR_TX_DONE; | 213 | isr &= ~BIT_DMA_EP_TX_ICR_TX_DONE; |
213 | for (i = 0; i < 24; i++) { | 214 | for (i = 0; i < 24; i++) { |
214 | u32 mask = BIT_DMA_EP_TX_ICR_TX_DONE_N(i); | 215 | u32 mask = BIT_DMA_EP_TX_ICR_TX_DONE_N(i); |
215 | if (isr & mask) { | 216 | if (isr & mask) { |
216 | isr &= ~mask; | 217 | isr &= ~mask; |
217 | wil_dbg_IRQ(wil, "TX done(%i)\n", i); | 218 | wil_dbg_irq(wil, "TX done(%i)\n", i); |
218 | wil_tx_complete(wil, i); | 219 | wil_tx_complete(wil, i); |
219 | } | 220 | } |
220 | } | 221 | } |
@@ -228,6 +229,17 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie) | |||
228 | return IRQ_HANDLED; | 229 | return IRQ_HANDLED; |
229 | } | 230 | } |
230 | 231 | ||
232 | static void wil_notify_fw_error(struct wil6210_priv *wil) | ||
233 | { | ||
234 | struct device *dev = &wil_to_ndev(wil)->dev; | ||
235 | char *envp[3] = { | ||
236 | [0] = "SOURCE=wil6210", | ||
237 | [1] = "EVENT=FW_ERROR", | ||
238 | [2] = NULL, | ||
239 | }; | ||
240 | kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp); | ||
241 | } | ||
242 | |||
231 | static irqreturn_t wil6210_irq_misc(int irq, void *cookie) | 243 | static irqreturn_t wil6210_irq_misc(int irq, void *cookie) |
232 | { | 244 | { |
233 | struct wil6210_priv *wil = cookie; | 245 | struct wil6210_priv *wil = cookie; |
@@ -235,7 +247,7 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie) | |||
235 | HOSTADDR(RGF_DMA_EP_MISC_ICR) + | 247 | HOSTADDR(RGF_DMA_EP_MISC_ICR) + |
236 | offsetof(struct RGF_ICR, ICR)); | 248 | offsetof(struct RGF_ICR, ICR)); |
237 | 249 | ||
238 | wil_dbg_IRQ(wil, "ISR MISC 0x%08x\n", isr); | 250 | wil_dbg_irq(wil, "ISR MISC 0x%08x\n", isr); |
239 | 251 | ||
240 | if (!isr) { | 252 | if (!isr) { |
241 | wil_err(wil, "spurious IRQ: MISC\n"); | 253 | wil_err(wil, "spurious IRQ: MISC\n"); |
@@ -244,8 +256,15 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie) | |||
244 | 256 | ||
245 | wil6210_mask_irq_misc(wil); | 257 | wil6210_mask_irq_misc(wil); |
246 | 258 | ||
259 | if (isr & ISR_MISC_FW_ERROR) { | ||
260 | wil_dbg_irq(wil, "IRQ: Firmware error\n"); | ||
261 | clear_bit(wil_status_fwready, &wil->status); | ||
262 | wil_notify_fw_error(wil); | ||
263 | isr &= ~ISR_MISC_FW_ERROR; | ||
264 | } | ||
265 | |||
247 | if (isr & ISR_MISC_FW_READY) { | 266 | if (isr & ISR_MISC_FW_READY) { |
248 | wil_dbg_IRQ(wil, "IRQ: FW ready\n"); | 267 | wil_dbg_irq(wil, "IRQ: FW ready\n"); |
249 | /** | 268 | /** |
250 | * Actual FW ready indicated by the | 269 | * Actual FW ready indicated by the |
251 | * WMI_FW_READY_EVENTID | 270 | * WMI_FW_READY_EVENTID |
@@ -268,10 +287,10 @@ static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie) | |||
268 | struct wil6210_priv *wil = cookie; | 287 | struct wil6210_priv *wil = cookie; |
269 | u32 isr = wil->isr_misc; | 288 | u32 isr = wil->isr_misc; |
270 | 289 | ||
271 | wil_dbg_IRQ(wil, "Thread ISR MISC 0x%08x\n", isr); | 290 | wil_dbg_irq(wil, "Thread ISR MISC 0x%08x\n", isr); |
272 | 291 | ||
273 | if (isr & ISR_MISC_MBOX_EVT) { | 292 | if (isr & ISR_MISC_MBOX_EVT) { |
274 | wil_dbg_IRQ(wil, "MBOX event\n"); | 293 | wil_dbg_irq(wil, "MBOX event\n"); |
275 | wmi_recv_cmd(wil); | 294 | wmi_recv_cmd(wil); |
276 | isr &= ~ISR_MISC_MBOX_EVT; | 295 | isr &= ~ISR_MISC_MBOX_EVT; |
277 | } | 296 | } |
@@ -293,7 +312,7 @@ static irqreturn_t wil6210_thread_irq(int irq, void *cookie) | |||
293 | { | 312 | { |
294 | struct wil6210_priv *wil = cookie; | 313 | struct wil6210_priv *wil = cookie; |
295 | 314 | ||
296 | wil_dbg_IRQ(wil, "Thread IRQ\n"); | 315 | wil_dbg_irq(wil, "Thread IRQ\n"); |
297 | /* Discover real IRQ cause */ | 316 | /* Discover real IRQ cause */ |
298 | if (wil->isr_misc) | 317 | if (wil->isr_misc) |
299 | wil6210_irq_misc_thread(irq, cookie); | 318 | wil6210_irq_misc_thread(irq, cookie); |
@@ -370,6 +389,8 @@ static irqreturn_t wil6210_hardirq(int irq, void *cookie) | |||
370 | if (wil6210_debug_irq_mask(wil, pseudo_cause)) | 389 | if (wil6210_debug_irq_mask(wil, pseudo_cause)) |
371 | return IRQ_NONE; | 390 | return IRQ_NONE; |
372 | 391 | ||
392 | wil_dbg_irq(wil, "Pseudo IRQ 0x%08x\n", pseudo_cause); | ||
393 | |||
373 | wil6210_mask_irq_pseudo(wil); | 394 | wil6210_mask_irq_pseudo(wil); |
374 | 395 | ||
375 | /* Discover real IRQ cause | 396 | /* Discover real IRQ cause |
@@ -401,8 +422,6 @@ static irqreturn_t wil6210_hardirq(int irq, void *cookie) | |||
401 | if (rc != IRQ_WAKE_THREAD) | 422 | if (rc != IRQ_WAKE_THREAD) |
402 | wil6210_unmask_irq_pseudo(wil); | 423 | wil6210_unmask_irq_pseudo(wil); |
403 | 424 | ||
404 | wil_dbg_IRQ(wil, "Hard IRQ 0x%08x\n", pseudo_cause); | ||
405 | |||
406 | return rc; | 425 | return rc; |
407 | } | 426 | } |
408 | 427 | ||
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 95fcd361322b..761c389586d4 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c | |||
@@ -64,7 +64,7 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, void *bssid) | |||
64 | struct net_device *ndev = wil_to_ndev(wil); | 64 | struct net_device *ndev = wil_to_ndev(wil); |
65 | struct wireless_dev *wdev = wil->wdev; | 65 | struct wireless_dev *wdev = wil->wdev; |
66 | 66 | ||
67 | wil_dbg(wil, "%s()\n", __func__); | 67 | wil_dbg_misc(wil, "%s()\n", __func__); |
68 | 68 | ||
69 | wil_link_off(wil); | 69 | wil_link_off(wil); |
70 | clear_bit(wil_status_fwconnected, &wil->status); | 70 | clear_bit(wil_status_fwconnected, &wil->status); |
@@ -80,11 +80,13 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, void *bssid) | |||
80 | GFP_KERNEL); | 80 | GFP_KERNEL); |
81 | break; | 81 | break; |
82 | default: | 82 | default: |
83 | ; | 83 | break; |
84 | } | 84 | } |
85 | 85 | ||
86 | for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) | 86 | for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) |
87 | wil_vring_fini_tx(wil, i); | 87 | wil_vring_fini_tx(wil, i); |
88 | |||
89 | clear_bit(wil_status_dontscan, &wil->status); | ||
88 | } | 90 | } |
89 | 91 | ||
90 | static void wil_disconnect_worker(struct work_struct *work) | 92 | static void wil_disconnect_worker(struct work_struct *work) |
@@ -99,7 +101,7 @@ static void wil_connect_timer_fn(ulong x) | |||
99 | { | 101 | { |
100 | struct wil6210_priv *wil = (void *)x; | 102 | struct wil6210_priv *wil = (void *)x; |
101 | 103 | ||
102 | wil_dbg(wil, "Connect timeout\n"); | 104 | wil_dbg_misc(wil, "Connect timeout\n"); |
103 | 105 | ||
104 | /* reschedule to thread context - disconnect won't | 106 | /* reschedule to thread context - disconnect won't |
105 | * run from atomic context | 107 | * run from atomic context |
@@ -107,9 +109,18 @@ static void wil_connect_timer_fn(ulong x) | |||
107 | schedule_work(&wil->disconnect_worker); | 109 | schedule_work(&wil->disconnect_worker); |
108 | } | 110 | } |
109 | 111 | ||
112 | static void wil_cache_mbox_regs(struct wil6210_priv *wil) | ||
113 | { | ||
114 | /* make shadow copy of registers that should not change on run time */ | ||
115 | wil_memcpy_fromio_32(&wil->mbox_ctl, wil->csr + HOST_MBOX, | ||
116 | sizeof(struct wil6210_mbox_ctl)); | ||
117 | wil_mbox_ring_le2cpus(&wil->mbox_ctl.rx); | ||
118 | wil_mbox_ring_le2cpus(&wil->mbox_ctl.tx); | ||
119 | } | ||
120 | |||
110 | int wil_priv_init(struct wil6210_priv *wil) | 121 | int wil_priv_init(struct wil6210_priv *wil) |
111 | { | 122 | { |
112 | wil_dbg(wil, "%s()\n", __func__); | 123 | wil_dbg_misc(wil, "%s()\n", __func__); |
113 | 124 | ||
114 | mutex_init(&wil->mutex); | 125 | mutex_init(&wil->mutex); |
115 | mutex_init(&wil->wmi_mutex); | 126 | mutex_init(&wil->wmi_mutex); |
@@ -136,11 +147,7 @@ int wil_priv_init(struct wil6210_priv *wil) | |||
136 | return -EAGAIN; | 147 | return -EAGAIN; |
137 | } | 148 | } |
138 | 149 | ||
139 | /* make shadow copy of registers that should not change on run time */ | 150 | wil_cache_mbox_regs(wil); |
140 | wil_memcpy_fromio_32(&wil->mbox_ctl, wil->csr + HOST_MBOX, | ||
141 | sizeof(struct wil6210_mbox_ctl)); | ||
142 | wil_mbox_ring_le2cpus(&wil->mbox_ctl.rx); | ||
143 | wil_mbox_ring_le2cpus(&wil->mbox_ctl.tx); | ||
144 | 151 | ||
145 | return 0; | 152 | return 0; |
146 | } | 153 | } |
@@ -162,7 +169,7 @@ void wil_priv_deinit(struct wil6210_priv *wil) | |||
162 | 169 | ||
163 | static void wil_target_reset(struct wil6210_priv *wil) | 170 | static void wil_target_reset(struct wil6210_priv *wil) |
164 | { | 171 | { |
165 | wil_dbg(wil, "Resetting...\n"); | 172 | wil_dbg_misc(wil, "Resetting...\n"); |
166 | 173 | ||
167 | /* register write */ | 174 | /* register write */ |
168 | #define W(a, v) iowrite32(v, wil->csr + HOSTADDR(a)) | 175 | #define W(a, v) iowrite32(v, wil->csr + HOSTADDR(a)) |
@@ -202,7 +209,7 @@ static void wil_target_reset(struct wil6210_priv *wil) | |||
202 | 209 | ||
203 | msleep(2000); | 210 | msleep(2000); |
204 | 211 | ||
205 | wil_dbg(wil, "Reset completed\n"); | 212 | wil_dbg_misc(wil, "Reset completed\n"); |
206 | 213 | ||
207 | #undef W | 214 | #undef W |
208 | #undef S | 215 | #undef S |
@@ -225,8 +232,8 @@ static int wil_wait_for_fw_ready(struct wil6210_priv *wil) | |||
225 | wil_err(wil, "Firmware not ready\n"); | 232 | wil_err(wil, "Firmware not ready\n"); |
226 | return -ETIME; | 233 | return -ETIME; |
227 | } else { | 234 | } else { |
228 | wil_dbg(wil, "FW ready after %d ms\n", | 235 | wil_dbg_misc(wil, "FW ready after %d ms\n", |
229 | jiffies_to_msecs(to-left)); | 236 | jiffies_to_msecs(to-left)); |
230 | } | 237 | } |
231 | return 0; | 238 | return 0; |
232 | } | 239 | } |
@@ -243,13 +250,13 @@ int wil_reset(struct wil6210_priv *wil) | |||
243 | cancel_work_sync(&wil->disconnect_worker); | 250 | cancel_work_sync(&wil->disconnect_worker); |
244 | wil6210_disconnect(wil, NULL); | 251 | wil6210_disconnect(wil, NULL); |
245 | 252 | ||
253 | wil6210_disable_irq(wil); | ||
254 | wil->status = 0; | ||
255 | |||
246 | wmi_event_flush(wil); | 256 | wmi_event_flush(wil); |
247 | 257 | ||
248 | flush_workqueue(wil->wmi_wq); | ||
249 | flush_workqueue(wil->wmi_wq_conn); | 258 | flush_workqueue(wil->wmi_wq_conn); |
250 | 259 | flush_workqueue(wil->wmi_wq); | |
251 | wil6210_disable_irq(wil); | ||
252 | wil->status = 0; | ||
253 | 260 | ||
254 | /* TODO: put MAC in reset */ | 261 | /* TODO: put MAC in reset */ |
255 | wil_target_reset(wil); | 262 | wil_target_reset(wil); |
@@ -258,11 +265,7 @@ int wil_reset(struct wil6210_priv *wil) | |||
258 | wil->pending_connect_cid = -1; | 265 | wil->pending_connect_cid = -1; |
259 | INIT_COMPLETION(wil->wmi_ready); | 266 | INIT_COMPLETION(wil->wmi_ready); |
260 | 267 | ||
261 | /* make shadow copy of registers that should not change on run time */ | 268 | wil_cache_mbox_regs(wil); |
262 | wil_memcpy_fromio_32(&wil->mbox_ctl, wil->csr + HOST_MBOX, | ||
263 | sizeof(struct wil6210_mbox_ctl)); | ||
264 | wil_mbox_ring_le2cpus(&wil->mbox_ctl.rx); | ||
265 | wil_mbox_ring_le2cpus(&wil->mbox_ctl.tx); | ||
266 | 269 | ||
267 | /* TODO: release MAC reset */ | 270 | /* TODO: release MAC reset */ |
268 | wil6210_enable_irq(wil); | 271 | wil6210_enable_irq(wil); |
@@ -278,7 +281,7 @@ void wil_link_on(struct wil6210_priv *wil) | |||
278 | { | 281 | { |
279 | struct net_device *ndev = wil_to_ndev(wil); | 282 | struct net_device *ndev = wil_to_ndev(wil); |
280 | 283 | ||
281 | wil_dbg(wil, "%s()\n", __func__); | 284 | wil_dbg_misc(wil, "%s()\n", __func__); |
282 | 285 | ||
283 | netif_carrier_on(ndev); | 286 | netif_carrier_on(ndev); |
284 | netif_tx_wake_all_queues(ndev); | 287 | netif_tx_wake_all_queues(ndev); |
@@ -288,7 +291,7 @@ void wil_link_off(struct wil6210_priv *wil) | |||
288 | { | 291 | { |
289 | struct net_device *ndev = wil_to_ndev(wil); | 292 | struct net_device *ndev = wil_to_ndev(wil); |
290 | 293 | ||
291 | wil_dbg(wil, "%s()\n", __func__); | 294 | wil_dbg_misc(wil, "%s()\n", __func__); |
292 | 295 | ||
293 | netif_tx_stop_all_queues(ndev); | 296 | netif_tx_stop_all_queues(ndev); |
294 | netif_carrier_off(ndev); | 297 | netif_carrier_off(ndev); |
@@ -311,27 +314,27 @@ static int __wil_up(struct wil6210_priv *wil) | |||
311 | wmi_nettype = wil_iftype_nl2wmi(NL80211_IFTYPE_ADHOC); | 314 | wmi_nettype = wil_iftype_nl2wmi(NL80211_IFTYPE_ADHOC); |
312 | switch (wdev->iftype) { | 315 | switch (wdev->iftype) { |
313 | case NL80211_IFTYPE_STATION: | 316 | case NL80211_IFTYPE_STATION: |
314 | wil_dbg(wil, "type: STATION\n"); | 317 | wil_dbg_misc(wil, "type: STATION\n"); |
315 | bi = 0; | 318 | bi = 0; |
316 | ndev->type = ARPHRD_ETHER; | 319 | ndev->type = ARPHRD_ETHER; |
317 | break; | 320 | break; |
318 | case NL80211_IFTYPE_AP: | 321 | case NL80211_IFTYPE_AP: |
319 | wil_dbg(wil, "type: AP\n"); | 322 | wil_dbg_misc(wil, "type: AP\n"); |
320 | bi = 100; | 323 | bi = 100; |
321 | ndev->type = ARPHRD_ETHER; | 324 | ndev->type = ARPHRD_ETHER; |
322 | break; | 325 | break; |
323 | case NL80211_IFTYPE_P2P_CLIENT: | 326 | case NL80211_IFTYPE_P2P_CLIENT: |
324 | wil_dbg(wil, "type: P2P_CLIENT\n"); | 327 | wil_dbg_misc(wil, "type: P2P_CLIENT\n"); |
325 | bi = 0; | 328 | bi = 0; |
326 | ndev->type = ARPHRD_ETHER; | 329 | ndev->type = ARPHRD_ETHER; |
327 | break; | 330 | break; |
328 | case NL80211_IFTYPE_P2P_GO: | 331 | case NL80211_IFTYPE_P2P_GO: |
329 | wil_dbg(wil, "type: P2P_GO\n"); | 332 | wil_dbg_misc(wil, "type: P2P_GO\n"); |
330 | bi = 100; | 333 | bi = 100; |
331 | ndev->type = ARPHRD_ETHER; | 334 | ndev->type = ARPHRD_ETHER; |
332 | break; | 335 | break; |
333 | case NL80211_IFTYPE_MONITOR: | 336 | case NL80211_IFTYPE_MONITOR: |
334 | wil_dbg(wil, "type: Monitor\n"); | 337 | wil_dbg_misc(wil, "type: Monitor\n"); |
335 | bi = 0; | 338 | bi = 0; |
336 | ndev->type = ARPHRD_IEEE80211_RADIOTAP; | 339 | ndev->type = ARPHRD_IEEE80211_RADIOTAP; |
337 | /* ARPHRD_IEEE80211 or ARPHRD_IEEE80211_RADIOTAP ? */ | 340 | /* ARPHRD_IEEE80211 or ARPHRD_IEEE80211_RADIOTAP ? */ |
@@ -354,7 +357,7 @@ static int __wil_up(struct wil6210_priv *wil) | |||
354 | wmi_set_channel(wil, channel->hw_value); | 357 | wmi_set_channel(wil, channel->hw_value); |
355 | break; | 358 | break; |
356 | default: | 359 | default: |
357 | ; | 360 | break; |
358 | } | 361 | } |
359 | 362 | ||
360 | /* MAC address - pre-requisite for other commands */ | 363 | /* MAC address - pre-requisite for other commands */ |
diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index 3068b5cb53a7..8ce2e33dce20 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c | |||
@@ -35,37 +35,12 @@ static int wil_stop(struct net_device *ndev) | |||
35 | return wil_down(wil); | 35 | return wil_down(wil); |
36 | } | 36 | } |
37 | 37 | ||
38 | /* | ||
39 | * AC to queue mapping | ||
40 | * | ||
41 | * AC_VO -> queue 3 | ||
42 | * AC_VI -> queue 2 | ||
43 | * AC_BE -> queue 1 | ||
44 | * AC_BK -> queue 0 | ||
45 | */ | ||
46 | static u16 wil_select_queue(struct net_device *ndev, struct sk_buff *skb) | ||
47 | { | ||
48 | static const u16 wil_1d_to_queue[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; | ||
49 | struct wil6210_priv *wil = ndev_to_wil(ndev); | ||
50 | u16 rc; | ||
51 | |||
52 | skb->priority = cfg80211_classify8021d(skb); | ||
53 | |||
54 | rc = wil_1d_to_queue[skb->priority]; | ||
55 | |||
56 | wil_dbg_TXRX(wil, "%s() %d -> %d\n", __func__, (int)skb->priority, | ||
57 | (int)rc); | ||
58 | |||
59 | return rc; | ||
60 | } | ||
61 | |||
62 | static const struct net_device_ops wil_netdev_ops = { | 38 | static const struct net_device_ops wil_netdev_ops = { |
63 | .ndo_open = wil_open, | 39 | .ndo_open = wil_open, |
64 | .ndo_stop = wil_stop, | 40 | .ndo_stop = wil_stop, |
65 | .ndo_start_xmit = wil_start_xmit, | 41 | .ndo_start_xmit = wil_start_xmit, |
66 | .ndo_select_queue = wil_select_queue, | 42 | .ndo_set_mac_address = eth_mac_addr, |
67 | .ndo_set_mac_address = eth_mac_addr, | 43 | .ndo_validate_addr = eth_validate_addr, |
68 | .ndo_validate_addr = eth_validate_addr, | ||
69 | }; | 44 | }; |
70 | 45 | ||
71 | void *wil_if_alloc(struct device *dev, void __iomem *csr) | 46 | void *wil_if_alloc(struct device *dev, void __iomem *csr) |
@@ -97,7 +72,7 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr) | |||
97 | ch = wdev->wiphy->bands[IEEE80211_BAND_60GHZ]->channels; | 72 | ch = wdev->wiphy->bands[IEEE80211_BAND_60GHZ]->channels; |
98 | cfg80211_chandef_create(&wdev->preset_chandef, ch, NL80211_CHAN_NO_HT); | 73 | cfg80211_chandef_create(&wdev->preset_chandef, ch, NL80211_CHAN_NO_HT); |
99 | 74 | ||
100 | ndev = alloc_netdev_mqs(0, "wlan%d", ether_setup, WIL6210_TX_QUEUES, 1); | 75 | ndev = alloc_netdev(0, "wlan%d", ether_setup); |
101 | if (!ndev) { | 76 | if (!ndev) { |
102 | dev_err(dev, "alloc_netdev_mqs failed\n"); | 77 | dev_err(dev, "alloc_netdev_mqs failed\n"); |
103 | rc = -ENOMEM; | 78 | rc = -ENOMEM; |
diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index 0fc83edd6bad..81c35c6e3832 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c | |||
@@ -53,7 +53,7 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil) | |||
53 | } | 53 | } |
54 | wil->n_msi = use_msi; | 54 | wil->n_msi = use_msi; |
55 | if (wil->n_msi) { | 55 | if (wil->n_msi) { |
56 | wil_dbg(wil, "Setup %d MSI interrupts\n", use_msi); | 56 | wil_dbg_misc(wil, "Setup %d MSI interrupts\n", use_msi); |
57 | rc = pci_enable_msi_block(pdev, wil->n_msi); | 57 | rc = pci_enable_msi_block(pdev, wil->n_msi); |
58 | if (rc && (wil->n_msi == 3)) { | 58 | if (rc && (wil->n_msi == 3)) { |
59 | wil_err(wil, "3 MSI mode failed, try 1 MSI\n"); | 59 | wil_err(wil, "3 MSI mode failed, try 1 MSI\n"); |
@@ -65,7 +65,7 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil) | |||
65 | wil->n_msi = 0; | 65 | wil->n_msi = 0; |
66 | } | 66 | } |
67 | } else { | 67 | } else { |
68 | wil_dbg(wil, "MSI interrupts disabled, use INTx\n"); | 68 | wil_dbg_misc(wil, "MSI interrupts disabled, use INTx\n"); |
69 | } | 69 | } |
70 | 70 | ||
71 | rc = wil6210_init_irq(wil, pdev->irq); | 71 | rc = wil6210_init_irq(wil, pdev->irq); |
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index f29c294413cf..64b971fdc3cc 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c | |||
@@ -100,8 +100,8 @@ static int wil_vring_alloc(struct wil6210_priv *wil, struct vring *vring) | |||
100 | d->dma.status = TX_DMA_STATUS_DU; | 100 | d->dma.status = TX_DMA_STATUS_DU; |
101 | } | 101 | } |
102 | 102 | ||
103 | wil_dbg(wil, "vring[%d] 0x%p:0x%016llx 0x%p\n", vring->size, | 103 | wil_dbg_misc(wil, "vring[%d] 0x%p:0x%016llx 0x%p\n", vring->size, |
104 | vring->va, (unsigned long long)vring->pa, vring->ctx); | 104 | vring->va, (unsigned long long)vring->pa, vring->ctx); |
105 | 105 | ||
106 | return 0; | 106 | return 0; |
107 | } | 107 | } |
@@ -353,8 +353,8 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, | |||
353 | if (ndev->type == ARPHRD_IEEE80211_RADIOTAP) | 353 | if (ndev->type == ARPHRD_IEEE80211_RADIOTAP) |
354 | wil_rx_add_radiotap_header(wil, skb, d); | 354 | wil_rx_add_radiotap_header(wil, skb, d); |
355 | 355 | ||
356 | wil_dbg_TXRX(wil, "Rx[%3d] : %d bytes\n", vring->swhead, d->dma.length); | 356 | wil_dbg_txrx(wil, "Rx[%3d] : %d bytes\n", vring->swhead, d->dma.length); |
357 | wil_hex_dump_TXRX("Rx ", DUMP_PREFIX_NONE, 32, 4, | 357 | wil_hex_dump_txrx("Rx ", DUMP_PREFIX_NONE, 32, 4, |
358 | (const void *)d, sizeof(*d), false); | 358 | (const void *)d, sizeof(*d), false); |
359 | 359 | ||
360 | wil_vring_advance_head(vring, 1); | 360 | wil_vring_advance_head(vring, 1); |
@@ -369,7 +369,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, | |||
369 | */ | 369 | */ |
370 | ftype = wil_rxdesc_ftype(d) << 2; | 370 | ftype = wil_rxdesc_ftype(d) << 2; |
371 | if (ftype != IEEE80211_FTYPE_DATA) { | 371 | if (ftype != IEEE80211_FTYPE_DATA) { |
372 | wil_dbg_TXRX(wil, "Non-data frame ftype 0x%08x\n", ftype); | 372 | wil_dbg_txrx(wil, "Non-data frame ftype 0x%08x\n", ftype); |
373 | /* TODO: process it */ | 373 | /* TODO: process it */ |
374 | kfree_skb(skb); | 374 | kfree_skb(skb); |
375 | return NULL; | 375 | return NULL; |
@@ -430,6 +430,8 @@ static void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) | |||
430 | int rc; | 430 | int rc; |
431 | unsigned int len = skb->len; | 431 | unsigned int len = skb->len; |
432 | 432 | ||
433 | skb_orphan(skb); | ||
434 | |||
433 | if (in_interrupt()) | 435 | if (in_interrupt()) |
434 | rc = netif_rx(skb); | 436 | rc = netif_rx(skb); |
435 | else | 437 | else |
@@ -459,13 +461,11 @@ void wil_rx_handle(struct wil6210_priv *wil) | |||
459 | wil_err(wil, "Rx IRQ while Rx not yet initialized\n"); | 461 | wil_err(wil, "Rx IRQ while Rx not yet initialized\n"); |
460 | return; | 462 | return; |
461 | } | 463 | } |
462 | wil_dbg_TXRX(wil, "%s()\n", __func__); | 464 | wil_dbg_txrx(wil, "%s()\n", __func__); |
463 | while (NULL != (skb = wil_vring_reap_rx(wil, v))) { | 465 | while (NULL != (skb = wil_vring_reap_rx(wil, v))) { |
464 | wil_hex_dump_TXRX("Rx ", DUMP_PREFIX_OFFSET, 16, 1, | 466 | wil_hex_dump_txrx("Rx ", DUMP_PREFIX_OFFSET, 16, 1, |
465 | skb->data, skb_headlen(skb), false); | 467 | skb->data, skb_headlen(skb), false); |
466 | 468 | ||
467 | skb_orphan(skb); | ||
468 | |||
469 | if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) { | 469 | if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) { |
470 | skb->dev = ndev; | 470 | skb->dev = ndev; |
471 | skb_reset_mac_header(skb); | 471 | skb_reset_mac_header(skb); |
@@ -484,53 +484,18 @@ void wil_rx_handle(struct wil6210_priv *wil) | |||
484 | 484 | ||
485 | int wil_rx_init(struct wil6210_priv *wil) | 485 | int wil_rx_init(struct wil6210_priv *wil) |
486 | { | 486 | { |
487 | struct net_device *ndev = wil_to_ndev(wil); | ||
488 | struct wireless_dev *wdev = wil->wdev; | ||
489 | struct vring *vring = &wil->vring_rx; | 487 | struct vring *vring = &wil->vring_rx; |
490 | int rc; | 488 | int rc; |
491 | struct wmi_cfg_rx_chain_cmd cmd = { | ||
492 | .action = WMI_RX_CHAIN_ADD, | ||
493 | .rx_sw_ring = { | ||
494 | .max_mpdu_size = cpu_to_le16(RX_BUF_LEN), | ||
495 | }, | ||
496 | .mid = 0, /* TODO - what is it? */ | ||
497 | .decap_trans_type = WMI_DECAP_TYPE_802_3, | ||
498 | }; | ||
499 | struct { | ||
500 | struct wil6210_mbox_hdr_wmi wmi; | ||
501 | struct wmi_cfg_rx_chain_done_event evt; | ||
502 | } __packed evt; | ||
503 | 489 | ||
504 | vring->size = WIL6210_RX_RING_SIZE; | 490 | vring->size = WIL6210_RX_RING_SIZE; |
505 | rc = wil_vring_alloc(wil, vring); | 491 | rc = wil_vring_alloc(wil, vring); |
506 | if (rc) | 492 | if (rc) |
507 | return rc; | 493 | return rc; |
508 | 494 | ||
509 | cmd.rx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa); | 495 | rc = wmi_rx_chain_add(wil, vring); |
510 | cmd.rx_sw_ring.ring_size = cpu_to_le16(vring->size); | ||
511 | if (wdev->iftype == NL80211_IFTYPE_MONITOR) { | ||
512 | struct ieee80211_channel *ch = wdev->preset_chandef.chan; | ||
513 | |||
514 | cmd.sniffer_cfg.mode = cpu_to_le32(WMI_SNIFFER_ON); | ||
515 | if (ch) | ||
516 | cmd.sniffer_cfg.channel = ch->hw_value - 1; | ||
517 | cmd.sniffer_cfg.phy_info_mode = | ||
518 | cpu_to_le32(ndev->type == ARPHRD_IEEE80211_RADIOTAP); | ||
519 | cmd.sniffer_cfg.phy_support = | ||
520 | cpu_to_le32((wil->monitor_flags & MONITOR_FLAG_CONTROL) | ||
521 | ? WMI_SNIFFER_CP : WMI_SNIFFER_DP); | ||
522 | } | ||
523 | /* typical time for secure PCP is 840ms */ | ||
524 | rc = wmi_call(wil, WMI_CFG_RX_CHAIN_CMDID, &cmd, sizeof(cmd), | ||
525 | WMI_CFG_RX_CHAIN_DONE_EVENTID, &evt, sizeof(evt), 2000); | ||
526 | if (rc) | 496 | if (rc) |
527 | goto err_free; | 497 | goto err_free; |
528 | 498 | ||
529 | vring->hwtail = le32_to_cpu(evt.evt.rx_ring_tail_ptr); | ||
530 | |||
531 | wil_dbg(wil, "Rx init: status %d tail 0x%08x\n", | ||
532 | le32_to_cpu(evt.evt.status), vring->hwtail); | ||
533 | |||
534 | rc = wil_rx_refill(wil, vring->size); | 499 | rc = wil_rx_refill(wil, vring->size); |
535 | if (rc) | 500 | if (rc) |
536 | goto err_free; | 501 | goto err_free; |
@@ -546,25 +511,8 @@ void wil_rx_fini(struct wil6210_priv *wil) | |||
546 | { | 511 | { |
547 | struct vring *vring = &wil->vring_rx; | 512 | struct vring *vring = &wil->vring_rx; |
548 | 513 | ||
549 | if (vring->va) { | 514 | if (vring->va) |
550 | int rc; | ||
551 | struct wmi_cfg_rx_chain_cmd cmd = { | ||
552 | .action = cpu_to_le32(WMI_RX_CHAIN_DEL), | ||
553 | .rx_sw_ring = { | ||
554 | .max_mpdu_size = cpu_to_le16(RX_BUF_LEN), | ||
555 | }, | ||
556 | }; | ||
557 | struct { | ||
558 | struct wil6210_mbox_hdr_wmi wmi; | ||
559 | struct wmi_cfg_rx_chain_done_event cfg; | ||
560 | } __packed wmi_rx_cfg_reply; | ||
561 | |||
562 | rc = wmi_call(wil, WMI_CFG_RX_CHAIN_CMDID, &cmd, sizeof(cmd), | ||
563 | WMI_CFG_RX_CHAIN_DONE_EVENTID, | ||
564 | &wmi_rx_cfg_reply, sizeof(wmi_rx_cfg_reply), | ||
565 | 100); | ||
566 | wil_vring_free(wil, vring, 0); | 515 | wil_vring_free(wil, vring, 0); |
567 | } | ||
568 | } | 516 | } |
569 | 517 | ||
570 | int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, | 518 | int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, |
@@ -617,6 +565,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, | |||
617 | if (reply.cmd.status != WMI_VRING_CFG_SUCCESS) { | 565 | if (reply.cmd.status != WMI_VRING_CFG_SUCCESS) { |
618 | wil_err(wil, "Tx config failed, status 0x%02x\n", | 566 | wil_err(wil, "Tx config failed, status 0x%02x\n", |
619 | reply.cmd.status); | 567 | reply.cmd.status); |
568 | rc = -EINVAL; | ||
620 | goto out_free; | 569 | goto out_free; |
621 | } | 570 | } |
622 | vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr); | 571 | vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr); |
@@ -689,7 +638,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, | |||
689 | uint i = swhead; | 638 | uint i = swhead; |
690 | dma_addr_t pa; | 639 | dma_addr_t pa; |
691 | 640 | ||
692 | wil_dbg_TXRX(wil, "%s()\n", __func__); | 641 | wil_dbg_txrx(wil, "%s()\n", __func__); |
693 | 642 | ||
694 | if (avail < vring->size/8) | 643 | if (avail < vring->size/8) |
695 | netif_tx_stop_all_queues(wil_to_ndev(wil)); | 644 | netif_tx_stop_all_queues(wil_to_ndev(wil)); |
@@ -706,9 +655,9 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, | |||
706 | pa = dma_map_single(dev, skb->data, | 655 | pa = dma_map_single(dev, skb->data, |
707 | skb_headlen(skb), DMA_TO_DEVICE); | 656 | skb_headlen(skb), DMA_TO_DEVICE); |
708 | 657 | ||
709 | wil_dbg_TXRX(wil, "Tx skb %d bytes %p -> %#08llx\n", skb_headlen(skb), | 658 | wil_dbg_txrx(wil, "Tx skb %d bytes %p -> %#08llx\n", skb_headlen(skb), |
710 | skb->data, (unsigned long long)pa); | 659 | skb->data, (unsigned long long)pa); |
711 | wil_hex_dump_TXRX("Tx ", DUMP_PREFIX_OFFSET, 16, 1, | 660 | wil_hex_dump_txrx("Tx ", DUMP_PREFIX_OFFSET, 16, 1, |
712 | skb->data, skb_headlen(skb), false); | 661 | skb->data, skb_headlen(skb), false); |
713 | 662 | ||
714 | if (unlikely(dma_mapping_error(dev, pa))) | 663 | if (unlikely(dma_mapping_error(dev, pa))) |
@@ -737,12 +686,12 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, | |||
737 | d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_DMA_IT_POS); | 686 | d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_DMA_IT_POS); |
738 | d->dma.d0 |= (vring_index << DMA_CFG_DESC_TX_0_QID_POS); | 687 | d->dma.d0 |= (vring_index << DMA_CFG_DESC_TX_0_QID_POS); |
739 | 688 | ||
740 | wil_hex_dump_TXRX("Tx ", DUMP_PREFIX_NONE, 32, 4, | 689 | wil_hex_dump_txrx("Tx ", DUMP_PREFIX_NONE, 32, 4, |
741 | (const void *)d, sizeof(*d), false); | 690 | (const void *)d, sizeof(*d), false); |
742 | 691 | ||
743 | /* advance swhead */ | 692 | /* advance swhead */ |
744 | wil_vring_advance_head(vring, nr_frags + 1); | 693 | wil_vring_advance_head(vring, nr_frags + 1); |
745 | wil_dbg_TXRX(wil, "Tx swhead %d -> %d\n", swhead, vring->swhead); | 694 | wil_dbg_txrx(wil, "Tx swhead %d -> %d\n", swhead, vring->swhead); |
746 | iowrite32(vring->swhead, wil->csr + HOSTADDR(vring->hwtail)); | 695 | iowrite32(vring->swhead, wil->csr + HOSTADDR(vring->hwtail)); |
747 | /* hold reference to skb | 696 | /* hold reference to skb |
748 | * to prevent skb release before accounting | 697 | * to prevent skb release before accounting |
@@ -775,7 +724,7 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) | |||
775 | struct vring *vring; | 724 | struct vring *vring; |
776 | int rc; | 725 | int rc; |
777 | 726 | ||
778 | wil_dbg_TXRX(wil, "%s()\n", __func__); | 727 | wil_dbg_txrx(wil, "%s()\n", __func__); |
779 | if (!test_bit(wil_status_fwready, &wil->status)) { | 728 | if (!test_bit(wil_status_fwready, &wil->status)) { |
780 | wil_err(wil, "FW not ready\n"); | 729 | wil_err(wil, "FW not ready\n"); |
781 | goto drop; | 730 | goto drop; |
@@ -802,15 +751,13 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) | |||
802 | } | 751 | } |
803 | switch (rc) { | 752 | switch (rc) { |
804 | case 0: | 753 | case 0: |
805 | ndev->stats.tx_packets++; | 754 | /* statistics will be updated on the tx_complete */ |
806 | ndev->stats.tx_bytes += skb->len; | ||
807 | dev_kfree_skb_any(skb); | 755 | dev_kfree_skb_any(skb); |
808 | return NETDEV_TX_OK; | 756 | return NETDEV_TX_OK; |
809 | case -ENOMEM: | 757 | case -ENOMEM: |
810 | return NETDEV_TX_BUSY; | 758 | return NETDEV_TX_BUSY; |
811 | default: | 759 | default: |
812 | ; /* goto drop; */ | 760 | break; /* goto drop; */ |
813 | break; | ||
814 | } | 761 | } |
815 | drop: | 762 | drop: |
816 | netif_tx_stop_all_queues(ndev); | 763 | netif_tx_stop_all_queues(ndev); |
@@ -827,6 +774,7 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) | |||
827 | */ | 774 | */ |
828 | void wil_tx_complete(struct wil6210_priv *wil, int ringid) | 775 | void wil_tx_complete(struct wil6210_priv *wil, int ringid) |
829 | { | 776 | { |
777 | struct net_device *ndev = wil_to_ndev(wil); | ||
830 | struct device *dev = wil_to_dev(wil); | 778 | struct device *dev = wil_to_dev(wil); |
831 | struct vring *vring = &wil->vring_tx[ringid]; | 779 | struct vring *vring = &wil->vring_tx[ringid]; |
832 | 780 | ||
@@ -835,7 +783,7 @@ void wil_tx_complete(struct wil6210_priv *wil, int ringid) | |||
835 | return; | 783 | return; |
836 | } | 784 | } |
837 | 785 | ||
838 | wil_dbg_TXRX(wil, "%s(%d)\n", __func__, ringid); | 786 | wil_dbg_txrx(wil, "%s(%d)\n", __func__, ringid); |
839 | 787 | ||
840 | while (!wil_vring_is_empty(vring)) { | 788 | while (!wil_vring_is_empty(vring)) { |
841 | volatile struct vring_tx_desc *d = &vring->va[vring->swtail].tx; | 789 | volatile struct vring_tx_desc *d = &vring->va[vring->swtail].tx; |
@@ -844,16 +792,23 @@ void wil_tx_complete(struct wil6210_priv *wil, int ringid) | |||
844 | if (!(d->dma.status & TX_DMA_STATUS_DU)) | 792 | if (!(d->dma.status & TX_DMA_STATUS_DU)) |
845 | break; | 793 | break; |
846 | 794 | ||
847 | wil_dbg_TXRX(wil, | 795 | wil_dbg_txrx(wil, |
848 | "Tx[%3d] : %d bytes, status 0x%02x err 0x%02x\n", | 796 | "Tx[%3d] : %d bytes, status 0x%02x err 0x%02x\n", |
849 | vring->swtail, d->dma.length, d->dma.status, | 797 | vring->swtail, d->dma.length, d->dma.status, |
850 | d->dma.error); | 798 | d->dma.error); |
851 | wil_hex_dump_TXRX("TxC ", DUMP_PREFIX_NONE, 32, 4, | 799 | wil_hex_dump_txrx("TxC ", DUMP_PREFIX_NONE, 32, 4, |
852 | (const void *)d, sizeof(*d), false); | 800 | (const void *)d, sizeof(*d), false); |
853 | 801 | ||
854 | pa = d->dma.addr_low | ((u64)d->dma.addr_high << 32); | 802 | pa = d->dma.addr_low | ((u64)d->dma.addr_high << 32); |
855 | skb = vring->ctx[vring->swtail]; | 803 | skb = vring->ctx[vring->swtail]; |
856 | if (skb) { | 804 | if (skb) { |
805 | if (d->dma.error == 0) { | ||
806 | ndev->stats.tx_packets++; | ||
807 | ndev->stats.tx_bytes += skb->len; | ||
808 | } else { | ||
809 | ndev->stats.tx_errors++; | ||
810 | } | ||
811 | |||
857 | dma_unmap_single(dev, pa, d->dma.length, DMA_TO_DEVICE); | 812 | dma_unmap_single(dev, pa, d->dma.length, DMA_TO_DEVICE); |
858 | dev_kfree_skb_any(skb); | 813 | dev_kfree_skb_any(skb); |
859 | vring->ctx[vring->swtail] = NULL; | 814 | vring->ctx[vring->swtail] = NULL; |
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 9bcfffa4006c..aea961ff8f08 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h | |||
@@ -36,8 +36,6 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1) | |||
36 | 36 | ||
37 | #define WIL6210_MEM_SIZE (2*1024*1024UL) | 37 | #define WIL6210_MEM_SIZE (2*1024*1024UL) |
38 | 38 | ||
39 | #define WIL6210_TX_QUEUES (4) | ||
40 | |||
41 | #define WIL6210_RX_RING_SIZE (128) | 39 | #define WIL6210_RX_RING_SIZE (128) |
42 | #define WIL6210_TX_RING_SIZE (128) | 40 | #define WIL6210_TX_RING_SIZE (128) |
43 | #define WIL6210_MAX_TX_RINGS (24) | 41 | #define WIL6210_MAX_TX_RINGS (24) |
@@ -101,8 +99,7 @@ struct RGF_ICR { | |||
101 | #define RGF_DMA_EP_MISC_ICR (0x881bec) /* struct RGF_ICR */ | 99 | #define RGF_DMA_EP_MISC_ICR (0x881bec) /* struct RGF_ICR */ |
102 | #define BIT_DMA_EP_MISC_ICR_RX_HTRSH BIT(0) | 100 | #define BIT_DMA_EP_MISC_ICR_RX_HTRSH BIT(0) |
103 | #define BIT_DMA_EP_MISC_ICR_TX_NO_ACT BIT(1) | 101 | #define BIT_DMA_EP_MISC_ICR_TX_NO_ACT BIT(1) |
104 | #define BIT_DMA_EP_MISC_ICR_FW_INT0 BIT(28) | 102 | #define BIT_DMA_EP_MISC_ICR_FW_INT(n) BIT(28+n) /* n = [0..3] */ |
105 | #define BIT_DMA_EP_MISC_ICR_FW_INT1 BIT(29) | ||
106 | 103 | ||
107 | /* Interrupt moderation control */ | 104 | /* Interrupt moderation control */ |
108 | #define RGF_DMA_ITR_CNT_TRSH (0x881c5c) | 105 | #define RGF_DMA_ITR_CNT_TRSH (0x881c5c) |
@@ -121,8 +118,9 @@ struct RGF_ICR { | |||
121 | #define SW_INT_MBOX BIT_USER_USER_ICR_SW_INT_2 | 118 | #define SW_INT_MBOX BIT_USER_USER_ICR_SW_INT_2 |
122 | 119 | ||
123 | /* ISR register bits */ | 120 | /* ISR register bits */ |
124 | #define ISR_MISC_FW_READY BIT_DMA_EP_MISC_ICR_FW_INT0 | 121 | #define ISR_MISC_FW_READY BIT_DMA_EP_MISC_ICR_FW_INT(0) |
125 | #define ISR_MISC_MBOX_EVT BIT_DMA_EP_MISC_ICR_FW_INT1 | 122 | #define ISR_MISC_MBOX_EVT BIT_DMA_EP_MISC_ICR_FW_INT(1) |
123 | #define ISR_MISC_FW_ERROR BIT_DMA_EP_MISC_ICR_FW_INT(3) | ||
126 | 124 | ||
127 | /* Hardware definitions end */ | 125 | /* Hardware definitions end */ |
128 | 126 | ||
@@ -272,17 +270,18 @@ struct wil6210_priv { | |||
272 | #define wil_info(wil, fmt, arg...) netdev_info(wil_to_ndev(wil), fmt, ##arg) | 270 | #define wil_info(wil, fmt, arg...) netdev_info(wil_to_ndev(wil), fmt, ##arg) |
273 | #define wil_err(wil, fmt, arg...) netdev_err(wil_to_ndev(wil), fmt, ##arg) | 271 | #define wil_err(wil, fmt, arg...) netdev_err(wil_to_ndev(wil), fmt, ##arg) |
274 | 272 | ||
275 | #define wil_dbg_IRQ(wil, fmt, arg...) wil_dbg(wil, "DBG[ IRQ]" fmt, ##arg) | 273 | #define wil_dbg_irq(wil, fmt, arg...) wil_dbg(wil, "DBG[ IRQ]" fmt, ##arg) |
276 | #define wil_dbg_TXRX(wil, fmt, arg...) wil_dbg(wil, "DBG[TXRX]" fmt, ##arg) | 274 | #define wil_dbg_txrx(wil, fmt, arg...) wil_dbg(wil, "DBG[TXRX]" fmt, ##arg) |
277 | #define wil_dbg_WMI(wil, fmt, arg...) wil_dbg(wil, "DBG[ WMI]" fmt, ##arg) | 275 | #define wil_dbg_wmi(wil, fmt, arg...) wil_dbg(wil, "DBG[ WMI]" fmt, ##arg) |
276 | #define wil_dbg_misc(wil, fmt, arg...) wil_dbg(wil, "DBG[MISC]" fmt, ##arg) | ||
278 | 277 | ||
279 | #define wil_hex_dump_TXRX(prefix_str, prefix_type, rowsize, \ | 278 | #define wil_hex_dump_txrx(prefix_str, prefix_type, rowsize, \ |
280 | groupsize, buf, len, ascii) \ | 279 | groupsize, buf, len, ascii) \ |
281 | wil_print_hex_dump_debug("DBG[TXRX]" prefix_str,\ | 280 | wil_print_hex_dump_debug("DBG[TXRX]" prefix_str,\ |
282 | prefix_type, rowsize, \ | 281 | prefix_type, rowsize, \ |
283 | groupsize, buf, len, ascii) | 282 | groupsize, buf, len, ascii) |
284 | 283 | ||
285 | #define wil_hex_dump_WMI(prefix_str, prefix_type, rowsize, \ | 284 | #define wil_hex_dump_wmi(prefix_str, prefix_type, rowsize, \ |
286 | groupsize, buf, len, ascii) \ | 285 | groupsize, buf, len, ascii) \ |
287 | wil_print_hex_dump_debug("DBG[ WMI]" prefix_str,\ | 286 | wil_print_hex_dump_debug("DBG[ WMI]" prefix_str,\ |
288 | prefix_type, rowsize, \ | 287 | prefix_type, rowsize, \ |
@@ -328,6 +327,7 @@ int wmi_add_cipher_key(struct wil6210_priv *wil, u8 key_index, | |||
328 | const void *mac_addr, int key_len, const void *key); | 327 | const void *mac_addr, int key_len, const void *key); |
329 | int wmi_echo(struct wil6210_priv *wil); | 328 | int wmi_echo(struct wil6210_priv *wil); |
330 | int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie); | 329 | int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie); |
330 | int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring); | ||
331 | 331 | ||
332 | int wil6210_init_irq(struct wil6210_priv *wil, int irq); | 332 | int wil6210_init_irq(struct wil6210_priv *wil, int irq); |
333 | void wil6210_fini_irq(struct wil6210_priv *wil, int irq); | 333 | void wil6210_fini_irq(struct wil6210_priv *wil, int irq); |
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 12915f6e7617..0b70e17cd1fb 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c | |||
@@ -18,8 +18,10 @@ | |||
18 | #include <linux/io.h> | 18 | #include <linux/io.h> |
19 | #include <linux/list.h> | 19 | #include <linux/list.h> |
20 | #include <linux/etherdevice.h> | 20 | #include <linux/etherdevice.h> |
21 | #include <linux/if_arp.h> | ||
21 | 22 | ||
22 | #include "wil6210.h" | 23 | #include "wil6210.h" |
24 | #include "txrx.h" | ||
23 | #include "wmi.h" | 25 | #include "wmi.h" |
24 | 26 | ||
25 | /** | 27 | /** |
@@ -186,7 +188,6 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len) | |||
186 | wil_err(wil, "WMI size too large: %d bytes, max is %d\n", | 188 | wil_err(wil, "WMI size too large: %d bytes, max is %d\n", |
187 | (int)(sizeof(cmd) + len), r->entry_size); | 189 | (int)(sizeof(cmd) + len), r->entry_size); |
188 | return -ERANGE; | 190 | return -ERANGE; |
189 | |||
190 | } | 191 | } |
191 | 192 | ||
192 | might_sleep(); | 193 | might_sleep(); |
@@ -213,7 +214,7 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len) | |||
213 | } | 214 | } |
214 | /* next head */ | 215 | /* next head */ |
215 | next_head = r->base + ((r->head - r->base + sizeof(d_head)) % r->size); | 216 | next_head = r->base + ((r->head - r->base + sizeof(d_head)) % r->size); |
216 | wil_dbg_WMI(wil, "Head 0x%08x -> 0x%08x\n", r->head, next_head); | 217 | wil_dbg_wmi(wil, "Head 0x%08x -> 0x%08x\n", r->head, next_head); |
217 | /* wait till FW finish with previous command */ | 218 | /* wait till FW finish with previous command */ |
218 | for (retry = 5; retry > 0; retry--) { | 219 | for (retry = 5; retry > 0; retry--) { |
219 | r->tail = ioread32(wil->csr + HOST_MBOX + | 220 | r->tail = ioread32(wil->csr + HOST_MBOX + |
@@ -234,10 +235,10 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len) | |||
234 | } | 235 | } |
235 | cmd.hdr.seq = cpu_to_le16(++wil->wmi_seq); | 236 | cmd.hdr.seq = cpu_to_le16(++wil->wmi_seq); |
236 | /* set command */ | 237 | /* set command */ |
237 | wil_dbg_WMI(wil, "WMI command 0x%04x [%d]\n", cmdid, len); | 238 | wil_dbg_wmi(wil, "WMI command 0x%04x [%d]\n", cmdid, len); |
238 | wil_hex_dump_WMI("Cmd ", DUMP_PREFIX_OFFSET, 16, 1, &cmd, | 239 | wil_hex_dump_wmi("Cmd ", DUMP_PREFIX_OFFSET, 16, 1, &cmd, |
239 | sizeof(cmd), true); | 240 | sizeof(cmd), true); |
240 | wil_hex_dump_WMI("cmd ", DUMP_PREFIX_OFFSET, 16, 1, buf, | 241 | wil_hex_dump_wmi("cmd ", DUMP_PREFIX_OFFSET, 16, 1, buf, |
241 | len, true); | 242 | len, true); |
242 | wil_memcpy_toio_32(dst, &cmd, sizeof(cmd)); | 243 | wil_memcpy_toio_32(dst, &cmd, sizeof(cmd)); |
243 | wil_memcpy_toio_32(dst + sizeof(cmd), buf, len); | 244 | wil_memcpy_toio_32(dst + sizeof(cmd), buf, len); |
@@ -273,7 +274,7 @@ static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len) | |||
273 | struct wmi_ready_event *evt = d; | 274 | struct wmi_ready_event *evt = d; |
274 | u32 ver = le32_to_cpu(evt->sw_version); | 275 | u32 ver = le32_to_cpu(evt->sw_version); |
275 | 276 | ||
276 | wil_dbg_WMI(wil, "FW ver. %d; MAC %pM\n", ver, evt->mac); | 277 | wil_dbg_wmi(wil, "FW ver. %d; MAC %pM\n", ver, evt->mac); |
277 | 278 | ||
278 | if (!is_valid_ether_addr(ndev->dev_addr)) { | 279 | if (!is_valid_ether_addr(ndev->dev_addr)) { |
279 | memcpy(ndev->dev_addr, evt->mac, ETH_ALEN); | 280 | memcpy(ndev->dev_addr, evt->mac, ETH_ALEN); |
@@ -286,7 +287,7 @@ static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len) | |||
286 | static void wmi_evt_fw_ready(struct wil6210_priv *wil, int id, void *d, | 287 | static void wmi_evt_fw_ready(struct wil6210_priv *wil, int id, void *d, |
287 | int len) | 288 | int len) |
288 | { | 289 | { |
289 | wil_dbg_WMI(wil, "WMI: FW ready\n"); | 290 | wil_dbg_wmi(wil, "WMI: FW ready\n"); |
290 | 291 | ||
291 | set_bit(wil_status_fwready, &wil->status); | 292 | set_bit(wil_status_fwready, &wil->status); |
292 | /* reuse wmi_ready for the firmware ready indication */ | 293 | /* reuse wmi_ready for the firmware ready indication */ |
@@ -309,11 +310,11 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len) | |||
309 | u32 d_len = le32_to_cpu(data->info.len); | 310 | u32 d_len = le32_to_cpu(data->info.len); |
310 | u16 d_status = le16_to_cpu(data->info.status); | 311 | u16 d_status = le16_to_cpu(data->info.status); |
311 | 312 | ||
312 | wil_dbg_WMI(wil, "MGMT: channel %d MCS %d SNR %d\n", | 313 | wil_dbg_wmi(wil, "MGMT: channel %d MCS %d SNR %d\n", |
313 | data->info.channel, data->info.mcs, data->info.snr); | 314 | data->info.channel, data->info.mcs, data->info.snr); |
314 | wil_dbg_WMI(wil, "status 0x%04x len %d stype %04x\n", d_status, d_len, | 315 | wil_dbg_wmi(wil, "status 0x%04x len %d stype %04x\n", d_status, d_len, |
315 | le16_to_cpu(data->info.stype)); | 316 | le16_to_cpu(data->info.stype)); |
316 | wil_dbg_WMI(wil, "qid %d mid %d cid %d\n", | 317 | wil_dbg_wmi(wil, "qid %d mid %d cid %d\n", |
317 | data->info.qid, data->info.mid, data->info.cid); | 318 | data->info.qid, data->info.mid, data->info.cid); |
318 | 319 | ||
319 | if (!channel) { | 320 | if (!channel) { |
@@ -329,13 +330,13 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len) | |||
329 | const u8 *ie_buf = rx_mgmt_frame->u.beacon.variable; | 330 | const u8 *ie_buf = rx_mgmt_frame->u.beacon.variable; |
330 | size_t ie_len = d_len - offsetof(struct ieee80211_mgmt, | 331 | size_t ie_len = d_len - offsetof(struct ieee80211_mgmt, |
331 | u.beacon.variable); | 332 | u.beacon.variable); |
332 | wil_dbg_WMI(wil, "Capability info : 0x%04x\n", cap); | 333 | wil_dbg_wmi(wil, "Capability info : 0x%04x\n", cap); |
333 | 334 | ||
334 | bss = cfg80211_inform_bss(wiphy, channel, rx_mgmt_frame->bssid, | 335 | bss = cfg80211_inform_bss(wiphy, channel, rx_mgmt_frame->bssid, |
335 | tsf, cap, bi, ie_buf, ie_len, | 336 | tsf, cap, bi, ie_buf, ie_len, |
336 | signal, GFP_KERNEL); | 337 | signal, GFP_KERNEL); |
337 | if (bss) { | 338 | if (bss) { |
338 | wil_dbg_WMI(wil, "Added BSS %pM\n", | 339 | wil_dbg_wmi(wil, "Added BSS %pM\n", |
339 | rx_mgmt_frame->bssid); | 340 | rx_mgmt_frame->bssid); |
340 | cfg80211_put_bss(bss); | 341 | cfg80211_put_bss(bss); |
341 | } else { | 342 | } else { |
@@ -351,7 +352,7 @@ static void wmi_evt_scan_complete(struct wil6210_priv *wil, int id, | |||
351 | struct wmi_scan_complete_event *data = d; | 352 | struct wmi_scan_complete_event *data = d; |
352 | bool aborted = (data->status != 0); | 353 | bool aborted = (data->status != 0); |
353 | 354 | ||
354 | wil_dbg_WMI(wil, "SCAN_COMPLETE(0x%08x)\n", data->status); | 355 | wil_dbg_wmi(wil, "SCAN_COMPLETE(0x%08x)\n", data->status); |
355 | cfg80211_scan_done(wil->scan_request, aborted); | 356 | cfg80211_scan_done(wil->scan_request, aborted); |
356 | wil->scan_request = NULL; | 357 | wil->scan_request = NULL; |
357 | } else { | 358 | } else { |
@@ -386,9 +387,9 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len) | |||
386 | return; | 387 | return; |
387 | } | 388 | } |
388 | ch = evt->channel + 1; | 389 | ch = evt->channel + 1; |
389 | wil_dbg_WMI(wil, "Connect %pM channel [%d] cid %d\n", | 390 | wil_dbg_wmi(wil, "Connect %pM channel [%d] cid %d\n", |
390 | evt->bssid, ch, evt->cid); | 391 | evt->bssid, ch, evt->cid); |
391 | wil_hex_dump_WMI("connect AI : ", DUMP_PREFIX_OFFSET, 16, 1, | 392 | wil_hex_dump_wmi("connect AI : ", DUMP_PREFIX_OFFSET, 16, 1, |
392 | evt->assoc_info, len - sizeof(*evt), true); | 393 | evt->assoc_info, len - sizeof(*evt), true); |
393 | 394 | ||
394 | /* figure out IE's */ | 395 | /* figure out IE's */ |
@@ -450,14 +451,13 @@ static void wmi_evt_disconnect(struct wil6210_priv *wil, int id, | |||
450 | { | 451 | { |
451 | struct wmi_disconnect_event *evt = d; | 452 | struct wmi_disconnect_event *evt = d; |
452 | 453 | ||
453 | wil_dbg_WMI(wil, "Disconnect %pM reason %d proto %d wmi\n", | 454 | wil_dbg_wmi(wil, "Disconnect %pM reason %d proto %d wmi\n", |
454 | evt->bssid, | 455 | evt->bssid, |
455 | evt->protocol_reason_status, evt->disconnect_reason); | 456 | evt->protocol_reason_status, evt->disconnect_reason); |
456 | 457 | ||
457 | wil->sinfo_gen++; | 458 | wil->sinfo_gen++; |
458 | 459 | ||
459 | wil6210_disconnect(wil, evt->bssid); | 460 | wil6210_disconnect(wil, evt->bssid); |
460 | clear_bit(wil_status_dontscan, &wil->status); | ||
461 | } | 461 | } |
462 | 462 | ||
463 | static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len) | 463 | static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len) |
@@ -476,7 +476,7 @@ static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len) | |||
476 | wil->stats.my_tx_sector = le16_to_cpu(evt->my_tx_sector); | 476 | wil->stats.my_tx_sector = le16_to_cpu(evt->my_tx_sector); |
477 | wil->stats.peer_rx_sector = le16_to_cpu(evt->other_rx_sector); | 477 | wil->stats.peer_rx_sector = le16_to_cpu(evt->other_rx_sector); |
478 | wil->stats.peer_tx_sector = le16_to_cpu(evt->other_tx_sector); | 478 | wil->stats.peer_tx_sector = le16_to_cpu(evt->other_tx_sector); |
479 | wil_dbg_WMI(wil, "Link status, MCS %d TSF 0x%016llx\n" | 479 | wil_dbg_wmi(wil, "Link status, MCS %d TSF 0x%016llx\n" |
480 | "BF status 0x%08x SNR 0x%08x\n" | 480 | "BF status 0x%08x SNR 0x%08x\n" |
481 | "Tx Tpt %d goodput %d Rx goodput %d\n" | 481 | "Tx Tpt %d goodput %d Rx goodput %d\n" |
482 | "Sectors(rx:tx) my %d:%d peer %d:%d\n", | 482 | "Sectors(rx:tx) my %d:%d peer %d:%d\n", |
@@ -501,7 +501,7 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id, | |||
501 | struct sk_buff *skb; | 501 | struct sk_buff *skb; |
502 | struct ethhdr *eth; | 502 | struct ethhdr *eth; |
503 | 503 | ||
504 | wil_dbg_WMI(wil, "EAPOL len %d from %pM\n", eapol_len, | 504 | wil_dbg_wmi(wil, "EAPOL len %d from %pM\n", eapol_len, |
505 | evt->src_mac); | 505 | evt->src_mac); |
506 | 506 | ||
507 | if (eapol_len > 196) { /* TODO: revisit size limit */ | 507 | if (eapol_len > 196) { /* TODO: revisit size limit */ |
@@ -599,15 +599,15 @@ void wmi_recv_cmd(struct wil6210_priv *wil) | |||
599 | iowrite32(0, wil->csr + HOSTADDR(r->tail) + | 599 | iowrite32(0, wil->csr + HOSTADDR(r->tail) + |
600 | offsetof(struct wil6210_mbox_ring_desc, sync)); | 600 | offsetof(struct wil6210_mbox_ring_desc, sync)); |
601 | /* indicate */ | 601 | /* indicate */ |
602 | wil_dbg_WMI(wil, "Mbox evt %04x %04x %04x %02x\n", | 602 | wil_dbg_wmi(wil, "Mbox evt %04x %04x %04x %02x\n", |
603 | le16_to_cpu(hdr.seq), len, le16_to_cpu(hdr.type), | 603 | le16_to_cpu(hdr.seq), len, le16_to_cpu(hdr.type), |
604 | hdr.flags); | 604 | hdr.flags); |
605 | if ((hdr.type == WIL_MBOX_HDR_TYPE_WMI) && | 605 | if ((hdr.type == WIL_MBOX_HDR_TYPE_WMI) && |
606 | (len >= sizeof(struct wil6210_mbox_hdr_wmi))) { | 606 | (len >= sizeof(struct wil6210_mbox_hdr_wmi))) { |
607 | wil_dbg_WMI(wil, "WMI event 0x%04x\n", | 607 | wil_dbg_wmi(wil, "WMI event 0x%04x\n", |
608 | evt->event.wmi.id); | 608 | evt->event.wmi.id); |
609 | } | 609 | } |
610 | wil_hex_dump_WMI("evt ", DUMP_PREFIX_OFFSET, 16, 1, | 610 | wil_hex_dump_wmi("evt ", DUMP_PREFIX_OFFSET, 16, 1, |
611 | &evt->event.hdr, sizeof(hdr) + len, true); | 611 | &evt->event.hdr, sizeof(hdr) + len, true); |
612 | 612 | ||
613 | /* advance tail */ | 613 | /* advance tail */ |
@@ -623,7 +623,7 @@ void wmi_recv_cmd(struct wil6210_priv *wil) | |||
623 | { | 623 | { |
624 | int q = queue_work(wil->wmi_wq, | 624 | int q = queue_work(wil->wmi_wq, |
625 | &wil->wmi_event_worker); | 625 | &wil->wmi_event_worker); |
626 | wil_dbg_WMI(wil, "queue_work -> %d\n", q); | 626 | wil_dbg_wmi(wil, "queue_work -> %d\n", q); |
627 | } | 627 | } |
628 | } | 628 | } |
629 | } | 629 | } |
@@ -650,7 +650,7 @@ int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len, | |||
650 | cmdid, reply_id, to_msec); | 650 | cmdid, reply_id, to_msec); |
651 | rc = -ETIME; | 651 | rc = -ETIME; |
652 | } else { | 652 | } else { |
653 | wil_dbg_WMI(wil, | 653 | wil_dbg_wmi(wil, |
654 | "wmi_call(0x%04x->0x%04x) completed in %d msec\n", | 654 | "wmi_call(0x%04x->0x%04x) completed in %d msec\n", |
655 | cmdid, reply_id, | 655 | cmdid, reply_id, |
656 | to_msec - jiffies_to_msecs(remain)); | 656 | to_msec - jiffies_to_msecs(remain)); |
@@ -680,7 +680,7 @@ int wmi_set_mac_address(struct wil6210_priv *wil, void *addr) | |||
680 | 680 | ||
681 | memcpy(cmd.mac, addr, ETH_ALEN); | 681 | memcpy(cmd.mac, addr, ETH_ALEN); |
682 | 682 | ||
683 | wil_dbg_WMI(wil, "Set MAC %pM\n", addr); | 683 | wil_dbg_wmi(wil, "Set MAC %pM\n", addr); |
684 | 684 | ||
685 | return wmi_send(wil, WMI_SET_MAC_ADDRESS_CMDID, &cmd, sizeof(cmd)); | 685 | return wmi_send(wil, WMI_SET_MAC_ADDRESS_CMDID, &cmd, sizeof(cmd)); |
686 | } | 686 | } |
@@ -778,7 +778,7 @@ int wmi_tx_eapol(struct wil6210_priv *wil, struct sk_buff *skb) | |||
778 | 778 | ||
779 | skb_set_mac_header(skb, 0); | 779 | skb_set_mac_header(skb, 0); |
780 | eth = eth_hdr(skb); | 780 | eth = eth_hdr(skb); |
781 | wil_dbg_WMI(wil, "EAPOL %d bytes to %pM\n", eapol_len, eth->h_dest); | 781 | wil_dbg_wmi(wil, "EAPOL %d bytes to %pM\n", eapol_len, eth->h_dest); |
782 | for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) { | 782 | for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) { |
783 | if (memcmp(wil->dst_addr[i], eth->h_dest, ETH_ALEN) == 0) | 783 | if (memcmp(wil->dst_addr[i], eth->h_dest, ETH_ALEN) == 0) |
784 | goto found_dest; | 784 | goto found_dest; |
@@ -853,11 +853,60 @@ int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie) | |||
853 | return rc; | 853 | return rc; |
854 | } | 854 | } |
855 | 855 | ||
856 | int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring) | ||
857 | { | ||
858 | struct wireless_dev *wdev = wil->wdev; | ||
859 | struct net_device *ndev = wil_to_ndev(wil); | ||
860 | struct wmi_cfg_rx_chain_cmd cmd = { | ||
861 | .action = WMI_RX_CHAIN_ADD, | ||
862 | .rx_sw_ring = { | ||
863 | .max_mpdu_size = cpu_to_le16(RX_BUF_LEN), | ||
864 | .ring_mem_base = cpu_to_le64(vring->pa), | ||
865 | .ring_size = cpu_to_le16(vring->size), | ||
866 | }, | ||
867 | .mid = 0, /* TODO - what is it? */ | ||
868 | .decap_trans_type = WMI_DECAP_TYPE_802_3, | ||
869 | }; | ||
870 | struct { | ||
871 | struct wil6210_mbox_hdr_wmi wmi; | ||
872 | struct wmi_cfg_rx_chain_done_event evt; | ||
873 | } __packed evt; | ||
874 | int rc; | ||
875 | |||
876 | if (wdev->iftype == NL80211_IFTYPE_MONITOR) { | ||
877 | struct ieee80211_channel *ch = wdev->preset_chandef.chan; | ||
878 | |||
879 | cmd.sniffer_cfg.mode = cpu_to_le32(WMI_SNIFFER_ON); | ||
880 | if (ch) | ||
881 | cmd.sniffer_cfg.channel = ch->hw_value - 1; | ||
882 | cmd.sniffer_cfg.phy_info_mode = | ||
883 | cpu_to_le32(ndev->type == ARPHRD_IEEE80211_RADIOTAP); | ||
884 | cmd.sniffer_cfg.phy_support = | ||
885 | cpu_to_le32((wil->monitor_flags & MONITOR_FLAG_CONTROL) | ||
886 | ? WMI_SNIFFER_CP : WMI_SNIFFER_DP); | ||
887 | } | ||
888 | /* typical time for secure PCP is 840ms */ | ||
889 | rc = wmi_call(wil, WMI_CFG_RX_CHAIN_CMDID, &cmd, sizeof(cmd), | ||
890 | WMI_CFG_RX_CHAIN_DONE_EVENTID, &evt, sizeof(evt), 2000); | ||
891 | if (rc) | ||
892 | return rc; | ||
893 | |||
894 | vring->hwtail = le32_to_cpu(evt.evt.rx_ring_tail_ptr); | ||
895 | |||
896 | wil_dbg_misc(wil, "Rx init: status %d tail 0x%08x\n", | ||
897 | le32_to_cpu(evt.evt.status), vring->hwtail); | ||
898 | |||
899 | if (le32_to_cpu(evt.evt.status) != WMI_CFG_RX_CHAIN_SUCCESS) | ||
900 | rc = -EINVAL; | ||
901 | |||
902 | return rc; | ||
903 | } | ||
904 | |||
856 | void wmi_event_flush(struct wil6210_priv *wil) | 905 | void wmi_event_flush(struct wil6210_priv *wil) |
857 | { | 906 | { |
858 | struct pending_wmi_event *evt, *t; | 907 | struct pending_wmi_event *evt, *t; |
859 | 908 | ||
860 | wil_dbg_WMI(wil, "%s()\n", __func__); | 909 | wil_dbg_wmi(wil, "%s()\n", __func__); |
861 | 910 | ||
862 | list_for_each_entry_safe(evt, t, &wil->pending_wmi_ev, list) { | 911 | list_for_each_entry_safe(evt, t, &wil->pending_wmi_ev, list) { |
863 | list_del(&evt->list); | 912 | list_del(&evt->list); |
@@ -899,7 +948,7 @@ static void wmi_event_handle(struct wil6210_priv *wil, | |||
899 | wmi_evt_call_handler(wil, id, evt_data, | 948 | wmi_evt_call_handler(wil, id, evt_data, |
900 | len - sizeof(*wmi)); | 949 | len - sizeof(*wmi)); |
901 | } | 950 | } |
902 | wil_dbg_WMI(wil, "Complete WMI 0x%04x\n", id); | 951 | wil_dbg_wmi(wil, "Complete WMI 0x%04x\n", id); |
903 | complete(&wil->wmi_ready); | 952 | complete(&wil->wmi_ready); |
904 | return; | 953 | return; |
905 | } | 954 | } |
@@ -964,7 +1013,7 @@ void wmi_connect_worker(struct work_struct *work) | |||
964 | return; | 1013 | return; |
965 | } | 1014 | } |
966 | 1015 | ||
967 | wil_dbg_WMI(wil, "Configure for connection CID %d\n", | 1016 | wil_dbg_wmi(wil, "Configure for connection CID %d\n", |
968 | wil->pending_connect_cid); | 1017 | wil->pending_connect_cid); |
969 | 1018 | ||
970 | rc = wil_vring_init_tx(wil, 0, WIL6210_TX_RING_SIZE, | 1019 | rc = wil_vring_init_tx(wil, 0, WIL6210_TX_RING_SIZE, |
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index 7fc49ca3f597..b1dd5600fd02 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c | |||
@@ -542,9 +542,8 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw, | |||
542 | 542 | ||
543 | if (changed & BSS_CHANGED_ARP_FILTER) { | 543 | if (changed & BSS_CHANGED_ARP_FILTER) { |
544 | /* Hardware ARP filter address list or state changed */ | 544 | /* Hardware ARP filter address list or state changed */ |
545 | brcms_err(core, "%s: arp filtering: enabled %s, count %d" | 545 | brcms_err(core, "%s: arp filtering: %d addresses" |
546 | " (implement)\n", __func__, info->arp_filter_enabled ? | 546 | " (implement)\n", __func__, info->arp_addr_cnt); |
547 | "true" : "false", info->arp_addr_cnt); | ||
548 | } | 547 | } |
549 | 548 | ||
550 | if (changed & BSS_CHANGED_QOS) { | 549 | if (changed & BSS_CHANGED_QOS) { |
diff --git a/drivers/net/wireless/iwlegacy/3945-mac.c b/drivers/net/wireless/iwlegacy/3945-mac.c index 050ce7c70d74..83856d1a6101 100644 --- a/drivers/net/wireless/iwlegacy/3945-mac.c +++ b/drivers/net/wireless/iwlegacy/3945-mac.c | |||
@@ -1001,12 +1001,12 @@ il3945_rx_allocate(struct il_priv *il, gfp_t priority) | |||
1001 | struct list_head *element; | 1001 | struct list_head *element; |
1002 | struct il_rx_buf *rxb; | 1002 | struct il_rx_buf *rxb; |
1003 | struct page *page; | 1003 | struct page *page; |
1004 | dma_addr_t page_dma; | ||
1004 | unsigned long flags; | 1005 | unsigned long flags; |
1005 | gfp_t gfp_mask = priority; | 1006 | gfp_t gfp_mask = priority; |
1006 | 1007 | ||
1007 | while (1) { | 1008 | while (1) { |
1008 | spin_lock_irqsave(&rxq->lock, flags); | 1009 | spin_lock_irqsave(&rxq->lock, flags); |
1009 | |||
1010 | if (list_empty(&rxq->rx_used)) { | 1010 | if (list_empty(&rxq->rx_used)) { |
1011 | spin_unlock_irqrestore(&rxq->lock, flags); | 1011 | spin_unlock_irqrestore(&rxq->lock, flags); |
1012 | return; | 1012 | return; |
@@ -1035,26 +1035,34 @@ il3945_rx_allocate(struct il_priv *il, gfp_t priority) | |||
1035 | break; | 1035 | break; |
1036 | } | 1036 | } |
1037 | 1037 | ||
1038 | /* Get physical address of RB/SKB */ | ||
1039 | page_dma = | ||
1040 | pci_map_page(il->pci_dev, page, 0, | ||
1041 | PAGE_SIZE << il->hw_params.rx_page_order, | ||
1042 | PCI_DMA_FROMDEVICE); | ||
1043 | |||
1044 | if (unlikely(pci_dma_mapping_error(il->pci_dev, page_dma))) { | ||
1045 | __free_pages(page, il->hw_params.rx_page_order); | ||
1046 | break; | ||
1047 | } | ||
1048 | |||
1038 | spin_lock_irqsave(&rxq->lock, flags); | 1049 | spin_lock_irqsave(&rxq->lock, flags); |
1050 | |||
1039 | if (list_empty(&rxq->rx_used)) { | 1051 | if (list_empty(&rxq->rx_used)) { |
1040 | spin_unlock_irqrestore(&rxq->lock, flags); | 1052 | spin_unlock_irqrestore(&rxq->lock, flags); |
1053 | pci_unmap_page(il->pci_dev, page_dma, | ||
1054 | PAGE_SIZE << il->hw_params.rx_page_order, | ||
1055 | PCI_DMA_FROMDEVICE); | ||
1041 | __free_pages(page, il->hw_params.rx_page_order); | 1056 | __free_pages(page, il->hw_params.rx_page_order); |
1042 | return; | 1057 | return; |
1043 | } | 1058 | } |
1059 | |||
1044 | element = rxq->rx_used.next; | 1060 | element = rxq->rx_used.next; |
1045 | rxb = list_entry(element, struct il_rx_buf, list); | 1061 | rxb = list_entry(element, struct il_rx_buf, list); |
1046 | list_del(element); | 1062 | list_del(element); |
1047 | spin_unlock_irqrestore(&rxq->lock, flags); | ||
1048 | 1063 | ||
1049 | rxb->page = page; | 1064 | rxb->page = page; |
1050 | /* Get physical address of RB/SKB */ | 1065 | rxb->page_dma = page_dma; |
1051 | rxb->page_dma = | ||
1052 | pci_map_page(il->pci_dev, page, 0, | ||
1053 | PAGE_SIZE << il->hw_params.rx_page_order, | ||
1054 | PCI_DMA_FROMDEVICE); | ||
1055 | |||
1056 | spin_lock_irqsave(&rxq->lock, flags); | ||
1057 | |||
1058 | list_add_tail(&rxb->list, &rxq->rx_free); | 1066 | list_add_tail(&rxb->list, &rxq->rx_free); |
1059 | rxq->free_count++; | 1067 | rxq->free_count++; |
1060 | il->alloc_rxb_page++; | 1068 | il->alloc_rxb_page++; |
@@ -1284,8 +1292,15 @@ il3945_rx_handle(struct il_priv *il) | |||
1284 | pci_map_page(il->pci_dev, rxb->page, 0, | 1292 | pci_map_page(il->pci_dev, rxb->page, 0, |
1285 | PAGE_SIZE << il->hw_params. | 1293 | PAGE_SIZE << il->hw_params. |
1286 | rx_page_order, PCI_DMA_FROMDEVICE); | 1294 | rx_page_order, PCI_DMA_FROMDEVICE); |
1287 | list_add_tail(&rxb->list, &rxq->rx_free); | 1295 | if (unlikely(pci_dma_mapping_error(il->pci_dev, |
1288 | rxq->free_count++; | 1296 | rxb->page_dma))) { |
1297 | __il_free_pages(il, rxb->page); | ||
1298 | rxb->page = NULL; | ||
1299 | list_add_tail(&rxb->list, &rxq->rx_used); | ||
1300 | } else { | ||
1301 | list_add_tail(&rxb->list, &rxq->rx_free); | ||
1302 | rxq->free_count++; | ||
1303 | } | ||
1289 | } else | 1304 | } else |
1290 | list_add_tail(&rxb->list, &rxq->rx_used); | 1305 | list_add_tail(&rxb->list, &rxq->rx_used); |
1291 | 1306 | ||
diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c index f1dc04006564..9741ac10a334 100644 --- a/drivers/net/wireless/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/iwlegacy/4965-mac.c | |||
@@ -319,6 +319,7 @@ il4965_rx_allocate(struct il_priv *il, gfp_t priority) | |||
319 | struct list_head *element; | 319 | struct list_head *element; |
320 | struct il_rx_buf *rxb; | 320 | struct il_rx_buf *rxb; |
321 | struct page *page; | 321 | struct page *page; |
322 | dma_addr_t page_dma; | ||
322 | unsigned long flags; | 323 | unsigned long flags; |
323 | gfp_t gfp_mask = priority; | 324 | gfp_t gfp_mask = priority; |
324 | 325 | ||
@@ -356,33 +357,35 @@ il4965_rx_allocate(struct il_priv *il, gfp_t priority) | |||
356 | return; | 357 | return; |
357 | } | 358 | } |
358 | 359 | ||
360 | /* Get physical address of the RB */ | ||
361 | page_dma = | ||
362 | pci_map_page(il->pci_dev, page, 0, | ||
363 | PAGE_SIZE << il->hw_params.rx_page_order, | ||
364 | PCI_DMA_FROMDEVICE); | ||
365 | if (unlikely(pci_dma_mapping_error(il->pci_dev, page_dma))) { | ||
366 | __free_pages(page, il->hw_params.rx_page_order); | ||
367 | break; | ||
368 | } | ||
369 | |||
359 | spin_lock_irqsave(&rxq->lock, flags); | 370 | spin_lock_irqsave(&rxq->lock, flags); |
360 | 371 | ||
361 | if (list_empty(&rxq->rx_used)) { | 372 | if (list_empty(&rxq->rx_used)) { |
362 | spin_unlock_irqrestore(&rxq->lock, flags); | 373 | spin_unlock_irqrestore(&rxq->lock, flags); |
374 | pci_unmap_page(il->pci_dev, page_dma, | ||
375 | PAGE_SIZE << il->hw_params.rx_page_order, | ||
376 | PCI_DMA_FROMDEVICE); | ||
363 | __free_pages(page, il->hw_params.rx_page_order); | 377 | __free_pages(page, il->hw_params.rx_page_order); |
364 | return; | 378 | return; |
365 | } | 379 | } |
380 | |||
366 | element = rxq->rx_used.next; | 381 | element = rxq->rx_used.next; |
367 | rxb = list_entry(element, struct il_rx_buf, list); | 382 | rxb = list_entry(element, struct il_rx_buf, list); |
368 | list_del(element); | 383 | list_del(element); |
369 | 384 | ||
370 | spin_unlock_irqrestore(&rxq->lock, flags); | ||
371 | |||
372 | BUG_ON(rxb->page); | 385 | BUG_ON(rxb->page); |
373 | rxb->page = page; | ||
374 | /* Get physical address of the RB */ | ||
375 | rxb->page_dma = | ||
376 | pci_map_page(il->pci_dev, page, 0, | ||
377 | PAGE_SIZE << il->hw_params.rx_page_order, | ||
378 | PCI_DMA_FROMDEVICE); | ||
379 | /* dma address must be no more than 36 bits */ | ||
380 | BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36)); | ||
381 | /* and also 256 byte aligned! */ | ||
382 | BUG_ON(rxb->page_dma & DMA_BIT_MASK(8)); | ||
383 | |||
384 | spin_lock_irqsave(&rxq->lock, flags); | ||
385 | 386 | ||
387 | rxb->page = page; | ||
388 | rxb->page_dma = page_dma; | ||
386 | list_add_tail(&rxb->list, &rxq->rx_free); | 389 | list_add_tail(&rxb->list, &rxq->rx_free); |
387 | rxq->free_count++; | 390 | rxq->free_count++; |
388 | il->alloc_rxb_page++; | 391 | il->alloc_rxb_page++; |
@@ -725,6 +728,16 @@ il4965_hdl_rx(struct il_priv *il, struct il_rx_buf *rxb) | |||
725 | if (rate_n_flags & RATE_MCS_SGI_MSK) | 728 | if (rate_n_flags & RATE_MCS_SGI_MSK) |
726 | rx_status.flag |= RX_FLAG_SHORT_GI; | 729 | rx_status.flag |= RX_FLAG_SHORT_GI; |
727 | 730 | ||
731 | if (phy_res->phy_flags & RX_RES_PHY_FLAGS_AGG_MSK) { | ||
732 | /* We know which subframes of an A-MPDU belong | ||
733 | * together since we get a single PHY response | ||
734 | * from the firmware for all of them. | ||
735 | */ | ||
736 | |||
737 | rx_status.flag |= RX_FLAG_AMPDU_DETAILS; | ||
738 | rx_status.ampdu_reference = il->_4965.ampdu_ref; | ||
739 | } | ||
740 | |||
728 | il4965_pass_packet_to_mac80211(il, header, len, ampdu_status, rxb, | 741 | il4965_pass_packet_to_mac80211(il, header, len, ampdu_status, rxb, |
729 | &rx_status); | 742 | &rx_status); |
730 | } | 743 | } |
@@ -736,6 +749,7 @@ il4965_hdl_rx_phy(struct il_priv *il, struct il_rx_buf *rxb) | |||
736 | { | 749 | { |
737 | struct il_rx_pkt *pkt = rxb_addr(rxb); | 750 | struct il_rx_pkt *pkt = rxb_addr(rxb); |
738 | il->_4965.last_phy_res_valid = true; | 751 | il->_4965.last_phy_res_valid = true; |
752 | il->_4965.ampdu_ref++; | ||
739 | memcpy(&il->_4965.last_phy_res, pkt->u.raw, | 753 | memcpy(&il->_4965.last_phy_res, pkt->u.raw, |
740 | sizeof(struct il_rx_phy_res)); | 754 | sizeof(struct il_rx_phy_res)); |
741 | } | 755 | } |
@@ -4281,8 +4295,16 @@ il4965_rx_handle(struct il_priv *il) | |||
4281 | pci_map_page(il->pci_dev, rxb->page, 0, | 4295 | pci_map_page(il->pci_dev, rxb->page, 0, |
4282 | PAGE_SIZE << il->hw_params. | 4296 | PAGE_SIZE << il->hw_params. |
4283 | rx_page_order, PCI_DMA_FROMDEVICE); | 4297 | rx_page_order, PCI_DMA_FROMDEVICE); |
4284 | list_add_tail(&rxb->list, &rxq->rx_free); | 4298 | |
4285 | rxq->free_count++; | 4299 | if (unlikely(pci_dma_mapping_error(il->pci_dev, |
4300 | rxb->page_dma))) { | ||
4301 | __il_free_pages(il, rxb->page); | ||
4302 | rxb->page = NULL; | ||
4303 | list_add_tail(&rxb->list, &rxq->rx_used); | ||
4304 | } else { | ||
4305 | list_add_tail(&rxb->list, &rxq->rx_free); | ||
4306 | rxq->free_count++; | ||
4307 | } | ||
4286 | } else | 4308 | } else |
4287 | list_add_tail(&rxb->list, &rxq->rx_used); | 4309 | list_add_tail(&rxb->list, &rxq->rx_used); |
4288 | 4310 | ||
@@ -6573,9 +6595,6 @@ il4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
6573 | if (err) | 6595 | if (err) |
6574 | goto out_free_eeprom; | 6596 | goto out_free_eeprom; |
6575 | 6597 | ||
6576 | if (err) | ||
6577 | goto out_free_eeprom; | ||
6578 | |||
6579 | /* extract MAC Address */ | 6598 | /* extract MAC Address */ |
6580 | il4965_eeprom_get_mac(il, il->addresses[0].addr); | 6599 | il4965_eeprom_get_mac(il, il->addresses[0].addr); |
6581 | D_INFO("MAC address: %pM\n", il->addresses[0].addr); | 6600 | D_INFO("MAC address: %pM\n", il->addresses[0].addr); |
diff --git a/drivers/net/wireless/iwlegacy/4965.c b/drivers/net/wireless/iwlegacy/4965.c index 5db11714e047..91eb2d07fdb8 100644 --- a/drivers/net/wireless/iwlegacy/4965.c +++ b/drivers/net/wireless/iwlegacy/4965.c | |||
@@ -1748,7 +1748,6 @@ static void | |||
1748 | il4965_post_associate(struct il_priv *il) | 1748 | il4965_post_associate(struct il_priv *il) |
1749 | { | 1749 | { |
1750 | struct ieee80211_vif *vif = il->vif; | 1750 | struct ieee80211_vif *vif = il->vif; |
1751 | struct ieee80211_conf *conf = NULL; | ||
1752 | int ret = 0; | 1751 | int ret = 0; |
1753 | 1752 | ||
1754 | if (!vif || !il->is_open) | 1753 | if (!vif || !il->is_open) |
@@ -1759,8 +1758,6 @@ il4965_post_associate(struct il_priv *il) | |||
1759 | 1758 | ||
1760 | il_scan_cancel_timeout(il, 200); | 1759 | il_scan_cancel_timeout(il, 200); |
1761 | 1760 | ||
1762 | conf = &il->hw->conf; | ||
1763 | |||
1764 | il->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; | 1761 | il->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; |
1765 | il_commit_rxon(il); | 1762 | il_commit_rxon(il); |
1766 | 1763 | ||
diff --git a/drivers/net/wireless/iwlegacy/commands.h b/drivers/net/wireless/iwlegacy/commands.h index 25dd7d28d022..3b6c99400892 100644 --- a/drivers/net/wireless/iwlegacy/commands.h +++ b/drivers/net/wireless/iwlegacy/commands.h | |||
@@ -1134,8 +1134,9 @@ struct il_wep_cmd { | |||
1134 | #define RX_RES_PHY_FLAGS_MOD_CCK_MSK cpu_to_le16(1 << 1) | 1134 | #define RX_RES_PHY_FLAGS_MOD_CCK_MSK cpu_to_le16(1 << 1) |
1135 | #define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK cpu_to_le16(1 << 2) | 1135 | #define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK cpu_to_le16(1 << 2) |
1136 | #define RX_RES_PHY_FLAGS_NARROW_BAND_MSK cpu_to_le16(1 << 3) | 1136 | #define RX_RES_PHY_FLAGS_NARROW_BAND_MSK cpu_to_le16(1 << 3) |
1137 | #define RX_RES_PHY_FLAGS_ANTENNA_MSK 0xf0 | 1137 | #define RX_RES_PHY_FLAGS_ANTENNA_MSK 0x70 |
1138 | #define RX_RES_PHY_FLAGS_ANTENNA_POS 4 | 1138 | #define RX_RES_PHY_FLAGS_ANTENNA_POS 4 |
1139 | #define RX_RES_PHY_FLAGS_AGG_MSK cpu_to_le16(1 << 7) | ||
1139 | 1140 | ||
1140 | #define RX_RES_STATUS_SEC_TYPE_MSK (0x7 << 8) | 1141 | #define RX_RES_STATUS_SEC_TYPE_MSK (0x7 << 8) |
1141 | #define RX_RES_STATUS_SEC_TYPE_NONE (0x0 << 8) | 1142 | #define RX_RES_STATUS_SEC_TYPE_NONE (0x0 << 8) |
diff --git a/drivers/net/wireless/iwlegacy/common.h b/drivers/net/wireless/iwlegacy/common.h index 37fe553b25e0..96f2025d936e 100644 --- a/drivers/net/wireless/iwlegacy/common.h +++ b/drivers/net/wireless/iwlegacy/common.h | |||
@@ -1356,6 +1356,7 @@ struct il_priv { | |||
1356 | struct { | 1356 | struct { |
1357 | struct il_rx_phy_res last_phy_res; | 1357 | struct il_rx_phy_res last_phy_res; |
1358 | bool last_phy_res_valid; | 1358 | bool last_phy_res_valid; |
1359 | u32 ampdu_ref; | ||
1359 | 1360 | ||
1360 | struct completion firmware_loading_complete; | 1361 | struct completion firmware_loading_complete; |
1361 | 1362 | ||
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index 5cf43236421e..ba319cba3f1e 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig | |||
@@ -43,8 +43,20 @@ config IWLWIFI | |||
43 | module will be called iwlwifi. | 43 | module will be called iwlwifi. |
44 | 44 | ||
45 | config IWLDVM | 45 | config IWLDVM |
46 | tristate "Intel Wireless WiFi" | 46 | tristate "Intel Wireless WiFi DVM Firmware support" |
47 | depends on IWLWIFI | 47 | depends on IWLWIFI |
48 | help | ||
49 | This is the driver supporting the DVM firmware which is | ||
50 | currently the only firmware available for existing devices. | ||
51 | |||
52 | config IWLMVM | ||
53 | tristate "Intel Wireless WiFi MVM Firmware support" | ||
54 | depends on IWLWIFI | ||
55 | help | ||
56 | This is the driver supporting the MVM firmware which is | ||
57 | currently only available for 7000 series devices. | ||
58 | |||
59 | Say yes if you have such a device. | ||
48 | 60 | ||
49 | menu "Debugging Options" | 61 | menu "Debugging Options" |
50 | depends on IWLWIFI | 62 | depends on IWLWIFI |
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 170ec330d2a9..6c7800044a04 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile | |||
@@ -5,8 +5,10 @@ iwlwifi-objs += iwl-drv.o | |||
5 | iwlwifi-objs += iwl-debug.o | 5 | iwlwifi-objs += iwl-debug.o |
6 | iwlwifi-objs += iwl-notif-wait.o | 6 | iwlwifi-objs += iwl-notif-wait.o |
7 | iwlwifi-objs += iwl-eeprom-read.o iwl-eeprom-parse.o | 7 | iwlwifi-objs += iwl-eeprom-read.o iwl-eeprom-parse.o |
8 | iwlwifi-objs += iwl-phy-db.o iwl-nvm-parse.o | ||
8 | iwlwifi-objs += pcie/drv.o pcie/rx.o pcie/tx.o pcie/trans.o | 9 | iwlwifi-objs += pcie/drv.o pcie/rx.o pcie/tx.o pcie/trans.o |
9 | iwlwifi-objs += pcie/1000.o pcie/2000.o pcie/5000.o pcie/6000.o | 10 | iwlwifi-objs += pcie/1000.o pcie/2000.o pcie/5000.o pcie/6000.o |
11 | iwlwifi-objs += pcie/7000.o | ||
10 | 12 | ||
11 | iwlwifi-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o | 13 | iwlwifi-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o |
12 | iwlwifi-$(CONFIG_IWLWIFI_DEVICE_TESTMODE) += iwl-test.o | 14 | iwlwifi-$(CONFIG_IWLWIFI_DEVICE_TESTMODE) += iwl-test.o |
@@ -15,5 +17,6 @@ ccflags-y += -D__CHECK_ENDIAN__ -I$(src) | |||
15 | 17 | ||
16 | 18 | ||
17 | obj-$(CONFIG_IWLDVM) += dvm/ | 19 | obj-$(CONFIG_IWLDVM) += dvm/ |
20 | obj-$(CONFIG_IWLMVM) += mvm/ | ||
18 | 21 | ||
19 | CFLAGS_iwl-devtrace.o := -I$(src) | 22 | CFLAGS_iwl-devtrace.o := -I$(src) |
diff --git a/drivers/net/wireless/iwlwifi/dvm/agn.h b/drivers/net/wireless/iwlwifi/dvm/agn.h index 33b3ad2e546b..f41ae79e6bc0 100644 --- a/drivers/net/wireless/iwlwifi/dvm/agn.h +++ b/drivers/net/wireless/iwlwifi/dvm/agn.h | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
diff --git a/drivers/net/wireless/iwlwifi/dvm/calib.c b/drivers/net/wireless/iwlwifi/dvm/calib.c index de54713b680c..6468de8634b0 100644 --- a/drivers/net/wireless/iwlwifi/dvm/calib.c +++ b/drivers/net/wireless/iwlwifi/dvm/calib.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
diff --git a/drivers/net/wireless/iwlwifi/dvm/calib.h b/drivers/net/wireless/iwlwifi/dvm/calib.h index 2349f393cc42..65e920cab2b7 100644 --- a/drivers/net/wireless/iwlwifi/dvm/calib.h +++ b/drivers/net/wireless/iwlwifi/dvm/calib.h | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
diff --git a/drivers/net/wireless/iwlwifi/dvm/commands.h b/drivers/net/wireless/iwlwifi/dvm/commands.h index 0ca99c13f7f2..8bce4b0148e0 100644 --- a/drivers/net/wireless/iwlwifi/dvm/commands.h +++ b/drivers/net/wireless/iwlwifi/dvm/commands.h | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
diff --git a/drivers/net/wireless/iwlwifi/dvm/debugfs.c b/drivers/net/wireless/iwlwifi/dvm/debugfs.c index 72c74af38138..20806cae11b7 100644 --- a/drivers/net/wireless/iwlwifi/dvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/dvm/debugfs.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * | 2 | * |
3 | * GPL LICENSE SUMMARY | 3 | * GPL LICENSE SUMMARY |
4 | * | 4 | * |
5 | * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved. | 5 | * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of version 2 of the GNU General Public License as | 8 | * it under the terms of version 2 of the GNU General Public License as |
diff --git a/drivers/net/wireless/iwlwifi/dvm/dev.h b/drivers/net/wireless/iwlwifi/dvm/dev.h index 2653a891cc7e..71ea77576d22 100644 --- a/drivers/net/wireless/iwlwifi/dvm/dev.h +++ b/drivers/net/wireless/iwlwifi/dvm/dev.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify it | 5 | * This program is free software; you can redistribute it and/or modify it |
6 | * under the terms of version 2 of the GNU General Public License as | 6 | * under the terms of version 2 of the GNU General Public License as |
diff --git a/drivers/net/wireless/iwlwifi/dvm/devices.c b/drivers/net/wireless/iwlwifi/dvm/devices.c index 8c72be3f37c1..15cca2ef9294 100644 --- a/drivers/net/wireless/iwlwifi/dvm/devices.c +++ b/drivers/net/wireless/iwlwifi/dvm/devices.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify it | 5 | * This program is free software; you can redistribute it and/or modify it |
6 | * under the terms of version 2 of the GNU General Public License as | 6 | * under the terms of version 2 of the GNU General Public License as |
diff --git a/drivers/net/wireless/iwlwifi/dvm/led.c b/drivers/net/wireless/iwlwifi/dvm/led.c index 844a17f99a18..33c7e15d24f5 100644 --- a/drivers/net/wireless/iwlwifi/dvm/led.c +++ b/drivers/net/wireless/iwlwifi/dvm/led.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify it | 5 | * This program is free software; you can redistribute it and/or modify it |
6 | * under the terms of version 2 of the GNU General Public License as | 6 | * under the terms of version 2 of the GNU General Public License as |
diff --git a/drivers/net/wireless/iwlwifi/dvm/led.h b/drivers/net/wireless/iwlwifi/dvm/led.h index b02a853103d3..8749dcfe695f 100644 --- a/drivers/net/wireless/iwlwifi/dvm/led.h +++ b/drivers/net/wireless/iwlwifi/dvm/led.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify it | 5 | * This program is free software; you can redistribute it and/or modify it |
6 | * under the terms of version 2 of the GNU General Public License as | 6 | * under the terms of version 2 of the GNU General Public License as |
diff --git a/drivers/net/wireless/iwlwifi/dvm/lib.c b/drivers/net/wireless/iwlwifi/dvm/lib.c index 6ff46605ad4f..86ea5f4c3939 100644 --- a/drivers/net/wireless/iwlwifi/dvm/lib.c +++ b/drivers/net/wireless/iwlwifi/dvm/lib.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * | 2 | * |
3 | * GPL LICENSE SUMMARY | 3 | * GPL LICENSE SUMMARY |
4 | * | 4 | * |
5 | * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved. | 5 | * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of version 2 of the GNU General Public License as | 8 | * it under the terms of version 2 of the GNU General Public License as |
diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c index 0353e1c0670d..c2f03ecd4bf8 100644 --- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * Portions of this file are derived from the ipw3945 project, as well | 5 | * Portions of this file are derived from the ipw3945 project, as well |
6 | * as portions of the ieee80211 subsystem header files. | 6 | * as portions of the ieee80211 subsystem header files. |
@@ -459,14 +459,12 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw) | |||
459 | 459 | ||
460 | base = priv->device_pointers.error_event_table; | 460 | base = priv->device_pointers.error_event_table; |
461 | if (iwlagn_hw_valid_rtc_data_addr(base)) { | 461 | if (iwlagn_hw_valid_rtc_data_addr(base)) { |
462 | spin_lock_irqsave(&priv->trans->reg_lock, flags); | 462 | if (iwl_trans_grab_nic_access(priv->trans, true, &flags)) { |
463 | if (iwl_trans_grab_nic_access(priv->trans, true)) { | ||
464 | iwl_write32(priv->trans, HBUS_TARG_MEM_RADDR, base); | 463 | iwl_write32(priv->trans, HBUS_TARG_MEM_RADDR, base); |
465 | status = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT); | 464 | status = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT); |
466 | iwl_trans_release_nic_access(priv->trans); | 465 | iwl_trans_release_nic_access(priv->trans, &flags); |
467 | ret = 0; | 466 | ret = 0; |
468 | } | 467 | } |
469 | spin_unlock_irqrestore(&priv->trans->reg_lock, flags); | ||
470 | 468 | ||
471 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 469 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
472 | if (ret == 0) { | 470 | if (ret == 0) { |
@@ -1154,6 +1152,7 @@ static int iwlagn_mac_cancel_remain_on_channel(struct ieee80211_hw *hw) | |||
1154 | } | 1152 | } |
1155 | 1153 | ||
1156 | static void iwlagn_mac_rssi_callback(struct ieee80211_hw *hw, | 1154 | static void iwlagn_mac_rssi_callback(struct ieee80211_hw *hw, |
1155 | struct ieee80211_vif *vif, | ||
1157 | enum ieee80211_rssi_event rssi_event) | 1156 | enum ieee80211_rssi_event rssi_event) |
1158 | { | 1157 | { |
1159 | struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); | 1158 | struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); |
diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c index a64f361e341c..b9e3517652d6 100644 --- a/drivers/net/wireless/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/iwlwifi/dvm/main.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * Portions of this file are derived from the ipw3945 project, as well | 5 | * Portions of this file are derived from the ipw3945 project, as well |
6 | * as portions of the ieee80211 subsystem header files. | 6 | * as portions of the ieee80211 subsystem header files. |
@@ -353,11 +353,8 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base, | |||
353 | ptr = base + (4 * sizeof(u32)) + (start_idx * 3 * sizeof(u32)); | 353 | ptr = base + (4 * sizeof(u32)) + (start_idx * 3 * sizeof(u32)); |
354 | 354 | ||
355 | /* Make sure device is powered up for SRAM reads */ | 355 | /* Make sure device is powered up for SRAM reads */ |
356 | spin_lock_irqsave(&priv->trans->reg_lock, reg_flags); | 356 | if (!iwl_trans_grab_nic_access(priv->trans, false, ®_flags)) |
357 | if (!iwl_trans_grab_nic_access(priv->trans, false)) { | ||
358 | spin_unlock_irqrestore(&priv->trans->reg_lock, reg_flags); | ||
359 | return; | 357 | return; |
360 | } | ||
361 | 358 | ||
362 | /* Set starting address; reads will auto-increment */ | 359 | /* Set starting address; reads will auto-increment */ |
363 | iwl_write32(priv->trans, HBUS_TARG_MEM_RADDR, ptr); | 360 | iwl_write32(priv->trans, HBUS_TARG_MEM_RADDR, ptr); |
@@ -388,8 +385,7 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base, | |||
388 | } | 385 | } |
389 | } | 386 | } |
390 | /* Allow device to power down */ | 387 | /* Allow device to power down */ |
391 | iwl_trans_release_nic_access(priv->trans); | 388 | iwl_trans_release_nic_access(priv->trans, ®_flags); |
392 | spin_unlock_irqrestore(&priv->trans->reg_lock, reg_flags); | ||
393 | } | 389 | } |
394 | 390 | ||
395 | static void iwl_continuous_event_trace(struct iwl_priv *priv) | 391 | static void iwl_continuous_event_trace(struct iwl_priv *priv) |
@@ -1717,9 +1713,8 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, | |||
1717 | ptr = base + EVENT_START_OFFSET + (start_idx * event_size); | 1713 | ptr = base + EVENT_START_OFFSET + (start_idx * event_size); |
1718 | 1714 | ||
1719 | /* Make sure device is powered up for SRAM reads */ | 1715 | /* Make sure device is powered up for SRAM reads */ |
1720 | spin_lock_irqsave(&trans->reg_lock, reg_flags); | 1716 | if (!iwl_trans_grab_nic_access(trans, false, ®_flags)) |
1721 | if (!iwl_trans_grab_nic_access(trans, false)) | 1717 | return pos; |
1722 | goto out_unlock; | ||
1723 | 1718 | ||
1724 | /* Set starting address; reads will auto-increment */ | 1719 | /* Set starting address; reads will auto-increment */ |
1725 | iwl_write32(trans, HBUS_TARG_MEM_RADDR, ptr); | 1720 | iwl_write32(trans, HBUS_TARG_MEM_RADDR, ptr); |
@@ -1757,9 +1752,7 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, | |||
1757 | } | 1752 | } |
1758 | 1753 | ||
1759 | /* Allow device to power down */ | 1754 | /* Allow device to power down */ |
1760 | iwl_trans_release_nic_access(trans); | 1755 | iwl_trans_release_nic_access(trans, ®_flags); |
1761 | out_unlock: | ||
1762 | spin_unlock_irqrestore(&trans->reg_lock, reg_flags); | ||
1763 | return pos; | 1756 | return pos; |
1764 | } | 1757 | } |
1765 | 1758 | ||
@@ -1991,13 +1984,13 @@ static void iwl_nic_config(struct iwl_op_mode *op_mode) | |||
1991 | struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); | 1984 | struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); |
1992 | 1985 | ||
1993 | /* SKU Control */ | 1986 | /* SKU Control */ |
1994 | iwl_set_bits_mask(priv->trans, CSR_HW_IF_CONFIG_REG, | 1987 | iwl_trans_set_bits_mask(priv->trans, CSR_HW_IF_CONFIG_REG, |
1995 | CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH | | 1988 | CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH | |
1996 | CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP, | 1989 | CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP, |
1997 | (CSR_HW_REV_STEP(priv->trans->hw_rev) << | 1990 | (CSR_HW_REV_STEP(priv->trans->hw_rev) << |
1998 | CSR_HW_IF_CONFIG_REG_POS_MAC_STEP) | | 1991 | CSR_HW_IF_CONFIG_REG_POS_MAC_STEP) | |
1999 | (CSR_HW_REV_DASH(priv->trans->hw_rev) << | 1992 | (CSR_HW_REV_DASH(priv->trans->hw_rev) << |
2000 | CSR_HW_IF_CONFIG_REG_POS_MAC_DASH)); | 1993 | CSR_HW_IF_CONFIG_REG_POS_MAC_DASH)); |
2001 | 1994 | ||
2002 | /* write radio config values to register */ | 1995 | /* write radio config values to register */ |
2003 | if (priv->nvm_data->radio_cfg_type <= EEPROM_RF_CONFIG_TYPE_MAX) { | 1996 | if (priv->nvm_data->radio_cfg_type <= EEPROM_RF_CONFIG_TYPE_MAX) { |
@@ -2009,10 +2002,11 @@ static void iwl_nic_config(struct iwl_op_mode *op_mode) | |||
2009 | priv->nvm_data->radio_cfg_dash << | 2002 | priv->nvm_data->radio_cfg_dash << |
2010 | CSR_HW_IF_CONFIG_REG_POS_PHY_DASH; | 2003 | CSR_HW_IF_CONFIG_REG_POS_PHY_DASH; |
2011 | 2004 | ||
2012 | iwl_set_bits_mask(priv->trans, CSR_HW_IF_CONFIG_REG, | 2005 | iwl_trans_set_bits_mask(priv->trans, CSR_HW_IF_CONFIG_REG, |
2013 | CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE | | 2006 | CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE | |
2014 | CSR_HW_IF_CONFIG_REG_MSK_PHY_STEP | | 2007 | CSR_HW_IF_CONFIG_REG_MSK_PHY_STEP | |
2015 | CSR_HW_IF_CONFIG_REG_MSK_PHY_DASH, reg_val); | 2008 | CSR_HW_IF_CONFIG_REG_MSK_PHY_DASH, |
2009 | reg_val); | ||
2016 | 2010 | ||
2017 | IWL_INFO(priv, "Radio type=0x%x-0x%x-0x%x\n", | 2011 | IWL_INFO(priv, "Radio type=0x%x-0x%x-0x%x\n", |
2018 | priv->nvm_data->radio_cfg_type, | 2012 | priv->nvm_data->radio_cfg_type, |
diff --git a/drivers/net/wireless/iwlwifi/dvm/power.c b/drivers/net/wireless/iwlwifi/dvm/power.c index 518cf3715809..bd69018d07a9 100644 --- a/drivers/net/wireless/iwlwifi/dvm/power.c +++ b/drivers/net/wireless/iwlwifi/dvm/power.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * Portions of this file are derived from the ipw3945 project, as well | 5 | * Portions of this file are derived from the ipw3945 project, as well |
6 | * as portions of the ieee80211 subsystem header files. | 6 | * as portions of the ieee80211 subsystem header files. |
diff --git a/drivers/net/wireless/iwlwifi/dvm/power.h b/drivers/net/wireless/iwlwifi/dvm/power.h index a2cee7f04848..7b03e1342d47 100644 --- a/drivers/net/wireless/iwlwifi/dvm/power.h +++ b/drivers/net/wireless/iwlwifi/dvm/power.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * Portions of this file are derived from the ipw3945 project, as well | 5 | * Portions of this file are derived from the ipw3945 project, as well |
6 | * as portions of the ieee80211 subsystem header files. | 6 | * as portions of the ieee80211 subsystem header files. |
diff --git a/drivers/net/wireless/iwlwifi/dvm/rs.c b/drivers/net/wireless/iwlwifi/dvm/rs.c index f3dd0da60d8a..a131227c49e9 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rs.c +++ b/drivers/net/wireless/iwlwifi/dvm/rs.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify it | 5 | * This program is free software; you can redistribute it and/or modify it |
6 | * under the terms of version 2 of the GNU General Public License as | 6 | * under the terms of version 2 of the GNU General Public License as |
@@ -411,8 +411,9 @@ static int rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv, | |||
411 | * BT traffic, as they would just be disrupted by BT. | 411 | * BT traffic, as they would just be disrupted by BT. |
412 | */ | 412 | */ |
413 | if (priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH) { | 413 | if (priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH) { |
414 | IWL_ERR(priv, "BT traffic (%d), no aggregation allowed\n", | 414 | IWL_DEBUG_COEX(priv, |
415 | priv->bt_traffic_load); | 415 | "BT traffic (%d), no aggregation allowed\n", |
416 | priv->bt_traffic_load); | ||
416 | return ret; | 417 | return ret; |
417 | } | 418 | } |
418 | 419 | ||
diff --git a/drivers/net/wireless/iwlwifi/dvm/rs.h b/drivers/net/wireless/iwlwifi/dvm/rs.h index ad3aea8f626a..5d83cab22d62 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rs.h +++ b/drivers/net/wireless/iwlwifi/dvm/rs.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify it | 5 | * This program is free software; you can redistribute it and/or modify it |
6 | * under the terms of version 2 of the GNU General Public License as | 6 | * under the terms of version 2 of the GNU General Public License as |
diff --git a/drivers/net/wireless/iwlwifi/dvm/rx.c b/drivers/net/wireless/iwlwifi/dvm/rx.c index cac4f37cc427..e8d5b90abf5c 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rx.c +++ b/drivers/net/wireless/iwlwifi/dvm/rx.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * Portions of this file are derived from the ipw3945 project, as well | 5 | * Portions of this file are derived from the ipw3945 project, as well |
6 | * as portionhelp of the ieee80211 subsystem header files. | 6 | * as portionhelp of the ieee80211 subsystem header files. |
diff --git a/drivers/net/wireless/iwlwifi/dvm/rxon.c b/drivers/net/wireless/iwlwifi/dvm/rxon.c index 9a891e6e60e8..9fabd26997ca 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rxon.c +++ b/drivers/net/wireless/iwlwifi/dvm/rxon.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify it | 5 | * This program is free software; you can redistribute it and/or modify it |
6 | * under the terms of version 2 of the GNU General Public License as | 6 | * under the terms of version 2 of the GNU General Public License as |
diff --git a/drivers/net/wireless/iwlwifi/dvm/scan.c b/drivers/net/wireless/iwlwifi/dvm/scan.c index 610ed2204e1f..3a4aa5239c45 100644 --- a/drivers/net/wireless/iwlwifi/dvm/scan.c +++ b/drivers/net/wireless/iwlwifi/dvm/scan.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * | 2 | * |
3 | * GPL LICENSE SUMMARY | 3 | * GPL LICENSE SUMMARY |
4 | * | 4 | * |
5 | * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved. | 5 | * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of version 2 of the GNU General Public License as | 8 | * it under the terms of version 2 of the GNU General Public License as |
diff --git a/drivers/net/wireless/iwlwifi/dvm/sta.c b/drivers/net/wireless/iwlwifi/dvm/sta.c index bdba9543c351..ab768045696b 100644 --- a/drivers/net/wireless/iwlwifi/dvm/sta.c +++ b/drivers/net/wireless/iwlwifi/dvm/sta.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * Portions of this file are derived from the ipw3945 project, as well | 5 | * Portions of this file are derived from the ipw3945 project, as well |
6 | * as portions of the ieee80211 subsystem header files. | 6 | * as portions of the ieee80211 subsystem header files. |
diff --git a/drivers/net/wireless/iwlwifi/dvm/testmode.c b/drivers/net/wireless/iwlwifi/dvm/testmode.c index 57b918ce3b5f..dc6f965a123a 100644 --- a/drivers/net/wireless/iwlwifi/dvm/testmode.c +++ b/drivers/net/wireless/iwlwifi/dvm/testmode.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2010 - 2012 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2010 - 2013 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2010 - 2012 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2010 - 2013 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
diff --git a/drivers/net/wireless/iwlwifi/dvm/tt.c b/drivers/net/wireless/iwlwifi/dvm/tt.c index b28cfc8553d7..67e2e1321b40 100644 --- a/drivers/net/wireless/iwlwifi/dvm/tt.c +++ b/drivers/net/wireless/iwlwifi/dvm/tt.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * Portions of this file are derived from the ipw3945 project, as well | 5 | * Portions of this file are derived from the ipw3945 project, as well |
6 | * as portions of the ieee80211 subsystem header files. | 6 | * as portions of the ieee80211 subsystem header files. |
@@ -185,10 +185,8 @@ static void iwl_tt_check_exit_ct_kill(unsigned long data) | |||
185 | priv->thermal_throttle.ct_kill_toggle = true; | 185 | priv->thermal_throttle.ct_kill_toggle = true; |
186 | } | 186 | } |
187 | iwl_read32(priv->trans, CSR_UCODE_DRV_GP1); | 187 | iwl_read32(priv->trans, CSR_UCODE_DRV_GP1); |
188 | spin_lock_irqsave(&priv->trans->reg_lock, flags); | 188 | if (iwl_trans_grab_nic_access(priv->trans, false, &flags)) |
189 | if (iwl_trans_grab_nic_access(priv->trans, false)) | 189 | iwl_trans_release_nic_access(priv->trans, &flags); |
190 | iwl_trans_release_nic_access(priv->trans); | ||
191 | spin_unlock_irqrestore(&priv->trans->reg_lock, flags); | ||
192 | 190 | ||
193 | /* Reschedule the ct_kill timer to occur in | 191 | /* Reschedule the ct_kill timer to occur in |
194 | * CT_KILL_EXIT_DURATION seconds to ensure we get a | 192 | * CT_KILL_EXIT_DURATION seconds to ensure we get a |
diff --git a/drivers/net/wireless/iwlwifi/dvm/tt.h b/drivers/net/wireless/iwlwifi/dvm/tt.h index 44c7c8f30a2d..9356c4b908ca 100644 --- a/drivers/net/wireless/iwlwifi/dvm/tt.h +++ b/drivers/net/wireless/iwlwifi/dvm/tt.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * Portions of this file are derived from the ipw3945 project, as well | 5 | * Portions of this file are derived from the ipw3945 project, as well |
6 | * as portions of the ieee80211 subsystem header files. | 6 | * as portions of the ieee80211 subsystem header files. |
diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c index 191b9d4bee47..f4a013675947 100644 --- a/drivers/net/wireless/iwlwifi/dvm/tx.c +++ b/drivers/net/wireless/iwlwifi/dvm/tx.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * | 2 | * |
3 | * GPL LICENSE SUMMARY | 3 | * GPL LICENSE SUMMARY |
4 | * | 4 | * |
5 | * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved. | 5 | * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of version 2 of the GNU General Public License as | 8 | * it under the terms of version 2 of the GNU General Public License as |
diff --git a/drivers/net/wireless/iwlwifi/dvm/ucode.c b/drivers/net/wireless/iwlwifi/dvm/ucode.c index ebec13a3329f..736fe9bb140e 100644 --- a/drivers/net/wireless/iwlwifi/dvm/ucode.c +++ b/drivers/net/wireless/iwlwifi/dvm/ucode.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * | 2 | * |
3 | * GPL LICENSE SUMMARY | 3 | * GPL LICENSE SUMMARY |
4 | * | 4 | * |
5 | * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved. | 5 | * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of version 2 of the GNU General Public License as | 8 | * it under the terms of version 2 of the GNU General Public License as |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hw.h b/drivers/net/wireless/iwlwifi/iwl-agn-hw.h index 7960a52f6ad4..e9975c54c276 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-hw.h | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index 864219d2136a..743b48343358 100644 --- a/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/iwlwifi/iwl-config.h | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
@@ -83,6 +83,7 @@ enum iwl_device_family { | |||
83 | IWL_DEVICE_FAMILY_6030, | 83 | IWL_DEVICE_FAMILY_6030, |
84 | IWL_DEVICE_FAMILY_6050, | 84 | IWL_DEVICE_FAMILY_6050, |
85 | IWL_DEVICE_FAMILY_6150, | 85 | IWL_DEVICE_FAMILY_6150, |
86 | IWL_DEVICE_FAMILY_7000, | ||
86 | }; | 87 | }; |
87 | 88 | ||
88 | /* | 89 | /* |
diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index b419a1efac0a..df3463a38704 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 42b20b0e83bc..8cf5db7fb5c9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * Portions of this file are derived from the ipw3945 project. | 5 | * Portions of this file are derived from the ipw3945 project. |
6 | * | 6 | * |
@@ -116,6 +116,7 @@ do { \ | |||
116 | #define IWL_DL_HCMD 0x00000004 | 116 | #define IWL_DL_HCMD 0x00000004 |
117 | #define IWL_DL_STATE 0x00000008 | 117 | #define IWL_DL_STATE 0x00000008 |
118 | /* 0x000000F0 - 0x00000010 */ | 118 | /* 0x000000F0 - 0x00000010 */ |
119 | #define IWL_DL_TE 0x00000020 | ||
119 | #define IWL_DL_EEPROM 0x00000040 | 120 | #define IWL_DL_EEPROM 0x00000040 |
120 | #define IWL_DL_RADIO 0x00000080 | 121 | #define IWL_DL_RADIO 0x00000080 |
121 | /* 0x00000F00 - 0x00000100 */ | 122 | /* 0x00000F00 - 0x00000100 */ |
@@ -156,6 +157,7 @@ do { \ | |||
156 | #define IWL_DEBUG_LED(p, f, a...) IWL_DEBUG(p, IWL_DL_LED, f, ## a) | 157 | #define IWL_DEBUG_LED(p, f, a...) IWL_DEBUG(p, IWL_DL_LED, f, ## a) |
157 | #define IWL_DEBUG_WEP(p, f, a...) IWL_DEBUG(p, IWL_DL_WEP, f, ## a) | 158 | #define IWL_DEBUG_WEP(p, f, a...) IWL_DEBUG(p, IWL_DL_WEP, f, ## a) |
158 | #define IWL_DEBUG_HC(p, f, a...) IWL_DEBUG(p, IWL_DL_HCMD, f, ## a) | 159 | #define IWL_DEBUG_HC(p, f, a...) IWL_DEBUG(p, IWL_DL_HCMD, f, ## a) |
160 | #define IWL_DEBUG_TE(p, f, a...) IWL_DEBUG(p, IWL_DL_TE, f, ## a) | ||
159 | #define IWL_DEBUG_EEPROM(d, f, a...) IWL_DEBUG_DEV(d, IWL_DL_EEPROM, f, ## a) | 161 | #define IWL_DEBUG_EEPROM(d, f, a...) IWL_DEBUG_DEV(d, IWL_DL_EEPROM, f, ## a) |
160 | #define IWL_DEBUG_CALIB(p, f, a...) IWL_DEBUG(p, IWL_DL_CALIB, f, ## a) | 162 | #define IWL_DEBUG_CALIB(p, f, a...) IWL_DEBUG(p, IWL_DL_CALIB, f, ## a) |
161 | #define IWL_DEBUG_FW(p, f, a...) IWL_DEBUG(p, IWL_DL_FW, f, ## a) | 163 | #define IWL_DEBUG_FW(p, f, a...) IWL_DEBUG(p, IWL_DL_FW, f, ## a) |
diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.c b/drivers/net/wireless/iwlwifi/iwl-devtrace.c index 70191ddbd8f6..8f61c717f619 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.c +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2009 - 2012 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2009 - 2013 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify it | 5 | * This program is free software; you can redistribute it and/or modify it |
6 | * under the terms of version 2 of the GNU General Public License as | 6 | * under the terms of version 2 of the GNU General Public License as |
diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h index dc7e26b2f383..9a0f45ec9e01 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2009 - 2012 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2009 - 2013 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify it | 5 | * This program is free software; you can redistribute it and/or modify it |
6 | * under the terms of version 2 of the GNU General Public License as | 6 | * under the terms of version 2 of the GNU General Public License as |
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index d3549f493a17..6f228bb2b844 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
@@ -139,8 +139,10 @@ struct iwl_drv { | |||
139 | #endif | 139 | #endif |
140 | }; | 140 | }; |
141 | 141 | ||
142 | #define DVM_OP_MODE 0 | 142 | enum { |
143 | #define MVM_OP_MODE 1 | 143 | DVM_OP_MODE = 0, |
144 | MVM_OP_MODE = 1, | ||
145 | }; | ||
144 | 146 | ||
145 | /* Protects the table contents, i.e. the ops pointer & drv list */ | 147 | /* Protects the table contents, i.e. the ops pointer & drv list */ |
146 | static struct mutex iwlwifi_opmode_table_mtx; | 148 | static struct mutex iwlwifi_opmode_table_mtx; |
@@ -149,8 +151,8 @@ static struct iwlwifi_opmode_table { | |||
149 | const struct iwl_op_mode_ops *ops; /* pointer to op_mode ops */ | 151 | const struct iwl_op_mode_ops *ops; /* pointer to op_mode ops */ |
150 | struct list_head drv; /* list of devices using this op_mode */ | 152 | struct list_head drv; /* list of devices using this op_mode */ |
151 | } iwlwifi_opmode_table[] = { /* ops set when driver is initialized */ | 153 | } iwlwifi_opmode_table[] = { /* ops set when driver is initialized */ |
152 | { .name = "iwldvm", .ops = NULL }, | 154 | [DVM_OP_MODE] = { .name = "iwldvm", .ops = NULL }, |
153 | { .name = "iwlmvm", .ops = NULL }, | 155 | [MVM_OP_MODE] = { .name = "iwlmvm", .ops = NULL }, |
154 | }; | 156 | }; |
155 | 157 | ||
156 | /* | 158 | /* |
@@ -268,7 +270,7 @@ struct fw_sec_parsing { | |||
268 | */ | 270 | */ |
269 | struct iwl_tlv_calib_data { | 271 | struct iwl_tlv_calib_data { |
270 | __le32 ucode_type; | 272 | __le32 ucode_type; |
271 | __le64 calib; | 273 | struct iwl_tlv_calib_ctrl calib; |
272 | } __packed; | 274 | } __packed; |
273 | 275 | ||
274 | struct iwl_firmware_pieces { | 276 | struct iwl_firmware_pieces { |
@@ -358,7 +360,11 @@ static int iwl_set_default_calib(struct iwl_drv *drv, const u8 *data) | |||
358 | ucode_type); | 360 | ucode_type); |
359 | return -EINVAL; | 361 | return -EINVAL; |
360 | } | 362 | } |
361 | drv->fw.default_calib[ucode_type] = le64_to_cpu(def_calib->calib); | 363 | drv->fw.default_calib[ucode_type].flow_trigger = |
364 | def_calib->calib.flow_trigger; | ||
365 | drv->fw.default_calib[ucode_type].event_trigger = | ||
366 | def_calib->calib.event_trigger; | ||
367 | |||
362 | return 0; | 368 | return 0; |
363 | } | 369 | } |
364 | 370 | ||
@@ -959,7 +965,10 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) | |||
959 | release_firmware(ucode_raw); | 965 | release_firmware(ucode_raw); |
960 | 966 | ||
961 | mutex_lock(&iwlwifi_opmode_table_mtx); | 967 | mutex_lock(&iwlwifi_opmode_table_mtx); |
962 | op = &iwlwifi_opmode_table[DVM_OP_MODE]; | 968 | if (fw->mvm_fw) |
969 | op = &iwlwifi_opmode_table[MVM_OP_MODE]; | ||
970 | else | ||
971 | op = &iwlwifi_opmode_table[DVM_OP_MODE]; | ||
963 | 972 | ||
964 | /* add this device to the list of devices using this op_mode */ | 973 | /* add this device to the list of devices using this op_mode */ |
965 | list_add_tail(&drv->list, &op->drv); | 974 | list_add_tail(&drv->list, &op->drv); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.h b/drivers/net/wireless/iwlwifi/iwl-drv.h index 285de5f68c05..594a5c71b272 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.h +++ b/drivers/net/wireless/iwlwifi/iwl-drv.h | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
@@ -66,7 +66,7 @@ | |||
66 | /* for all modules */ | 66 | /* for all modules */ |
67 | #define DRV_NAME "iwlwifi" | 67 | #define DRV_NAME "iwlwifi" |
68 | #define IWLWIFI_VERSION "in-tree:" | 68 | #define IWLWIFI_VERSION "in-tree:" |
69 | #define DRV_COPYRIGHT "Copyright(c) 2003-2012 Intel Corporation" | 69 | #define DRV_COPYRIGHT "Copyright(c) 2003-2013 Intel Corporation" |
70 | #define DRV_AUTHOR "<ilw@linux.intel.com>" | 70 | #define DRV_AUTHOR "<ilw@linux.intel.com>" |
71 | 71 | ||
72 | 72 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c index 471986690cf0..034f2ff4f43d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
@@ -703,9 +703,9 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, | |||
703 | return n_channels; | 703 | return n_channels; |
704 | } | 704 | } |
705 | 705 | ||
706 | static int iwl_init_sband_channels(struct iwl_nvm_data *data, | 706 | int iwl_init_sband_channels(struct iwl_nvm_data *data, |
707 | struct ieee80211_supported_band *sband, | 707 | struct ieee80211_supported_band *sband, |
708 | int n_channels, enum ieee80211_band band) | 708 | int n_channels, enum ieee80211_band band) |
709 | { | 709 | { |
710 | struct ieee80211_channel *chan = &data->channels[0]; | 710 | struct ieee80211_channel *chan = &data->channels[0]; |
711 | int n = 0, idx = 0; | 711 | int n = 0, idx = 0; |
@@ -728,10 +728,10 @@ static int iwl_init_sband_channels(struct iwl_nvm_data *data, | |||
728 | #define MAX_BIT_RATE_40_MHZ 150 /* Mbps */ | 728 | #define MAX_BIT_RATE_40_MHZ 150 /* Mbps */ |
729 | #define MAX_BIT_RATE_20_MHZ 72 /* Mbps */ | 729 | #define MAX_BIT_RATE_20_MHZ 72 /* Mbps */ |
730 | 730 | ||
731 | static void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg, | 731 | void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg, |
732 | struct iwl_nvm_data *data, | 732 | struct iwl_nvm_data *data, |
733 | struct ieee80211_sta_ht_cap *ht_info, | 733 | struct ieee80211_sta_ht_cap *ht_info, |
734 | enum ieee80211_band band) | 734 | enum ieee80211_band band) |
735 | { | 735 | { |
736 | int max_bit_rate = 0; | 736 | int max_bit_rate = 0; |
737 | u8 rx_chains; | 737 | u8 rx_chains; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h index 555f0eb61d48..683fe6a8c58f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
@@ -126,4 +126,13 @@ static inline void iwl_free_nvm_data(struct iwl_nvm_data *data) | |||
126 | int iwl_nvm_check_version(struct iwl_nvm_data *data, | 126 | int iwl_nvm_check_version(struct iwl_nvm_data *data, |
127 | struct iwl_trans *trans); | 127 | struct iwl_trans *trans); |
128 | 128 | ||
129 | int iwl_init_sband_channels(struct iwl_nvm_data *data, | ||
130 | struct ieee80211_supported_band *sband, | ||
131 | int n_channels, enum ieee80211_band band); | ||
132 | |||
133 | void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg, | ||
134 | struct iwl_nvm_data *data, | ||
135 | struct ieee80211_sta_ht_cap *ht_info, | ||
136 | enum ieee80211_band band); | ||
137 | |||
129 | #endif /* __iwl_eeprom_parse_h__ */ | 138 | #endif /* __iwl_eeprom_parse_h__ */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-read.c b/drivers/net/wireless/iwlwifi/iwl-eeprom-read.c index 27c7da3c6ed1..ef4806f27cf8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom-read.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-read.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-read.h b/drivers/net/wireless/iwlwifi/iwl-eeprom-read.h index 1337c9d36fee..b2588c5cbf93 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom-read.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-read.h | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h index c646a90b725e..f5592fb3b1ed 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/iwlwifi/iwl-fh.h | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
@@ -414,6 +414,7 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl) | |||
414 | * uCode/driver must write "1" in order to clear this flag | 414 | * uCode/driver must write "1" in order to clear this flag |
415 | */ | 415 | */ |
416 | #define FH_TSSR_TX_ERROR_REG (FH_TSSR_LOWER_BOUND + 0x018) | 416 | #define FH_TSSR_TX_ERROR_REG (FH_TSSR_LOWER_BOUND + 0x018) |
417 | #define FH_TSSR_TX_MSG_CONFIG_REG (FH_TSSR_LOWER_BOUND + 0x008) | ||
417 | 418 | ||
418 | #define FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(_chnl) ((1 << (_chnl)) << 16) | 419 | #define FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(_chnl) ((1 << (_chnl)) << 16) |
419 | 420 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index e71564053e7f..90873eca35f7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index 715291eb7f8e..b545178e46e3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
@@ -139,6 +139,19 @@ struct fw_img { | |||
139 | #define IWL_UCODE_API(ver) (((ver) & 0x0000FF00) >> 8) | 139 | #define IWL_UCODE_API(ver) (((ver) & 0x0000FF00) >> 8) |
140 | #define IWL_UCODE_SERIAL(ver) ((ver) & 0x000000FF) | 140 | #define IWL_UCODE_SERIAL(ver) ((ver) & 0x000000FF) |
141 | 141 | ||
142 | /* | ||
143 | * Calibration control struct. | ||
144 | * Sent as part of the phy configuration command. | ||
145 | * @flow_trigger: bitmap for which calibrations to perform according to | ||
146 | * flow triggers. | ||
147 | * @event_trigger: bitmap for which calibrations to perform according to | ||
148 | * event triggers. | ||
149 | */ | ||
150 | struct iwl_tlv_calib_ctrl { | ||
151 | __le32 flow_trigger; | ||
152 | __le32 event_trigger; | ||
153 | } __packed; | ||
154 | |||
142 | /** | 155 | /** |
143 | * struct iwl_fw - variables associated with the firmware | 156 | * struct iwl_fw - variables associated with the firmware |
144 | * | 157 | * |
@@ -153,6 +166,7 @@ struct fw_img { | |||
153 | * @inst_evtlog_ptr: event log offset for runtime ucode. | 166 | * @inst_evtlog_ptr: event log offset for runtime ucode. |
154 | * @inst_evtlog_size: event log size for runtime ucode. | 167 | * @inst_evtlog_size: event log size for runtime ucode. |
155 | * @inst_errlog_ptr: error log offfset for runtime ucode. | 168 | * @inst_errlog_ptr: error log offfset for runtime ucode. |
169 | * @mvm_fw: indicates this is MVM firmware | ||
156 | */ | 170 | */ |
157 | struct iwl_fw { | 171 | struct iwl_fw { |
158 | u32 ucode_ver; | 172 | u32 ucode_ver; |
@@ -168,7 +182,7 @@ struct iwl_fw { | |||
168 | u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr; | 182 | u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr; |
169 | u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; | 183 | u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; |
170 | 184 | ||
171 | u64 default_calib[IWL_UCODE_TYPE_MAX]; | 185 | struct iwl_tlv_calib_ctrl default_calib[IWL_UCODE_TYPE_MAX]; |
172 | u32 phy_config; | 186 | u32 phy_config; |
173 | 187 | ||
174 | bool mvm_fw; | 188 | bool mvm_fw; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c index bff3ac96c00b..276410d82de4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.c +++ b/drivers/net/wireless/iwlwifi/iwl-io.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * Portions of this file are derived from the ipw3945 project. | 5 | * Portions of this file are derived from the ipw3945 project. |
6 | * | 6 | * |
@@ -35,54 +35,6 @@ | |||
35 | 35 | ||
36 | #define IWL_POLL_INTERVAL 10 /* microseconds */ | 36 | #define IWL_POLL_INTERVAL 10 /* microseconds */ |
37 | 37 | ||
38 | void __iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask) | ||
39 | { | ||
40 | iwl_write32(trans, reg, iwl_read32(trans, reg) | mask); | ||
41 | } | ||
42 | |||
43 | void __iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask) | ||
44 | { | ||
45 | iwl_write32(trans, reg, iwl_read32(trans, reg) & ~mask); | ||
46 | } | ||
47 | |||
48 | void iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask) | ||
49 | { | ||
50 | unsigned long flags; | ||
51 | |||
52 | spin_lock_irqsave(&trans->reg_lock, flags); | ||
53 | __iwl_set_bit(trans, reg, mask); | ||
54 | spin_unlock_irqrestore(&trans->reg_lock, flags); | ||
55 | } | ||
56 | EXPORT_SYMBOL_GPL(iwl_set_bit); | ||
57 | |||
58 | void iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask) | ||
59 | { | ||
60 | unsigned long flags; | ||
61 | |||
62 | spin_lock_irqsave(&trans->reg_lock, flags); | ||
63 | __iwl_clear_bit(trans, reg, mask); | ||
64 | spin_unlock_irqrestore(&trans->reg_lock, flags); | ||
65 | } | ||
66 | EXPORT_SYMBOL_GPL(iwl_clear_bit); | ||
67 | |||
68 | void iwl_set_bits_mask(struct iwl_trans *trans, u32 reg, u32 mask, u32 value) | ||
69 | { | ||
70 | unsigned long flags; | ||
71 | u32 v; | ||
72 | |||
73 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
74 | WARN_ON_ONCE(value & ~mask); | ||
75 | #endif | ||
76 | |||
77 | spin_lock_irqsave(&trans->reg_lock, flags); | ||
78 | v = iwl_read32(trans, reg); | ||
79 | v &= ~mask; | ||
80 | v |= value; | ||
81 | iwl_write32(trans, reg, v); | ||
82 | spin_unlock_irqrestore(&trans->reg_lock, flags); | ||
83 | } | ||
84 | EXPORT_SYMBOL_GPL(iwl_set_bits_mask); | ||
85 | |||
86 | int iwl_poll_bit(struct iwl_trans *trans, u32 addr, | 38 | int iwl_poll_bit(struct iwl_trans *trans, u32 addr, |
87 | u32 bits, u32 mask, int timeout) | 39 | u32 bits, u32 mask, int timeout) |
88 | { | 40 | { |
@@ -103,13 +55,10 @@ u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg) | |||
103 | { | 55 | { |
104 | u32 value = 0x5a5a5a5a; | 56 | u32 value = 0x5a5a5a5a; |
105 | unsigned long flags; | 57 | unsigned long flags; |
106 | 58 | if (iwl_trans_grab_nic_access(trans, false, &flags)) { | |
107 | spin_lock_irqsave(&trans->reg_lock, flags); | ||
108 | if (iwl_trans_grab_nic_access(trans, false)) { | ||
109 | value = iwl_read32(trans, reg); | 59 | value = iwl_read32(trans, reg); |
110 | iwl_trans_release_nic_access(trans); | 60 | iwl_trans_release_nic_access(trans, &flags); |
111 | } | 61 | } |
112 | spin_unlock_irqrestore(&trans->reg_lock, flags); | ||
113 | 62 | ||
114 | return value; | 63 | return value; |
115 | } | 64 | } |
@@ -119,12 +68,10 @@ void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value) | |||
119 | { | 68 | { |
120 | unsigned long flags; | 69 | unsigned long flags; |
121 | 70 | ||
122 | spin_lock_irqsave(&trans->reg_lock, flags); | 71 | if (iwl_trans_grab_nic_access(trans, false, &flags)) { |
123 | if (iwl_trans_grab_nic_access(trans, false)) { | ||
124 | iwl_write32(trans, reg, value); | 72 | iwl_write32(trans, reg, value); |
125 | iwl_trans_release_nic_access(trans); | 73 | iwl_trans_release_nic_access(trans, &flags); |
126 | } | 74 | } |
127 | spin_unlock_irqrestore(&trans->reg_lock, flags); | ||
128 | } | 75 | } |
129 | EXPORT_SYMBOL_GPL(iwl_write_direct32); | 76 | EXPORT_SYMBOL_GPL(iwl_write_direct32); |
130 | 77 | ||
@@ -162,12 +109,10 @@ u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs) | |||
162 | unsigned long flags; | 109 | unsigned long flags; |
163 | u32 val = 0x5a5a5a5a; | 110 | u32 val = 0x5a5a5a5a; |
164 | 111 | ||
165 | spin_lock_irqsave(&trans->reg_lock, flags); | 112 | if (iwl_trans_grab_nic_access(trans, false, &flags)) { |
166 | if (iwl_trans_grab_nic_access(trans, false)) { | ||
167 | val = __iwl_read_prph(trans, ofs); | 113 | val = __iwl_read_prph(trans, ofs); |
168 | iwl_trans_release_nic_access(trans); | 114 | iwl_trans_release_nic_access(trans, &flags); |
169 | } | 115 | } |
170 | spin_unlock_irqrestore(&trans->reg_lock, flags); | ||
171 | return val; | 116 | return val; |
172 | } | 117 | } |
173 | EXPORT_SYMBOL_GPL(iwl_read_prph); | 118 | EXPORT_SYMBOL_GPL(iwl_read_prph); |
@@ -176,12 +121,10 @@ void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val) | |||
176 | { | 121 | { |
177 | unsigned long flags; | 122 | unsigned long flags; |
178 | 123 | ||
179 | spin_lock_irqsave(&trans->reg_lock, flags); | 124 | if (iwl_trans_grab_nic_access(trans, false, &flags)) { |
180 | if (iwl_trans_grab_nic_access(trans, false)) { | ||
181 | __iwl_write_prph(trans, ofs, val); | 125 | __iwl_write_prph(trans, ofs, val); |
182 | iwl_trans_release_nic_access(trans); | 126 | iwl_trans_release_nic_access(trans, &flags); |
183 | } | 127 | } |
184 | spin_unlock_irqrestore(&trans->reg_lock, flags); | ||
185 | } | 128 | } |
186 | EXPORT_SYMBOL_GPL(iwl_write_prph); | 129 | EXPORT_SYMBOL_GPL(iwl_write_prph); |
187 | 130 | ||
@@ -189,13 +132,11 @@ void iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask) | |||
189 | { | 132 | { |
190 | unsigned long flags; | 133 | unsigned long flags; |
191 | 134 | ||
192 | spin_lock_irqsave(&trans->reg_lock, flags); | 135 | if (iwl_trans_grab_nic_access(trans, false, &flags)) { |
193 | if (iwl_trans_grab_nic_access(trans, false)) { | ||
194 | __iwl_write_prph(trans, ofs, | 136 | __iwl_write_prph(trans, ofs, |
195 | __iwl_read_prph(trans, ofs) | mask); | 137 | __iwl_read_prph(trans, ofs) | mask); |
196 | iwl_trans_release_nic_access(trans); | 138 | iwl_trans_release_nic_access(trans, &flags); |
197 | } | 139 | } |
198 | spin_unlock_irqrestore(&trans->reg_lock, flags); | ||
199 | } | 140 | } |
200 | EXPORT_SYMBOL_GPL(iwl_set_bits_prph); | 141 | EXPORT_SYMBOL_GPL(iwl_set_bits_prph); |
201 | 142 | ||
@@ -204,13 +145,11 @@ void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs, | |||
204 | { | 145 | { |
205 | unsigned long flags; | 146 | unsigned long flags; |
206 | 147 | ||
207 | spin_lock_irqsave(&trans->reg_lock, flags); | 148 | if (iwl_trans_grab_nic_access(trans, false, &flags)) { |
208 | if (iwl_trans_grab_nic_access(trans, false)) { | ||
209 | __iwl_write_prph(trans, ofs, | 149 | __iwl_write_prph(trans, ofs, |
210 | (__iwl_read_prph(trans, ofs) & mask) | bits); | 150 | (__iwl_read_prph(trans, ofs) & mask) | bits); |
211 | iwl_trans_release_nic_access(trans); | 151 | iwl_trans_release_nic_access(trans, &flags); |
212 | } | 152 | } |
213 | spin_unlock_irqrestore(&trans->reg_lock, flags); | ||
214 | } | 153 | } |
215 | EXPORT_SYMBOL_GPL(iwl_set_bits_mask_prph); | 154 | EXPORT_SYMBOL_GPL(iwl_set_bits_mask_prph); |
216 | 155 | ||
@@ -219,12 +158,10 @@ void iwl_clear_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask) | |||
219 | unsigned long flags; | 158 | unsigned long flags; |
220 | u32 val; | 159 | u32 val; |
221 | 160 | ||
222 | spin_lock_irqsave(&trans->reg_lock, flags); | 161 | if (iwl_trans_grab_nic_access(trans, false, &flags)) { |
223 | if (iwl_trans_grab_nic_access(trans, false)) { | ||
224 | val = __iwl_read_prph(trans, ofs); | 162 | val = __iwl_read_prph(trans, ofs); |
225 | __iwl_write_prph(trans, ofs, (val & ~mask)); | 163 | __iwl_write_prph(trans, ofs, (val & ~mask)); |
226 | iwl_trans_release_nic_access(trans); | 164 | iwl_trans_release_nic_access(trans, &flags); |
227 | } | 165 | } |
228 | spin_unlock_irqrestore(&trans->reg_lock, flags); | ||
229 | } | 166 | } |
230 | EXPORT_SYMBOL_GPL(iwl_clear_bits_prph); | 167 | EXPORT_SYMBOL_GPL(iwl_clear_bits_prph); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index dc478068596b..fd9f5b97fff3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * Portions of this file are derived from the ipw3945 project. | 5 | * Portions of this file are derived from the ipw3945 project. |
6 | * | 6 | * |
@@ -51,12 +51,15 @@ static inline u32 iwl_read32(struct iwl_trans *trans, u32 ofs) | |||
51 | return val; | 51 | return val; |
52 | } | 52 | } |
53 | 53 | ||
54 | void iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask); | 54 | static inline void iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask) |
55 | void iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask); | 55 | { |
56 | void __iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask); | 56 | iwl_trans_set_bits_mask(trans, reg, mask, mask); |
57 | void __iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask); | 57 | } |
58 | 58 | ||
59 | void iwl_set_bits_mask(struct iwl_trans *trans, u32 reg, u32 mask, u32 value); | 59 | static inline void iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask) |
60 | { | ||
61 | iwl_trans_set_bits_mask(trans, reg, mask, 0); | ||
62 | } | ||
60 | 63 | ||
61 | int iwl_poll_bit(struct iwl_trans *trans, u32 addr, | 64 | int iwl_poll_bit(struct iwl_trans *trans, u32 addr, |
62 | u32 bits, u32 mask, int timeout); | 65 | u32 bits, u32 mask, int timeout); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-modparams.h b/drivers/net/wireless/iwlwifi/iwl-modparams.h index d9a86d6b2bd7..e5e3a79eae2f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-modparams.h +++ b/drivers/net/wireless/iwlwifi/iwl-modparams.h | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
diff --git a/drivers/net/wireless/iwlwifi/iwl-notif-wait.c b/drivers/net/wireless/iwlwifi/iwl-notif-wait.c index c61f2070f15a..c3affbc62cdf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-notif-wait.c +++ b/drivers/net/wireless/iwlwifi/iwl-notif-wait.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
diff --git a/drivers/net/wireless/iwlwifi/iwl-notif-wait.h b/drivers/net/wireless/iwlwifi/iwl-notif-wait.h index 821523100cf1..c2ce764463a3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-notif-wait.h +++ b/drivers/net/wireless/iwlwifi/iwl-notif-wait.h | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c new file mode 100644 index 000000000000..a70213bdb83c --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | |||
@@ -0,0 +1,346 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called LICENSE.GPL. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | *****************************************************************************/ | ||
62 | #include <linux/types.h> | ||
63 | #include <linux/slab.h> | ||
64 | #include <linux/export.h> | ||
65 | #include "iwl-modparams.h" | ||
66 | #include "iwl-nvm-parse.h" | ||
67 | |||
68 | /* NVM offsets (in words) definitions */ | ||
69 | enum wkp_nvm_offsets { | ||
70 | /* NVM HW-Section offset (in words) definitions */ | ||
71 | HW_ADDR = 0x15, | ||
72 | |||
73 | /* NVM SW-Section offset (in words) definitions */ | ||
74 | NVM_SW_SECTION = 0x1C0, | ||
75 | NVM_VERSION = 0, | ||
76 | RADIO_CFG = 1, | ||
77 | SKU = 2, | ||
78 | N_HW_ADDRS = 3, | ||
79 | NVM_CHANNELS = 0x1E0 - NVM_SW_SECTION, | ||
80 | |||
81 | /* NVM calibration section offset (in words) definitions */ | ||
82 | NVM_CALIB_SECTION = 0x2B8, | ||
83 | XTAL_CALIB = 0x316 - NVM_CALIB_SECTION | ||
84 | }; | ||
85 | |||
86 | /* SKU Capabilities (actual values from NVM definition) */ | ||
87 | enum nvm_sku_bits { | ||
88 | NVM_SKU_CAP_BAND_24GHZ = BIT(0), | ||
89 | NVM_SKU_CAP_BAND_52GHZ = BIT(1), | ||
90 | NVM_SKU_CAP_11N_ENABLE = BIT(2), | ||
91 | }; | ||
92 | |||
93 | /* radio config bits (actual values from NVM definition) */ | ||
94 | #define NVM_RF_CFG_DASH_MSK(x) (x & 0x3) /* bits 0-1 */ | ||
95 | #define NVM_RF_CFG_STEP_MSK(x) ((x >> 2) & 0x3) /* bits 2-3 */ | ||
96 | #define NVM_RF_CFG_TYPE_MSK(x) ((x >> 4) & 0x3) /* bits 4-5 */ | ||
97 | #define NVM_RF_CFG_PNUM_MSK(x) ((x >> 6) & 0x3) /* bits 6-7 */ | ||
98 | #define NVM_RF_CFG_TX_ANT_MSK(x) ((x >> 8) & 0xF) /* bits 8-11 */ | ||
99 | #define NVM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */ | ||
100 | |||
101 | /* | ||
102 | * These are the channel numbers in the order that they are stored in the NVM | ||
103 | */ | ||
104 | static const u8 iwl_nvm_channels[] = { | ||
105 | /* 2.4 GHz */ | ||
106 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, | ||
107 | /* 5 GHz */ | ||
108 | 36, 40, 44 , 48, 52, 56, 60, 64, | ||
109 | 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, | ||
110 | 149, 153, 157, 161, 165 | ||
111 | }; | ||
112 | |||
113 | #define IWL_NUM_CHANNELS ARRAY_SIZE(iwl_nvm_channels) | ||
114 | #define NUM_2GHZ_CHANNELS 14 | ||
115 | #define FIRST_2GHZ_HT_MINUS 5 | ||
116 | #define LAST_2GHZ_HT_PLUS 9 | ||
117 | #define LAST_5GHZ_HT 161 | ||
118 | |||
119 | |||
120 | /* rate data (static) */ | ||
121 | static struct ieee80211_rate iwl_cfg80211_rates[] = { | ||
122 | { .bitrate = 1 * 10, .hw_value = 0, .hw_value_short = 0, }, | ||
123 | { .bitrate = 2 * 10, .hw_value = 1, .hw_value_short = 1, | ||
124 | .flags = IEEE80211_RATE_SHORT_PREAMBLE, }, | ||
125 | { .bitrate = 5.5 * 10, .hw_value = 2, .hw_value_short = 2, | ||
126 | .flags = IEEE80211_RATE_SHORT_PREAMBLE, }, | ||
127 | { .bitrate = 11 * 10, .hw_value = 3, .hw_value_short = 3, | ||
128 | .flags = IEEE80211_RATE_SHORT_PREAMBLE, }, | ||
129 | { .bitrate = 6 * 10, .hw_value = 4, .hw_value_short = 4, }, | ||
130 | { .bitrate = 9 * 10, .hw_value = 5, .hw_value_short = 5, }, | ||
131 | { .bitrate = 12 * 10, .hw_value = 6, .hw_value_short = 6, }, | ||
132 | { .bitrate = 18 * 10, .hw_value = 7, .hw_value_short = 7, }, | ||
133 | { .bitrate = 24 * 10, .hw_value = 8, .hw_value_short = 8, }, | ||
134 | { .bitrate = 36 * 10, .hw_value = 9, .hw_value_short = 9, }, | ||
135 | { .bitrate = 48 * 10, .hw_value = 10, .hw_value_short = 10, }, | ||
136 | { .bitrate = 54 * 10, .hw_value = 11, .hw_value_short = 11, }, | ||
137 | }; | ||
138 | #define RATES_24_OFFS 0 | ||
139 | #define N_RATES_24 ARRAY_SIZE(iwl_cfg80211_rates) | ||
140 | #define RATES_52_OFFS 4 | ||
141 | #define N_RATES_52 (N_RATES_24 - RATES_52_OFFS) | ||
142 | |||
143 | /** | ||
144 | * enum iwl_nvm_channel_flags - channel flags in NVM | ||
145 | * @NVM_CHANNEL_VALID: channel is usable for this SKU/geo | ||
146 | * @NVM_CHANNEL_IBSS: usable as an IBSS channel | ||
147 | * @NVM_CHANNEL_ACTIVE: active scanning allowed | ||
148 | * @NVM_CHANNEL_RADAR: radar detection required | ||
149 | * @NVM_CHANNEL_DFS: dynamic freq selection candidate | ||
150 | * @NVM_CHANNEL_WIDE: 20 MHz channel okay (?) | ||
151 | * @NVM_CHANNEL_40MHZ: 40 MHz channel okay (?) | ||
152 | */ | ||
153 | enum iwl_nvm_channel_flags { | ||
154 | NVM_CHANNEL_VALID = BIT(0), | ||
155 | NVM_CHANNEL_IBSS = BIT(1), | ||
156 | NVM_CHANNEL_ACTIVE = BIT(3), | ||
157 | NVM_CHANNEL_RADAR = BIT(4), | ||
158 | NVM_CHANNEL_DFS = BIT(7), | ||
159 | NVM_CHANNEL_WIDE = BIT(8), | ||
160 | NVM_CHANNEL_40MHZ = BIT(9), | ||
161 | }; | ||
162 | |||
163 | #define CHECK_AND_PRINT_I(x) \ | ||
164 | ((ch_flags & NVM_CHANNEL_##x) ? # x " " : "") | ||
165 | |||
166 | static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, | ||
167 | struct iwl_nvm_data *data, | ||
168 | const __le16 * const nvm_ch_flags) | ||
169 | { | ||
170 | int ch_idx; | ||
171 | int n_channels = 0; | ||
172 | struct ieee80211_channel *channel; | ||
173 | u16 ch_flags; | ||
174 | bool is_5ghz; | ||
175 | |||
176 | for (ch_idx = 0; ch_idx < IWL_NUM_CHANNELS; ch_idx++) { | ||
177 | ch_flags = __le16_to_cpup(nvm_ch_flags + ch_idx); | ||
178 | if (!(ch_flags & NVM_CHANNEL_VALID)) { | ||
179 | IWL_DEBUG_EEPROM(dev, | ||
180 | "Ch. %d Flags %x [%sGHz] - No traffic\n", | ||
181 | iwl_nvm_channels[ch_idx], | ||
182 | ch_flags, | ||
183 | (ch_idx >= NUM_2GHZ_CHANNELS) ? | ||
184 | "5.2" : "2.4"); | ||
185 | continue; | ||
186 | } | ||
187 | |||
188 | channel = &data->channels[n_channels]; | ||
189 | n_channels++; | ||
190 | |||
191 | channel->hw_value = iwl_nvm_channels[ch_idx]; | ||
192 | channel->band = (ch_idx < NUM_2GHZ_CHANNELS) ? | ||
193 | IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; | ||
194 | channel->center_freq = | ||
195 | ieee80211_channel_to_frequency( | ||
196 | channel->hw_value, channel->band); | ||
197 | |||
198 | /* TODO: Need to be dependent to the NVM */ | ||
199 | channel->flags = IEEE80211_CHAN_NO_HT40; | ||
200 | if (ch_idx < NUM_2GHZ_CHANNELS && | ||
201 | (ch_flags & NVM_CHANNEL_40MHZ)) { | ||
202 | if (iwl_nvm_channels[ch_idx] <= LAST_2GHZ_HT_PLUS) | ||
203 | channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS; | ||
204 | if (iwl_nvm_channels[ch_idx] >= FIRST_2GHZ_HT_MINUS) | ||
205 | channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS; | ||
206 | } else if (iwl_nvm_channels[ch_idx] <= LAST_5GHZ_HT && | ||
207 | (ch_flags & NVM_CHANNEL_40MHZ)) { | ||
208 | if ((ch_idx - NUM_2GHZ_CHANNELS) % 2 == 0) | ||
209 | channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS; | ||
210 | else | ||
211 | channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS; | ||
212 | } | ||
213 | |||
214 | if (!(ch_flags & NVM_CHANNEL_IBSS)) | ||
215 | channel->flags |= IEEE80211_CHAN_NO_IBSS; | ||
216 | |||
217 | if (!(ch_flags & NVM_CHANNEL_ACTIVE)) | ||
218 | channel->flags |= IEEE80211_CHAN_PASSIVE_SCAN; | ||
219 | |||
220 | if (ch_flags & NVM_CHANNEL_RADAR) | ||
221 | channel->flags |= IEEE80211_CHAN_RADAR; | ||
222 | |||
223 | /* Initialize regulatory-based run-time data */ | ||
224 | |||
225 | /* TODO: read the real value from the NVM */ | ||
226 | channel->max_power = 0; | ||
227 | is_5ghz = channel->band == IEEE80211_BAND_5GHZ; | ||
228 | IWL_DEBUG_EEPROM(dev, | ||
229 | "Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x %ddBm): Ad-Hoc %ssupported\n", | ||
230 | channel->hw_value, | ||
231 | is_5ghz ? "5.2" : "2.4", | ||
232 | CHECK_AND_PRINT_I(VALID), | ||
233 | CHECK_AND_PRINT_I(IBSS), | ||
234 | CHECK_AND_PRINT_I(ACTIVE), | ||
235 | CHECK_AND_PRINT_I(RADAR), | ||
236 | CHECK_AND_PRINT_I(WIDE), | ||
237 | CHECK_AND_PRINT_I(DFS), | ||
238 | ch_flags, | ||
239 | channel->max_power, | ||
240 | ((ch_flags & NVM_CHANNEL_IBSS) && | ||
241 | !(ch_flags & NVM_CHANNEL_RADAR)) | ||
242 | ? "" : "not "); | ||
243 | } | ||
244 | |||
245 | return n_channels; | ||
246 | } | ||
247 | |||
248 | static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg, | ||
249 | struct iwl_nvm_data *data, const __le16 *nvm_sw) | ||
250 | { | ||
251 | int n_channels = iwl_init_channel_map(dev, cfg, data, | ||
252 | &nvm_sw[NVM_CHANNELS]); | ||
253 | int n_used = 0; | ||
254 | struct ieee80211_supported_band *sband; | ||
255 | |||
256 | sband = &data->bands[IEEE80211_BAND_2GHZ]; | ||
257 | sband->band = IEEE80211_BAND_2GHZ; | ||
258 | sband->bitrates = &iwl_cfg80211_rates[RATES_24_OFFS]; | ||
259 | sband->n_bitrates = N_RATES_24; | ||
260 | n_used += iwl_init_sband_channels(data, sband, n_channels, | ||
261 | IEEE80211_BAND_2GHZ); | ||
262 | iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_2GHZ); | ||
263 | |||
264 | sband = &data->bands[IEEE80211_BAND_5GHZ]; | ||
265 | sband->band = IEEE80211_BAND_5GHZ; | ||
266 | sband->bitrates = &iwl_cfg80211_rates[RATES_52_OFFS]; | ||
267 | sband->n_bitrates = N_RATES_52; | ||
268 | n_used += iwl_init_sband_channels(data, sband, n_channels, | ||
269 | IEEE80211_BAND_5GHZ); | ||
270 | iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_5GHZ); | ||
271 | |||
272 | if (n_channels != n_used) | ||
273 | IWL_ERR_DEV(dev, "NVM: used only %d of %d channels\n", | ||
274 | n_used, n_channels); | ||
275 | } | ||
276 | |||
277 | struct iwl_nvm_data * | ||
278 | iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, | ||
279 | const __le16 *nvm_hw, const __le16 *nvm_sw, | ||
280 | const __le16 *nvm_calib) | ||
281 | { | ||
282 | struct iwl_nvm_data *data; | ||
283 | u8 hw_addr[ETH_ALEN]; | ||
284 | u16 radio_cfg, sku; | ||
285 | |||
286 | data = kzalloc(sizeof(*data) + | ||
287 | sizeof(struct ieee80211_channel) * IWL_NUM_CHANNELS, | ||
288 | GFP_KERNEL); | ||
289 | if (!data) | ||
290 | return NULL; | ||
291 | |||
292 | data->nvm_version = le16_to_cpup(nvm_sw + NVM_VERSION); | ||
293 | |||
294 | radio_cfg = le16_to_cpup(nvm_sw + RADIO_CFG); | ||
295 | data->radio_cfg_type = NVM_RF_CFG_TYPE_MSK(radio_cfg); | ||
296 | data->radio_cfg_step = NVM_RF_CFG_STEP_MSK(radio_cfg); | ||
297 | data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK(radio_cfg); | ||
298 | data->radio_cfg_pnum = NVM_RF_CFG_PNUM_MSK(radio_cfg); | ||
299 | data->valid_tx_ant = NVM_RF_CFG_TX_ANT_MSK(radio_cfg); | ||
300 | data->valid_rx_ant = NVM_RF_CFG_RX_ANT_MSK(radio_cfg); | ||
301 | |||
302 | sku = le16_to_cpup(nvm_sw + SKU); | ||
303 | data->sku_cap_band_24GHz_enable = sku & NVM_SKU_CAP_BAND_24GHZ; | ||
304 | data->sku_cap_band_52GHz_enable = sku & NVM_SKU_CAP_BAND_52GHZ; | ||
305 | data->sku_cap_11n_enable = sku & NVM_SKU_CAP_11N_ENABLE; | ||
306 | if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_ALL) | ||
307 | data->sku_cap_11n_enable = false; | ||
308 | |||
309 | /* check overrides (some devices have wrong NVM) */ | ||
310 | if (cfg->valid_tx_ant) | ||
311 | data->valid_tx_ant = cfg->valid_tx_ant; | ||
312 | if (cfg->valid_rx_ant) | ||
313 | data->valid_rx_ant = cfg->valid_rx_ant; | ||
314 | |||
315 | if (!data->valid_tx_ant || !data->valid_rx_ant) { | ||
316 | IWL_ERR_DEV(dev, "invalid antennas (0x%x, 0x%x)\n", | ||
317 | data->valid_tx_ant, data->valid_rx_ant); | ||
318 | kfree(data); | ||
319 | return NULL; | ||
320 | } | ||
321 | |||
322 | data->n_hw_addrs = le16_to_cpup(nvm_sw + N_HW_ADDRS); | ||
323 | |||
324 | data->xtal_calib[0] = *(nvm_calib + XTAL_CALIB); | ||
325 | data->xtal_calib[1] = *(nvm_calib + XTAL_CALIB + 1); | ||
326 | |||
327 | /* The byte order is little endian 16 bit, meaning 214365 */ | ||
328 | memcpy(hw_addr, nvm_hw + HW_ADDR, ETH_ALEN); | ||
329 | data->hw_addr[0] = hw_addr[1]; | ||
330 | data->hw_addr[1] = hw_addr[0]; | ||
331 | data->hw_addr[2] = hw_addr[3]; | ||
332 | data->hw_addr[3] = hw_addr[2]; | ||
333 | data->hw_addr[4] = hw_addr[5]; | ||
334 | data->hw_addr[5] = hw_addr[4]; | ||
335 | |||
336 | iwl_init_sbands(dev, cfg, data, nvm_sw); | ||
337 | |||
338 | data->calib_version = 255; /* TODO: | ||
339 | this value will prevent some checks from | ||
340 | failing, we need to check if this | ||
341 | field is still needed, and if it does, | ||
342 | where is it in the NVM*/ | ||
343 | |||
344 | return data; | ||
345 | } | ||
346 | EXPORT_SYMBOL_GPL(iwl_parse_nvm_data); | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h new file mode 100644 index 000000000000..b2692bd287fa --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h | |||
@@ -0,0 +1,80 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called LICENSE.GPL. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | *****************************************************************************/ | ||
62 | #ifndef __iwl_nvm_parse_h__ | ||
63 | #define __iwl_nvm_parse_h__ | ||
64 | |||
65 | #include "iwl-eeprom-parse.h" | ||
66 | |||
67 | /** | ||
68 | * iwl_parse_nvm_data - parse NVM data and return values | ||
69 | * | ||
70 | * This function parses all NVM values we need and then | ||
71 | * returns a (newly allocated) struct containing all the | ||
72 | * relevant values for driver use. The struct must be freed | ||
73 | * later with iwl_free_nvm_data(). | ||
74 | */ | ||
75 | struct iwl_nvm_data * | ||
76 | iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, | ||
77 | const __le16 *nvm_hw, const __le16 *nvm_sw, | ||
78 | const __le16 *nvm_calib); | ||
79 | |||
80 | #endif /* __iwl_nvm_parse_h__ */ | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/iwlwifi/iwl-op-mode.h index c8d9b9517468..dc792584f401 100644 --- a/drivers/net/wireless/iwlwifi/iwl-op-mode.h +++ b/drivers/net/wireless/iwlwifi/iwl-op-mode.h | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
@@ -63,6 +63,8 @@ | |||
63 | #ifndef __iwl_op_mode_h__ | 63 | #ifndef __iwl_op_mode_h__ |
64 | #define __iwl_op_mode_h__ | 64 | #define __iwl_op_mode_h__ |
65 | 65 | ||
66 | #include <linux/debugfs.h> | ||
67 | |||
66 | struct iwl_op_mode; | 68 | struct iwl_op_mode; |
67 | struct iwl_trans; | 69 | struct iwl_trans; |
68 | struct sk_buff; | 70 | struct sk_buff; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-phy-db.c b/drivers/net/wireless/iwlwifi/iwl-phy-db.c new file mode 100644 index 000000000000..14fc8d39fc28 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-phy-db.c | |||
@@ -0,0 +1,514 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called LICENSE.GPL. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | * | ||
62 | *****************************************************************************/ | ||
63 | |||
64 | #include <linux/slab.h> | ||
65 | #include <linux/string.h> | ||
66 | #include <linux/export.h> | ||
67 | |||
68 | #include "iwl-phy-db.h" | ||
69 | #include "iwl-debug.h" | ||
70 | #include "iwl-op-mode.h" | ||
71 | #include "iwl-trans.h" | ||
72 | |||
73 | #define CHANNEL_NUM_SIZE 4 /* num of channels in calib_ch size */ | ||
74 | #define IWL_NUM_PAPD_CH_GROUPS 4 | ||
75 | #define IWL_NUM_TXP_CH_GROUPS 9 | ||
76 | |||
77 | struct iwl_phy_db_entry { | ||
78 | u16 size; | ||
79 | u8 *data; | ||
80 | }; | ||
81 | |||
82 | /** | ||
83 | * struct iwl_phy_db - stores phy configuration and calibration data. | ||
84 | * | ||
85 | * @cfg: phy configuration. | ||
86 | * @calib_nch: non channel specific calibration data. | ||
87 | * @calib_ch: channel specific calibration data. | ||
88 | * @calib_ch_group_papd: calibration data related to papd channel group. | ||
89 | * @calib_ch_group_txp: calibration data related to tx power chanel group. | ||
90 | */ | ||
91 | struct iwl_phy_db { | ||
92 | struct iwl_phy_db_entry cfg; | ||
93 | struct iwl_phy_db_entry calib_nch; | ||
94 | struct iwl_phy_db_entry calib_ch; | ||
95 | struct iwl_phy_db_entry calib_ch_group_papd[IWL_NUM_PAPD_CH_GROUPS]; | ||
96 | struct iwl_phy_db_entry calib_ch_group_txp[IWL_NUM_TXP_CH_GROUPS]; | ||
97 | |||
98 | u32 channel_num; | ||
99 | u32 channel_size; | ||
100 | |||
101 | struct iwl_trans *trans; | ||
102 | }; | ||
103 | |||
104 | enum iwl_phy_db_section_type { | ||
105 | IWL_PHY_DB_CFG = 1, | ||
106 | IWL_PHY_DB_CALIB_NCH, | ||
107 | IWL_PHY_DB_CALIB_CH, | ||
108 | IWL_PHY_DB_CALIB_CHG_PAPD, | ||
109 | IWL_PHY_DB_CALIB_CHG_TXP, | ||
110 | IWL_PHY_DB_MAX | ||
111 | }; | ||
112 | |||
113 | #define PHY_DB_CMD 0x6c /* TEMP API - The actual is 0x8c */ | ||
114 | |||
115 | /* | ||
116 | * phy db - configure operational ucode | ||
117 | */ | ||
118 | struct iwl_phy_db_cmd { | ||
119 | __le16 type; | ||
120 | __le16 length; | ||
121 | u8 data[]; | ||
122 | } __packed; | ||
123 | |||
124 | /* for parsing of tx power channel group data that comes from the firmware*/ | ||
125 | struct iwl_phy_db_chg_txp { | ||
126 | __le32 space; | ||
127 | __le16 max_channel_idx; | ||
128 | } __packed; | ||
129 | |||
130 | /* | ||
131 | * phy db - Receieve phy db chunk after calibrations | ||
132 | */ | ||
133 | struct iwl_calib_res_notif_phy_db { | ||
134 | __le16 type; | ||
135 | __le16 length; | ||
136 | u8 data[]; | ||
137 | } __packed; | ||
138 | |||
139 | #define IWL_PHY_DB_STATIC_PIC cpu_to_le32(0x21436587) | ||
140 | static inline void iwl_phy_db_test_pic(__le32 pic) | ||
141 | { | ||
142 | WARN_ON(IWL_PHY_DB_STATIC_PIC != pic); | ||
143 | } | ||
144 | |||
145 | struct iwl_phy_db *iwl_phy_db_init(struct iwl_trans *trans) | ||
146 | { | ||
147 | struct iwl_phy_db *phy_db = kzalloc(sizeof(struct iwl_phy_db), | ||
148 | GFP_KERNEL); | ||
149 | |||
150 | if (!phy_db) | ||
151 | return phy_db; | ||
152 | |||
153 | phy_db->trans = trans; | ||
154 | |||
155 | /* TODO: add default values of the phy db. */ | ||
156 | return phy_db; | ||
157 | } | ||
158 | EXPORT_SYMBOL(iwl_phy_db_init); | ||
159 | |||
160 | /* | ||
161 | * get phy db section: returns a pointer to a phy db section specified by | ||
162 | * type and channel group id. | ||
163 | */ | ||
164 | static struct iwl_phy_db_entry * | ||
165 | iwl_phy_db_get_section(struct iwl_phy_db *phy_db, | ||
166 | enum iwl_phy_db_section_type type, | ||
167 | u16 chg_id) | ||
168 | { | ||
169 | if (!phy_db || type >= IWL_PHY_DB_MAX) | ||
170 | return NULL; | ||
171 | |||
172 | switch (type) { | ||
173 | case IWL_PHY_DB_CFG: | ||
174 | return &phy_db->cfg; | ||
175 | case IWL_PHY_DB_CALIB_NCH: | ||
176 | return &phy_db->calib_nch; | ||
177 | case IWL_PHY_DB_CALIB_CH: | ||
178 | return &phy_db->calib_ch; | ||
179 | case IWL_PHY_DB_CALIB_CHG_PAPD: | ||
180 | if (chg_id >= IWL_NUM_PAPD_CH_GROUPS) | ||
181 | return NULL; | ||
182 | return &phy_db->calib_ch_group_papd[chg_id]; | ||
183 | case IWL_PHY_DB_CALIB_CHG_TXP: | ||
184 | if (chg_id >= IWL_NUM_TXP_CH_GROUPS) | ||
185 | return NULL; | ||
186 | return &phy_db->calib_ch_group_txp[chg_id]; | ||
187 | default: | ||
188 | return NULL; | ||
189 | } | ||
190 | return NULL; | ||
191 | } | ||
192 | |||
193 | static void iwl_phy_db_free_section(struct iwl_phy_db *phy_db, | ||
194 | enum iwl_phy_db_section_type type, | ||
195 | u16 chg_id) | ||
196 | { | ||
197 | struct iwl_phy_db_entry *entry = | ||
198 | iwl_phy_db_get_section(phy_db, type, chg_id); | ||
199 | if (!entry) | ||
200 | return; | ||
201 | |||
202 | kfree(entry->data); | ||
203 | entry->data = NULL; | ||
204 | entry->size = 0; | ||
205 | } | ||
206 | |||
207 | void iwl_phy_db_free(struct iwl_phy_db *phy_db) | ||
208 | { | ||
209 | int i; | ||
210 | |||
211 | if (!phy_db) | ||
212 | return; | ||
213 | |||
214 | iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CFG, 0); | ||
215 | iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_NCH, 0); | ||
216 | iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_CH, 0); | ||
217 | for (i = 0; i < IWL_NUM_PAPD_CH_GROUPS; i++) | ||
218 | iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_CHG_PAPD, i); | ||
219 | for (i = 0; i < IWL_NUM_TXP_CH_GROUPS; i++) | ||
220 | iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_CHG_TXP, i); | ||
221 | |||
222 | kfree(phy_db); | ||
223 | } | ||
224 | EXPORT_SYMBOL(iwl_phy_db_free); | ||
225 | |||
226 | int iwl_phy_db_set_section(struct iwl_phy_db *phy_db, struct iwl_rx_packet *pkt, | ||
227 | gfp_t alloc_ctx) | ||
228 | { | ||
229 | struct iwl_calib_res_notif_phy_db *phy_db_notif = | ||
230 | (struct iwl_calib_res_notif_phy_db *)pkt->data; | ||
231 | enum iwl_phy_db_section_type type = le16_to_cpu(phy_db_notif->type); | ||
232 | u16 size = le16_to_cpu(phy_db_notif->length); | ||
233 | struct iwl_phy_db_entry *entry; | ||
234 | u16 chg_id = 0; | ||
235 | |||
236 | if (!phy_db) | ||
237 | return -EINVAL; | ||
238 | |||
239 | if (type == IWL_PHY_DB_CALIB_CHG_PAPD || | ||
240 | type == IWL_PHY_DB_CALIB_CHG_TXP) | ||
241 | chg_id = le16_to_cpup((__le16 *)phy_db_notif->data); | ||
242 | |||
243 | entry = iwl_phy_db_get_section(phy_db, type, chg_id); | ||
244 | if (!entry) | ||
245 | return -EINVAL; | ||
246 | |||
247 | kfree(entry->data); | ||
248 | entry->data = kmemdup(phy_db_notif->data, size, alloc_ctx); | ||
249 | if (!entry->data) { | ||
250 | entry->size = 0; | ||
251 | return -ENOMEM; | ||
252 | } | ||
253 | |||
254 | entry->size = size; | ||
255 | |||
256 | if (type == IWL_PHY_DB_CALIB_CH) { | ||
257 | phy_db->channel_num = | ||
258 | le32_to_cpup((__le32 *)phy_db_notif->data); | ||
259 | phy_db->channel_size = | ||
260 | (size - CHANNEL_NUM_SIZE) / phy_db->channel_num; | ||
261 | } | ||
262 | |||
263 | /* Test PIC */ | ||
264 | if (type != IWL_PHY_DB_CFG) | ||
265 | iwl_phy_db_test_pic(*(((__le32 *)phy_db_notif->data) + | ||
266 | (size / sizeof(__le32)) - 1)); | ||
267 | |||
268 | IWL_DEBUG_INFO(phy_db->trans, | ||
269 | "%s(%d): [PHYDB]SET: Type %d , Size: %d\n", | ||
270 | __func__, __LINE__, type, size); | ||
271 | |||
272 | return 0; | ||
273 | } | ||
274 | EXPORT_SYMBOL(iwl_phy_db_set_section); | ||
275 | |||
276 | static int is_valid_channel(u16 ch_id) | ||
277 | { | ||
278 | if (ch_id <= 14 || | ||
279 | (36 <= ch_id && ch_id <= 64 && ch_id % 4 == 0) || | ||
280 | (100 <= ch_id && ch_id <= 140 && ch_id % 4 == 0) || | ||
281 | (145 <= ch_id && ch_id <= 165 && ch_id % 4 == 1)) | ||
282 | return 1; | ||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | static u8 ch_id_to_ch_index(u16 ch_id) | ||
287 | { | ||
288 | if (WARN_ON(!is_valid_channel(ch_id))) | ||
289 | return 0xff; | ||
290 | |||
291 | if (ch_id <= 14) | ||
292 | return ch_id - 1; | ||
293 | if (ch_id <= 64) | ||
294 | return (ch_id + 20) / 4; | ||
295 | if (ch_id <= 140) | ||
296 | return (ch_id - 12) / 4; | ||
297 | return (ch_id - 13) / 4; | ||
298 | } | ||
299 | |||
300 | |||
301 | static u16 channel_id_to_papd(u16 ch_id) | ||
302 | { | ||
303 | if (WARN_ON(!is_valid_channel(ch_id))) | ||
304 | return 0xff; | ||
305 | |||
306 | if (1 <= ch_id && ch_id <= 14) | ||
307 | return 0; | ||
308 | if (36 <= ch_id && ch_id <= 64) | ||
309 | return 1; | ||
310 | if (100 <= ch_id && ch_id <= 140) | ||
311 | return 2; | ||
312 | return 3; | ||
313 | } | ||
314 | |||
315 | static u16 channel_id_to_txp(struct iwl_phy_db *phy_db, u16 ch_id) | ||
316 | { | ||
317 | struct iwl_phy_db_chg_txp *txp_chg; | ||
318 | int i; | ||
319 | u8 ch_index = ch_id_to_ch_index(ch_id); | ||
320 | if (ch_index == 0xff) | ||
321 | return 0xff; | ||
322 | |||
323 | for (i = 0; i < IWL_NUM_TXP_CH_GROUPS; i++) { | ||
324 | txp_chg = (void *)phy_db->calib_ch_group_txp[i].data; | ||
325 | if (!txp_chg) | ||
326 | return 0xff; | ||
327 | /* | ||
328 | * Looking for the first channel group that its max channel is | ||
329 | * higher then wanted channel. | ||
330 | */ | ||
331 | if (le16_to_cpu(txp_chg->max_channel_idx) >= ch_index) | ||
332 | return i; | ||
333 | } | ||
334 | return 0xff; | ||
335 | } | ||
336 | static | ||
337 | int iwl_phy_db_get_section_data(struct iwl_phy_db *phy_db, | ||
338 | u32 type, u8 **data, u16 *size, u16 ch_id) | ||
339 | { | ||
340 | struct iwl_phy_db_entry *entry; | ||
341 | u32 channel_num; | ||
342 | u32 channel_size; | ||
343 | u16 ch_group_id = 0; | ||
344 | u16 index; | ||
345 | |||
346 | if (!phy_db) | ||
347 | return -EINVAL; | ||
348 | |||
349 | /* find wanted channel group */ | ||
350 | if (type == IWL_PHY_DB_CALIB_CHG_PAPD) | ||
351 | ch_group_id = channel_id_to_papd(ch_id); | ||
352 | else if (type == IWL_PHY_DB_CALIB_CHG_TXP) | ||
353 | ch_group_id = channel_id_to_txp(phy_db, ch_id); | ||
354 | |||
355 | entry = iwl_phy_db_get_section(phy_db, type, ch_group_id); | ||
356 | if (!entry) | ||
357 | return -EINVAL; | ||
358 | |||
359 | if (type == IWL_PHY_DB_CALIB_CH) { | ||
360 | index = ch_id_to_ch_index(ch_id); | ||
361 | channel_num = phy_db->channel_num; | ||
362 | channel_size = phy_db->channel_size; | ||
363 | if (index >= channel_num) { | ||
364 | IWL_ERR(phy_db->trans, "Wrong channel number %d\n", | ||
365 | ch_id); | ||
366 | return -EINVAL; | ||
367 | } | ||
368 | *data = entry->data + CHANNEL_NUM_SIZE + index * channel_size; | ||
369 | *size = channel_size; | ||
370 | } else { | ||
371 | *data = entry->data; | ||
372 | *size = entry->size; | ||
373 | } | ||
374 | |||
375 | /* Test PIC */ | ||
376 | if (type != IWL_PHY_DB_CFG) | ||
377 | iwl_phy_db_test_pic(*(((__le32 *)*data) + | ||
378 | (*size / sizeof(__le32)) - 1)); | ||
379 | |||
380 | IWL_DEBUG_INFO(phy_db->trans, | ||
381 | "%s(%d): [PHYDB] GET: Type %d , Size: %d\n", | ||
382 | __func__, __LINE__, type, *size); | ||
383 | |||
384 | return 0; | ||
385 | } | ||
386 | |||
387 | static int iwl_send_phy_db_cmd(struct iwl_phy_db *phy_db, u16 type, | ||
388 | u16 length, void *data) | ||
389 | { | ||
390 | struct iwl_phy_db_cmd phy_db_cmd; | ||
391 | struct iwl_host_cmd cmd = { | ||
392 | .id = PHY_DB_CMD, | ||
393 | .flags = CMD_SYNC, | ||
394 | }; | ||
395 | |||
396 | IWL_DEBUG_INFO(phy_db->trans, | ||
397 | "Sending PHY-DB hcmd of type %d, of length %d\n", | ||
398 | type, length); | ||
399 | |||
400 | /* Set phy db cmd variables */ | ||
401 | phy_db_cmd.type = cpu_to_le16(type); | ||
402 | phy_db_cmd.length = cpu_to_le16(length); | ||
403 | |||
404 | /* Set hcmd variables */ | ||
405 | cmd.data[0] = &phy_db_cmd; | ||
406 | cmd.len[0] = sizeof(struct iwl_phy_db_cmd); | ||
407 | cmd.data[1] = data; | ||
408 | cmd.len[1] = length; | ||
409 | cmd.dataflags[1] = IWL_HCMD_DFL_NOCOPY; | ||
410 | |||
411 | return iwl_trans_send_cmd(phy_db->trans, &cmd); | ||
412 | } | ||
413 | |||
414 | static int iwl_phy_db_send_all_channel_groups( | ||
415 | struct iwl_phy_db *phy_db, | ||
416 | enum iwl_phy_db_section_type type, | ||
417 | u8 max_ch_groups) | ||
418 | { | ||
419 | u16 i; | ||
420 | int err; | ||
421 | struct iwl_phy_db_entry *entry; | ||
422 | |||
423 | /* Send all the channel specific groups to operational fw */ | ||
424 | for (i = 0; i < max_ch_groups; i++) { | ||
425 | entry = iwl_phy_db_get_section(phy_db, | ||
426 | type, | ||
427 | i); | ||
428 | if (!entry) | ||
429 | return -EINVAL; | ||
430 | |||
431 | /* Send the requested PHY DB section */ | ||
432 | err = iwl_send_phy_db_cmd(phy_db, | ||
433 | type, | ||
434 | entry->size, | ||
435 | entry->data); | ||
436 | if (err) { | ||
437 | IWL_ERR(phy_db->trans, | ||
438 | "Can't SEND phy_db section %d (%d), err %d", | ||
439 | type, i, err); | ||
440 | return err; | ||
441 | } | ||
442 | |||
443 | IWL_DEBUG_INFO(phy_db->trans, | ||
444 | "Sent PHY_DB HCMD, type = %d num = %d", | ||
445 | type, i); | ||
446 | } | ||
447 | |||
448 | return 0; | ||
449 | } | ||
450 | |||
451 | int iwl_send_phy_db_data(struct iwl_phy_db *phy_db) | ||
452 | { | ||
453 | u8 *data = NULL; | ||
454 | u16 size = 0; | ||
455 | int err; | ||
456 | |||
457 | IWL_DEBUG_INFO(phy_db->trans, | ||
458 | "Sending phy db data and configuration to runtime image\n"); | ||
459 | |||
460 | /* Send PHY DB CFG section */ | ||
461 | err = iwl_phy_db_get_section_data(phy_db, IWL_PHY_DB_CFG, | ||
462 | &data, &size, 0); | ||
463 | if (err) { | ||
464 | IWL_ERR(phy_db->trans, "Cannot get Phy DB cfg section\n"); | ||
465 | return err; | ||
466 | } | ||
467 | |||
468 | err = iwl_send_phy_db_cmd(phy_db, IWL_PHY_DB_CFG, size, data); | ||
469 | if (err) { | ||
470 | IWL_ERR(phy_db->trans, | ||
471 | "Cannot send HCMD of Phy DB cfg section\n"); | ||
472 | return err; | ||
473 | } | ||
474 | |||
475 | err = iwl_phy_db_get_section_data(phy_db, IWL_PHY_DB_CALIB_NCH, | ||
476 | &data, &size, 0); | ||
477 | if (err) { | ||
478 | IWL_ERR(phy_db->trans, | ||
479 | "Cannot get Phy DB non specific channel section\n"); | ||
480 | return err; | ||
481 | } | ||
482 | |||
483 | err = iwl_send_phy_db_cmd(phy_db, IWL_PHY_DB_CALIB_NCH, size, data); | ||
484 | if (err) { | ||
485 | IWL_ERR(phy_db->trans, | ||
486 | "Cannot send HCMD of Phy DB non specific channel section\n"); | ||
487 | return err; | ||
488 | } | ||
489 | |||
490 | /* Send all the TXP channel specific data */ | ||
491 | err = iwl_phy_db_send_all_channel_groups(phy_db, | ||
492 | IWL_PHY_DB_CALIB_CHG_PAPD, | ||
493 | IWL_NUM_PAPD_CH_GROUPS); | ||
494 | if (err) { | ||
495 | IWL_ERR(phy_db->trans, | ||
496 | "Cannot send channel specific PAPD groups"); | ||
497 | return err; | ||
498 | } | ||
499 | |||
500 | /* Send all the TXP channel specific data */ | ||
501 | err = iwl_phy_db_send_all_channel_groups(phy_db, | ||
502 | IWL_PHY_DB_CALIB_CHG_TXP, | ||
503 | IWL_NUM_TXP_CH_GROUPS); | ||
504 | if (err) { | ||
505 | IWL_ERR(phy_db->trans, | ||
506 | "Cannot send channel specific TX power groups"); | ||
507 | return err; | ||
508 | } | ||
509 | |||
510 | IWL_DEBUG_INFO(phy_db->trans, | ||
511 | "Finished sending phy db non channel data\n"); | ||
512 | return 0; | ||
513 | } | ||
514 | EXPORT_SYMBOL(iwl_send_phy_db_data); | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-phy-db.h b/drivers/net/wireless/iwlwifi/iwl-phy-db.h new file mode 100644 index 000000000000..d0e43d96ab38 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-phy-db.h | |||
@@ -0,0 +1,82 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called LICENSE.GPL. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | * | ||
62 | *****************************************************************************/ | ||
63 | |||
64 | #ifndef __IWL_PHYDB_H__ | ||
65 | #define __IWL_PHYDB_H__ | ||
66 | |||
67 | #include <linux/types.h> | ||
68 | |||
69 | #include "iwl-op-mode.h" | ||
70 | #include "iwl-trans.h" | ||
71 | |||
72 | struct iwl_phy_db *iwl_phy_db_init(struct iwl_trans *trans); | ||
73 | |||
74 | void iwl_phy_db_free(struct iwl_phy_db *phy_db); | ||
75 | |||
76 | int iwl_phy_db_set_section(struct iwl_phy_db *phy_db, struct iwl_rx_packet *pkt, | ||
77 | gfp_t alloc_ctx); | ||
78 | |||
79 | |||
80 | int iwl_send_phy_db_data(struct iwl_phy_db *phy_db); | ||
81 | |||
82 | #endif /* __IWL_PHYDB_H__ */ | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index c3a4bb41e533..f76e9cad7757 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
@@ -97,6 +97,9 @@ | |||
97 | 97 | ||
98 | #define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800) | 98 | #define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800) |
99 | 99 | ||
100 | /* Device system time */ | ||
101 | #define DEVICE_SYSTEM_TIME_REG 0xA0206C | ||
102 | |||
100 | /** | 103 | /** |
101 | * Tx Scheduler | 104 | * Tx Scheduler |
102 | * | 105 | * |
diff --git a/drivers/net/wireless/iwlwifi/iwl-test.c b/drivers/net/wireless/iwlwifi/iwl-test.c index 1a226114fe73..ce0c67b425ee 100644 --- a/drivers/net/wireless/iwlwifi/iwl-test.c +++ b/drivers/net/wireless/iwlwifi/iwl-test.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2010 - 2012 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2010 - 2013 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2010 - 2012 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2010 - 2013 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
@@ -466,9 +466,7 @@ static int iwl_test_indirect_read(struct iwl_test *tst, u32 addr, u32 size) | |||
466 | /* Hard-coded periphery absolute address */ | 466 | /* Hard-coded periphery absolute address */ |
467 | if (IWL_ABS_PRPH_START <= addr && | 467 | if (IWL_ABS_PRPH_START <= addr && |
468 | addr < IWL_ABS_PRPH_START + PRPH_END) { | 468 | addr < IWL_ABS_PRPH_START + PRPH_END) { |
469 | spin_lock_irqsave(&trans->reg_lock, flags); | 469 | if (!iwl_trans_grab_nic_access(trans, false, &flags)) { |
470 | if (!iwl_trans_grab_nic_access(trans, false)) { | ||
471 | spin_unlock_irqrestore(&trans->reg_lock, flags); | ||
472 | return -EIO; | 470 | return -EIO; |
473 | } | 471 | } |
474 | iwl_write32(trans, HBUS_TARG_PRPH_RADDR, | 472 | iwl_write32(trans, HBUS_TARG_PRPH_RADDR, |
@@ -476,8 +474,7 @@ static int iwl_test_indirect_read(struct iwl_test *tst, u32 addr, u32 size) | |||
476 | for (i = 0; i < size; i += 4) | 474 | for (i = 0; i < size; i += 4) |
477 | *(u32 *)(tst->mem.addr + i) = | 475 | *(u32 *)(tst->mem.addr + i) = |
478 | iwl_read32(trans, HBUS_TARG_PRPH_RDAT); | 476 | iwl_read32(trans, HBUS_TARG_PRPH_RDAT); |
479 | iwl_trans_release_nic_access(trans); | 477 | iwl_trans_release_nic_access(trans, &flags); |
480 | spin_unlock_irqrestore(&trans->reg_lock, flags); | ||
481 | } else { /* target memory (SRAM) */ | 478 | } else { /* target memory (SRAM) */ |
482 | iwl_trans_read_mem(trans, addr, tst->mem.addr, | 479 | iwl_trans_read_mem(trans, addr, tst->mem.addr, |
483 | tst->mem.size / 4); | 480 | tst->mem.size / 4); |
@@ -506,19 +503,13 @@ static int iwl_test_indirect_write(struct iwl_test *tst, u32 addr, | |||
506 | /* Periphery writes can be 1-3 bytes long, or DWORDs */ | 503 | /* Periphery writes can be 1-3 bytes long, or DWORDs */ |
507 | if (size < 4) { | 504 | if (size < 4) { |
508 | memcpy(&val, buf, size); | 505 | memcpy(&val, buf, size); |
509 | spin_lock_irqsave(&trans->reg_lock, flags); | 506 | if (!iwl_trans_grab_nic_access(trans, false, &flags)) |
510 | if (!iwl_trans_grab_nic_access(trans, false)) { | ||
511 | spin_unlock_irqrestore(&trans->reg_lock, flags); | ||
512 | return -EIO; | 507 | return -EIO; |
513 | } | ||
514 | iwl_write32(trans, HBUS_TARG_PRPH_WADDR, | 508 | iwl_write32(trans, HBUS_TARG_PRPH_WADDR, |
515 | (addr & 0x0000FFFF) | | 509 | (addr & 0x0000FFFF) | |
516 | ((size - 1) << 24)); | 510 | ((size - 1) << 24)); |
517 | iwl_write32(trans, HBUS_TARG_PRPH_WDAT, val); | 511 | iwl_write32(trans, HBUS_TARG_PRPH_WDAT, val); |
518 | iwl_trans_release_nic_access(trans); | 512 | iwl_trans_release_nic_access(trans, &flags); |
519 | /* needed after consecutive writes w/o read */ | ||
520 | mmiowb(); | ||
521 | spin_unlock_irqrestore(&trans->reg_lock, flags); | ||
522 | } else { | 513 | } else { |
523 | if (size % 4) | 514 | if (size % 4) |
524 | return -EINVAL; | 515 | return -EINVAL; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-test.h b/drivers/net/wireless/iwlwifi/iwl-test.h index e13ffa8acc02..7fbf4d717caa 100644 --- a/drivers/net/wireless/iwlwifi/iwl-test.h +++ b/drivers/net/wireless/iwlwifi/iwl-test.h | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2010 - 2012 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2010 - 2013 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2010 - 2012 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2010 - 2013 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
diff --git a/drivers/net/wireless/iwlwifi/iwl-testmode.h b/drivers/net/wireless/iwlwifi/iwl-testmode.h index 6ba211b09426..a963f45c6849 100644 --- a/drivers/net/wireless/iwlwifi/iwl-testmode.h +++ b/drivers/net/wireless/iwlwifi/iwl-testmode.h | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2010 - 2012 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2010 - 2013 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2010 - 2012 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2010 - 2013 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 0f85eb305878..0a3d4df5f434 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
@@ -193,11 +193,11 @@ struct iwl_rx_packet { | |||
193 | * @CMD_ON_DEMAND: This command is sent by the test mode pipe. | 193 | * @CMD_ON_DEMAND: This command is sent by the test mode pipe. |
194 | */ | 194 | */ |
195 | enum CMD_MODE { | 195 | enum CMD_MODE { |
196 | CMD_SYNC = 0, | 196 | CMD_SYNC = 0, |
197 | CMD_ASYNC = BIT(0), | 197 | CMD_ASYNC = BIT(0), |
198 | CMD_WANT_SKB = BIT(1), | 198 | CMD_WANT_SKB = BIT(1), |
199 | CMD_WANT_HCMD = BIT(2), | 199 | CMD_WANT_HCMD = BIT(2), |
200 | CMD_ON_DEMAND = BIT(3), | 200 | CMD_ON_DEMAND = BIT(3), |
201 | }; | 201 | }; |
202 | 202 | ||
203 | #define DEF_CMD_PAYLOAD_SIZE 320 | 203 | #define DEF_CMD_PAYLOAD_SIZE 320 |
@@ -274,6 +274,7 @@ struct iwl_rx_cmd_buffer { | |||
274 | struct page *_page; | 274 | struct page *_page; |
275 | int _offset; | 275 | int _offset; |
276 | bool _page_stolen; | 276 | bool _page_stolen; |
277 | u32 _rx_page_order; | ||
277 | unsigned int truesize; | 278 | unsigned int truesize; |
278 | }; | 279 | }; |
279 | 280 | ||
@@ -294,6 +295,11 @@ static inline struct page *rxb_steal_page(struct iwl_rx_cmd_buffer *r) | |||
294 | return r->_page; | 295 | return r->_page; |
295 | } | 296 | } |
296 | 297 | ||
298 | static inline void iwl_free_rxb(struct iwl_rx_cmd_buffer *r) | ||
299 | { | ||
300 | __free_pages(r->_page, r->_rx_page_order); | ||
301 | } | ||
302 | |||
297 | #define MAX_NO_RECLAIM_CMDS 6 | 303 | #define MAX_NO_RECLAIM_CMDS 6 |
298 | 304 | ||
299 | #define IWL_MASK(lo, hi) ((1 << (hi)) | ((1 << (hi)) - (1 << (lo)))) | 305 | #define IWL_MASK(lo, hi) ((1 << (hi)) | ((1 << (hi)) - (1 << (lo)))) |
@@ -410,8 +416,12 @@ struct iwl_trans; | |||
410 | * the op_mode. May be called several times before start_fw, can't be | 416 | * the op_mode. May be called several times before start_fw, can't be |
411 | * called after that. | 417 | * called after that. |
412 | * @set_pmi: set the power pmi state | 418 | * @set_pmi: set the power pmi state |
413 | * @grab_nic_access: wake the NIC to be able to access non-HBUS regs | 419 | * @grab_nic_access: wake the NIC to be able to access non-HBUS regs. |
414 | * @release_nic_access: let the NIC go to sleep | 420 | * Sleeping is not allowed between grab_nic_access and |
421 | * release_nic_access. | ||
422 | * @release_nic_access: let the NIC go to sleep. The "flags" parameter | ||
423 | * must be the same one that was sent before to the grab_nic_access. | ||
424 | * @set_bits_mask - set SRAM register according to value and mask. | ||
415 | */ | 425 | */ |
416 | struct iwl_trans_ops { | 426 | struct iwl_trans_ops { |
417 | 427 | ||
@@ -454,8 +464,12 @@ struct iwl_trans_ops { | |||
454 | void (*configure)(struct iwl_trans *trans, | 464 | void (*configure)(struct iwl_trans *trans, |
455 | const struct iwl_trans_config *trans_cfg); | 465 | const struct iwl_trans_config *trans_cfg); |
456 | void (*set_pmi)(struct iwl_trans *trans, bool state); | 466 | void (*set_pmi)(struct iwl_trans *trans, bool state); |
457 | bool (*grab_nic_access)(struct iwl_trans *trans, bool silent); | 467 | bool (*grab_nic_access)(struct iwl_trans *trans, bool silent, |
458 | void (*release_nic_access)(struct iwl_trans *trans); | 468 | unsigned long *flags); |
469 | void (*release_nic_access)(struct iwl_trans *trans, | ||
470 | unsigned long *flags); | ||
471 | void (*set_bits_mask)(struct iwl_trans *trans, u32 reg, u32 mask, | ||
472 | u32 value); | ||
459 | }; | 473 | }; |
460 | 474 | ||
461 | /** | 475 | /** |
@@ -475,7 +489,6 @@ enum iwl_trans_state { | |||
475 | * @ops - pointer to iwl_trans_ops | 489 | * @ops - pointer to iwl_trans_ops |
476 | * @op_mode - pointer to the op_mode | 490 | * @op_mode - pointer to the op_mode |
477 | * @cfg - pointer to the configuration | 491 | * @cfg - pointer to the configuration |
478 | * @reg_lock - protect hw register access | ||
479 | * @dev - pointer to struct device * that represents the device | 492 | * @dev - pointer to struct device * that represents the device |
480 | * @hw_id: a u32 with the ID of the device / subdevice. | 493 | * @hw_id: a u32 with the ID of the device / subdevice. |
481 | * Set during transport allocation. | 494 | * Set during transport allocation. |
@@ -496,7 +509,6 @@ struct iwl_trans { | |||
496 | struct iwl_op_mode *op_mode; | 509 | struct iwl_op_mode *op_mode; |
497 | const struct iwl_cfg *cfg; | 510 | const struct iwl_cfg *cfg; |
498 | enum iwl_trans_state state; | 511 | enum iwl_trans_state state; |
499 | spinlock_t reg_lock; | ||
500 | 512 | ||
501 | struct device *dev; | 513 | struct device *dev; |
502 | u32 hw_rev; | 514 | u32 hw_rev; |
@@ -756,14 +768,20 @@ static inline void iwl_trans_set_pmi(struct iwl_trans *trans, bool state) | |||
756 | trans->ops->set_pmi(trans, state); | 768 | trans->ops->set_pmi(trans, state); |
757 | } | 769 | } |
758 | 770 | ||
759 | #define iwl_trans_grab_nic_access(trans, silent) \ | 771 | static inline void |
772 | iwl_trans_set_bits_mask(struct iwl_trans *trans, u32 reg, u32 mask, u32 value) | ||
773 | { | ||
774 | trans->ops->set_bits_mask(trans, reg, mask, value); | ||
775 | } | ||
776 | |||
777 | #define iwl_trans_grab_nic_access(trans, silent, flags) \ | ||
760 | __cond_lock(nic_access, \ | 778 | __cond_lock(nic_access, \ |
761 | likely((trans)->ops->grab_nic_access(trans, silent))) | 779 | likely((trans)->ops->grab_nic_access(trans, silent, flags))) |
762 | 780 | ||
763 | static inline void __releases(nic_access) | 781 | static inline void __releases(nic_access) |
764 | iwl_trans_release_nic_access(struct iwl_trans *trans) | 782 | iwl_trans_release_nic_access(struct iwl_trans *trans, unsigned long *flags) |
765 | { | 783 | { |
766 | trans->ops->release_nic_access(trans); | 784 | trans->ops->release_nic_access(trans, flags); |
767 | __release(nic_access); | 785 | __release(nic_access); |
768 | } | 786 | } |
769 | 787 | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/Makefile b/drivers/net/wireless/iwlwifi/mvm/Makefile new file mode 100644 index 000000000000..807b250ec396 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/Makefile | |||
@@ -0,0 +1,10 @@ | |||
1 | obj-$(CONFIG_IWLMVM) += iwlmvm.o | ||
2 | iwlmvm-y += fw.o mac80211.o nvm.o ops.o phy-ctxt.o mac-ctxt.o | ||
3 | iwlmvm-y += utils.o rx.o tx.o binding.o quota.o sta.o | ||
4 | iwlmvm-y += scan.o time-event.o rs.o | ||
5 | iwlmvm-y += power.o | ||
6 | iwlmvm-y += led.o | ||
7 | iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o | ||
8 | iwlmvm-$(CONFIG_PM_SLEEP) += d3.o | ||
9 | |||
10 | ccflags-y += -D__CHECK_ENDIAN__ -I$(src)/../ | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/binding.c b/drivers/net/wireless/iwlwifi/mvm/binding.c new file mode 100644 index 000000000000..73d24aacb90a --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/binding.c | |||
@@ -0,0 +1,197 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called LICENSE.GPL. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | * | ||
62 | *****************************************************************************/ | ||
63 | |||
64 | #include <net/mac80211.h> | ||
65 | #include "fw-api.h" | ||
66 | #include "mvm.h" | ||
67 | |||
68 | struct iwl_mvm_iface_iterator_data { | ||
69 | struct ieee80211_vif *ignore_vif; | ||
70 | int idx; | ||
71 | |||
72 | struct iwl_mvm_phy_ctxt *phyctxt; | ||
73 | |||
74 | u16 ids[MAX_MACS_IN_BINDING]; | ||
75 | u16 colors[MAX_MACS_IN_BINDING]; | ||
76 | }; | ||
77 | |||
78 | static int iwl_mvm_binding_cmd(struct iwl_mvm *mvm, u32 action, | ||
79 | struct iwl_mvm_iface_iterator_data *data) | ||
80 | { | ||
81 | struct iwl_binding_cmd cmd; | ||
82 | struct iwl_mvm_phy_ctxt *phyctxt = data->phyctxt; | ||
83 | int i, ret; | ||
84 | u32 status; | ||
85 | |||
86 | memset(&cmd, 0, sizeof(cmd)); | ||
87 | |||
88 | cmd.id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(phyctxt->id, | ||
89 | phyctxt->color)); | ||
90 | cmd.action = cpu_to_le32(action); | ||
91 | cmd.phy = cpu_to_le32(FW_CMD_ID_AND_COLOR(phyctxt->id, | ||
92 | phyctxt->color)); | ||
93 | |||
94 | for (i = 0; i < MAX_MACS_IN_BINDING; i++) | ||
95 | cmd.macs[i] = cpu_to_le32(FW_CTXT_INVALID); | ||
96 | for (i = 0; i < data->idx; i++) | ||
97 | cmd.macs[i] = cpu_to_le32(FW_CMD_ID_AND_COLOR(data->ids[i], | ||
98 | data->colors[i])); | ||
99 | |||
100 | status = 0; | ||
101 | ret = iwl_mvm_send_cmd_pdu_status(mvm, BINDING_CONTEXT_CMD, | ||
102 | sizeof(cmd), &cmd, &status); | ||
103 | if (ret) { | ||
104 | IWL_ERR(mvm, "Failed to send binding (action:%d): %d\n", | ||
105 | action, ret); | ||
106 | return ret; | ||
107 | } | ||
108 | |||
109 | if (status) { | ||
110 | IWL_ERR(mvm, "Binding command failed: %u\n", status); | ||
111 | ret = -EIO; | ||
112 | } | ||
113 | |||
114 | return ret; | ||
115 | } | ||
116 | |||
117 | static void iwl_mvm_iface_iterator(void *_data, u8 *mac, | ||
118 | struct ieee80211_vif *vif) | ||
119 | { | ||
120 | struct iwl_mvm_iface_iterator_data *data = _data; | ||
121 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
122 | |||
123 | if (vif == data->ignore_vif) | ||
124 | return; | ||
125 | |||
126 | if (mvmvif->phy_ctxt != data->phyctxt) | ||
127 | return; | ||
128 | |||
129 | if (WARN_ON_ONCE(data->idx >= MAX_MACS_IN_BINDING)) | ||
130 | return; | ||
131 | |||
132 | data->ids[data->idx] = mvmvif->id; | ||
133 | data->colors[data->idx] = mvmvif->color; | ||
134 | data->idx++; | ||
135 | } | ||
136 | |||
137 | static int iwl_mvm_binding_update(struct iwl_mvm *mvm, | ||
138 | struct ieee80211_vif *vif, | ||
139 | struct iwl_mvm_phy_ctxt *phyctxt, | ||
140 | bool add) | ||
141 | { | ||
142 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
143 | struct iwl_mvm_iface_iterator_data data = { | ||
144 | .ignore_vif = vif, | ||
145 | .phyctxt = phyctxt, | ||
146 | }; | ||
147 | u32 action = FW_CTXT_ACTION_MODIFY; | ||
148 | |||
149 | lockdep_assert_held(&mvm->mutex); | ||
150 | |||
151 | ieee80211_iterate_active_interfaces_atomic(mvm->hw, | ||
152 | IEEE80211_IFACE_ITER_NORMAL, | ||
153 | iwl_mvm_iface_iterator, | ||
154 | &data); | ||
155 | |||
156 | /* | ||
157 | * If there are no other interfaces yet we | ||
158 | * need to create a new binding. | ||
159 | */ | ||
160 | if (data.idx == 0) { | ||
161 | if (add) | ||
162 | action = FW_CTXT_ACTION_ADD; | ||
163 | else | ||
164 | action = FW_CTXT_ACTION_REMOVE; | ||
165 | } | ||
166 | |||
167 | if (add) { | ||
168 | if (WARN_ON_ONCE(data.idx >= MAX_MACS_IN_BINDING)) | ||
169 | return -EINVAL; | ||
170 | |||
171 | data.ids[data.idx] = mvmvif->id; | ||
172 | data.colors[data.idx] = mvmvif->color; | ||
173 | data.idx++; | ||
174 | } | ||
175 | |||
176 | return iwl_mvm_binding_cmd(mvm, action, &data); | ||
177 | } | ||
178 | |||
179 | int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | ||
180 | { | ||
181 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
182 | |||
183 | if (WARN_ON_ONCE(!mvmvif->phy_ctxt)) | ||
184 | return -EINVAL; | ||
185 | |||
186 | return iwl_mvm_binding_update(mvm, vif, mvmvif->phy_ctxt, true); | ||
187 | } | ||
188 | |||
189 | int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | ||
190 | { | ||
191 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
192 | |||
193 | if (WARN_ON_ONCE(!mvmvif->phy_ctxt)) | ||
194 | return -EINVAL; | ||
195 | |||
196 | return iwl_mvm_binding_update(mvm, vif, mvmvif->phy_ctxt, false); | ||
197 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c new file mode 100644 index 000000000000..9a95c374990d --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c | |||
@@ -0,0 +1,841 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called LICENSE.GPL. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | * | ||
62 | *****************************************************************************/ | ||
63 | |||
64 | #include <net/cfg80211.h> | ||
65 | #include <net/ipv6.h> | ||
66 | #include "iwl-modparams.h" | ||
67 | #include "fw-api.h" | ||
68 | #include "mvm.h" | ||
69 | |||
70 | void iwl_mvm_set_rekey_data(struct ieee80211_hw *hw, | ||
71 | struct ieee80211_vif *vif, | ||
72 | struct cfg80211_gtk_rekey_data *data) | ||
73 | { | ||
74 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
75 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
76 | |||
77 | if (iwlwifi_mod_params.sw_crypto) | ||
78 | return; | ||
79 | |||
80 | mutex_lock(&mvm->mutex); | ||
81 | |||
82 | memcpy(mvmvif->rekey_data.kek, data->kek, NL80211_KEK_LEN); | ||
83 | memcpy(mvmvif->rekey_data.kck, data->kck, NL80211_KCK_LEN); | ||
84 | mvmvif->rekey_data.replay_ctr = | ||
85 | cpu_to_le64(be64_to_cpup((__be64 *)&data->replay_ctr)); | ||
86 | mvmvif->rekey_data.valid = true; | ||
87 | |||
88 | mutex_unlock(&mvm->mutex); | ||
89 | } | ||
90 | |||
91 | #if IS_ENABLED(CONFIG_IPV6) | ||
92 | void iwl_mvm_ipv6_addr_change(struct ieee80211_hw *hw, | ||
93 | struct ieee80211_vif *vif, | ||
94 | struct inet6_dev *idev) | ||
95 | { | ||
96 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
97 | struct inet6_ifaddr *ifa; | ||
98 | int idx = 0; | ||
99 | |||
100 | read_lock(&idev->lock); | ||
101 | list_for_each_entry(ifa, &idev->addr_list, if_list) { | ||
102 | mvmvif->target_ipv6_addrs[idx] = ifa->addr; | ||
103 | idx++; | ||
104 | if (idx >= IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS) | ||
105 | break; | ||
106 | } | ||
107 | read_unlock(&idev->lock); | ||
108 | |||
109 | mvmvif->num_target_ipv6_addrs = idx; | ||
110 | } | ||
111 | #endif | ||
112 | |||
113 | void iwl_mvm_set_default_unicast_key(struct ieee80211_hw *hw, | ||
114 | struct ieee80211_vif *vif, int idx) | ||
115 | { | ||
116 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
117 | |||
118 | mvmvif->tx_key_idx = idx; | ||
119 | } | ||
120 | |||
121 | static void iwl_mvm_convert_p1k(u16 *p1k, __le16 *out) | ||
122 | { | ||
123 | int i; | ||
124 | |||
125 | for (i = 0; i < IWL_P1K_SIZE; i++) | ||
126 | out[i] = cpu_to_le16(p1k[i]); | ||
127 | } | ||
128 | |||
129 | struct wowlan_key_data { | ||
130 | struct iwl_wowlan_rsc_tsc_params_cmd *rsc_tsc; | ||
131 | struct iwl_wowlan_tkip_params_cmd *tkip; | ||
132 | bool error, use_rsc_tsc, use_tkip; | ||
133 | int gtk_key_idx; | ||
134 | }; | ||
135 | |||
136 | static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, | ||
137 | struct ieee80211_vif *vif, | ||
138 | struct ieee80211_sta *sta, | ||
139 | struct ieee80211_key_conf *key, | ||
140 | void *_data) | ||
141 | { | ||
142 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
143 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
144 | struct wowlan_key_data *data = _data; | ||
145 | struct aes_sc *aes_sc, *aes_tx_sc = NULL; | ||
146 | struct tkip_sc *tkip_sc, *tkip_tx_sc = NULL; | ||
147 | struct iwl_p1k_cache *rx_p1ks; | ||
148 | u8 *rx_mic_key; | ||
149 | struct ieee80211_key_seq seq; | ||
150 | u32 cur_rx_iv32 = 0; | ||
151 | u16 p1k[IWL_P1K_SIZE]; | ||
152 | int ret, i; | ||
153 | |||
154 | mutex_lock(&mvm->mutex); | ||
155 | |||
156 | switch (key->cipher) { | ||
157 | case WLAN_CIPHER_SUITE_WEP40: | ||
158 | case WLAN_CIPHER_SUITE_WEP104: { /* hack it for now */ | ||
159 | struct { | ||
160 | struct iwl_mvm_wep_key_cmd wep_key_cmd; | ||
161 | struct iwl_mvm_wep_key wep_key; | ||
162 | } __packed wkc = { | ||
163 | .wep_key_cmd.mac_id_n_color = | ||
164 | cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, | ||
165 | mvmvif->color)), | ||
166 | .wep_key_cmd.num_keys = 1, | ||
167 | /* firmware sets STA_KEY_FLG_WEP_13BYTES */ | ||
168 | .wep_key_cmd.decryption_type = STA_KEY_FLG_WEP, | ||
169 | .wep_key.key_index = key->keyidx, | ||
170 | .wep_key.key_size = key->keylen, | ||
171 | }; | ||
172 | |||
173 | /* | ||
174 | * This will fail -- the key functions don't set support | ||
175 | * pairwise WEP keys. However, that's better than silently | ||
176 | * failing WoWLAN. Or maybe not? | ||
177 | */ | ||
178 | if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) | ||
179 | break; | ||
180 | |||
181 | memcpy(&wkc.wep_key.key[3], key->key, key->keylen); | ||
182 | if (key->keyidx == mvmvif->tx_key_idx) { | ||
183 | /* TX key must be at offset 0 */ | ||
184 | wkc.wep_key.key_offset = 0; | ||
185 | } else { | ||
186 | /* others start at 1 */ | ||
187 | data->gtk_key_idx++; | ||
188 | wkc.wep_key.key_offset = data->gtk_key_idx; | ||
189 | } | ||
190 | |||
191 | ret = iwl_mvm_send_cmd_pdu(mvm, WEP_KEY, CMD_SYNC, | ||
192 | sizeof(wkc), &wkc); | ||
193 | data->error = ret != 0; | ||
194 | |||
195 | /* don't upload key again */ | ||
196 | goto out_unlock; | ||
197 | } | ||
198 | default: | ||
199 | data->error = true; | ||
200 | goto out_unlock; | ||
201 | case WLAN_CIPHER_SUITE_AES_CMAC: | ||
202 | /* | ||
203 | * Ignore CMAC keys -- the WoWLAN firmware doesn't support them | ||
204 | * but we also shouldn't abort suspend due to that. It does have | ||
205 | * support for the IGTK key renewal, but doesn't really use the | ||
206 | * IGTK for anything. This means we could spuriously wake up or | ||
207 | * be deauthenticated, but that was considered acceptable. | ||
208 | */ | ||
209 | goto out_unlock; | ||
210 | case WLAN_CIPHER_SUITE_TKIP: | ||
211 | if (sta) { | ||
212 | tkip_sc = data->rsc_tsc->all_tsc_rsc.tkip.unicast_rsc; | ||
213 | tkip_tx_sc = &data->rsc_tsc->all_tsc_rsc.tkip.tsc; | ||
214 | |||
215 | rx_p1ks = data->tkip->rx_uni; | ||
216 | |||
217 | ieee80211_get_key_tx_seq(key, &seq); | ||
218 | tkip_tx_sc->iv16 = cpu_to_le16(seq.tkip.iv16); | ||
219 | tkip_tx_sc->iv32 = cpu_to_le32(seq.tkip.iv32); | ||
220 | |||
221 | ieee80211_get_tkip_p1k_iv(key, seq.tkip.iv32, p1k); | ||
222 | iwl_mvm_convert_p1k(p1k, data->tkip->tx.p1k); | ||
223 | |||
224 | memcpy(data->tkip->mic_keys.tx, | ||
225 | &key->key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY], | ||
226 | IWL_MIC_KEY_SIZE); | ||
227 | |||
228 | rx_mic_key = data->tkip->mic_keys.rx_unicast; | ||
229 | } else { | ||
230 | tkip_sc = | ||
231 | data->rsc_tsc->all_tsc_rsc.tkip.multicast_rsc; | ||
232 | rx_p1ks = data->tkip->rx_multi; | ||
233 | rx_mic_key = data->tkip->mic_keys.rx_mcast; | ||
234 | } | ||
235 | |||
236 | /* | ||
237 | * For non-QoS this relies on the fact that both the uCode and | ||
238 | * mac80211 use TID 0 (as they need to to avoid replay attacks) | ||
239 | * for checking the IV in the frames. | ||
240 | */ | ||
241 | for (i = 0; i < IWL_NUM_RSC; i++) { | ||
242 | ieee80211_get_key_rx_seq(key, i, &seq); | ||
243 | tkip_sc[i].iv16 = cpu_to_le16(seq.tkip.iv16); | ||
244 | tkip_sc[i].iv32 = cpu_to_le32(seq.tkip.iv32); | ||
245 | /* wrapping isn't allowed, AP must rekey */ | ||
246 | if (seq.tkip.iv32 > cur_rx_iv32) | ||
247 | cur_rx_iv32 = seq.tkip.iv32; | ||
248 | } | ||
249 | |||
250 | ieee80211_get_tkip_rx_p1k(key, vif->bss_conf.bssid, | ||
251 | cur_rx_iv32, p1k); | ||
252 | iwl_mvm_convert_p1k(p1k, rx_p1ks[0].p1k); | ||
253 | ieee80211_get_tkip_rx_p1k(key, vif->bss_conf.bssid, | ||
254 | cur_rx_iv32 + 1, p1k); | ||
255 | iwl_mvm_convert_p1k(p1k, rx_p1ks[1].p1k); | ||
256 | |||
257 | memcpy(rx_mic_key, | ||
258 | &key->key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY], | ||
259 | IWL_MIC_KEY_SIZE); | ||
260 | |||
261 | data->use_tkip = true; | ||
262 | data->use_rsc_tsc = true; | ||
263 | break; | ||
264 | case WLAN_CIPHER_SUITE_CCMP: | ||
265 | if (sta) { | ||
266 | u8 *pn = seq.ccmp.pn; | ||
267 | |||
268 | aes_sc = data->rsc_tsc->all_tsc_rsc.aes.unicast_rsc; | ||
269 | aes_tx_sc = &data->rsc_tsc->all_tsc_rsc.aes.tsc; | ||
270 | |||
271 | ieee80211_get_key_tx_seq(key, &seq); | ||
272 | aes_tx_sc->pn = cpu_to_le64((u64)pn[5] | | ||
273 | ((u64)pn[4] << 8) | | ||
274 | ((u64)pn[3] << 16) | | ||
275 | ((u64)pn[2] << 24) | | ||
276 | ((u64)pn[1] << 32) | | ||
277 | ((u64)pn[0] << 40)); | ||
278 | } else { | ||
279 | aes_sc = data->rsc_tsc->all_tsc_rsc.aes.multicast_rsc; | ||
280 | } | ||
281 | |||
282 | /* | ||
283 | * For non-QoS this relies on the fact that both the uCode and | ||
284 | * mac80211 use TID 0 for checking the IV in the frames. | ||
285 | */ | ||
286 | for (i = 0; i < IWL_NUM_RSC; i++) { | ||
287 | u8 *pn = seq.ccmp.pn; | ||
288 | |||
289 | ieee80211_get_key_rx_seq(key, i, &seq); | ||
290 | aes_sc->pn = cpu_to_le64((u64)pn[5] | | ||
291 | ((u64)pn[4] << 8) | | ||
292 | ((u64)pn[3] << 16) | | ||
293 | ((u64)pn[2] << 24) | | ||
294 | ((u64)pn[1] << 32) | | ||
295 | ((u64)pn[0] << 40)); | ||
296 | } | ||
297 | data->use_rsc_tsc = true; | ||
298 | break; | ||
299 | } | ||
300 | |||
301 | /* | ||
302 | * The D3 firmware hardcodes the key offset 0 as the key it uses | ||
303 | * to transmit packets to the AP, i.e. the PTK. | ||
304 | */ | ||
305 | if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { | ||
306 | key->hw_key_idx = 0; | ||
307 | } else { | ||
308 | data->gtk_key_idx++; | ||
309 | key->hw_key_idx = data->gtk_key_idx; | ||
310 | } | ||
311 | |||
312 | ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, true); | ||
313 | data->error = ret != 0; | ||
314 | out_unlock: | ||
315 | mutex_unlock(&mvm->mutex); | ||
316 | } | ||
317 | |||
318 | static int iwl_mvm_send_patterns(struct iwl_mvm *mvm, | ||
319 | struct cfg80211_wowlan *wowlan) | ||
320 | { | ||
321 | struct iwl_wowlan_patterns_cmd *pattern_cmd; | ||
322 | struct iwl_host_cmd cmd = { | ||
323 | .id = WOWLAN_PATTERNS, | ||
324 | .dataflags[0] = IWL_HCMD_DFL_NOCOPY, | ||
325 | .flags = CMD_SYNC, | ||
326 | }; | ||
327 | int i, err; | ||
328 | |||
329 | if (!wowlan->n_patterns) | ||
330 | return 0; | ||
331 | |||
332 | cmd.len[0] = sizeof(*pattern_cmd) + | ||
333 | wowlan->n_patterns * sizeof(struct iwl_wowlan_pattern); | ||
334 | |||
335 | pattern_cmd = kmalloc(cmd.len[0], GFP_KERNEL); | ||
336 | if (!pattern_cmd) | ||
337 | return -ENOMEM; | ||
338 | |||
339 | pattern_cmd->n_patterns = cpu_to_le32(wowlan->n_patterns); | ||
340 | |||
341 | for (i = 0; i < wowlan->n_patterns; i++) { | ||
342 | int mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8); | ||
343 | |||
344 | memcpy(&pattern_cmd->patterns[i].mask, | ||
345 | wowlan->patterns[i].mask, mask_len); | ||
346 | memcpy(&pattern_cmd->patterns[i].pattern, | ||
347 | wowlan->patterns[i].pattern, | ||
348 | wowlan->patterns[i].pattern_len); | ||
349 | pattern_cmd->patterns[i].mask_size = mask_len; | ||
350 | pattern_cmd->patterns[i].pattern_size = | ||
351 | wowlan->patterns[i].pattern_len; | ||
352 | } | ||
353 | |||
354 | cmd.data[0] = pattern_cmd; | ||
355 | err = iwl_mvm_send_cmd(mvm, &cmd); | ||
356 | kfree(pattern_cmd); | ||
357 | return err; | ||
358 | } | ||
359 | |||
360 | static int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, | ||
361 | struct ieee80211_vif *vif) | ||
362 | { | ||
363 | struct iwl_proto_offload_cmd cmd = {}; | ||
364 | #if IS_ENABLED(CONFIG_IPV6) | ||
365 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
366 | int i; | ||
367 | |||
368 | if (mvmvif->num_target_ipv6_addrs) { | ||
369 | cmd.enabled |= cpu_to_le32(IWL_D3_PROTO_OFFLOAD_NS); | ||
370 | memcpy(cmd.ndp_mac_addr, vif->addr, ETH_ALEN); | ||
371 | } | ||
372 | |||
373 | BUILD_BUG_ON(sizeof(cmd.target_ipv6_addr[i]) != | ||
374 | sizeof(mvmvif->target_ipv6_addrs[i])); | ||
375 | |||
376 | for (i = 0; i < mvmvif->num_target_ipv6_addrs; i++) | ||
377 | memcpy(cmd.target_ipv6_addr[i], | ||
378 | &mvmvif->target_ipv6_addrs[i], | ||
379 | sizeof(cmd.target_ipv6_addr[i])); | ||
380 | #endif | ||
381 | |||
382 | if (vif->bss_conf.arp_addr_cnt) { | ||
383 | cmd.enabled |= cpu_to_le32(IWL_D3_PROTO_OFFLOAD_ARP); | ||
384 | cmd.host_ipv4_addr = vif->bss_conf.arp_addr_list[0]; | ||
385 | memcpy(cmd.arp_mac_addr, vif->addr, ETH_ALEN); | ||
386 | } | ||
387 | |||
388 | if (!cmd.enabled) | ||
389 | return 0; | ||
390 | |||
391 | return iwl_mvm_send_cmd_pdu(mvm, PROT_OFFLOAD_CONFIG_CMD, CMD_SYNC, | ||
392 | sizeof(cmd), &cmd); | ||
393 | } | ||
394 | |||
395 | struct iwl_d3_iter_data { | ||
396 | struct iwl_mvm *mvm; | ||
397 | struct ieee80211_vif *vif; | ||
398 | bool error; | ||
399 | }; | ||
400 | |||
401 | static void iwl_mvm_d3_iface_iterator(void *_data, u8 *mac, | ||
402 | struct ieee80211_vif *vif) | ||
403 | { | ||
404 | struct iwl_d3_iter_data *data = _data; | ||
405 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
406 | |||
407 | if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) | ||
408 | return; | ||
409 | |||
410 | if (mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT) | ||
411 | return; | ||
412 | |||
413 | if (data->vif) { | ||
414 | IWL_ERR(data->mvm, "More than one managed interface active!\n"); | ||
415 | data->error = true; | ||
416 | return; | ||
417 | } | ||
418 | |||
419 | data->vif = vif; | ||
420 | } | ||
421 | |||
422 | static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
423 | struct ieee80211_sta *ap_sta) | ||
424 | { | ||
425 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
426 | struct ieee80211_chanctx_conf *ctx; | ||
427 | u8 chains_static, chains_dynamic; | ||
428 | struct cfg80211_chan_def chandef; | ||
429 | int ret, i; | ||
430 | struct iwl_binding_cmd binding_cmd = {}; | ||
431 | struct iwl_time_quota_cmd quota_cmd = {}; | ||
432 | u32 status; | ||
433 | |||
434 | /* add back the PHY */ | ||
435 | if (WARN_ON(!mvmvif->phy_ctxt)) | ||
436 | return -EINVAL; | ||
437 | |||
438 | rcu_read_lock(); | ||
439 | ctx = rcu_dereference(vif->chanctx_conf); | ||
440 | if (WARN_ON(!ctx)) { | ||
441 | rcu_read_unlock(); | ||
442 | return -EINVAL; | ||
443 | } | ||
444 | chandef = ctx->def; | ||
445 | chains_static = ctx->rx_chains_static; | ||
446 | chains_dynamic = ctx->rx_chains_dynamic; | ||
447 | rcu_read_unlock(); | ||
448 | |||
449 | ret = iwl_mvm_phy_ctxt_add(mvm, mvmvif->phy_ctxt, &chandef, | ||
450 | chains_static, chains_dynamic); | ||
451 | if (ret) | ||
452 | return ret; | ||
453 | |||
454 | /* add back the MAC */ | ||
455 | mvmvif->uploaded = false; | ||
456 | |||
457 | if (WARN_ON(!vif->bss_conf.assoc)) | ||
458 | return -EINVAL; | ||
459 | /* hack */ | ||
460 | vif->bss_conf.assoc = false; | ||
461 | ret = iwl_mvm_mac_ctxt_add(mvm, vif); | ||
462 | vif->bss_conf.assoc = true; | ||
463 | if (ret) | ||
464 | return ret; | ||
465 | |||
466 | /* add back binding - XXX refactor? */ | ||
467 | binding_cmd.id_and_color = | ||
468 | cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->phy_ctxt->id, | ||
469 | mvmvif->phy_ctxt->color)); | ||
470 | binding_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD); | ||
471 | binding_cmd.phy = | ||
472 | cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->phy_ctxt->id, | ||
473 | mvmvif->phy_ctxt->color)); | ||
474 | binding_cmd.macs[0] = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, | ||
475 | mvmvif->color)); | ||
476 | for (i = 1; i < MAX_MACS_IN_BINDING; i++) | ||
477 | binding_cmd.macs[i] = cpu_to_le32(FW_CTXT_INVALID); | ||
478 | |||
479 | status = 0; | ||
480 | ret = iwl_mvm_send_cmd_pdu_status(mvm, BINDING_CONTEXT_CMD, | ||
481 | sizeof(binding_cmd), &binding_cmd, | ||
482 | &status); | ||
483 | if (ret) { | ||
484 | IWL_ERR(mvm, "Failed to add binding: %d\n", ret); | ||
485 | return ret; | ||
486 | } | ||
487 | |||
488 | if (status) { | ||
489 | IWL_ERR(mvm, "Binding command failed: %u\n", status); | ||
490 | return -EIO; | ||
491 | } | ||
492 | |||
493 | ret = iwl_mvm_sta_add_to_fw(mvm, ap_sta); | ||
494 | if (ret) | ||
495 | return ret; | ||
496 | rcu_assign_pointer(mvm->fw_id_to_mac_id[mvmvif->ap_sta_id], ap_sta); | ||
497 | |||
498 | ret = iwl_mvm_mac_ctxt_changed(mvm, vif); | ||
499 | if (ret) | ||
500 | return ret; | ||
501 | |||
502 | /* and some quota */ | ||
503 | quota_cmd.quotas[0].id_and_color = | ||
504 | cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->phy_ctxt->id, | ||
505 | mvmvif->phy_ctxt->color)); | ||
506 | quota_cmd.quotas[0].quota = cpu_to_le32(100); | ||
507 | quota_cmd.quotas[0].max_duration = cpu_to_le32(1000); | ||
508 | |||
509 | for (i = 1; i < MAX_BINDINGS; i++) | ||
510 | quota_cmd.quotas[i].id_and_color = cpu_to_le32(FW_CTXT_INVALID); | ||
511 | |||
512 | ret = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, CMD_SYNC, | ||
513 | sizeof(quota_cmd), "a_cmd); | ||
514 | if (ret) | ||
515 | IWL_ERR(mvm, "Failed to send quota: %d\n", ret); | ||
516 | |||
517 | return 0; | ||
518 | } | ||
519 | |||
520 | int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | ||
521 | { | ||
522 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
523 | struct iwl_d3_iter_data suspend_iter_data = { | ||
524 | .mvm = mvm, | ||
525 | }; | ||
526 | struct ieee80211_vif *vif; | ||
527 | struct iwl_mvm_vif *mvmvif; | ||
528 | struct ieee80211_sta *ap_sta; | ||
529 | struct iwl_mvm_sta *mvm_ap_sta; | ||
530 | struct iwl_wowlan_config_cmd wowlan_config_cmd = {}; | ||
531 | struct iwl_wowlan_kek_kck_material_cmd kek_kck_cmd = {}; | ||
532 | struct iwl_wowlan_tkip_params_cmd tkip_cmd = {}; | ||
533 | struct iwl_d3_manager_config d3_cfg_cmd = {}; | ||
534 | struct wowlan_key_data key_data = { | ||
535 | .use_rsc_tsc = false, | ||
536 | .tkip = &tkip_cmd, | ||
537 | .use_tkip = false, | ||
538 | }; | ||
539 | int ret, i; | ||
540 | u16 seq; | ||
541 | u8 old_aux_sta_id, old_ap_sta_id = IWL_MVM_STATION_COUNT; | ||
542 | |||
543 | if (WARN_ON(!wowlan)) | ||
544 | return -EINVAL; | ||
545 | |||
546 | key_data.rsc_tsc = kzalloc(sizeof(*key_data.rsc_tsc), GFP_KERNEL); | ||
547 | if (!key_data.rsc_tsc) | ||
548 | return -ENOMEM; | ||
549 | |||
550 | mutex_lock(&mvm->mutex); | ||
551 | |||
552 | old_aux_sta_id = mvm->aux_sta.sta_id; | ||
553 | |||
554 | /* see if there's only a single BSS vif and it's associated */ | ||
555 | ieee80211_iterate_active_interfaces_atomic( | ||
556 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, | ||
557 | iwl_mvm_d3_iface_iterator, &suspend_iter_data); | ||
558 | |||
559 | if (suspend_iter_data.error || !suspend_iter_data.vif) { | ||
560 | ret = 1; | ||
561 | goto out_noreset; | ||
562 | } | ||
563 | |||
564 | vif = suspend_iter_data.vif; | ||
565 | mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
566 | |||
567 | ap_sta = rcu_dereference_protected( | ||
568 | mvm->fw_id_to_mac_id[mvmvif->ap_sta_id], | ||
569 | lockdep_is_held(&mvm->mutex)); | ||
570 | if (IS_ERR_OR_NULL(ap_sta)) { | ||
571 | ret = -EINVAL; | ||
572 | goto out_noreset; | ||
573 | } | ||
574 | |||
575 | mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv; | ||
576 | |||
577 | /* | ||
578 | * The D3 firmware still hardcodes the AP station ID for the | ||
579 | * BSS we're associated with as 0. Store the real STA ID here | ||
580 | * and assign 0. When we leave this function, we'll restore | ||
581 | * the original value for the resume code. | ||
582 | */ | ||
583 | old_ap_sta_id = mvm_ap_sta->sta_id; | ||
584 | mvm_ap_sta->sta_id = 0; | ||
585 | mvmvif->ap_sta_id = 0; | ||
586 | |||
587 | /* TODO: wowlan_config_cmd.wowlan_ba_teardown_tids */ | ||
588 | |||
589 | wowlan_config_cmd.is_11n_connection = ap_sta->ht_cap.ht_supported; | ||
590 | |||
591 | /* | ||
592 | * We know the last used seqno, and the uCode expects to know that | ||
593 | * one, it will increment before TX. | ||
594 | */ | ||
595 | seq = mvm_ap_sta->last_seq_ctl & IEEE80211_SCTL_SEQ; | ||
596 | wowlan_config_cmd.non_qos_seq = cpu_to_le16(seq); | ||
597 | |||
598 | /* | ||
599 | * For QoS counters, we store the one to use next, so subtract 0x10 | ||
600 | * since the uCode will add 0x10 *before* using the value while we | ||
601 | * increment after using the value (i.e. store the next value to use). | ||
602 | */ | ||
603 | for (i = 0; i < IWL_MAX_TID_COUNT; i++) { | ||
604 | seq = mvm_ap_sta->tid_data[i].seq_number; | ||
605 | seq -= 0x10; | ||
606 | wowlan_config_cmd.qos_seq[i] = cpu_to_le16(seq); | ||
607 | } | ||
608 | |||
609 | if (wowlan->disconnect) | ||
610 | wowlan_config_cmd.wakeup_filter |= | ||
611 | cpu_to_le32(IWL_WOWLAN_WAKEUP_BEACON_MISS | | ||
612 | IWL_WOWLAN_WAKEUP_LINK_CHANGE); | ||
613 | if (wowlan->magic_pkt) | ||
614 | wowlan_config_cmd.wakeup_filter |= | ||
615 | cpu_to_le32(IWL_WOWLAN_WAKEUP_MAGIC_PACKET); | ||
616 | if (wowlan->gtk_rekey_failure) | ||
617 | wowlan_config_cmd.wakeup_filter |= | ||
618 | cpu_to_le32(IWL_WOWLAN_WAKEUP_GTK_REKEY_FAIL); | ||
619 | if (wowlan->eap_identity_req) | ||
620 | wowlan_config_cmd.wakeup_filter |= | ||
621 | cpu_to_le32(IWL_WOWLAN_WAKEUP_EAP_IDENT_REQ); | ||
622 | if (wowlan->four_way_handshake) | ||
623 | wowlan_config_cmd.wakeup_filter |= | ||
624 | cpu_to_le32(IWL_WOWLAN_WAKEUP_4WAY_HANDSHAKE); | ||
625 | if (wowlan->n_patterns) | ||
626 | wowlan_config_cmd.wakeup_filter |= | ||
627 | cpu_to_le32(IWL_WOWLAN_WAKEUP_PATTERN_MATCH); | ||
628 | |||
629 | if (wowlan->rfkill_release) | ||
630 | d3_cfg_cmd.wakeup_flags |= | ||
631 | cpu_to_le32(IWL_WOWLAN_WAKEUP_RF_KILL_DEASSERT); | ||
632 | |||
633 | iwl_mvm_cancel_scan(mvm); | ||
634 | |||
635 | iwl_trans_stop_device(mvm->trans); | ||
636 | |||
637 | /* | ||
638 | * Set the HW restart bit -- this is mostly true as we're | ||
639 | * going to load new firmware and reprogram that, though | ||
640 | * the reprogramming is going to be manual to avoid adding | ||
641 | * all the MACs that aren't support. | ||
642 | * We don't have to clear up everything though because the | ||
643 | * reprogramming is manual. When we resume, we'll actually | ||
644 | * go through a proper restart sequence again to switch | ||
645 | * back to the runtime firmware image. | ||
646 | */ | ||
647 | set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); | ||
648 | |||
649 | /* We reprogram keys and shouldn't allocate new key indices */ | ||
650 | memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table)); | ||
651 | |||
652 | /* | ||
653 | * The D3 firmware still hardcodes the AP station ID for the | ||
654 | * BSS we're associated with as 0. As a result, we have to move | ||
655 | * the auxiliary station to ID 1 so the ID 0 remains free for | ||
656 | * the AP station for later. | ||
657 | * We set the sta_id to 1 here, and reset it to its previous | ||
658 | * value (that we stored above) later. | ||
659 | */ | ||
660 | mvm->aux_sta.sta_id = 1; | ||
661 | |||
662 | ret = iwl_mvm_load_d3_fw(mvm); | ||
663 | if (ret) | ||
664 | goto out; | ||
665 | |||
666 | ret = iwl_mvm_d3_reprogram(mvm, vif, ap_sta); | ||
667 | if (ret) | ||
668 | goto out; | ||
669 | |||
670 | if (!iwlwifi_mod_params.sw_crypto) { | ||
671 | /* | ||
672 | * This needs to be unlocked due to lock ordering | ||
673 | * constraints. Since we're in the suspend path | ||
674 | * that isn't really a problem though. | ||
675 | */ | ||
676 | mutex_unlock(&mvm->mutex); | ||
677 | ieee80211_iter_keys(mvm->hw, vif, | ||
678 | iwl_mvm_wowlan_program_keys, | ||
679 | &key_data); | ||
680 | mutex_lock(&mvm->mutex); | ||
681 | if (key_data.error) { | ||
682 | ret = -EIO; | ||
683 | goto out; | ||
684 | } | ||
685 | |||
686 | if (key_data.use_rsc_tsc) { | ||
687 | struct iwl_host_cmd rsc_tsc_cmd = { | ||
688 | .id = WOWLAN_TSC_RSC_PARAM, | ||
689 | .flags = CMD_SYNC, | ||
690 | .data[0] = key_data.rsc_tsc, | ||
691 | .dataflags[0] = IWL_HCMD_DFL_NOCOPY, | ||
692 | .len[0] = sizeof(*key_data.rsc_tsc), | ||
693 | }; | ||
694 | |||
695 | ret = iwl_mvm_send_cmd(mvm, &rsc_tsc_cmd); | ||
696 | if (ret) | ||
697 | goto out; | ||
698 | } | ||
699 | |||
700 | if (key_data.use_tkip) { | ||
701 | ret = iwl_mvm_send_cmd_pdu(mvm, | ||
702 | WOWLAN_TKIP_PARAM, | ||
703 | CMD_SYNC, sizeof(tkip_cmd), | ||
704 | &tkip_cmd); | ||
705 | if (ret) | ||
706 | goto out; | ||
707 | } | ||
708 | |||
709 | if (mvmvif->rekey_data.valid) { | ||
710 | memset(&kek_kck_cmd, 0, sizeof(kek_kck_cmd)); | ||
711 | memcpy(kek_kck_cmd.kck, mvmvif->rekey_data.kck, | ||
712 | NL80211_KCK_LEN); | ||
713 | kek_kck_cmd.kck_len = cpu_to_le16(NL80211_KCK_LEN); | ||
714 | memcpy(kek_kck_cmd.kek, mvmvif->rekey_data.kek, | ||
715 | NL80211_KEK_LEN); | ||
716 | kek_kck_cmd.kek_len = cpu_to_le16(NL80211_KEK_LEN); | ||
717 | kek_kck_cmd.replay_ctr = mvmvif->rekey_data.replay_ctr; | ||
718 | |||
719 | ret = iwl_mvm_send_cmd_pdu(mvm, | ||
720 | WOWLAN_KEK_KCK_MATERIAL, | ||
721 | CMD_SYNC, | ||
722 | sizeof(kek_kck_cmd), | ||
723 | &kek_kck_cmd); | ||
724 | if (ret) | ||
725 | goto out; | ||
726 | } | ||
727 | } | ||
728 | |||
729 | ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, | ||
730 | CMD_SYNC, sizeof(wowlan_config_cmd), | ||
731 | &wowlan_config_cmd); | ||
732 | if (ret) | ||
733 | goto out; | ||
734 | |||
735 | ret = iwl_mvm_send_patterns(mvm, wowlan); | ||
736 | if (ret) | ||
737 | goto out; | ||
738 | |||
739 | ret = iwl_mvm_send_proto_offload(mvm, vif); | ||
740 | if (ret) | ||
741 | goto out; | ||
742 | |||
743 | /* must be last -- this switches firmware state */ | ||
744 | ret = iwl_mvm_send_cmd_pdu(mvm, D3_CONFIG_CMD, CMD_SYNC, | ||
745 | sizeof(d3_cfg_cmd), &d3_cfg_cmd); | ||
746 | if (ret) | ||
747 | goto out; | ||
748 | |||
749 | clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); | ||
750 | |||
751 | iwl_trans_d3_suspend(mvm->trans); | ||
752 | out: | ||
753 | mvm->aux_sta.sta_id = old_aux_sta_id; | ||
754 | mvm_ap_sta->sta_id = old_ap_sta_id; | ||
755 | mvmvif->ap_sta_id = old_ap_sta_id; | ||
756 | out_noreset: | ||
757 | kfree(key_data.rsc_tsc); | ||
758 | if (ret < 0) | ||
759 | ieee80211_restart_hw(mvm->hw); | ||
760 | |||
761 | mutex_unlock(&mvm->mutex); | ||
762 | |||
763 | return ret; | ||
764 | } | ||
765 | |||
766 | int iwl_mvm_resume(struct ieee80211_hw *hw) | ||
767 | { | ||
768 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
769 | struct iwl_d3_iter_data resume_iter_data = { | ||
770 | .mvm = mvm, | ||
771 | }; | ||
772 | struct ieee80211_vif *vif = NULL; | ||
773 | u32 base; | ||
774 | int ret; | ||
775 | enum iwl_d3_status d3_status; | ||
776 | struct error_table_start { | ||
777 | /* cf. struct iwl_error_event_table */ | ||
778 | u32 valid; | ||
779 | u32 error_id; | ||
780 | } err_info; | ||
781 | |||
782 | mutex_lock(&mvm->mutex); | ||
783 | |||
784 | /* get the BSS vif pointer again */ | ||
785 | ieee80211_iterate_active_interfaces_atomic( | ||
786 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, | ||
787 | iwl_mvm_d3_iface_iterator, &resume_iter_data); | ||
788 | |||
789 | if (WARN_ON(resume_iter_data.error || !resume_iter_data.vif)) | ||
790 | goto out_unlock; | ||
791 | |||
792 | vif = resume_iter_data.vif; | ||
793 | |||
794 | ret = iwl_trans_d3_resume(mvm->trans, &d3_status); | ||
795 | if (ret) | ||
796 | goto out_unlock; | ||
797 | |||
798 | if (d3_status != IWL_D3_STATUS_ALIVE) { | ||
799 | IWL_INFO(mvm, "Device was reset during suspend\n"); | ||
800 | goto out_unlock; | ||
801 | } | ||
802 | |||
803 | base = mvm->error_event_table; | ||
804 | |||
805 | iwl_trans_read_mem_bytes(mvm->trans, base, | ||
806 | &err_info, sizeof(err_info)); | ||
807 | |||
808 | if (err_info.valid) { | ||
809 | IWL_INFO(mvm, "error table is valid (%d)\n", | ||
810 | err_info.valid); | ||
811 | if (err_info.error_id == RF_KILL_INDICATOR_FOR_WOWLAN) | ||
812 | IWL_ERR(mvm, "this was due to RF-kill\n"); | ||
813 | goto out_unlock; | ||
814 | } | ||
815 | |||
816 | /* TODO: get status and whatever else ... */ | ||
817 | ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_GET_STATUSES, CMD_SYNC, 0, NULL); | ||
818 | if (ret) | ||
819 | IWL_ERR(mvm, "failed to query status (%d)\n", ret); | ||
820 | |||
821 | ret = iwl_mvm_send_cmd_pdu(mvm, OFFLOADS_QUERY_CMD, CMD_SYNC, 0, NULL); | ||
822 | if (ret) | ||
823 | IWL_ERR(mvm, "failed to query offloads (%d)\n", ret); | ||
824 | |||
825 | out_unlock: | ||
826 | mutex_unlock(&mvm->mutex); | ||
827 | |||
828 | if (vif) | ||
829 | ieee80211_resume_disconnect(vif); | ||
830 | |||
831 | /* return 1 to reconfigure the device */ | ||
832 | set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); | ||
833 | return 1; | ||
834 | } | ||
835 | |||
836 | void iwl_mvm_set_wakeup(struct ieee80211_hw *hw, bool enabled) | ||
837 | { | ||
838 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
839 | |||
840 | device_set_wakeup_enable(mvm->trans->dev, enabled); | ||
841 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c new file mode 100644 index 000000000000..c1bdb5582126 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c | |||
@@ -0,0 +1,378 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called LICENSE.GPL. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | * | ||
62 | *****************************************************************************/ | ||
63 | #include "mvm.h" | ||
64 | #include "sta.h" | ||
65 | #include "iwl-io.h" | ||
66 | |||
67 | struct iwl_dbgfs_mvm_ctx { | ||
68 | struct iwl_mvm *mvm; | ||
69 | struct ieee80211_vif *vif; | ||
70 | }; | ||
71 | |||
72 | static int iwl_dbgfs_open_file_generic(struct inode *inode, struct file *file) | ||
73 | { | ||
74 | file->private_data = inode->i_private; | ||
75 | return 0; | ||
76 | } | ||
77 | |||
78 | static ssize_t iwl_dbgfs_tx_flush_write(struct file *file, | ||
79 | const char __user *user_buf, | ||
80 | size_t count, loff_t *ppos) | ||
81 | { | ||
82 | struct iwl_mvm *mvm = file->private_data; | ||
83 | |||
84 | char buf[16]; | ||
85 | int buf_size, ret; | ||
86 | u32 scd_q_msk; | ||
87 | |||
88 | if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR) | ||
89 | return -EIO; | ||
90 | |||
91 | memset(buf, 0, sizeof(buf)); | ||
92 | buf_size = min(count, sizeof(buf) - 1); | ||
93 | if (copy_from_user(buf, user_buf, buf_size)) | ||
94 | return -EFAULT; | ||
95 | |||
96 | if (sscanf(buf, "%x", &scd_q_msk) != 1) | ||
97 | return -EINVAL; | ||
98 | |||
99 | IWL_ERR(mvm, "FLUSHING queues: scd_q_msk = 0x%x\n", scd_q_msk); | ||
100 | |||
101 | mutex_lock(&mvm->mutex); | ||
102 | ret = iwl_mvm_flush_tx_path(mvm, scd_q_msk, true) ? : count; | ||
103 | mutex_unlock(&mvm->mutex); | ||
104 | |||
105 | return ret; | ||
106 | } | ||
107 | |||
108 | static ssize_t iwl_dbgfs_sta_drain_write(struct file *file, | ||
109 | const char __user *user_buf, | ||
110 | size_t count, loff_t *ppos) | ||
111 | { | ||
112 | struct iwl_mvm *mvm = file->private_data; | ||
113 | struct ieee80211_sta *sta; | ||
114 | |||
115 | char buf[8]; | ||
116 | int buf_size, sta_id, drain, ret; | ||
117 | |||
118 | if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR) | ||
119 | return -EIO; | ||
120 | |||
121 | memset(buf, 0, sizeof(buf)); | ||
122 | buf_size = min(count, sizeof(buf) - 1); | ||
123 | if (copy_from_user(buf, user_buf, buf_size)) | ||
124 | return -EFAULT; | ||
125 | |||
126 | if (sscanf(buf, "%d %d", &sta_id, &drain) != 2) | ||
127 | return -EINVAL; | ||
128 | |||
129 | mutex_lock(&mvm->mutex); | ||
130 | |||
131 | sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], | ||
132 | lockdep_is_held(&mvm->mutex)); | ||
133 | if (IS_ERR_OR_NULL(sta)) | ||
134 | ret = -ENOENT; | ||
135 | else | ||
136 | ret = iwl_mvm_drain_sta(mvm, (void *)sta->drv_priv, drain) ? : | ||
137 | count; | ||
138 | |||
139 | mutex_unlock(&mvm->mutex); | ||
140 | |||
141 | return ret; | ||
142 | } | ||
143 | |||
144 | static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf, | ||
145 | size_t count, loff_t *ppos) | ||
146 | { | ||
147 | struct iwl_mvm *mvm = file->private_data; | ||
148 | const struct fw_img *img; | ||
149 | int ofs, len, pos = 0; | ||
150 | size_t bufsz, ret; | ||
151 | char *buf; | ||
152 | u8 *ptr; | ||
153 | |||
154 | /* default is to dump the entire data segment */ | ||
155 | if (!mvm->dbgfs_sram_offset && !mvm->dbgfs_sram_len) { | ||
156 | mvm->dbgfs_sram_offset = 0x800000; | ||
157 | if (!mvm->ucode_loaded) | ||
158 | return -EINVAL; | ||
159 | img = &mvm->fw->img[mvm->cur_ucode]; | ||
160 | mvm->dbgfs_sram_len = img->sec[IWL_UCODE_SECTION_DATA].len; | ||
161 | } | ||
162 | len = mvm->dbgfs_sram_len; | ||
163 | |||
164 | bufsz = len * 4 + 256; | ||
165 | buf = kzalloc(bufsz, GFP_KERNEL); | ||
166 | if (!buf) | ||
167 | return -ENOMEM; | ||
168 | |||
169 | ptr = kzalloc(len, GFP_KERNEL); | ||
170 | if (!ptr) { | ||
171 | kfree(buf); | ||
172 | return -ENOMEM; | ||
173 | } | ||
174 | |||
175 | pos += scnprintf(buf + pos, bufsz - pos, "sram_len: 0x%x\n", len); | ||
176 | pos += scnprintf(buf + pos, bufsz - pos, "sram_offset: 0x%x\n", | ||
177 | mvm->dbgfs_sram_offset); | ||
178 | |||
179 | iwl_trans_read_mem_bytes(mvm->trans, | ||
180 | mvm->dbgfs_sram_offset, | ||
181 | ptr, len); | ||
182 | for (ofs = 0; ofs < len; ofs += 16) { | ||
183 | pos += scnprintf(buf + pos, bufsz - pos, "0x%.4x ", ofs); | ||
184 | hex_dump_to_buffer(ptr + ofs, 16, 16, 1, buf + pos, | ||
185 | bufsz - pos, false); | ||
186 | pos += strlen(buf + pos); | ||
187 | if (bufsz - pos > 0) | ||
188 | buf[pos++] = '\n'; | ||
189 | } | ||
190 | |||
191 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); | ||
192 | |||
193 | kfree(buf); | ||
194 | kfree(ptr); | ||
195 | |||
196 | return ret; | ||
197 | } | ||
198 | |||
199 | static ssize_t iwl_dbgfs_sram_write(struct file *file, | ||
200 | const char __user *user_buf, size_t count, | ||
201 | loff_t *ppos) | ||
202 | { | ||
203 | struct iwl_mvm *mvm = file->private_data; | ||
204 | char buf[64]; | ||
205 | int buf_size; | ||
206 | u32 offset, len; | ||
207 | |||
208 | memset(buf, 0, sizeof(buf)); | ||
209 | buf_size = min(count, sizeof(buf) - 1); | ||
210 | if (copy_from_user(buf, user_buf, buf_size)) | ||
211 | return -EFAULT; | ||
212 | |||
213 | if (sscanf(buf, "%x,%x", &offset, &len) == 2) { | ||
214 | if ((offset & 0x3) || (len & 0x3)) | ||
215 | return -EINVAL; | ||
216 | mvm->dbgfs_sram_offset = offset; | ||
217 | mvm->dbgfs_sram_len = len; | ||
218 | } else { | ||
219 | mvm->dbgfs_sram_offset = 0; | ||
220 | mvm->dbgfs_sram_len = 0; | ||
221 | } | ||
222 | |||
223 | return count; | ||
224 | } | ||
225 | |||
226 | static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, | ||
227 | size_t count, loff_t *ppos) | ||
228 | { | ||
229 | struct iwl_mvm *mvm = file->private_data; | ||
230 | struct ieee80211_sta *sta; | ||
231 | char buf[400]; | ||
232 | int i, pos = 0, bufsz = sizeof(buf); | ||
233 | |||
234 | mutex_lock(&mvm->mutex); | ||
235 | |||
236 | for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { | ||
237 | pos += scnprintf(buf + pos, bufsz - pos, "%.2d: ", i); | ||
238 | sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], | ||
239 | lockdep_is_held(&mvm->mutex)); | ||
240 | if (!sta) | ||
241 | pos += scnprintf(buf + pos, bufsz - pos, "N/A\n"); | ||
242 | else if (IS_ERR(sta)) | ||
243 | pos += scnprintf(buf + pos, bufsz - pos, "%ld\n", | ||
244 | PTR_ERR(sta)); | ||
245 | else | ||
246 | pos += scnprintf(buf + pos, bufsz - pos, "%pM\n", | ||
247 | sta->addr); | ||
248 | } | ||
249 | |||
250 | mutex_unlock(&mvm->mutex); | ||
251 | |||
252 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); | ||
253 | } | ||
254 | |||
255 | static ssize_t iwl_dbgfs_power_down_allow_write(struct file *file, | ||
256 | const char __user *user_buf, | ||
257 | size_t count, loff_t *ppos) | ||
258 | { | ||
259 | struct iwl_mvm *mvm = file->private_data; | ||
260 | char buf[8] = {}; | ||
261 | int allow; | ||
262 | |||
263 | if (!mvm->ucode_loaded) | ||
264 | return -EIO; | ||
265 | |||
266 | if (copy_from_user(buf, user_buf, sizeof(buf))) | ||
267 | return -EFAULT; | ||
268 | |||
269 | if (sscanf(buf, "%d", &allow) != 1) | ||
270 | return -EINVAL; | ||
271 | |||
272 | IWL_DEBUG_POWER(mvm, "%s device power down\n", | ||
273 | allow ? "allow" : "prevent"); | ||
274 | |||
275 | /* | ||
276 | * TODO: Send REPLY_DEBUG_CMD (0xf0) when FW support it | ||
277 | */ | ||
278 | |||
279 | return count; | ||
280 | } | ||
281 | |||
282 | static ssize_t iwl_dbgfs_power_down_d3_allow_write(struct file *file, | ||
283 | const char __user *user_buf, | ||
284 | size_t count, loff_t *ppos) | ||
285 | { | ||
286 | struct iwl_mvm *mvm = file->private_data; | ||
287 | char buf[8] = {}; | ||
288 | int allow; | ||
289 | |||
290 | if (copy_from_user(buf, user_buf, sizeof(buf))) | ||
291 | return -EFAULT; | ||
292 | |||
293 | if (sscanf(buf, "%d", &allow) != 1) | ||
294 | return -EINVAL; | ||
295 | |||
296 | IWL_DEBUG_POWER(mvm, "%s device power down in d3\n", | ||
297 | allow ? "allow" : "prevent"); | ||
298 | |||
299 | /* | ||
300 | * TODO: When WoWLAN FW alive notification happens, driver will send | ||
301 | * REPLY_DEBUG_CMD setting power_down_allow flag according to | ||
302 | * mvm->prevent_power_down_d3 | ||
303 | */ | ||
304 | mvm->prevent_power_down_d3 = !allow; | ||
305 | |||
306 | return count; | ||
307 | } | ||
308 | |||
309 | #define MVM_DEBUGFS_READ_FILE_OPS(name) \ | ||
310 | static const struct file_operations iwl_dbgfs_##name##_ops = { \ | ||
311 | .read = iwl_dbgfs_##name##_read, \ | ||
312 | .open = iwl_dbgfs_open_file_generic, \ | ||
313 | .llseek = generic_file_llseek, \ | ||
314 | } | ||
315 | |||
316 | #define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name) \ | ||
317 | static const struct file_operations iwl_dbgfs_##name##_ops = { \ | ||
318 | .write = iwl_dbgfs_##name##_write, \ | ||
319 | .read = iwl_dbgfs_##name##_read, \ | ||
320 | .open = iwl_dbgfs_open_file_generic, \ | ||
321 | .llseek = generic_file_llseek, \ | ||
322 | }; | ||
323 | |||
324 | #define MVM_DEBUGFS_WRITE_FILE_OPS(name) \ | ||
325 | static const struct file_operations iwl_dbgfs_##name##_ops = { \ | ||
326 | .write = iwl_dbgfs_##name##_write, \ | ||
327 | .open = iwl_dbgfs_open_file_generic, \ | ||
328 | .llseek = generic_file_llseek, \ | ||
329 | }; | ||
330 | |||
331 | #define MVM_DEBUGFS_ADD_FILE(name, parent, mode) do { \ | ||
332 | if (!debugfs_create_file(#name, mode, parent, mvm, \ | ||
333 | &iwl_dbgfs_##name##_ops)) \ | ||
334 | goto err; \ | ||
335 | } while (0) | ||
336 | |||
337 | #define MVM_DEBUGFS_ADD_FILE_VIF(name, parent, mode) do { \ | ||
338 | if (!debugfs_create_file(#name, mode, parent, vif, \ | ||
339 | &iwl_dbgfs_##name##_ops)) \ | ||
340 | goto err; \ | ||
341 | } while (0) | ||
342 | |||
343 | /* Device wide debugfs entries */ | ||
344 | MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush); | ||
345 | MVM_DEBUGFS_WRITE_FILE_OPS(sta_drain); | ||
346 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(sram); | ||
347 | MVM_DEBUGFS_READ_FILE_OPS(stations); | ||
348 | MVM_DEBUGFS_WRITE_FILE_OPS(power_down_allow); | ||
349 | MVM_DEBUGFS_WRITE_FILE_OPS(power_down_d3_allow); | ||
350 | |||
351 | int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) | ||
352 | { | ||
353 | char buf[100]; | ||
354 | |||
355 | mvm->debugfs_dir = dbgfs_dir; | ||
356 | |||
357 | MVM_DEBUGFS_ADD_FILE(tx_flush, mvm->debugfs_dir, S_IWUSR); | ||
358 | MVM_DEBUGFS_ADD_FILE(sta_drain, mvm->debugfs_dir, S_IWUSR); | ||
359 | MVM_DEBUGFS_ADD_FILE(sram, mvm->debugfs_dir, S_IWUSR | S_IRUSR); | ||
360 | MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR); | ||
361 | MVM_DEBUGFS_ADD_FILE(power_down_allow, mvm->debugfs_dir, S_IWUSR); | ||
362 | MVM_DEBUGFS_ADD_FILE(power_down_d3_allow, mvm->debugfs_dir, S_IWUSR); | ||
363 | |||
364 | /* | ||
365 | * Create a symlink with mac80211. It will be removed when mac80211 | ||
366 | * exists (before the opmode exists which removes the target.) | ||
367 | */ | ||
368 | snprintf(buf, 100, "../../%s/%s", | ||
369 | dbgfs_dir->d_parent->d_parent->d_name.name, | ||
370 | dbgfs_dir->d_parent->d_name.name); | ||
371 | if (!debugfs_create_symlink("iwlwifi", mvm->hw->wiphy->debugfsdir, buf)) | ||
372 | goto err; | ||
373 | |||
374 | return 0; | ||
375 | err: | ||
376 | IWL_ERR(mvm, "Can't create the mvm debugfs directory\n"); | ||
377 | return -ENOMEM; | ||
378 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h new file mode 100644 index 000000000000..cf6f9a02fb74 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h | |||
@@ -0,0 +1,282 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called LICENSE.GPL. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | *****************************************************************************/ | ||
62 | |||
63 | #ifndef __fw_api_d3_h__ | ||
64 | #define __fw_api_d3_h__ | ||
65 | |||
66 | /** | ||
67 | * enum iwl_d3_wakeup_flags - D3 manager wakeup flags | ||
68 | * @IWL_WAKEUP_D3_CONFIG_FW_ERROR: wake up on firmware sysassert | ||
69 | */ | ||
70 | enum iwl_d3_wakeup_flags { | ||
71 | IWL_WAKEUP_D3_CONFIG_FW_ERROR = BIT(0), | ||
72 | }; /* D3_MANAGER_WAKEUP_CONFIG_API_E_VER_3 */ | ||
73 | |||
74 | /** | ||
75 | * struct iwl_d3_manager_config - D3 manager configuration command | ||
76 | * @min_sleep_time: minimum sleep time (in usec) | ||
77 | * @wakeup_flags: wakeup flags, see &enum iwl_d3_wakeup_flags | ||
78 | * | ||
79 | * The structure is used for the D3_CONFIG_CMD command. | ||
80 | */ | ||
81 | struct iwl_d3_manager_config { | ||
82 | __le32 min_sleep_time; | ||
83 | __le32 wakeup_flags; | ||
84 | } __packed; /* D3_MANAGER_CONFIG_CMD_S_VER_3 */ | ||
85 | |||
86 | |||
87 | /* TODO: OFFLOADS_QUERY_API_S_VER_1 */ | ||
88 | |||
89 | /** | ||
90 | * enum iwl_d3_proto_offloads - enabled protocol offloads | ||
91 | * @IWL_D3_PROTO_OFFLOAD_ARP: ARP data is enabled | ||
92 | * @IWL_D3_PROTO_OFFLOAD_NS: NS (Neighbor Solicitation) is enabled | ||
93 | */ | ||
94 | enum iwl_proto_offloads { | ||
95 | IWL_D3_PROTO_OFFLOAD_ARP = BIT(0), | ||
96 | IWL_D3_PROTO_OFFLOAD_NS = BIT(1), | ||
97 | }; | ||
98 | |||
99 | #define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS 2 | ||
100 | |||
101 | /** | ||
102 | * struct iwl_proto_offload_cmd - ARP/NS offload configuration | ||
103 | * @enabled: enable flags | ||
104 | * @remote_ipv4_addr: remote address to answer to (or zero if all) | ||
105 | * @host_ipv4_addr: our IPv4 address to respond to queries for | ||
106 | * @arp_mac_addr: our MAC address for ARP responses | ||
107 | * @remote_ipv6_addr: remote address to answer to (or zero if all) | ||
108 | * @solicited_node_ipv6_addr: broken -- solicited node address exists | ||
109 | * for each target address | ||
110 | * @target_ipv6_addr: our target addresses | ||
111 | * @ndp_mac_addr: neighbor soliciation response MAC address | ||
112 | */ | ||
113 | struct iwl_proto_offload_cmd { | ||
114 | __le32 enabled; | ||
115 | __be32 remote_ipv4_addr; | ||
116 | __be32 host_ipv4_addr; | ||
117 | u8 arp_mac_addr[ETH_ALEN]; | ||
118 | __le16 reserved1; | ||
119 | |||
120 | u8 remote_ipv6_addr[16]; | ||
121 | u8 solicited_node_ipv6_addr[16]; | ||
122 | u8 target_ipv6_addr[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS][16]; | ||
123 | u8 ndp_mac_addr[ETH_ALEN]; | ||
124 | __le16 reserved2; | ||
125 | } __packed; /* PROT_OFFLOAD_CONFIG_CMD_DB_S_VER_1 */ | ||
126 | |||
127 | |||
128 | /* | ||
129 | * WOWLAN_PATTERNS | ||
130 | */ | ||
131 | #define IWL_WOWLAN_MIN_PATTERN_LEN 16 | ||
132 | #define IWL_WOWLAN_MAX_PATTERN_LEN 128 | ||
133 | |||
134 | struct iwl_wowlan_pattern { | ||
135 | u8 mask[IWL_WOWLAN_MAX_PATTERN_LEN / 8]; | ||
136 | u8 pattern[IWL_WOWLAN_MAX_PATTERN_LEN]; | ||
137 | u8 mask_size; | ||
138 | u8 pattern_size; | ||
139 | __le16 reserved; | ||
140 | } __packed; /* WOWLAN_PATTERN_API_S_VER_1 */ | ||
141 | |||
142 | #define IWL_WOWLAN_MAX_PATTERNS 20 | ||
143 | |||
144 | struct iwl_wowlan_patterns_cmd { | ||
145 | __le32 n_patterns; | ||
146 | struct iwl_wowlan_pattern patterns[]; | ||
147 | } __packed; /* WOWLAN_PATTERN_ARRAY_API_S_VER_1 */ | ||
148 | |||
149 | enum iwl_wowlan_wakeup_filters { | ||
150 | IWL_WOWLAN_WAKEUP_MAGIC_PACKET = BIT(0), | ||
151 | IWL_WOWLAN_WAKEUP_PATTERN_MATCH = BIT(1), | ||
152 | IWL_WOWLAN_WAKEUP_BEACON_MISS = BIT(2), | ||
153 | IWL_WOWLAN_WAKEUP_LINK_CHANGE = BIT(3), | ||
154 | IWL_WOWLAN_WAKEUP_GTK_REKEY_FAIL = BIT(4), | ||
155 | IWL_WOWLAN_WAKEUP_EAP_IDENT_REQ = BIT(5), | ||
156 | IWL_WOWLAN_WAKEUP_4WAY_HANDSHAKE = BIT(6), | ||
157 | IWL_WOWLAN_WAKEUP_ENABLE_NET_DETECT = BIT(7), | ||
158 | IWL_WOWLAN_WAKEUP_RF_KILL_DEASSERT = BIT(8), | ||
159 | IWL_WOWLAN_WAKEUP_REMOTE_LINK_LOSS = BIT(9), | ||
160 | IWL_WOWLAN_WAKEUP_REMOTE_SIGNATURE_TABLE = BIT(10), | ||
161 | /* BIT(11) reserved */ | ||
162 | IWL_WOWLAN_WAKEUP_REMOTE_WAKEUP_PACKET = BIT(12), | ||
163 | }; /* WOWLAN_WAKEUP_FILTER_API_E_VER_4 */ | ||
164 | |||
165 | struct iwl_wowlan_config_cmd { | ||
166 | __le32 wakeup_filter; | ||
167 | __le16 non_qos_seq; | ||
168 | __le16 qos_seq[8]; | ||
169 | u8 wowlan_ba_teardown_tids; | ||
170 | u8 is_11n_connection; | ||
171 | } __packed; /* WOWLAN_CONFIG_API_S_VER_2 */ | ||
172 | |||
173 | /* | ||
174 | * WOWLAN_TSC_RSC_PARAMS | ||
175 | */ | ||
176 | #define IWL_NUM_RSC 16 | ||
177 | |||
178 | struct tkip_sc { | ||
179 | __le16 iv16; | ||
180 | __le16 pad; | ||
181 | __le32 iv32; | ||
182 | } __packed; /* TKIP_SC_API_U_VER_1 */ | ||
183 | |||
184 | struct iwl_tkip_rsc_tsc { | ||
185 | struct tkip_sc unicast_rsc[IWL_NUM_RSC]; | ||
186 | struct tkip_sc multicast_rsc[IWL_NUM_RSC]; | ||
187 | struct tkip_sc tsc; | ||
188 | } __packed; /* TKIP_TSC_RSC_API_S_VER_1 */ | ||
189 | |||
190 | struct aes_sc { | ||
191 | __le64 pn; | ||
192 | } __packed; /* TKIP_AES_SC_API_U_VER_1 */ | ||
193 | |||
194 | struct iwl_aes_rsc_tsc { | ||
195 | struct aes_sc unicast_rsc[IWL_NUM_RSC]; | ||
196 | struct aes_sc multicast_rsc[IWL_NUM_RSC]; | ||
197 | struct aes_sc tsc; | ||
198 | } __packed; /* AES_TSC_RSC_API_S_VER_1 */ | ||
199 | |||
200 | union iwl_all_tsc_rsc { | ||
201 | struct iwl_tkip_rsc_tsc tkip; | ||
202 | struct iwl_aes_rsc_tsc aes; | ||
203 | }; /* ALL_TSC_RSC_API_S_VER_2 */ | ||
204 | |||
205 | struct iwl_wowlan_rsc_tsc_params_cmd { | ||
206 | union iwl_all_tsc_rsc all_tsc_rsc; | ||
207 | } __packed; /* ALL_TSC_RSC_API_S_VER_2 */ | ||
208 | |||
209 | #define IWL_MIC_KEY_SIZE 8 | ||
210 | struct iwl_mic_keys { | ||
211 | u8 tx[IWL_MIC_KEY_SIZE]; | ||
212 | u8 rx_unicast[IWL_MIC_KEY_SIZE]; | ||
213 | u8 rx_mcast[IWL_MIC_KEY_SIZE]; | ||
214 | } __packed; /* MIC_KEYS_API_S_VER_1 */ | ||
215 | |||
216 | #define IWL_P1K_SIZE 5 | ||
217 | struct iwl_p1k_cache { | ||
218 | __le16 p1k[IWL_P1K_SIZE]; | ||
219 | } __packed; | ||
220 | |||
221 | #define IWL_NUM_RX_P1K_CACHE 2 | ||
222 | |||
223 | struct iwl_wowlan_tkip_params_cmd { | ||
224 | struct iwl_mic_keys mic_keys; | ||
225 | struct iwl_p1k_cache tx; | ||
226 | struct iwl_p1k_cache rx_uni[IWL_NUM_RX_P1K_CACHE]; | ||
227 | struct iwl_p1k_cache rx_multi[IWL_NUM_RX_P1K_CACHE]; | ||
228 | } __packed; /* WOWLAN_TKIP_SETTING_API_S_VER_1 */ | ||
229 | |||
230 | #define IWL_KCK_MAX_SIZE 32 | ||
231 | #define IWL_KEK_MAX_SIZE 32 | ||
232 | |||
233 | struct iwl_wowlan_kek_kck_material_cmd { | ||
234 | u8 kck[IWL_KCK_MAX_SIZE]; | ||
235 | u8 kek[IWL_KEK_MAX_SIZE]; | ||
236 | __le16 kck_len; | ||
237 | __le16 kek_len; | ||
238 | __le64 replay_ctr; | ||
239 | } __packed; /* KEK_KCK_MATERIAL_API_S_VER_2 */ | ||
240 | |||
241 | #define RF_KILL_INDICATOR_FOR_WOWLAN 0x87 | ||
242 | |||
243 | enum iwl_wowlan_rekey_status { | ||
244 | IWL_WOWLAN_REKEY_POST_REKEY = 0, | ||
245 | IWL_WOWLAN_REKEY_WHILE_REKEY = 1, | ||
246 | }; /* WOWLAN_REKEY_STATUS_API_E_VER_1 */ | ||
247 | |||
248 | enum iwl_wowlan_wakeup_reason { | ||
249 | IWL_WOWLAN_WAKEUP_BY_NON_WIRELESS = 0, | ||
250 | IWL_WOWLAN_WAKEUP_BY_MAGIC_PACKET = BIT(0), | ||
251 | IWL_WOWLAN_WAKEUP_BY_PATTERN = BIT(1), | ||
252 | IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON = BIT(2), | ||
253 | IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH = BIT(3), | ||
254 | IWL_WOWLAN_WAKEUP_BY_GTK_REKEY_FAILURE = BIT(4), | ||
255 | IWL_WOWLAN_WAKEUP_BY_RFKILL_DEASSERTED = BIT(5), | ||
256 | IWL_WOWLAN_WAKEUP_BY_UCODE_ERROR = BIT(6), | ||
257 | IWL_WOWLAN_WAKEUP_BY_EAPOL_REQUEST = BIT(7), | ||
258 | IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE = BIT(8), | ||
259 | IWL_WOWLAN_WAKEUP_BY_REM_WAKE_LINK_LOSS = BIT(9), | ||
260 | IWL_WOWLAN_WAKEUP_BY_REM_WAKE_SIGNATURE_TABLE = BIT(10), | ||
261 | IWL_WOWLAN_WAKEUP_BY_REM_WAKE_TCP_EXTERNAL = BIT(11), | ||
262 | IWL_WOWLAN_WAKEUP_BY_REM_WAKE_WAKEUP_PACKET = BIT(12), | ||
263 | }; /* WOWLAN_WAKE_UP_REASON_API_E_VER_2 */ | ||
264 | |||
265 | struct iwl_wowlan_status { | ||
266 | __le64 replay_ctr; | ||
267 | __le16 pattern_number; | ||
268 | __le16 non_qos_seq_ctr; | ||
269 | __le16 qos_seq_ctr[8]; | ||
270 | __le32 wakeup_reasons; | ||
271 | __le32 rekey_status; | ||
272 | __le32 num_of_gtk_rekeys; | ||
273 | __le32 transmitted_ndps; | ||
274 | __le32 received_beacons; | ||
275 | __le32 wake_packet_length; | ||
276 | __le32 wake_packet_bufsize; | ||
277 | u8 wake_packet[]; /* can be truncated from _length to _bufsize */ | ||
278 | } __packed; /* WOWLAN_STATUSES_API_S_VER_4 */ | ||
279 | |||
280 | /* TODO: NetDetect API */ | ||
281 | |||
282 | #endif /* __fw_api_d3_h__ */ | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h new file mode 100644 index 000000000000..ae39b7dfda7b --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h | |||
@@ -0,0 +1,369 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called LICENSE.GPL. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | *****************************************************************************/ | ||
62 | |||
63 | #ifndef __fw_api_mac_h__ | ||
64 | #define __fw_api_mac_h__ | ||
65 | |||
66 | /* | ||
67 | * The first MAC indices (starting from 0) | ||
68 | * are available to the driver, AUX follows | ||
69 | */ | ||
70 | #define MAC_INDEX_AUX 4 | ||
71 | #define MAC_INDEX_MIN_DRIVER 0 | ||
72 | #define NUM_MAC_INDEX_DRIVER MAC_INDEX_AUX | ||
73 | |||
74 | #define AC_NUM 4 /* Number of access categories */ | ||
75 | |||
76 | /** | ||
77 | * enum iwl_mac_protection_flags - MAC context flags | ||
78 | * @MAC_PROT_FLG_TGG_PROTECT: 11g protection when transmitting OFDM frames, | ||
79 | * this will require CCK RTS/CTS2self. | ||
80 | * RTS/CTS will protect full burst time. | ||
81 | * @MAC_PROT_FLG_HT_PROT: enable HT protection | ||
82 | * @MAC_PROT_FLG_FAT_PROT: protect 40 MHz transmissions | ||
83 | * @MAC_PROT_FLG_SELF_CTS_EN: allow CTS2self | ||
84 | */ | ||
85 | enum iwl_mac_protection_flags { | ||
86 | MAC_PROT_FLG_TGG_PROTECT = BIT(3), | ||
87 | MAC_PROT_FLG_HT_PROT = BIT(23), | ||
88 | MAC_PROT_FLG_FAT_PROT = BIT(24), | ||
89 | MAC_PROT_FLG_SELF_CTS_EN = BIT(30), | ||
90 | }; | ||
91 | |||
92 | #define MAC_FLG_SHORT_SLOT BIT(4) | ||
93 | #define MAC_FLG_SHORT_PREAMBLE BIT(5) | ||
94 | |||
95 | /** | ||
96 | * enum iwl_mac_types - Supported MAC types | ||
97 | * @FW_MAC_TYPE_FIRST: lowest supported MAC type | ||
98 | * @FW_MAC_TYPE_AUX: Auxiliary MAC (internal) | ||
99 | * @FW_MAC_TYPE_LISTENER: monitor MAC type (?) | ||
100 | * @FW_MAC_TYPE_PIBSS: Pseudo-IBSS | ||
101 | * @FW_MAC_TYPE_IBSS: IBSS | ||
102 | * @FW_MAC_TYPE_BSS_STA: BSS (managed) station | ||
103 | * @FW_MAC_TYPE_P2P_DEVICE: P2P Device | ||
104 | * @FW_MAC_TYPE_P2P_STA: P2P client | ||
105 | * @FW_MAC_TYPE_GO: P2P GO | ||
106 | * @FW_MAC_TYPE_TEST: ? | ||
107 | * @FW_MAC_TYPE_MAX: highest support MAC type | ||
108 | */ | ||
109 | enum iwl_mac_types { | ||
110 | FW_MAC_TYPE_FIRST = 1, | ||
111 | FW_MAC_TYPE_AUX = FW_MAC_TYPE_FIRST, | ||
112 | FW_MAC_TYPE_LISTENER, | ||
113 | FW_MAC_TYPE_PIBSS, | ||
114 | FW_MAC_TYPE_IBSS, | ||
115 | FW_MAC_TYPE_BSS_STA, | ||
116 | FW_MAC_TYPE_P2P_DEVICE, | ||
117 | FW_MAC_TYPE_P2P_STA, | ||
118 | FW_MAC_TYPE_GO, | ||
119 | FW_MAC_TYPE_TEST, | ||
120 | FW_MAC_TYPE_MAX = FW_MAC_TYPE_TEST | ||
121 | }; /* MAC_CONTEXT_TYPE_API_E_VER_1 */ | ||
122 | |||
123 | /** | ||
124 | * enum iwl_tsf_id - TSF hw timer ID | ||
125 | * @TSF_ID_A: use TSF A | ||
126 | * @TSF_ID_B: use TSF B | ||
127 | * @TSF_ID_C: use TSF C | ||
128 | * @TSF_ID_D: use TSF D | ||
129 | * @NUM_TSF_IDS: number of TSF timers available | ||
130 | */ | ||
131 | enum iwl_tsf_id { | ||
132 | TSF_ID_A = 0, | ||
133 | TSF_ID_B = 1, | ||
134 | TSF_ID_C = 2, | ||
135 | TSF_ID_D = 3, | ||
136 | NUM_TSF_IDS = 4, | ||
137 | }; /* TSF_ID_API_E_VER_1 */ | ||
138 | |||
139 | /** | ||
140 | * struct iwl_mac_data_ap - configuration data for AP MAC context | ||
141 | * @beacon_time: beacon transmit time in system time | ||
142 | * @beacon_tsf: beacon transmit time in TSF | ||
143 | * @bi: beacon interval in TU | ||
144 | * @bi_reciprocal: 2^32 / bi | ||
145 | * @dtim_interval: dtim transmit time in TU | ||
146 | * @dtim_reciprocal: 2^32 / dtim_interval | ||
147 | * @mcast_qid: queue ID for multicast traffic | ||
148 | * @beacon_template: beacon template ID | ||
149 | */ | ||
150 | struct iwl_mac_data_ap { | ||
151 | __le32 beacon_time; | ||
152 | __le64 beacon_tsf; | ||
153 | __le32 bi; | ||
154 | __le32 bi_reciprocal; | ||
155 | __le32 dtim_interval; | ||
156 | __le32 dtim_reciprocal; | ||
157 | __le32 mcast_qid; | ||
158 | __le32 beacon_template; | ||
159 | } __packed; /* AP_MAC_DATA_API_S_VER_1 */ | ||
160 | |||
161 | /** | ||
162 | * struct iwl_mac_data_ibss - configuration data for IBSS MAC context | ||
163 | * @beacon_time: beacon transmit time in system time | ||
164 | * @beacon_tsf: beacon transmit time in TSF | ||
165 | * @bi: beacon interval in TU | ||
166 | * @bi_reciprocal: 2^32 / bi | ||
167 | */ | ||
168 | struct iwl_mac_data_ibss { | ||
169 | __le32 beacon_time; | ||
170 | __le64 beacon_tsf; | ||
171 | __le32 bi; | ||
172 | __le32 bi_reciprocal; | ||
173 | } __packed; /* IBSS_MAC_DATA_API_S_VER_1 */ | ||
174 | |||
175 | /** | ||
176 | * struct iwl_mac_data_sta - configuration data for station MAC context | ||
177 | * @is_assoc: 1 for associated state, 0 otherwise | ||
178 | * @dtim_time: DTIM arrival time in system time | ||
179 | * @dtim_tsf: DTIM arrival time in TSF | ||
180 | * @bi: beacon interval in TU, applicable only when associated | ||
181 | * @bi_reciprocal: 2^32 / bi , applicable only when associated | ||
182 | * @dtim_interval: DTIM interval in TU, applicable only when associated | ||
183 | * @dtim_reciprocal: 2^32 / dtim_interval , applicable only when associated | ||
184 | * @listen_interval: in beacon intervals, applicable only when associated | ||
185 | * @assoc_id: unique ID assigned by the AP during association | ||
186 | */ | ||
187 | struct iwl_mac_data_sta { | ||
188 | __le32 is_assoc; | ||
189 | __le32 dtim_time; | ||
190 | __le64 dtim_tsf; | ||
191 | __le32 bi; | ||
192 | __le32 bi_reciprocal; | ||
193 | __le32 dtim_interval; | ||
194 | __le32 dtim_reciprocal; | ||
195 | __le32 listen_interval; | ||
196 | __le32 assoc_id; | ||
197 | __le32 assoc_beacon_arrive_time; | ||
198 | } __packed; /* STA_MAC_DATA_API_S_VER_1 */ | ||
199 | |||
200 | /** | ||
201 | * struct iwl_mac_data_go - configuration data for P2P GO MAC context | ||
202 | * @ap: iwl_mac_data_ap struct with most config data | ||
203 | * @ctwin: client traffic window in TU (period after TBTT when GO is present). | ||
204 | * 0 indicates that there is no CT window. | ||
205 | * @opp_ps_enabled: indicate that opportunistic PS allowed | ||
206 | */ | ||
207 | struct iwl_mac_data_go { | ||
208 | struct iwl_mac_data_ap ap; | ||
209 | __le32 ctwin; | ||
210 | __le32 opp_ps_enabled; | ||
211 | } __packed; /* GO_MAC_DATA_API_S_VER_1 */ | ||
212 | |||
213 | /** | ||
214 | * struct iwl_mac_data_p2p_sta - configuration data for P2P client MAC context | ||
215 | * @sta: iwl_mac_data_sta struct with most config data | ||
216 | * @ctwin: client traffic window in TU (period after TBTT when GO is present). | ||
217 | * 0 indicates that there is no CT window. | ||
218 | */ | ||
219 | struct iwl_mac_data_p2p_sta { | ||
220 | struct iwl_mac_data_sta sta; | ||
221 | __le32 ctwin; | ||
222 | } __packed; /* P2P_STA_MAC_DATA_API_S_VER_1 */ | ||
223 | |||
224 | /** | ||
225 | * struct iwl_mac_data_pibss - Pseudo IBSS config data | ||
226 | * @stats_interval: interval in TU between statistics notifications to host. | ||
227 | */ | ||
228 | struct iwl_mac_data_pibss { | ||
229 | __le32 stats_interval; | ||
230 | } __packed; /* PIBSS_MAC_DATA_API_S_VER_1 */ | ||
231 | |||
232 | /* | ||
233 | * struct iwl_mac_data_p2p_dev - configuration data for the P2P Device MAC | ||
234 | * context. | ||
235 | * @is_disc_extended: if set to true, P2P Device discoverability is enabled on | ||
236 | * other channels as well. This should be to true only in case that the | ||
237 | * device is discoverable and there is an active GO. Note that setting this | ||
238 | * field when not needed, will increase the number of interrupts and have | ||
239 | * effect on the platform power, as this setting opens the Rx filters on | ||
240 | * all macs. | ||
241 | */ | ||
242 | struct iwl_mac_data_p2p_dev { | ||
243 | __le32 is_disc_extended; | ||
244 | } __packed; /* _P2P_DEV_MAC_DATA_API_S_VER_1 */ | ||
245 | |||
246 | /** | ||
247 | * enum iwl_mac_filter_flags - MAC context filter flags | ||
248 | * @MAC_FILTER_IN_PROMISC: accept all data frames | ||
249 | * @MAC_FILTER_IN_CONTROL_AND_MGMT: pass all mangement and | ||
250 | * control frames to the host | ||
251 | * @MAC_FILTER_ACCEPT_GRP: accept multicast frames | ||
252 | * @MAC_FILTER_DIS_DECRYPT: don't decrypt unicast frames | ||
253 | * @MAC_FILTER_DIS_GRP_DECRYPT: don't decrypt multicast frames | ||
254 | * @MAC_FILTER_IN_BEACON: transfer foreign BSS's beacons to host | ||
255 | * (in station mode when associated) | ||
256 | * @MAC_FILTER_OUT_BCAST: filter out all broadcast frames | ||
257 | * @MAC_FILTER_IN_CRC32: extract FCS and append it to frames | ||
258 | * @MAC_FILTER_IN_PROBE_REQUEST: pass probe requests to host | ||
259 | */ | ||
260 | enum iwl_mac_filter_flags { | ||
261 | MAC_FILTER_IN_PROMISC = BIT(0), | ||
262 | MAC_FILTER_IN_CONTROL_AND_MGMT = BIT(1), | ||
263 | MAC_FILTER_ACCEPT_GRP = BIT(2), | ||
264 | MAC_FILTER_DIS_DECRYPT = BIT(3), | ||
265 | MAC_FILTER_DIS_GRP_DECRYPT = BIT(4), | ||
266 | MAC_FILTER_IN_BEACON = BIT(6), | ||
267 | MAC_FILTER_OUT_BCAST = BIT(8), | ||
268 | MAC_FILTER_IN_CRC32 = BIT(11), | ||
269 | MAC_FILTER_IN_PROBE_REQUEST = BIT(12), | ||
270 | }; | ||
271 | |||
272 | /** | ||
273 | * enum iwl_mac_qos_flags - QoS flags | ||
274 | * @MAC_QOS_FLG_UPDATE_EDCA: ? | ||
275 | * @MAC_QOS_FLG_TGN: HT is enabled | ||
276 | * @MAC_QOS_FLG_TXOP_TYPE: ? | ||
277 | * | ||
278 | */ | ||
279 | enum iwl_mac_qos_flags { | ||
280 | MAC_QOS_FLG_UPDATE_EDCA = BIT(0), | ||
281 | MAC_QOS_FLG_TGN = BIT(1), | ||
282 | MAC_QOS_FLG_TXOP_TYPE = BIT(4), | ||
283 | }; | ||
284 | |||
285 | /** | ||
286 | * struct iwl_ac_qos - QOS timing params for MAC_CONTEXT_CMD | ||
287 | * @cw_min: Contention window, start value in numbers of slots. | ||
288 | * Should be a power-of-2, minus 1. Device's default is 0x0f. | ||
289 | * @cw_max: Contention window, max value in numbers of slots. | ||
290 | * Should be a power-of-2, minus 1. Device's default is 0x3f. | ||
291 | * @aifsn: Number of slots in Arbitration Interframe Space (before | ||
292 | * performing random backoff timing prior to Tx). Device default 1. | ||
293 | * @fifos_mask: FIFOs used by this MAC for this AC | ||
294 | * @edca_txop: Length of Tx opportunity, in uSecs. Device default is 0. | ||
295 | * | ||
296 | * One instance of this config struct for each of 4 EDCA access categories | ||
297 | * in struct iwl_qosparam_cmd. | ||
298 | * | ||
299 | * Device will automatically increase contention window by (2*CW) + 1 for each | ||
300 | * transmission retry. Device uses cw_max as a bit mask, ANDed with new CW | ||
301 | * value, to cap the CW value. | ||
302 | */ | ||
303 | struct iwl_ac_qos { | ||
304 | __le16 cw_min; | ||
305 | __le16 cw_max; | ||
306 | u8 aifsn; | ||
307 | u8 fifos_mask; | ||
308 | __le16 edca_txop; | ||
309 | } __packed; /* AC_QOS_API_S_VER_2 */ | ||
310 | |||
311 | /** | ||
312 | * struct iwl_mac_ctx_cmd - command structure to configure MAC contexts | ||
313 | * ( MAC_CONTEXT_CMD = 0x28 ) | ||
314 | * @id_and_color: ID and color of the MAC | ||
315 | * @action: action to perform, one of FW_CTXT_ACTION_* | ||
316 | * @mac_type: one of FW_MAC_TYPE_* | ||
317 | * @tsd_id: TSF HW timer, one of TSF_ID_* | ||
318 | * @node_addr: MAC address | ||
319 | * @bssid_addr: BSSID | ||
320 | * @cck_rates: basic rates available for CCK | ||
321 | * @ofdm_rates: basic rates available for OFDM | ||
322 | * @protection_flags: combination of MAC_PROT_FLG_FLAG_* | ||
323 | * @cck_short_preamble: 0x20 for enabling short preamble, 0 otherwise | ||
324 | * @short_slot: 0x10 for enabling short slots, 0 otherwise | ||
325 | * @filter_flags: combination of MAC_FILTER_* | ||
326 | * @qos_flags: from MAC_QOS_FLG_* | ||
327 | * @ac: one iwl_mac_qos configuration for each AC | ||
328 | * @mac_specific: one of struct iwl_mac_data_*, according to mac_type | ||
329 | */ | ||
330 | struct iwl_mac_ctx_cmd { | ||
331 | /* COMMON_INDEX_HDR_API_S_VER_1 */ | ||
332 | __le32 id_and_color; | ||
333 | __le32 action; | ||
334 | /* MAC_CONTEXT_COMMON_DATA_API_S_VER_1 */ | ||
335 | __le32 mac_type; | ||
336 | __le32 tsf_id; | ||
337 | u8 node_addr[6]; | ||
338 | __le16 reserved_for_node_addr; | ||
339 | u8 bssid_addr[6]; | ||
340 | __le16 reserved_for_bssid_addr; | ||
341 | __le32 cck_rates; | ||
342 | __le32 ofdm_rates; | ||
343 | __le32 protection_flags; | ||
344 | __le32 cck_short_preamble; | ||
345 | __le32 short_slot; | ||
346 | __le32 filter_flags; | ||
347 | /* MAC_QOS_PARAM_API_S_VER_1 */ | ||
348 | __le32 qos_flags; | ||
349 | struct iwl_ac_qos ac[AC_NUM+1]; | ||
350 | /* MAC_CONTEXT_COMMON_DATA_API_S */ | ||
351 | union { | ||
352 | struct iwl_mac_data_ap ap; | ||
353 | struct iwl_mac_data_go go; | ||
354 | struct iwl_mac_data_sta sta; | ||
355 | struct iwl_mac_data_p2p_sta p2p_sta; | ||
356 | struct iwl_mac_data_p2p_dev p2p_dev; | ||
357 | struct iwl_mac_data_pibss pibss; | ||
358 | struct iwl_mac_data_ibss ibss; | ||
359 | }; | ||
360 | } __packed; /* MAC_CONTEXT_CMD_API_S_VER_1 */ | ||
361 | |||
362 | static inline u32 iwl_mvm_reciprocal(u32 v) | ||
363 | { | ||
364 | if (!v) | ||
365 | return 0; | ||
366 | return 0xFFFFFFFF / v; | ||
367 | } | ||
368 | |||
369 | #endif /* __fw_api_mac_h__ */ | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h new file mode 100644 index 000000000000..be36b7604b7f --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h | |||
@@ -0,0 +1,140 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called LICENSE.GPL. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | * | ||
62 | *****************************************************************************/ | ||
63 | |||
64 | #ifndef __fw_api_power_h__ | ||
65 | #define __fw_api_power_h__ | ||
66 | |||
67 | /* Power Management Commands, Responses, Notifications */ | ||
68 | |||
69 | /** | ||
70 | * enum iwl_scan_flags - masks for power table command flags | ||
71 | * @POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK: '0' Driver disables power management, | ||
72 | * '1' Driver enables PM (use rest of parameters) | ||
73 | * @POWER_FLAGS_SLEEP_OVER_DTIM_MSK: '0' PM have to walk up every DTIM, | ||
74 | * '1' PM could sleep over DTIM till listen Interval. | ||
75 | * @POWER_FLAGS_LPRX_ENA_MSK: Low Power RX enable. | ||
76 | * @POWER_FLAGS_SNOOZE_ENA_MSK: Enable snoozing only if uAPSD is enabled and all | ||
77 | * access categories are both delivery and trigger enabled. | ||
78 | * @POWER_FLAGS_BT_SCO_ENA: Enable BT SCO coex only if uAPSD and | ||
79 | * PBW Snoozing enabled | ||
80 | * @POWER_FLAGS_ADVANCE_PM_ENA_MSK: Advanced PM (uAPSD) enable mask | ||
81 | */ | ||
82 | enum iwl_power_flags { | ||
83 | POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK = BIT(0), | ||
84 | POWER_FLAGS_SLEEP_OVER_DTIM_MSK = BIT(1), | ||
85 | POWER_FLAGS_LPRX_ENA_MSK = BIT(2), | ||
86 | POWER_FLAGS_SNOOZE_ENA_MSK = BIT(3), | ||
87 | POWER_FLAGS_BT_SCO_ENA = BIT(4), | ||
88 | POWER_FLAGS_ADVANCE_PM_ENA_MSK = BIT(5) | ||
89 | }; | ||
90 | |||
91 | /** | ||
92 | * struct iwl_powertable_cmd - Power Table Command | ||
93 | * POWER_TABLE_CMD = 0x77 (command, has simple generic response) | ||
94 | * | ||
95 | * @id_and_color: MAC contex identifier | ||
96 | * @action: Action on context - no action, add new, | ||
97 | * modify existent, remove | ||
98 | * @flags: Power table command flags from POWER_FLAGS_* | ||
99 | * @keep_alive_seconds: Keep alive period in seconds. Default - 25 sec. | ||
100 | * Minimum allowed:- 3 * DTIM | ||
101 | * @rx_data_timeout: Minimum time (usec) from last Rx packet for AM to | ||
102 | * PSM transition - legacy PM | ||
103 | * @tx_data_timeout: Minimum time (usec) from last Tx packet for AM to | ||
104 | * PSM transition - legacy PM | ||
105 | * @rx_data_timeout_uapsd: Minimum time (usec) from last Rx packet for AM to | ||
106 | * PSM transition - uAPSD | ||
107 | * @tx_data_timeout_uapsd: Minimum time (usec) from last Tx packet for AM to | ||
108 | * PSM transition - uAPSD | ||
109 | * @lprx_rssi_threshold: Signal strength up to which LP RX can be enabled. | ||
110 | * Default: 80dbm | ||
111 | * @num_skip_dtim: Number of DTIMs to skip if Skip over DTIM flag is set | ||
112 | * @snooze_interval: TBD | ||
113 | * @snooze_window: TBD | ||
114 | * @snooze_step: TBD | ||
115 | * @qndp_tid: TBD | ||
116 | * @uapsd_ac_flags: TBD | ||
117 | * @uapsd_max_sp: TBD | ||
118 | */ | ||
119 | struct iwl_powertable_cmd { | ||
120 | /* COMMON_INDEX_HDR_API_S_VER_1 */ | ||
121 | __le32 id_and_color; | ||
122 | __le32 action; | ||
123 | __le16 flags; | ||
124 | u8 reserved; | ||
125 | __le16 keep_alive_seconds; | ||
126 | __le32 rx_data_timeout; | ||
127 | __le32 tx_data_timeout; | ||
128 | __le32 rx_data_timeout_uapsd; | ||
129 | __le32 tx_data_timeout_uapsd; | ||
130 | u8 lprx_rssi_threshold; | ||
131 | u8 num_skip_dtim; | ||
132 | __le16 snooze_interval; | ||
133 | __le16 snooze_window; | ||
134 | u8 snooze_step; | ||
135 | u8 qndp_tid; | ||
136 | u8 uapsd_ac_flags; | ||
137 | u8 uapsd_max_sp; | ||
138 | } __packed; | ||
139 | |||
140 | #endif | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h new file mode 100644 index 000000000000..aa3474d08231 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h | |||
@@ -0,0 +1,312 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called LICENSE.GPL. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | *****************************************************************************/ | ||
62 | |||
63 | #ifndef __fw_api_rs_h__ | ||
64 | #define __fw_api_rs_h__ | ||
65 | |||
66 | #include "fw-api-mac.h" | ||
67 | |||
68 | /* | ||
69 | * These serve as indexes into | ||
70 | * struct iwl_rate_info fw_rate_idx_to_plcp[IWL_RATE_COUNT]; | ||
71 | */ | ||
72 | enum { | ||
73 | IWL_RATE_1M_INDEX = 0, | ||
74 | IWL_FIRST_CCK_RATE = IWL_RATE_1M_INDEX, | ||
75 | IWL_RATE_2M_INDEX, | ||
76 | IWL_RATE_5M_INDEX, | ||
77 | IWL_RATE_11M_INDEX, | ||
78 | IWL_LAST_CCK_RATE = IWL_RATE_11M_INDEX, | ||
79 | IWL_RATE_6M_INDEX, | ||
80 | IWL_FIRST_OFDM_RATE = IWL_RATE_6M_INDEX, | ||
81 | IWL_RATE_9M_INDEX, | ||
82 | IWL_RATE_12M_INDEX, | ||
83 | IWL_RATE_18M_INDEX, | ||
84 | IWL_RATE_24M_INDEX, | ||
85 | IWL_RATE_36M_INDEX, | ||
86 | IWL_RATE_48M_INDEX, | ||
87 | IWL_RATE_54M_INDEX, | ||
88 | IWL_LAST_NON_HT_RATE = IWL_RATE_54M_INDEX, | ||
89 | IWL_RATE_60M_INDEX, | ||
90 | IWL_LAST_OFDM_RATE = IWL_RATE_60M_INDEX, | ||
91 | IWL_RATE_COUNT_LEGACY = IWL_LAST_NON_HT_RATE + 1, | ||
92 | IWL_RATE_COUNT, | ||
93 | }; | ||
94 | |||
95 | #define IWL_RATE_BIT_MSK(r) BIT(IWL_RATE_##r##M_INDEX) | ||
96 | |||
97 | /* fw API values for legacy bit rates, both OFDM and CCK */ | ||
98 | enum { | ||
99 | IWL_RATE_6M_PLCP = 13, | ||
100 | IWL_RATE_9M_PLCP = 15, | ||
101 | IWL_RATE_12M_PLCP = 5, | ||
102 | IWL_RATE_18M_PLCP = 7, | ||
103 | IWL_RATE_24M_PLCP = 9, | ||
104 | IWL_RATE_36M_PLCP = 11, | ||
105 | IWL_RATE_48M_PLCP = 1, | ||
106 | IWL_RATE_54M_PLCP = 3, | ||
107 | IWL_RATE_1M_PLCP = 10, | ||
108 | IWL_RATE_2M_PLCP = 20, | ||
109 | IWL_RATE_5M_PLCP = 55, | ||
110 | IWL_RATE_11M_PLCP = 110, | ||
111 | }; | ||
112 | |||
113 | /* | ||
114 | * rate_n_flags bit fields | ||
115 | * | ||
116 | * The 32-bit value has different layouts in the low 8 bites depending on the | ||
117 | * format. There are three formats, HT, VHT and legacy (11abg, with subformats | ||
118 | * for CCK and OFDM). | ||
119 | * | ||
120 | * High-throughput (HT) rate format | ||
121 | * bit 8 is 1, bit 26 is 0, bit 9 is 0 (OFDM) | ||
122 | * Very High-throughput (VHT) rate format | ||
123 | * bit 8 is 0, bit 26 is 1, bit 9 is 0 (OFDM) | ||
124 | * Legacy OFDM rate format for bits 7:0 | ||
125 | * bit 8 is 0, bit 26 is 0, bit 9 is 0 (OFDM) | ||
126 | * Legacy CCK rate format for bits 7:0: | ||
127 | * bit 8 is 0, bit 26 is 0, bit 9 is 1 (CCK) | ||
128 | */ | ||
129 | |||
130 | /* Bit 8: (1) HT format, (0) legacy or VHT format */ | ||
131 | #define RATE_MCS_HT_POS 8 | ||
132 | #define RATE_MCS_HT_MSK (1 << RATE_MCS_HT_POS) | ||
133 | |||
134 | /* Bit 9: (1) CCK, (0) OFDM. HT (bit 8) must be "0" for this bit to be valid */ | ||
135 | #define RATE_MCS_CCK_POS 9 | ||
136 | #define RATE_MCS_CCK_MSK (1 << RATE_MCS_CCK_POS) | ||
137 | |||
138 | /* Bit 26: (1) VHT format, (0) legacy format in bits 8:0 */ | ||
139 | #define RATE_MCS_VHT_POS 26 | ||
140 | #define RATE_MCS_VHT_MSK (1 << RATE_MCS_VHT_POS) | ||
141 | |||
142 | |||
143 | /* | ||
144 | * High-throughput (HT) rate format for bits 7:0 | ||
145 | * | ||
146 | * 2-0: MCS rate base | ||
147 | * 0) 6 Mbps | ||
148 | * 1) 12 Mbps | ||
149 | * 2) 18 Mbps | ||
150 | * 3) 24 Mbps | ||
151 | * 4) 36 Mbps | ||
152 | * 5) 48 Mbps | ||
153 | * 6) 54 Mbps | ||
154 | * 7) 60 Mbps | ||
155 | * 4-3: 0) Single stream (SISO) | ||
156 | * 1) Dual stream (MIMO) | ||
157 | * 2) Triple stream (MIMO) | ||
158 | * 5: Value of 0x20 in bits 7:0 indicates 6 Mbps HT40 duplicate data | ||
159 | * (bits 7-6 are zero) | ||
160 | * | ||
161 | * Together the low 5 bits work out to the MCS index because we don't | ||
162 | * support MCSes above 15/23, and 0-7 have one stream, 8-15 have two | ||
163 | * streams and 16-23 have three streams. We could also support MCS 32 | ||
164 | * which is the duplicate 20 MHz MCS (bit 5 set, all others zero.) | ||
165 | */ | ||
166 | #define RATE_HT_MCS_RATE_CODE_MSK 0x7 | ||
167 | |||
168 | /* Bit 10: (1) Use Green Field preamble */ | ||
169 | #define RATE_HT_MCS_GF_POS 10 | ||
170 | #define RATE_HT_MCS_GF_MSK (1 << RATE_HT_MCS_GF_POS) | ||
171 | |||
172 | #define RATE_HT_MCS_INDEX_MSK 0x3f | ||
173 | |||
174 | /* | ||
175 | * Very High-throughput (VHT) rate format for bits 7:0 | ||
176 | * | ||
177 | * 3-0: VHT MCS (0-9) | ||
178 | * 5-4: number of streams - 1: | ||
179 | * 0) Single stream (SISO) | ||
180 | * 1) Dual stream (MIMO) | ||
181 | * 2) Triple stream (MIMO) | ||
182 | */ | ||
183 | |||
184 | /* Bit 4-5: (0) SISO, (1) MIMO2 (2) MIMO3 */ | ||
185 | #define RATE_VHT_MCS_RATE_CODE_MSK 0xf | ||
186 | #define RATE_VHT_MCS_NSS_POS 4 | ||
187 | #define RATE_VHT_MCS_NSS_MSK (3 << RATE_VHT_MCS_NSS_POS) | ||
188 | |||
189 | /* | ||
190 | * Legacy OFDM rate format for bits 7:0 | ||
191 | * | ||
192 | * 3-0: 0xD) 6 Mbps | ||
193 | * 0xF) 9 Mbps | ||
194 | * 0x5) 12 Mbps | ||
195 | * 0x7) 18 Mbps | ||
196 | * 0x9) 24 Mbps | ||
197 | * 0xB) 36 Mbps | ||
198 | * 0x1) 48 Mbps | ||
199 | * 0x3) 54 Mbps | ||
200 | * (bits 7-4 are 0) | ||
201 | * | ||
202 | * Legacy CCK rate format for bits 7:0: | ||
203 | * bit 8 is 0, bit 26 is 0, bit 9 is 1 (CCK): | ||
204 | * | ||
205 | * 6-0: 10) 1 Mbps | ||
206 | * 20) 2 Mbps | ||
207 | * 55) 5.5 Mbps | ||
208 | * 110) 11 Mbps | ||
209 | * (bit 7 is 0) | ||
210 | */ | ||
211 | #define RATE_LEGACY_RATE_MSK 0xff | ||
212 | |||
213 | |||
214 | /* | ||
215 | * Bit 11-12: (0) 20MHz, (1) 40MHz, (2) 80MHz, (3) 160MHz | ||
216 | * 0 and 1 are valid for HT and VHT, 2 and 3 only for VHT | ||
217 | */ | ||
218 | #define RATE_MCS_CHAN_WIDTH_POS 11 | ||
219 | #define RATE_MCS_CHAN_WIDTH_MSK (3 << RATE_MCS_CHAN_WIDTH_POS) | ||
220 | #define RATE_MCS_CHAN_WIDTH_20 (0 << RATE_MCS_CHAN_WIDTH_POS) | ||
221 | #define RATE_MCS_CHAN_WIDTH_40 (1 << RATE_MCS_CHAN_WIDTH_POS) | ||
222 | #define RATE_MCS_CHAN_WIDTH_80 (2 << RATE_MCS_CHAN_WIDTH_POS) | ||
223 | #define RATE_MCS_CHAN_WIDTH_160 (3 << RATE_MCS_CHAN_WIDTH_POS) | ||
224 | |||
225 | /* Bit 13: (1) Short guard interval (0.4 usec), (0) normal GI (0.8 usec) */ | ||
226 | #define RATE_MCS_SGI_POS 13 | ||
227 | #define RATE_MCS_SGI_MSK (1 << RATE_MCS_SGI_POS) | ||
228 | |||
229 | /* Bit 14-16: Antenna selection (1) Ant A, (2) Ant B, (4) Ant C */ | ||
230 | #define RATE_MCS_ANT_POS 14 | ||
231 | #define RATE_MCS_ANT_A_MSK (1 << RATE_MCS_ANT_POS) | ||
232 | #define RATE_MCS_ANT_B_MSK (2 << RATE_MCS_ANT_POS) | ||
233 | #define RATE_MCS_ANT_C_MSK (4 << RATE_MCS_ANT_POS) | ||
234 | #define RATE_MCS_ANT_AB_MSK (RATE_MCS_ANT_A_MSK | \ | ||
235 | RATE_MCS_ANT_B_MSK) | ||
236 | #define RATE_MCS_ANT_ABC_MSK (RATE_MCS_ANT_AB_MSK | \ | ||
237 | RATE_MCS_ANT_C_MSK) | ||
238 | #define RATE_MCS_ANT_MSK RATE_MCS_ANT_ABC_MSK | ||
239 | #define RATE_MCS_ANT_NUM 3 | ||
240 | |||
241 | /* Bit 17-18: (0) SS, (1) SS*2 */ | ||
242 | #define RATE_MCS_STBC_POS 17 | ||
243 | #define RATE_MCS_STBC_MSK (1 << RATE_MCS_STBC_POS) | ||
244 | |||
245 | /* Bit 19: (0) Beamforming is off, (1) Beamforming is on */ | ||
246 | #define RATE_MCS_BF_POS 19 | ||
247 | #define RATE_MCS_BF_MSK (1 << RATE_MCS_BF_POS) | ||
248 | |||
249 | /* Bit 20: (0) ZLF is off, (1) ZLF is on */ | ||
250 | #define RATE_MCS_ZLF_POS 20 | ||
251 | #define RATE_MCS_ZLF_MSK (1 << RATE_MCS_ZLF_POS) | ||
252 | |||
253 | /* Bit 24-25: (0) 20MHz (no dup), (1) 2x20MHz, (2) 4x20MHz, 3 8x20MHz */ | ||
254 | #define RATE_MCS_DUP_POS 24 | ||
255 | #define RATE_MCS_DUP_MSK (3 << RATE_MCS_DUP_POS) | ||
256 | |||
257 | /* Bit 27: (1) LDPC enabled, (0) LDPC disabled */ | ||
258 | #define RATE_MCS_LDPC_POS 27 | ||
259 | #define RATE_MCS_LDPC_MSK (1 << RATE_MCS_LDPC_POS) | ||
260 | |||
261 | |||
262 | /* Link Quality definitions */ | ||
263 | |||
264 | /* # entries in rate scale table to support Tx retries */ | ||
265 | #define LQ_MAX_RETRY_NUM 16 | ||
266 | |||
267 | /* Link quality command flags, only this one is available */ | ||
268 | #define LQ_FLAG_SET_STA_TLC_RTS_MSK BIT(0) | ||
269 | |||
270 | /** | ||
271 | * struct iwl_lq_cmd - link quality command | ||
272 | * @sta_id: station to update | ||
273 | * @control: not used | ||
274 | * @flags: combination of LQ_FLAG_* | ||
275 | * @mimo_delim: the first SISO index in rs_table, which separates MIMO | ||
276 | * and SISO rates | ||
277 | * @single_stream_ant_msk: best antenna for SISO (can be dual in CDD). | ||
278 | * Should be ANT_[ABC] | ||
279 | * @dual_stream_ant_msk: best antennas for MIMO, combination of ANT_[ABC] | ||
280 | * @initial_rate_index: first index from rs_table per AC category | ||
281 | * @agg_time_limit: aggregation max time threshold in usec/100, meaning | ||
282 | * value of 100 is one usec. Range is 100 to 8000 | ||
283 | * @agg_disable_start_th: try-count threshold for starting aggregation. | ||
284 | * If a frame has higher try-count, it should not be selected for | ||
285 | * starting an aggregation sequence. | ||
286 | * @agg_frame_cnt_limit: max frame count in an aggregation. | ||
287 | * 0: no limit | ||
288 | * 1: no aggregation (one frame per aggregation) | ||
289 | * 2 - 0x3f: maximal number of frames (up to 3f == 63) | ||
290 | * @rs_table: array of rates for each TX try, each is rate_n_flags, | ||
291 | * meaning it is a combination of RATE_MCS_* and IWL_RATE_*_PLCP | ||
292 | * @bf_params: beam forming params, currently not used | ||
293 | */ | ||
294 | struct iwl_lq_cmd { | ||
295 | u8 sta_id; | ||
296 | u8 reserved1; | ||
297 | u16 control; | ||
298 | /* LINK_QUAL_GENERAL_PARAMS_API_S_VER_1 */ | ||
299 | u8 flags; | ||
300 | u8 mimo_delim; | ||
301 | u8 single_stream_ant_msk; | ||
302 | u8 dual_stream_ant_msk; | ||
303 | u8 initial_rate_index[AC_NUM]; | ||
304 | /* LINK_QUAL_AGG_PARAMS_API_S_VER_1 */ | ||
305 | __le16 agg_time_limit; | ||
306 | u8 agg_disable_start_th; | ||
307 | u8 agg_frame_cnt_limit; | ||
308 | __le32 reserved2; | ||
309 | __le32 rs_table[LQ_MAX_RETRY_NUM]; | ||
310 | __le32 bf_params; | ||
311 | }; /* LINK_QUALITY_CMD_API_S_VER_1 */ | ||
312 | #endif /* __fw_api_rs_h__ */ | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h new file mode 100644 index 000000000000..670ac8f95e26 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h | |||
@@ -0,0 +1,561 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called LICENSE.GPL. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | * | ||
62 | *****************************************************************************/ | ||
63 | |||
64 | #ifndef __fw_api_scan_h__ | ||
65 | #define __fw_api_scan_h__ | ||
66 | |||
67 | #include "fw-api.h" | ||
68 | |||
69 | /* Scan Commands, Responses, Notifications */ | ||
70 | |||
71 | /* Masks for iwl_scan_channel.type flags */ | ||
72 | #define SCAN_CHANNEL_TYPE_PASSIVE 0 | ||
73 | #define SCAN_CHANNEL_TYPE_ACTIVE BIT(0) | ||
74 | #define SCAN_CHANNEL_NARROW_BAND BIT(22) | ||
75 | |||
76 | /* Max number of IEs for direct SSID scans in a command */ | ||
77 | #define PROBE_OPTION_MAX 20 | ||
78 | |||
79 | /** | ||
80 | * struct iwl_scan_channel - entry in REPLY_SCAN_CMD channel table | ||
81 | * @channel: band is selected by iwl_scan_cmd "flags" field | ||
82 | * @tx_gain: gain for analog radio | ||
83 | * @dsp_atten: gain for DSP | ||
84 | * @active_dwell: dwell time for active scan in TU, typically 5-50 | ||
85 | * @passive_dwell: dwell time for passive scan in TU, typically 20-500 | ||
86 | * @type: type is broken down to these bits: | ||
87 | * bit 0: 0 = passive, 1 = active | ||
88 | * bits 1-20: SSID direct bit map. If any of these bits is set then | ||
89 | * the corresponding SSID IE is transmitted in probe request | ||
90 | * (bit i adds IE in position i to the probe request) | ||
91 | * bit 22: channel width, 0 = regular, 1 = TGj narrow channel | ||
92 | * | ||
93 | * @iteration_count: | ||
94 | * @iteration_interval: | ||
95 | * This struct is used once for each channel in the scan list. | ||
96 | * Each channel can independently select: | ||
97 | * 1) SSID for directed active scans | ||
98 | * 2) Txpower setting (for rate specified within Tx command) | ||
99 | * 3) How long to stay on-channel (behavior may be modified by quiet_time, | ||
100 | * quiet_plcp_th, good_CRC_th) | ||
101 | * | ||
102 | * To avoid uCode errors, make sure the following are true (see comments | ||
103 | * under struct iwl_scan_cmd about max_out_time and quiet_time): | ||
104 | * 1) If using passive_dwell (i.e. passive_dwell != 0): | ||
105 | * active_dwell <= passive_dwell (< max_out_time if max_out_time != 0) | ||
106 | * 2) quiet_time <= active_dwell | ||
107 | * 3) If restricting off-channel time (i.e. max_out_time !=0): | ||
108 | * passive_dwell < max_out_time | ||
109 | * active_dwell < max_out_time | ||
110 | */ | ||
111 | struct iwl_scan_channel { | ||
112 | __le32 type; | ||
113 | __le16 channel; | ||
114 | __le16 iteration_count; | ||
115 | __le32 iteration_interval; | ||
116 | __le16 active_dwell; | ||
117 | __le16 passive_dwell; | ||
118 | } __packed; /* SCAN_CHANNEL_CONTROL_API_S_VER_1 */ | ||
119 | |||
120 | /** | ||
121 | * struct iwl_ssid_ie - directed scan network information element | ||
122 | * | ||
123 | * Up to 20 of these may appear in REPLY_SCAN_CMD, | ||
124 | * selected by "type" bit field in struct iwl_scan_channel; | ||
125 | * each channel may select different ssids from among the 20 entries. | ||
126 | * SSID IEs get transmitted in reverse order of entry. | ||
127 | */ | ||
128 | struct iwl_ssid_ie { | ||
129 | u8 id; | ||
130 | u8 len; | ||
131 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | ||
132 | } __packed; /* SCAN_DIRECT_SSID_IE_API_S_VER_1 */ | ||
133 | |||
134 | /** | ||
135 | * iwl_scan_flags - masks for scan command flags | ||
136 | *@SCAN_FLAGS_PERIODIC_SCAN: | ||
137 | *@SCAN_FLAGS_P2P_PUBLIC_ACTION_FRAME_TX: | ||
138 | *@SCAN_FLAGS_DELAYED_SCAN_LOWBAND: | ||
139 | *@SCAN_FLAGS_DELAYED_SCAN_HIGHBAND: | ||
140 | *@SCAN_FLAGS_FRAGMENTED_SCAN: | ||
141 | */ | ||
142 | enum iwl_scan_flags { | ||
143 | SCAN_FLAGS_PERIODIC_SCAN = BIT(0), | ||
144 | SCAN_FLAGS_P2P_PUBLIC_ACTION_FRAME_TX = BIT(1), | ||
145 | SCAN_FLAGS_DELAYED_SCAN_LOWBAND = BIT(2), | ||
146 | SCAN_FLAGS_DELAYED_SCAN_HIGHBAND = BIT(3), | ||
147 | SCAN_FLAGS_FRAGMENTED_SCAN = BIT(4), | ||
148 | }; | ||
149 | |||
150 | /** | ||
151 | * enum iwl_scan_type - Scan types for scan command | ||
152 | * @SCAN_TYPE_FORCED: | ||
153 | * @SCAN_TYPE_BACKGROUND: | ||
154 | * @SCAN_TYPE_OS: | ||
155 | * @SCAN_TYPE_ROAMING: | ||
156 | * @SCAN_TYPE_ACTION: | ||
157 | * @SCAN_TYPE_DISCOVERY: | ||
158 | * @SCAN_TYPE_DISCOVERY_FORCED: | ||
159 | */ | ||
160 | enum iwl_scan_type { | ||
161 | SCAN_TYPE_FORCED = 0, | ||
162 | SCAN_TYPE_BACKGROUND = 1, | ||
163 | SCAN_TYPE_OS = 2, | ||
164 | SCAN_TYPE_ROAMING = 3, | ||
165 | SCAN_TYPE_ACTION = 4, | ||
166 | SCAN_TYPE_DISCOVERY = 5, | ||
167 | SCAN_TYPE_DISCOVERY_FORCED = 6, | ||
168 | }; /* SCAN_ACTIVITY_TYPE_E_VER_1 */ | ||
169 | |||
170 | /* Maximal number of channels to scan */ | ||
171 | #define MAX_NUM_SCAN_CHANNELS 0x24 | ||
172 | |||
173 | /** | ||
174 | * struct iwl_scan_cmd - scan request command | ||
175 | * ( SCAN_REQUEST_CMD = 0x80 ) | ||
176 | * @len: command length in bytes | ||
177 | * @scan_flags: scan flags from SCAN_FLAGS_* | ||
178 | * @channel_count: num of channels in channel list (1 - MAX_NUM_SCAN_CHANNELS) | ||
179 | * @quiet_time: in msecs, dwell this time for active scan on quiet channels | ||
180 | * @quiet_plcp_th: quiet PLCP threshold (channel is quiet if less than | ||
181 | * this number of packets were received (typically 1) | ||
182 | * @passive2active: is auto switching from passive to active allowed (0 or 1) | ||
183 | * @rxchain_sel_flags: RXON_RX_CHAIN_* | ||
184 | * @max_out_time: in usecs, max out of serving channel time | ||
185 | * @suspend_time: how long to pause scan when returning to service channel: | ||
186 | * bits 0-19: beacon interal in usecs (suspend before executing) | ||
187 | * bits 20-23: reserved | ||
188 | * bits 24-31: number of beacons (suspend between channels) | ||
189 | * @rxon_flags: RXON_FLG_* | ||
190 | * @filter_flags: RXON_FILTER_* | ||
191 | * @tx_cmd: for active scans (zero for passive), w/o payload, | ||
192 | * no RS so specify TX rate | ||
193 | * @direct_scan: direct scan SSIDs | ||
194 | * @type: one of SCAN_TYPE_* | ||
195 | * @repeats: how many time to repeat the scan | ||
196 | */ | ||
197 | struct iwl_scan_cmd { | ||
198 | __le16 len; | ||
199 | u8 scan_flags; | ||
200 | u8 channel_count; | ||
201 | __le16 quiet_time; | ||
202 | __le16 quiet_plcp_th; | ||
203 | __le16 passive2active; | ||
204 | __le16 rxchain_sel_flags; | ||
205 | __le32 max_out_time; | ||
206 | __le32 suspend_time; | ||
207 | /* RX_ON_FLAGS_API_S_VER_1 */ | ||
208 | __le32 rxon_flags; | ||
209 | __le32 filter_flags; | ||
210 | struct iwl_tx_cmd tx_cmd; | ||
211 | struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX]; | ||
212 | __le32 type; | ||
213 | __le32 repeats; | ||
214 | |||
215 | /* | ||
216 | * Probe request frame, followed by channel list. | ||
217 | * | ||
218 | * Size of probe request frame is specified by byte count in tx_cmd. | ||
219 | * Channel list follows immediately after probe request frame. | ||
220 | * Number of channels in list is specified by channel_count. | ||
221 | * Each channel in list is of type: | ||
222 | * | ||
223 | * struct iwl_scan_channel channels[0]; | ||
224 | * | ||
225 | * NOTE: Only one band of channels can be scanned per pass. You | ||
226 | * must not mix 2.4GHz channels and 5.2GHz channels, and you must wait | ||
227 | * for one scan to complete (i.e. receive SCAN_COMPLETE_NOTIFICATION) | ||
228 | * before requesting another scan. | ||
229 | */ | ||
230 | u8 data[0]; | ||
231 | } __packed; /* SCAN_REQUEST_FIXED_PART_API_S_VER_5 */ | ||
232 | |||
233 | /* Response to scan request contains only status with one of these values */ | ||
234 | #define SCAN_RESPONSE_OK 0x1 | ||
235 | #define SCAN_RESPONSE_ERROR 0x2 | ||
236 | |||
237 | /* | ||
238 | * SCAN_ABORT_CMD = 0x81 | ||
239 | * When scan abort is requested, the command has no fields except the common | ||
240 | * header. The response contains only a status with one of these values. | ||
241 | */ | ||
242 | #define SCAN_ABORT_POSSIBLE 0x1 | ||
243 | #define SCAN_ABORT_IGNORED 0x2 /* no pending scans */ | ||
244 | |||
245 | /* TODO: complete documentation */ | ||
246 | #define SCAN_OWNER_STATUS 0x1 | ||
247 | #define MEASURE_OWNER_STATUS 0x2 | ||
248 | |||
249 | /** | ||
250 | * struct iwl_scan_start_notif - notifies start of scan in the device | ||
251 | * ( SCAN_START_NOTIFICATION = 0x82 ) | ||
252 | * @tsf_low: TSF timer (lower half) in usecs | ||
253 | * @tsf_high: TSF timer (higher half) in usecs | ||
254 | * @beacon_timer: structured as follows: | ||
255 | * bits 0:19 - beacon interval in usecs | ||
256 | * bits 20:23 - reserved (0) | ||
257 | * bits 24:31 - number of beacons | ||
258 | * @channel: which channel is scanned | ||
259 | * @band: 0 for 5.2 GHz, 1 for 2.4 GHz | ||
260 | * @status: one of *_OWNER_STATUS | ||
261 | */ | ||
262 | struct iwl_scan_start_notif { | ||
263 | __le32 tsf_low; | ||
264 | __le32 tsf_high; | ||
265 | __le32 beacon_timer; | ||
266 | u8 channel; | ||
267 | u8 band; | ||
268 | u8 reserved[2]; | ||
269 | __le32 status; | ||
270 | } __packed; /* SCAN_START_NTF_API_S_VER_1 */ | ||
271 | |||
272 | /* scan results probe_status first bit indicates success */ | ||
273 | #define SCAN_PROBE_STATUS_OK 0 | ||
274 | #define SCAN_PROBE_STATUS_TX_FAILED BIT(0) | ||
275 | /* error statuses combined with TX_FAILED */ | ||
276 | #define SCAN_PROBE_STATUS_FAIL_TTL BIT(1) | ||
277 | #define SCAN_PROBE_STATUS_FAIL_BT BIT(2) | ||
278 | |||
279 | /* How many statistics are gathered for each channel */ | ||
280 | #define SCAN_RESULTS_STATISTICS 1 | ||
281 | |||
282 | /** | ||
283 | * enum iwl_scan_complete_status - status codes for scan complete notifications | ||
284 | * @SCAN_COMP_STATUS_OK: scan completed successfully | ||
285 | * @SCAN_COMP_STATUS_ABORT: scan was aborted by user | ||
286 | * @SCAN_COMP_STATUS_ERR_SLEEP: sending null sleep packet failed | ||
287 | * @SCAN_COMP_STATUS_ERR_CHAN_TIMEOUT: timeout before channel is ready | ||
288 | * @SCAN_COMP_STATUS_ERR_PROBE: sending probe request failed | ||
289 | * @SCAN_COMP_STATUS_ERR_WAKEUP: sending null wakeup packet failed | ||
290 | * @SCAN_COMP_STATUS_ERR_ANTENNAS: invalid antennas chosen at scan command | ||
291 | * @SCAN_COMP_STATUS_ERR_INTERNAL: internal error caused scan abort | ||
292 | * @SCAN_COMP_STATUS_ERR_COEX: medium was lost ot WiMax | ||
293 | * @SCAN_COMP_STATUS_P2P_ACTION_OK: P2P public action frame TX was successful | ||
294 | * (not an error!) | ||
295 | * @SCAN_COMP_STATUS_ITERATION_END: indicates end of one repeatition the driver | ||
296 | * asked for | ||
297 | * @SCAN_COMP_STATUS_ERR_ALLOC_TE: scan could not allocate time events | ||
298 | */ | ||
299 | enum iwl_scan_complete_status { | ||
300 | SCAN_COMP_STATUS_OK = 0x1, | ||
301 | SCAN_COMP_STATUS_ABORT = 0x2, | ||
302 | SCAN_COMP_STATUS_ERR_SLEEP = 0x3, | ||
303 | SCAN_COMP_STATUS_ERR_CHAN_TIMEOUT = 0x4, | ||
304 | SCAN_COMP_STATUS_ERR_PROBE = 0x5, | ||
305 | SCAN_COMP_STATUS_ERR_WAKEUP = 0x6, | ||
306 | SCAN_COMP_STATUS_ERR_ANTENNAS = 0x7, | ||
307 | SCAN_COMP_STATUS_ERR_INTERNAL = 0x8, | ||
308 | SCAN_COMP_STATUS_ERR_COEX = 0x9, | ||
309 | SCAN_COMP_STATUS_P2P_ACTION_OK = 0xA, | ||
310 | SCAN_COMP_STATUS_ITERATION_END = 0x0B, | ||
311 | SCAN_COMP_STATUS_ERR_ALLOC_TE = 0x0C, | ||
312 | }; | ||
313 | |||
314 | /** | ||
315 | * struct iwl_scan_results_notif - scan results for one channel | ||
316 | * ( SCAN_RESULTS_NOTIFICATION = 0x83 ) | ||
317 | * @channel: which channel the results are from | ||
318 | * @band: 0 for 5.2 GHz, 1 for 2.4 GHz | ||
319 | * @probe_status: SCAN_PROBE_STATUS_*, indicates success of probe request | ||
320 | * @num_probe_not_sent: # of request that weren't sent due to not enough time | ||
321 | * @duration: duration spent in channel, in usecs | ||
322 | * @statistics: statistics gathered for this channel | ||
323 | */ | ||
324 | struct iwl_scan_results_notif { | ||
325 | u8 channel; | ||
326 | u8 band; | ||
327 | u8 probe_status; | ||
328 | u8 num_probe_not_sent; | ||
329 | __le32 duration; | ||
330 | __le32 statistics[SCAN_RESULTS_STATISTICS]; | ||
331 | } __packed; /* SCAN_RESULT_NTF_API_S_VER_2 */ | ||
332 | |||
333 | /** | ||
334 | * struct iwl_scan_complete_notif - notifies end of scanning (all channels) | ||
335 | * ( SCAN_COMPLETE_NOTIFICATION = 0x84 ) | ||
336 | * @scanned_channels: number of channels scanned (and number of valid results) | ||
337 | * @status: one of SCAN_COMP_STATUS_* | ||
338 | * @bt_status: BT on/off status | ||
339 | * @last_channel: last channel that was scanned | ||
340 | * @tsf_low: TSF timer (lower half) in usecs | ||
341 | * @tsf_high: TSF timer (higher half) in usecs | ||
342 | * @results: all scan results, only "scanned_channels" of them are valid | ||
343 | */ | ||
344 | struct iwl_scan_complete_notif { | ||
345 | u8 scanned_channels; | ||
346 | u8 status; | ||
347 | u8 bt_status; | ||
348 | u8 last_channel; | ||
349 | __le32 tsf_low; | ||
350 | __le32 tsf_high; | ||
351 | struct iwl_scan_results_notif results[MAX_NUM_SCAN_CHANNELS]; | ||
352 | } __packed; /* SCAN_COMPLETE_NTF_API_S_VER_2 */ | ||
353 | |||
354 | /* scan offload */ | ||
355 | #define IWL_MAX_SCAN_CHANNELS 40 | ||
356 | #define IWL_SCAN_MAX_BLACKLIST_LEN 64 | ||
357 | #define IWL_SCAN_MAX_PROFILES 11 | ||
358 | #define SCAN_OFFLOAD_PROBE_REQ_SIZE 512 | ||
359 | |||
360 | /* Default watchdog (in MS) for scheduled scan iteration */ | ||
361 | #define IWL_SCHED_SCAN_WATCHDOG cpu_to_le16(15000) | ||
362 | |||
363 | #define IWL_GOOD_CRC_TH_DEFAULT cpu_to_le16(1) | ||
364 | #define CAN_ABORT_STATUS 1 | ||
365 | |||
366 | #define IWL_FULL_SCAN_MULTIPLIER 5 | ||
367 | #define IWL_FAST_SCHED_SCAN_ITERATIONS 3 | ||
368 | |||
369 | /** | ||
370 | * struct iwl_scan_offload_cmd - SCAN_REQUEST_FIXED_PART_API_S_VER_6 | ||
371 | * @scan_flags: see enum iwl_scan_flags | ||
372 | * @channel_count: channels in channel list | ||
373 | * @quiet_time: dwell time, in milisiconds, on quiet channel | ||
374 | * @quiet_plcp_th: quiet channel num of packets threshold | ||
375 | * @good_CRC_th: passive to active promotion threshold | ||
376 | * @rx_chain: RXON rx chain. | ||
377 | * @max_out_time: max uSec to be out of assoceated channel | ||
378 | * @suspend_time: pause scan this long when returning to service channel | ||
379 | * @flags: RXON flags | ||
380 | * @filter_flags: RXONfilter | ||
381 | * @tx_cmd: tx command for active scan; for 2GHz and for 5GHz. | ||
382 | * @direct_scan: list of SSIDs for directed active scan | ||
383 | * @scan_type: see enum iwl_scan_type. | ||
384 | * @rep_count: repetition count for each scheduled scan iteration. | ||
385 | */ | ||
386 | struct iwl_scan_offload_cmd { | ||
387 | __le16 len; | ||
388 | u8 scan_flags; | ||
389 | u8 channel_count; | ||
390 | __le16 quiet_time; | ||
391 | __le16 quiet_plcp_th; | ||
392 | __le16 good_CRC_th; | ||
393 | __le16 rx_chain; | ||
394 | __le32 max_out_time; | ||
395 | __le32 suspend_time; | ||
396 | /* RX_ON_FLAGS_API_S_VER_1 */ | ||
397 | __le32 flags; | ||
398 | __le32 filter_flags; | ||
399 | struct iwl_tx_cmd tx_cmd[2]; | ||
400 | /* SCAN_DIRECT_SSID_IE_API_S_VER_1 */ | ||
401 | struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX]; | ||
402 | __le32 scan_type; | ||
403 | __le32 rep_count; | ||
404 | } __packed; | ||
405 | |||
406 | enum iwl_scan_offload_channel_flags { | ||
407 | IWL_SCAN_OFFLOAD_CHANNEL_ACTIVE = BIT(0), | ||
408 | IWL_SCAN_OFFLOAD_CHANNEL_NARROW = BIT(22), | ||
409 | IWL_SCAN_OFFLOAD_CHANNEL_FULL = BIT(24), | ||
410 | IWL_SCAN_OFFLOAD_CHANNEL_PARTIAL = BIT(25), | ||
411 | }; | ||
412 | |||
413 | /** | ||
414 | * iwl_scan_channel_cfg - SCAN_CHANNEL_CFG_S | ||
415 | * @type: bitmap - see enum iwl_scan_offload_channel_flags. | ||
416 | * 0: passive (0) or active (1) scan. | ||
417 | * 1-20: directed scan to i'th ssid. | ||
418 | * 22: channel width configuation - 1 for narrow. | ||
419 | * 24: full scan. | ||
420 | * 25: partial scan. | ||
421 | * @channel_number: channel number 1-13 etc. | ||
422 | * @iter_count: repetition count for the channel. | ||
423 | * @iter_interval: interval between two innteration on one channel. | ||
424 | * @dwell_time: entry 0 - active scan, entry 1 - passive scan. | ||
425 | */ | ||
426 | struct iwl_scan_channel_cfg { | ||
427 | __le32 type[IWL_MAX_SCAN_CHANNELS]; | ||
428 | __le16 channel_number[IWL_MAX_SCAN_CHANNELS]; | ||
429 | __le16 iter_count[IWL_MAX_SCAN_CHANNELS]; | ||
430 | __le32 iter_interval[IWL_MAX_SCAN_CHANNELS]; | ||
431 | u8 dwell_time[IWL_MAX_SCAN_CHANNELS][2]; | ||
432 | } __packed; | ||
433 | |||
434 | /** | ||
435 | * iwl_scan_offload_cfg - SCAN_OFFLOAD_CONFIG_API_S | ||
436 | * @scan_cmd: scan command fixed part | ||
437 | * @channel_cfg: scan channel configuration | ||
438 | * @data: probe request frames (one per band) | ||
439 | */ | ||
440 | struct iwl_scan_offload_cfg { | ||
441 | struct iwl_scan_offload_cmd scan_cmd; | ||
442 | struct iwl_scan_channel_cfg channel_cfg; | ||
443 | u8 data[0]; | ||
444 | } __packed; | ||
445 | |||
446 | /** | ||
447 | * iwl_scan_offload_blacklist - SCAN_OFFLOAD_BLACKLIST_S | ||
448 | * @ssid: MAC address to filter out | ||
449 | * @reported_rssi: AP rssi reported to the host | ||
450 | */ | ||
451 | struct iwl_scan_offload_blacklist { | ||
452 | u8 ssid[ETH_ALEN]; | ||
453 | u8 reported_rssi; | ||
454 | u8 reserved; | ||
455 | } __packed; | ||
456 | |||
457 | enum iwl_scan_offload_network_type { | ||
458 | IWL_NETWORK_TYPE_BSS = 1, | ||
459 | IWL_NETWORK_TYPE_IBSS = 2, | ||
460 | IWL_NETWORK_TYPE_ANY = 3, | ||
461 | }; | ||
462 | |||
463 | enum iwl_scan_offload_band_selection { | ||
464 | IWL_SCAN_OFFLOAD_SELECT_2_4 = 0x4, | ||
465 | IWL_SCAN_OFFLOAD_SELECT_5_2 = 0x8, | ||
466 | IWL_SCAN_OFFLOAD_SELECT_ANY = 0xc, | ||
467 | }; | ||
468 | |||
469 | /** | ||
470 | * iwl_scan_offload_profile - SCAN_OFFLOAD_PROFILE_S | ||
471 | * @ssid_index: index to ssid list in fixed part | ||
472 | * @unicast_cipher: encryption olgorithm to match - bitmap | ||
473 | * @aut_alg: authentication olgorithm to match - bitmap | ||
474 | * @network_type: enum iwl_scan_offload_network_type | ||
475 | * @band_selection: enum iwl_scan_offload_band_selection | ||
476 | */ | ||
477 | struct iwl_scan_offload_profile { | ||
478 | u8 ssid_index; | ||
479 | u8 unicast_cipher; | ||
480 | u8 auth_alg; | ||
481 | u8 network_type; | ||
482 | u8 band_selection; | ||
483 | u8 reserved[3]; | ||
484 | } __packed; | ||
485 | |||
486 | /** | ||
487 | * iwl_scan_offload_profile_cfg - SCAN_OFFLOAD_PROFILES_CFG_API_S_VER_1 | ||
488 | * @blaclist: AP list to filter off from scan results | ||
489 | * @profiles: profiles to search for match | ||
490 | * @blacklist_len: length of blacklist | ||
491 | * @num_profiles: num of profiles in the list | ||
492 | */ | ||
493 | struct iwl_scan_offload_profile_cfg { | ||
494 | struct iwl_scan_offload_blacklist blacklist[IWL_SCAN_MAX_BLACKLIST_LEN]; | ||
495 | struct iwl_scan_offload_profile profiles[IWL_SCAN_MAX_PROFILES]; | ||
496 | u8 blacklist_len; | ||
497 | u8 num_profiles; | ||
498 | u8 reserved[2]; | ||
499 | } __packed; | ||
500 | |||
501 | /** | ||
502 | * iwl_scan_offload_schedule - schedule of scan offload | ||
503 | * @delay: delay between iterations, in seconds. | ||
504 | * @iterations: num of scan iterations | ||
505 | * @full_scan_mul: number of partial scans before each full scan | ||
506 | */ | ||
507 | struct iwl_scan_offload_schedule { | ||
508 | u16 delay; | ||
509 | u8 iterations; | ||
510 | u8 full_scan_mul; | ||
511 | } __packed; | ||
512 | |||
513 | /* | ||
514 | * iwl_scan_offload_flags | ||
515 | * | ||
516 | * IWL_SCAN_OFFLOAD_FLAG_FILTER_SSID: filter mode - upload every beacon or match | ||
517 | * ssid list. | ||
518 | * IWL_SCAN_OFFLOAD_FLAG_CACHED_CHANNEL: add cached channels to partial scan. | ||
519 | * IWL_SCAN_OFFLOAD_FLAG_ENERGY_SCAN: use energy based scan before partial scan | ||
520 | * on A band. | ||
521 | */ | ||
522 | enum iwl_scan_offload_flags { | ||
523 | IWL_SCAN_OFFLOAD_FLAG_FILTER_SSID = BIT(0), | ||
524 | IWL_SCAN_OFFLOAD_FLAG_CACHED_CHANNEL = BIT(2), | ||
525 | IWL_SCAN_OFFLOAD_FLAG_ENERGY_SCAN = BIT(3), | ||
526 | }; | ||
527 | |||
528 | /** | ||
529 | * iwl_scan_offload_req - scan offload request command | ||
530 | * @flags: bitmap - enum iwl_scan_offload_flags. | ||
531 | * @watchdog: maximum scan duration in TU. | ||
532 | * @delay: delay in seconds before first iteration. | ||
533 | * @schedule_line: scan offload schedule, for fast and regular scan. | ||
534 | */ | ||
535 | struct iwl_scan_offload_req { | ||
536 | __le16 flags; | ||
537 | __le16 watchdog; | ||
538 | __le16 delay; | ||
539 | __le16 reserved; | ||
540 | struct iwl_scan_offload_schedule schedule_line[2]; | ||
541 | } __packed; | ||
542 | |||
543 | enum iwl_scan_offload_compleate_status { | ||
544 | IWL_SCAN_OFFLOAD_COMPLETED = 1, | ||
545 | IWL_SCAN_OFFLOAD_ABORTED = 2, | ||
546 | }; | ||
547 | |||
548 | /** | ||
549 | * iwl_scan_offload_complete - SCAN_OFFLOAD_COMPLETE_NTF_API_S_VER_1 | ||
550 | * @last_schedule_line: last schedule line executed (fast or regular) | ||
551 | * @last_schedule_iteration: last scan iteration executed before scan abort | ||
552 | * @status: enum iwl_scan_offload_compleate_status | ||
553 | */ | ||
554 | struct iwl_scan_offload_complete { | ||
555 | u8 last_schedule_line; | ||
556 | u8 last_schedule_iteration; | ||
557 | u8 status; | ||
558 | u8 reserved; | ||
559 | } __packed; | ||
560 | |||
561 | #endif | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h new file mode 100644 index 000000000000..0acb53dda22d --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h | |||
@@ -0,0 +1,380 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called LICENSE.GPL. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | *****************************************************************************/ | ||
62 | |||
63 | #ifndef __fw_api_sta_h__ | ||
64 | #define __fw_api_sta_h__ | ||
65 | |||
66 | /** | ||
67 | * enum iwl_sta_flags - flags for the ADD_STA host command | ||
68 | * @STA_FLG_REDUCED_TX_PWR_CTRL: | ||
69 | * @STA_FLG_REDUCED_TX_PWR_DATA: | ||
70 | * @STA_FLG_FLG_ANT_MSK: Antenna selection | ||
71 | * @STA_FLG_PS: set if STA is in Power Save | ||
72 | * @STA_FLG_INVALID: set if STA is invalid | ||
73 | * @STA_FLG_DLP_EN: Direct Link Protocol is enabled | ||
74 | * @STA_FLG_SET_ALL_KEYS: the current key applies to all key IDs | ||
75 | * @STA_FLG_DRAIN_FLOW: drain flow | ||
76 | * @STA_FLG_PAN: STA is for PAN interface | ||
77 | * @STA_FLG_CLASS_AUTH: | ||
78 | * @STA_FLG_CLASS_ASSOC: | ||
79 | * @STA_FLG_CLASS_MIMO_PROT: | ||
80 | * @STA_FLG_MAX_AGG_SIZE_MSK: maximal size for A-MPDU | ||
81 | * @STA_FLG_AGG_MPDU_DENS_MSK: maximal MPDU density for Tx aggregation | ||
82 | * @STA_FLG_FAT_EN_MSK: support for channel width (for Tx). This flag is | ||
83 | * initialised by driver and can be updated by fw upon reception of | ||
84 | * action frames that can change the channel width. When cleared the fw | ||
85 | * will send all the frames in 20MHz even when FAT channel is requested. | ||
86 | * @STA_FLG_MIMO_EN_MSK: support for MIMO. This flag is initialised by the | ||
87 | * driver and can be updated by fw upon reception of action frames. | ||
88 | * @STA_FLG_MFP_EN: Management Frame Protection | ||
89 | */ | ||
90 | enum iwl_sta_flags { | ||
91 | STA_FLG_REDUCED_TX_PWR_CTRL = BIT(3), | ||
92 | STA_FLG_REDUCED_TX_PWR_DATA = BIT(6), | ||
93 | |||
94 | STA_FLG_FLG_ANT_A = (1 << 4), | ||
95 | STA_FLG_FLG_ANT_B = (2 << 4), | ||
96 | STA_FLG_FLG_ANT_MSK = (STA_FLG_FLG_ANT_A | | ||
97 | STA_FLG_FLG_ANT_B), | ||
98 | |||
99 | STA_FLG_PS = BIT(8), | ||
100 | STA_FLG_INVALID = BIT(9), | ||
101 | STA_FLG_DLP_EN = BIT(10), | ||
102 | STA_FLG_SET_ALL_KEYS = BIT(11), | ||
103 | STA_FLG_DRAIN_FLOW = BIT(12), | ||
104 | STA_FLG_PAN = BIT(13), | ||
105 | STA_FLG_CLASS_AUTH = BIT(14), | ||
106 | STA_FLG_CLASS_ASSOC = BIT(15), | ||
107 | STA_FLG_RTS_MIMO_PROT = BIT(17), | ||
108 | |||
109 | STA_FLG_MAX_AGG_SIZE_SHIFT = 19, | ||
110 | STA_FLG_MAX_AGG_SIZE_8K = (0 << STA_FLG_MAX_AGG_SIZE_SHIFT), | ||
111 | STA_FLG_MAX_AGG_SIZE_16K = (1 << STA_FLG_MAX_AGG_SIZE_SHIFT), | ||
112 | STA_FLG_MAX_AGG_SIZE_32K = (2 << STA_FLG_MAX_AGG_SIZE_SHIFT), | ||
113 | STA_FLG_MAX_AGG_SIZE_64K = (3 << STA_FLG_MAX_AGG_SIZE_SHIFT), | ||
114 | STA_FLG_MAX_AGG_SIZE_128K = (4 << STA_FLG_MAX_AGG_SIZE_SHIFT), | ||
115 | STA_FLG_MAX_AGG_SIZE_256K = (5 << STA_FLG_MAX_AGG_SIZE_SHIFT), | ||
116 | STA_FLG_MAX_AGG_SIZE_512K = (6 << STA_FLG_MAX_AGG_SIZE_SHIFT), | ||
117 | STA_FLG_MAX_AGG_SIZE_1024K = (7 << STA_FLG_MAX_AGG_SIZE_SHIFT), | ||
118 | STA_FLG_MAX_AGG_SIZE_MSK = (7 << STA_FLG_MAX_AGG_SIZE_SHIFT), | ||
119 | |||
120 | STA_FLG_AGG_MPDU_DENS_SHIFT = 23, | ||
121 | STA_FLG_AGG_MPDU_DENS_2US = (4 << STA_FLG_AGG_MPDU_DENS_SHIFT), | ||
122 | STA_FLG_AGG_MPDU_DENS_4US = (5 << STA_FLG_AGG_MPDU_DENS_SHIFT), | ||
123 | STA_FLG_AGG_MPDU_DENS_8US = (6 << STA_FLG_AGG_MPDU_DENS_SHIFT), | ||
124 | STA_FLG_AGG_MPDU_DENS_16US = (7 << STA_FLG_AGG_MPDU_DENS_SHIFT), | ||
125 | STA_FLG_AGG_MPDU_DENS_MSK = (7 << STA_FLG_AGG_MPDU_DENS_SHIFT), | ||
126 | |||
127 | STA_FLG_FAT_EN_20MHZ = (0 << 26), | ||
128 | STA_FLG_FAT_EN_40MHZ = (1 << 26), | ||
129 | STA_FLG_FAT_EN_80MHZ = (2 << 26), | ||
130 | STA_FLG_FAT_EN_160MHZ = (3 << 26), | ||
131 | STA_FLG_FAT_EN_MSK = (3 << 26), | ||
132 | |||
133 | STA_FLG_MIMO_EN_SISO = (0 << 28), | ||
134 | STA_FLG_MIMO_EN_MIMO2 = (1 << 28), | ||
135 | STA_FLG_MIMO_EN_MIMO3 = (2 << 28), | ||
136 | STA_FLG_MIMO_EN_MSK = (3 << 28), | ||
137 | }; | ||
138 | |||
139 | /** | ||
140 | * enum iwl_sta_key_flag - key flags for the ADD_STA host command | ||
141 | * @STA_KEY_FLG_EN_MSK: mask for encryption algorithm | ||
142 | * @STA_KEY_FLG_WEP_KEY_MAP: wep is either a group key (0 - legacy WEP) or from | ||
143 | * station info array (1 - n 1X mode) | ||
144 | * @STA_KEY_FLG_KEYID_MSK: the index of the key | ||
145 | * @STA_KEY_NOT_VALID: key is invalid | ||
146 | * @STA_KEY_FLG_WEP_13BYTES: set for 13 bytes WEP key | ||
147 | * @STA_KEY_MULTICAST: set for multical key | ||
148 | * @STA_KEY_MFP: key is used for Management Frame Protection | ||
149 | */ | ||
150 | enum iwl_sta_key_flag { | ||
151 | STA_KEY_FLG_NO_ENC = (0 << 0), | ||
152 | STA_KEY_FLG_WEP = (1 << 0), | ||
153 | STA_KEY_FLG_CCM = (2 << 0), | ||
154 | STA_KEY_FLG_TKIP = (3 << 0), | ||
155 | STA_KEY_FLG_CMAC = (6 << 0), | ||
156 | STA_KEY_FLG_ENC_UNKNOWN = (7 << 0), | ||
157 | STA_KEY_FLG_EN_MSK = (7 << 0), | ||
158 | |||
159 | STA_KEY_FLG_WEP_KEY_MAP = BIT(3), | ||
160 | STA_KEY_FLG_KEYID_POS = 8, | ||
161 | STA_KEY_FLG_KEYID_MSK = (3 << STA_KEY_FLG_KEYID_POS), | ||
162 | STA_KEY_NOT_VALID = BIT(11), | ||
163 | STA_KEY_FLG_WEP_13BYTES = BIT(12), | ||
164 | STA_KEY_MULTICAST = BIT(14), | ||
165 | STA_KEY_MFP = BIT(15), | ||
166 | }; | ||
167 | |||
168 | /** | ||
169 | * enum iwl_sta_modify_flag - indicate to the fw what flag are being changed | ||
170 | * @STA_MODIFY_KEY: this command modifies %key | ||
171 | * @STA_MODIFY_TID_DISABLE_TX: this command modifies %tid_disable_tx | ||
172 | * @STA_MODIFY_TX_RATE: unused | ||
173 | * @STA_MODIFY_ADD_BA_TID: this command modifies %add_immediate_ba_tid | ||
174 | * @STA_MODIFY_REMOVE_BA_TID: this command modifies %remove_immediate_ba_tid | ||
175 | * @STA_MODIFY_SLEEPING_STA_TX_COUNT: this command modifies %sleep_tx_count | ||
176 | * @STA_MODIFY_PROT_TH: | ||
177 | * @STA_MODIFY_QUEUES: modify the queues used by this station | ||
178 | */ | ||
179 | enum iwl_sta_modify_flag { | ||
180 | STA_MODIFY_KEY = BIT(0), | ||
181 | STA_MODIFY_TID_DISABLE_TX = BIT(1), | ||
182 | STA_MODIFY_TX_RATE = BIT(2), | ||
183 | STA_MODIFY_ADD_BA_TID = BIT(3), | ||
184 | STA_MODIFY_REMOVE_BA_TID = BIT(4), | ||
185 | STA_MODIFY_SLEEPING_STA_TX_COUNT = BIT(5), | ||
186 | STA_MODIFY_PROT_TH = BIT(6), | ||
187 | STA_MODIFY_QUEUES = BIT(7), | ||
188 | }; | ||
189 | |||
190 | #define STA_MODE_MODIFY 1 | ||
191 | |||
192 | /** | ||
193 | * enum iwl_sta_sleep_flag - type of sleep of the station | ||
194 | * @STA_SLEEP_STATE_AWAKE: | ||
195 | * @STA_SLEEP_STATE_PS_POLL: | ||
196 | * @STA_SLEEP_STATE_UAPSD: | ||
197 | */ | ||
198 | enum iwl_sta_sleep_flag { | ||
199 | STA_SLEEP_STATE_AWAKE = 0, | ||
200 | STA_SLEEP_STATE_PS_POLL = BIT(0), | ||
201 | STA_SLEEP_STATE_UAPSD = BIT(1), | ||
202 | }; | ||
203 | |||
204 | /* STA ID and color bits definitions */ | ||
205 | #define STA_ID_SEED (0x0f) | ||
206 | #define STA_ID_POS (0) | ||
207 | #define STA_ID_MSK (STA_ID_SEED << STA_ID_POS) | ||
208 | |||
209 | #define STA_COLOR_SEED (0x7) | ||
210 | #define STA_COLOR_POS (4) | ||
211 | #define STA_COLOR_MSK (STA_COLOR_SEED << STA_COLOR_POS) | ||
212 | |||
213 | #define STA_ID_N_COLOR_GET_COLOR(id_n_color) \ | ||
214 | (((id_n_color) & STA_COLOR_MSK) >> STA_COLOR_POS) | ||
215 | #define STA_ID_N_COLOR_GET_ID(id_n_color) \ | ||
216 | (((id_n_color) & STA_ID_MSK) >> STA_ID_POS) | ||
217 | |||
218 | #define STA_KEY_MAX_NUM (16) | ||
219 | #define STA_KEY_IDX_INVALID (0xff) | ||
220 | #define STA_KEY_MAX_DATA_KEY_NUM (4) | ||
221 | #define IWL_MAX_GLOBAL_KEYS (4) | ||
222 | #define STA_KEY_LEN_WEP40 (5) | ||
223 | #define STA_KEY_LEN_WEP104 (13) | ||
224 | |||
225 | /** | ||
226 | * struct iwl_mvm_keyinfo - key information | ||
227 | * @key_flags: type %iwl_sta_key_flag | ||
228 | * @tkip_rx_tsc_byte2: TSC[2] for key mix ph1 detection | ||
229 | * @tkip_rx_ttak: 10-byte unicast TKIP TTAK for Rx | ||
230 | * @key_offset: key offset in the fw's key table | ||
231 | * @key: 16-byte unicast decryption key | ||
232 | * @tx_secur_seq_cnt: initial RSC / PN needed for replay check | ||
233 | * @hw_tkip_mic_rx_key: byte: MIC Rx Key - used for TKIP only | ||
234 | * @hw_tkip_mic_tx_key: byte: MIC Tx Key - used for TKIP only | ||
235 | */ | ||
236 | struct iwl_mvm_keyinfo { | ||
237 | __le16 key_flags; | ||
238 | u8 tkip_rx_tsc_byte2; | ||
239 | u8 reserved1; | ||
240 | __le16 tkip_rx_ttak[5]; | ||
241 | u8 key_offset; | ||
242 | u8 reserved2; | ||
243 | u8 key[16]; | ||
244 | __le64 tx_secur_seq_cnt; | ||
245 | __le64 hw_tkip_mic_rx_key; | ||
246 | __le64 hw_tkip_mic_tx_key; | ||
247 | } __packed; | ||
248 | |||
249 | /** | ||
250 | * struct iwl_mvm_add_sta_cmd - Add / modify a station in the fw's station table | ||
251 | * ( REPLY_ADD_STA = 0x18 ) | ||
252 | * @add_modify: 1: modify existing, 0: add new station | ||
253 | * @unicast_tx_key_id: unicast tx key id. Relevant only when unicast key sent | ||
254 | * @multicast_tx_key_id: multicast tx key id. Relevant only when multicast key | ||
255 | * sent | ||
256 | * @mac_id_n_color: the Mac context this station belongs to | ||
257 | * @addr[ETH_ALEN]: station's MAC address | ||
258 | * @sta_id: index of station in uCode's station table | ||
259 | * @modify_mask: STA_MODIFY_*, selects which parameters to modify vs. leave | ||
260 | * alone. 1 - modify, 0 - don't change. | ||
261 | * @key: look at %iwl_mvm_keyinfo | ||
262 | * @station_flags: look at %iwl_sta_flags | ||
263 | * @station_flags_msk: what of %station_flags have changed | ||
264 | * @tid_disable_tx: is tid BIT(tid) enabled for Tx. Clear BIT(x) to enable | ||
265 | * AMPDU for tid x. Set %STA_MODIFY_TID_DISABLE_TX to change this field. | ||
266 | * @add_immediate_ba_tid: tid for which to add block-ack support (Rx) | ||
267 | * Set %STA_MODIFY_ADD_BA_TID to use this field, and also set | ||
268 | * add_immediate_ba_ssn. | ||
269 | * @remove_immediate_ba_tid: tid for which to remove block-ack support (Rx) | ||
270 | * Set %STA_MODIFY_REMOVE_BA_TID to use this field | ||
271 | * @add_immediate_ba_ssn: ssn for the Rx block-ack session. Used together with | ||
272 | * add_immediate_ba_tid. | ||
273 | * @sleep_tx_count: number of packets to transmit to station even though it is | ||
274 | * asleep. Used to synchronise PS-poll and u-APSD responses while ucode | ||
275 | * keeps track of STA sleep state. | ||
276 | * @sleep_state_flags: Look at %iwl_sta_sleep_flag. | ||
277 | * @assoc_id: assoc_id to be sent in VHT PLCP (9-bit), for grp use 0, for AP | ||
278 | * mac-addr. | ||
279 | * @beamform_flags: beam forming controls | ||
280 | * @tfd_queue_msk: tfd queues used by this station | ||
281 | * | ||
282 | * The device contains an internal table of per-station information, with info | ||
283 | * on security keys, aggregation parameters, and Tx rates for initial Tx | ||
284 | * attempt and any retries (set by REPLY_TX_LINK_QUALITY_CMD). | ||
285 | * | ||
286 | * ADD_STA sets up the table entry for one station, either creating a new | ||
287 | * entry, or modifying a pre-existing one. | ||
288 | */ | ||
289 | struct iwl_mvm_add_sta_cmd { | ||
290 | u8 add_modify; | ||
291 | u8 unicast_tx_key_id; | ||
292 | u8 multicast_tx_key_id; | ||
293 | u8 reserved1; | ||
294 | __le32 mac_id_n_color; | ||
295 | u8 addr[ETH_ALEN]; | ||
296 | __le16 reserved2; | ||
297 | u8 sta_id; | ||
298 | u8 modify_mask; | ||
299 | __le16 reserved3; | ||
300 | struct iwl_mvm_keyinfo key; | ||
301 | __le32 station_flags; | ||
302 | __le32 station_flags_msk; | ||
303 | __le16 tid_disable_tx; | ||
304 | __le16 reserved4; | ||
305 | u8 add_immediate_ba_tid; | ||
306 | u8 remove_immediate_ba_tid; | ||
307 | __le16 add_immediate_ba_ssn; | ||
308 | __le16 sleep_tx_count; | ||
309 | __le16 sleep_state_flags; | ||
310 | __le16 assoc_id; | ||
311 | __le16 beamform_flags; | ||
312 | __le32 tfd_queue_msk; | ||
313 | } __packed; /* ADD_STA_CMD_API_S_VER_5 */ | ||
314 | |||
315 | /** | ||
316 | * enum iwl_mvm_add_sta_rsp_status - status in the response to ADD_STA command | ||
317 | * @ADD_STA_SUCCESS: operation was executed successfully | ||
318 | * @ADD_STA_STATIONS_OVERLOAD: no room left in the fw's station table | ||
319 | * @ADD_STA_IMMEDIATE_BA_FAILURE: can't add Rx block ack session | ||
320 | * @ADD_STA_MODIFY_NON_EXISTING_STA: driver requested to modify a station that | ||
321 | * doesn't exist. | ||
322 | */ | ||
323 | enum iwl_mvm_add_sta_rsp_status { | ||
324 | ADD_STA_SUCCESS = 0x1, | ||
325 | ADD_STA_STATIONS_OVERLOAD = 0x2, | ||
326 | ADD_STA_IMMEDIATE_BA_FAILURE = 0x4, | ||
327 | ADD_STA_MODIFY_NON_EXISTING_STA = 0x8, | ||
328 | }; | ||
329 | |||
330 | /** | ||
331 | * struct iwl_mvm_rm_sta_cmd - Add / modify a station in the fw's station table | ||
332 | * ( REMOVE_STA = 0x19 ) | ||
333 | * @sta_id: the station id of the station to be removed | ||
334 | */ | ||
335 | struct iwl_mvm_rm_sta_cmd { | ||
336 | u8 sta_id; | ||
337 | u8 reserved[3]; | ||
338 | } __packed; /* REMOVE_STA_CMD_API_S_VER_2 */ | ||
339 | |||
340 | /** | ||
341 | * struct iwl_mvm_mgmt_mcast_key_cmd | ||
342 | * ( MGMT_MCAST_KEY = 0x1f ) | ||
343 | * @ctrl_flags: %iwl_sta_key_flag | ||
344 | * @IGTK: | ||
345 | * @K1: IGTK master key | ||
346 | * @K2: IGTK sub key | ||
347 | * @sta_id: station ID that support IGTK | ||
348 | * @key_id: | ||
349 | * @receive_seq_cnt: initial RSC/PN needed for replay check | ||
350 | */ | ||
351 | struct iwl_mvm_mgmt_mcast_key_cmd { | ||
352 | __le32 ctrl_flags; | ||
353 | u8 IGTK[16]; | ||
354 | u8 K1[16]; | ||
355 | u8 K2[16]; | ||
356 | __le32 key_id; | ||
357 | __le32 sta_id; | ||
358 | __le64 receive_seq_cnt; | ||
359 | } __packed; /* SEC_MGMT_MULTICAST_KEY_CMD_API_S_VER_1 */ | ||
360 | |||
361 | struct iwl_mvm_wep_key { | ||
362 | u8 key_index; | ||
363 | u8 key_offset; | ||
364 | __le16 reserved1; | ||
365 | u8 key_size; | ||
366 | u8 reserved2[3]; | ||
367 | u8 key[16]; | ||
368 | } __packed; | ||
369 | |||
370 | struct iwl_mvm_wep_key_cmd { | ||
371 | __le32 mac_id_n_color; | ||
372 | u8 num_keys; | ||
373 | u8 decryption_type; | ||
374 | u8 flags; | ||
375 | u8 reserved; | ||
376 | struct iwl_mvm_wep_key wep_key[0]; | ||
377 | } __packed; /* SEC_CURR_WEP_KEY_CMD_API_S_VER_2 */ | ||
378 | |||
379 | |||
380 | #endif /* __fw_api_sta_h__ */ | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h new file mode 100644 index 000000000000..2677914bf0a6 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h | |||
@@ -0,0 +1,580 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called LICENSE.GPL. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | *****************************************************************************/ | ||
62 | |||
63 | #ifndef __fw_api_tx_h__ | ||
64 | #define __fw_api_tx_h__ | ||
65 | |||
66 | /** | ||
67 | * enum iwl_tx_flags - bitmasks for tx_flags in TX command | ||
68 | * @TX_CMD_FLG_PROT_REQUIRE: use RTS or CTS-to-self to protect the frame | ||
69 | * @TX_CMD_FLG_ACK: expect ACK from receiving station | ||
70 | * @TX_CMD_FLG_STA_RATE: use RS table with initial index from the TX command. | ||
71 | * Otherwise, use rate_n_flags from the TX command | ||
72 | * @TX_CMD_FLG_BA: this frame is a block ack | ||
73 | * @TX_CMD_FLG_BAR: this frame is a BA request, immediate BAR is expected | ||
74 | * Must set TX_CMD_FLG_ACK with this flag. | ||
75 | * @TX_CMD_FLG_TXOP_PROT: protect frame with full TXOP protection | ||
76 | * @TX_CMD_FLG_VHT_NDPA: mark frame is NDPA for VHT beamformer sequence | ||
77 | * @TX_CMD_FLG_HT_NDPA: mark frame is NDPA for HT beamformer sequence | ||
78 | * @TX_CMD_FLG_CSI_FDBK2HOST: mark to send feedback to host (only if good CRC) | ||
79 | * @TX_CMD_FLG_BT_DIS: disable BT priority for this frame | ||
80 | * @TX_CMD_FLG_SEQ_CTL: set if FW should override the sequence control. | ||
81 | * Should be set for mgmt, non-QOS data, mcast, bcast and in scan command | ||
82 | * @TX_CMD_FLG_MORE_FRAG: this frame is non-last MPDU | ||
83 | * @TX_CMD_FLG_NEXT_FRAME: this frame includes information of the next frame | ||
84 | * @TX_CMD_FLG_TSF: FW should calculate and insert TSF in the frame | ||
85 | * Should be set for beacons and probe responses | ||
86 | * @TX_CMD_FLG_CALIB: activate PA TX power calibrations | ||
87 | * @TX_CMD_FLG_KEEP_SEQ_CTL: if seq_ctl is set, don't increase inner seq count | ||
88 | * @TX_CMD_FLG_AGG_START: allow this frame to start aggregation | ||
89 | * @TX_CMD_FLG_MH_PAD: driver inserted 2 byte padding after MAC header. | ||
90 | * Should be set for 26/30 length MAC headers | ||
91 | * @TX_CMD_FLG_RESP_TO_DRV: zero this if the response should go only to FW | ||
92 | * @TX_CMD_FLG_CCMP_AGG: this frame uses CCMP for aggregation acceleration | ||
93 | * @TX_CMD_FLG_TKIP_MIC_DONE: FW already performed TKIP MIC calculation | ||
94 | * @TX_CMD_FLG_CTS_ONLY: send CTS only, no data after that | ||
95 | * @TX_CMD_FLG_DUR: disable duration overwriting used in PS-Poll Assoc-id | ||
96 | * @TX_CMD_FLG_FW_DROP: FW should mark frame to be dropped | ||
97 | * @TX_CMD_FLG_EXEC_PAPD: execute PAPD | ||
98 | * @TX_CMD_FLG_PAPD_TYPE: 0 for reference power, 1 for nominal power | ||
99 | * @TX_CMD_FLG_HCCA_CHUNK: mark start of TSPEC chunk | ||
100 | */ | ||
101 | enum iwl_tx_flags { | ||
102 | TX_CMD_FLG_PROT_REQUIRE = BIT(0), | ||
103 | TX_CMD_FLG_ACK = BIT(3), | ||
104 | TX_CMD_FLG_STA_RATE = BIT(4), | ||
105 | TX_CMD_FLG_BA = BIT(5), | ||
106 | TX_CMD_FLG_BAR = BIT(6), | ||
107 | TX_CMD_FLG_TXOP_PROT = BIT(7), | ||
108 | TX_CMD_FLG_VHT_NDPA = BIT(8), | ||
109 | TX_CMD_FLG_HT_NDPA = BIT(9), | ||
110 | TX_CMD_FLG_CSI_FDBK2HOST = BIT(10), | ||
111 | TX_CMD_FLG_BT_DIS = BIT(12), | ||
112 | TX_CMD_FLG_SEQ_CTL = BIT(13), | ||
113 | TX_CMD_FLG_MORE_FRAG = BIT(14), | ||
114 | TX_CMD_FLG_NEXT_FRAME = BIT(15), | ||
115 | TX_CMD_FLG_TSF = BIT(16), | ||
116 | TX_CMD_FLG_CALIB = BIT(17), | ||
117 | TX_CMD_FLG_KEEP_SEQ_CTL = BIT(18), | ||
118 | TX_CMD_FLG_AGG_START = BIT(19), | ||
119 | TX_CMD_FLG_MH_PAD = BIT(20), | ||
120 | TX_CMD_FLG_RESP_TO_DRV = BIT(21), | ||
121 | TX_CMD_FLG_CCMP_AGG = BIT(22), | ||
122 | TX_CMD_FLG_TKIP_MIC_DONE = BIT(23), | ||
123 | TX_CMD_FLG_CTS_ONLY = BIT(24), | ||
124 | TX_CMD_FLG_DUR = BIT(25), | ||
125 | TX_CMD_FLG_FW_DROP = BIT(26), | ||
126 | TX_CMD_FLG_EXEC_PAPD = BIT(27), | ||
127 | TX_CMD_FLG_PAPD_TYPE = BIT(28), | ||
128 | TX_CMD_FLG_HCCA_CHUNK = BIT(31) | ||
129 | }; /* TX_FLAGS_BITS_API_S_VER_1 */ | ||
130 | |||
131 | /* | ||
132 | * TX command security control | ||
133 | */ | ||
134 | #define TX_CMD_SEC_WEP 0x01 | ||
135 | #define TX_CMD_SEC_CCM 0x02 | ||
136 | #define TX_CMD_SEC_TKIP 0x03 | ||
137 | #define TX_CMD_SEC_WEP_KEY_IDX_POS 6 | ||
138 | #define TX_CMD_SEC_WEP_KEY_IDX_MSK 0xc0 | ||
139 | #define TX_CMD_SEC_KEY128 0x08 | ||
140 | |||
141 | /* TODO: how does these values are OK with only 16 bit variable??? */ | ||
142 | /* | ||
143 | * TX command next frame info | ||
144 | * | ||
145 | * bits 0:2 - security control (TX_CMD_SEC_*) | ||
146 | * bit 3 - immediate ACK required | ||
147 | * bit 4 - rate is taken from STA table | ||
148 | * bit 5 - frame belongs to BA stream | ||
149 | * bit 6 - immediate BA response expected | ||
150 | * bit 7 - unused | ||
151 | * bits 8:15 - Station ID | ||
152 | * bits 16:31 - rate | ||
153 | */ | ||
154 | #define TX_CMD_NEXT_FRAME_ACK_MSK (0x8) | ||
155 | #define TX_CMD_NEXT_FRAME_STA_RATE_MSK (0x10) | ||
156 | #define TX_CMD_NEXT_FRAME_BA_MSK (0x20) | ||
157 | #define TX_CMD_NEXT_FRAME_IMM_BA_RSP_MSK (0x40) | ||
158 | #define TX_CMD_NEXT_FRAME_FLAGS_MSK (0xf8) | ||
159 | #define TX_CMD_NEXT_FRAME_STA_ID_MSK (0xff00) | ||
160 | #define TX_CMD_NEXT_FRAME_STA_ID_POS (8) | ||
161 | #define TX_CMD_NEXT_FRAME_RATE_MSK (0xffff0000) | ||
162 | #define TX_CMD_NEXT_FRAME_RATE_POS (16) | ||
163 | |||
164 | /* | ||
165 | * TX command Frame life time in us - to be written in pm_frame_timeout | ||
166 | */ | ||
167 | #define TX_CMD_LIFE_TIME_INFINITE 0xFFFFFFFF | ||
168 | #define TX_CMD_LIFE_TIME_DEFAULT 2000000 /* 2000 ms*/ | ||
169 | #define TX_CMD_LIFE_TIME_PROBE_RESP 40000 /* 40 ms */ | ||
170 | #define TX_CMD_LIFE_TIME_EXPIRED_FRAME 0 | ||
171 | |||
172 | /* | ||
173 | * TID for non QoS frames - to be written in tid_tspec | ||
174 | */ | ||
175 | #define IWL_TID_NON_QOS IWL_MAX_TID_COUNT | ||
176 | |||
177 | /* | ||
178 | * Limits on the retransmissions - to be written in {data,rts}_retry_limit | ||
179 | */ | ||
180 | #define IWL_DEFAULT_TX_RETRY 15 | ||
181 | #define IWL_MGMT_DFAULT_RETRY_LIMIT 3 | ||
182 | #define IWL_RTS_DFAULT_RETRY_LIMIT 60 | ||
183 | #define IWL_BAR_DFAULT_RETRY_LIMIT 60 | ||
184 | #define IWL_LOW_RETRY_LIMIT 7 | ||
185 | |||
186 | /* TODO: complete documentation for try_cnt and btkill_cnt */ | ||
187 | /** | ||
188 | * struct iwl_tx_cmd - TX command struct to FW | ||
189 | * ( TX_CMD = 0x1c ) | ||
190 | * @len: in bytes of the payload, see below for details | ||
191 | * @next_frame_len: same as len, but for next frame (0 if not applicable) | ||
192 | * Used for fragmentation and bursting, but not in 11n aggregation. | ||
193 | * @tx_flags: combination of TX_CMD_FLG_* | ||
194 | * @rate_n_flags: rate for *all* Tx attempts, if TX_CMD_FLG_STA_RATE_MSK is | ||
195 | * cleared. Combination of RATE_MCS_* | ||
196 | * @sta_id: index of destination station in FW station table | ||
197 | * @sec_ctl: security control, TX_CMD_SEC_* | ||
198 | * @initial_rate_index: index into the the rate table for initial TX attempt. | ||
199 | * Applied if TX_CMD_FLG_STA_RATE_MSK is set, normally 0 for data frames. | ||
200 | * @key: security key | ||
201 | * @next_frame_flags: TX_CMD_SEC_* and TX_CMD_NEXT_FRAME_* | ||
202 | * @life_time: frame life time (usecs??) | ||
203 | * @dram_lsb_ptr: Physical address of scratch area in the command (try_cnt + | ||
204 | * btkill_cnd + reserved), first 32 bits. "0" disables usage. | ||
205 | * @dram_msb_ptr: upper bits of the scratch physical address | ||
206 | * @rts_retry_limit: max attempts for RTS | ||
207 | * @data_retry_limit: max attempts to send the data packet | ||
208 | * @tid_spec: TID/tspec | ||
209 | * @pm_frame_timeout: PM TX frame timeout | ||
210 | * @driver_txop: duration od EDCA TXOP, in 32-usec units. Set this if not | ||
211 | * specified by HCCA protocol | ||
212 | * | ||
213 | * The byte count (both len and next_frame_len) includes MAC header | ||
214 | * (24/26/30/32 bytes) | ||
215 | * + 2 bytes pad if 26/30 header size | ||
216 | * + 8 byte IV for CCM or TKIP (not used for WEP) | ||
217 | * + Data payload | ||
218 | * + 8-byte MIC (not used for CCM/WEP) | ||
219 | * It does not include post-MAC padding, i.e., | ||
220 | * MIC (CCM) 8 bytes, ICV (WEP/TKIP/CKIP) 4 bytes, CRC 4 bytes. | ||
221 | * Range of len: 14-2342 bytes. | ||
222 | * | ||
223 | * After the struct fields the MAC header is placed, plus any padding, | ||
224 | * and then the actial payload. | ||
225 | */ | ||
226 | struct iwl_tx_cmd { | ||
227 | __le16 len; | ||
228 | __le16 next_frame_len; | ||
229 | __le32 tx_flags; | ||
230 | /* DRAM_SCRATCH_API_U_VER_1 */ | ||
231 | u8 try_cnt; | ||
232 | u8 btkill_cnt; | ||
233 | __le16 reserved; | ||
234 | __le32 rate_n_flags; | ||
235 | u8 sta_id; | ||
236 | u8 sec_ctl; | ||
237 | u8 initial_rate_index; | ||
238 | u8 reserved2; | ||
239 | u8 key[16]; | ||
240 | __le16 next_frame_flags; | ||
241 | __le16 reserved3; | ||
242 | __le32 life_time; | ||
243 | __le32 dram_lsb_ptr; | ||
244 | u8 dram_msb_ptr; | ||
245 | u8 rts_retry_limit; | ||
246 | u8 data_retry_limit; | ||
247 | u8 tid_tspec; | ||
248 | __le16 pm_frame_timeout; | ||
249 | __le16 driver_txop; | ||
250 | u8 payload[0]; | ||
251 | struct ieee80211_hdr hdr[0]; | ||
252 | } __packed; /* TX_CMD_API_S_VER_3 */ | ||
253 | |||
254 | /* | ||
255 | * TX response related data | ||
256 | */ | ||
257 | |||
258 | /* | ||
259 | * enum iwl_tx_status - status that is returned by the fw after attempts to Tx | ||
260 | * @TX_STATUS_SUCCESS: | ||
261 | * @TX_STATUS_DIRECT_DONE: | ||
262 | * @TX_STATUS_POSTPONE_DELAY: | ||
263 | * @TX_STATUS_POSTPONE_FEW_BYTES: | ||
264 | * @TX_STATUS_POSTPONE_BT_PRIO: | ||
265 | * @TX_STATUS_POSTPONE_QUIET_PERIOD: | ||
266 | * @TX_STATUS_POSTPONE_CALC_TTAK: | ||
267 | * @TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY: | ||
268 | * @TX_STATUS_FAIL_SHORT_LIMIT: | ||
269 | * @TX_STATUS_FAIL_LONG_LIMIT: | ||
270 | * @TX_STATUS_FAIL_UNDERRUN: | ||
271 | * @TX_STATUS_FAIL_DRAIN_FLOW: | ||
272 | * @TX_STATUS_FAIL_RFKILL_FLUSH: | ||
273 | * @TX_STATUS_FAIL_LIFE_EXPIRE: | ||
274 | * @TX_STATUS_FAIL_DEST_PS: | ||
275 | * @TX_STATUS_FAIL_HOST_ABORTED: | ||
276 | * @TX_STATUS_FAIL_BT_RETRY: | ||
277 | * @TX_STATUS_FAIL_STA_INVALID: | ||
278 | * @TX_TATUS_FAIL_FRAG_DROPPED: | ||
279 | * @TX_STATUS_FAIL_TID_DISABLE: | ||
280 | * @TX_STATUS_FAIL_FIFO_FLUSHED: | ||
281 | * @TX_STATUS_FAIL_SMALL_CF_POLL: | ||
282 | * @TX_STATUS_FAIL_FW_DROP: | ||
283 | * @TX_STATUS_FAIL_STA_COLOR_MISMATCH: mismatch between color of Tx cmd and | ||
284 | * STA table | ||
285 | * @TX_FRAME_STATUS_INTERNAL_ABORT: | ||
286 | * @TX_MODE_MSK: | ||
287 | * @TX_MODE_NO_BURST: | ||
288 | * @TX_MODE_IN_BURST_SEQ: | ||
289 | * @TX_MODE_FIRST_IN_BURST: | ||
290 | * @TX_QUEUE_NUM_MSK: | ||
291 | * | ||
292 | * Valid only if frame_count =1 | ||
293 | * TODO: complete documentation | ||
294 | */ | ||
295 | enum iwl_tx_status { | ||
296 | TX_STATUS_MSK = 0x000000ff, | ||
297 | TX_STATUS_SUCCESS = 0x01, | ||
298 | TX_STATUS_DIRECT_DONE = 0x02, | ||
299 | /* postpone TX */ | ||
300 | TX_STATUS_POSTPONE_DELAY = 0x40, | ||
301 | TX_STATUS_POSTPONE_FEW_BYTES = 0x41, | ||
302 | TX_STATUS_POSTPONE_BT_PRIO = 0x42, | ||
303 | TX_STATUS_POSTPONE_QUIET_PERIOD = 0x43, | ||
304 | TX_STATUS_POSTPONE_CALC_TTAK = 0x44, | ||
305 | /* abort TX */ | ||
306 | TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY = 0x81, | ||
307 | TX_STATUS_FAIL_SHORT_LIMIT = 0x82, | ||
308 | TX_STATUS_FAIL_LONG_LIMIT = 0x83, | ||
309 | TX_STATUS_FAIL_UNDERRUN = 0x84, | ||
310 | TX_STATUS_FAIL_DRAIN_FLOW = 0x85, | ||
311 | TX_STATUS_FAIL_RFKILL_FLUSH = 0x86, | ||
312 | TX_STATUS_FAIL_LIFE_EXPIRE = 0x87, | ||
313 | TX_STATUS_FAIL_DEST_PS = 0x88, | ||
314 | TX_STATUS_FAIL_HOST_ABORTED = 0x89, | ||
315 | TX_STATUS_FAIL_BT_RETRY = 0x8a, | ||
316 | TX_STATUS_FAIL_STA_INVALID = 0x8b, | ||
317 | TX_STATUS_FAIL_FRAG_DROPPED = 0x8c, | ||
318 | TX_STATUS_FAIL_TID_DISABLE = 0x8d, | ||
319 | TX_STATUS_FAIL_FIFO_FLUSHED = 0x8e, | ||
320 | TX_STATUS_FAIL_SMALL_CF_POLL = 0x8f, | ||
321 | TX_STATUS_FAIL_FW_DROP = 0x90, | ||
322 | TX_STATUS_FAIL_STA_COLOR_MISMATCH = 0x91, | ||
323 | TX_STATUS_INTERNAL_ABORT = 0x92, | ||
324 | TX_MODE_MSK = 0x00000f00, | ||
325 | TX_MODE_NO_BURST = 0x00000000, | ||
326 | TX_MODE_IN_BURST_SEQ = 0x00000100, | ||
327 | TX_MODE_FIRST_IN_BURST = 0x00000200, | ||
328 | TX_QUEUE_NUM_MSK = 0x0001f000, | ||
329 | TX_NARROW_BW_MSK = 0x00060000, | ||
330 | TX_NARROW_BW_1DIV2 = 0x00020000, | ||
331 | TX_NARROW_BW_1DIV4 = 0x00040000, | ||
332 | TX_NARROW_BW_1DIV8 = 0x00060000, | ||
333 | }; | ||
334 | |||
335 | /* | ||
336 | * enum iwl_tx_agg_status - TX aggregation status | ||
337 | * @AGG_TX_STATE_STATUS_MSK: | ||
338 | * @AGG_TX_STATE_TRANSMITTED: | ||
339 | * @AGG_TX_STATE_UNDERRUN: | ||
340 | * @AGG_TX_STATE_BT_PRIO: | ||
341 | * @AGG_TX_STATE_FEW_BYTES: | ||
342 | * @AGG_TX_STATE_ABORT: | ||
343 | * @AGG_TX_STATE_LAST_SENT_TTL: | ||
344 | * @AGG_TX_STATE_LAST_SENT_TRY_CNT: | ||
345 | * @AGG_TX_STATE_LAST_SENT_BT_KILL: | ||
346 | * @AGG_TX_STATE_SCD_QUERY: | ||
347 | * @AGG_TX_STATE_TEST_BAD_CRC32: | ||
348 | * @AGG_TX_STATE_RESPONSE: | ||
349 | * @AGG_TX_STATE_DUMP_TX: | ||
350 | * @AGG_TX_STATE_DELAY_TX: | ||
351 | * @AGG_TX_STATE_TRY_CNT_MSK: Retry count for 1st frame in aggregation (retries | ||
352 | * occur if tx failed for this frame when it was a member of a previous | ||
353 | * aggregation block). If rate scaling is used, retry count indicates the | ||
354 | * rate table entry used for all frames in the new agg. | ||
355 | *@ AGG_TX_STATE_SEQ_NUM_MSK: Command ID and sequence number of Tx command for | ||
356 | * this frame | ||
357 | * | ||
358 | * TODO: complete documentation | ||
359 | */ | ||
360 | enum iwl_tx_agg_status { | ||
361 | AGG_TX_STATE_STATUS_MSK = 0x00fff, | ||
362 | AGG_TX_STATE_TRANSMITTED = 0x000, | ||
363 | AGG_TX_STATE_UNDERRUN = 0x001, | ||
364 | AGG_TX_STATE_BT_PRIO = 0x002, | ||
365 | AGG_TX_STATE_FEW_BYTES = 0x004, | ||
366 | AGG_TX_STATE_ABORT = 0x008, | ||
367 | AGG_TX_STATE_LAST_SENT_TTL = 0x010, | ||
368 | AGG_TX_STATE_LAST_SENT_TRY_CNT = 0x020, | ||
369 | AGG_TX_STATE_LAST_SENT_BT_KILL = 0x040, | ||
370 | AGG_TX_STATE_SCD_QUERY = 0x080, | ||
371 | AGG_TX_STATE_TEST_BAD_CRC32 = 0x0100, | ||
372 | AGG_TX_STATE_RESPONSE = 0x1ff, | ||
373 | AGG_TX_STATE_DUMP_TX = 0x200, | ||
374 | AGG_TX_STATE_DELAY_TX = 0x400, | ||
375 | AGG_TX_STATE_TRY_CNT_POS = 12, | ||
376 | AGG_TX_STATE_TRY_CNT_MSK = 0xf << AGG_TX_STATE_TRY_CNT_POS, | ||
377 | }; | ||
378 | |||
379 | #define AGG_TX_STATE_LAST_SENT_MSK (AGG_TX_STATE_LAST_SENT_TTL| \ | ||
380 | AGG_TX_STATE_LAST_SENT_TRY_CNT| \ | ||
381 | AGG_TX_STATE_LAST_SENT_BT_KILL) | ||
382 | |||
383 | /* | ||
384 | * The mask below describes a status where we are absolutely sure that the MPDU | ||
385 | * wasn't sent. For BA/Underrun we cannot be that sure. All we know that we've | ||
386 | * written the bytes to the TXE, but we know nothing about what the DSP did. | ||
387 | */ | ||
388 | #define AGG_TX_STAT_FRAME_NOT_SENT (AGG_TX_STATE_FEW_BYTES | \ | ||
389 | AGG_TX_STATE_ABORT | \ | ||
390 | AGG_TX_STATE_SCD_QUERY) | ||
391 | |||
392 | /* | ||
393 | * REPLY_TX = 0x1c (response) | ||
394 | * | ||
395 | * This response may be in one of two slightly different formats, indicated | ||
396 | * by the frame_count field: | ||
397 | * | ||
398 | * 1) No aggregation (frame_count == 1). This reports Tx results for a single | ||
399 | * frame. Multiple attempts, at various bit rates, may have been made for | ||
400 | * this frame. | ||
401 | * | ||
402 | * 2) Aggregation (frame_count > 1). This reports Tx results for two or more | ||
403 | * frames that used block-acknowledge. All frames were transmitted at | ||
404 | * same rate. Rate scaling may have been used if first frame in this new | ||
405 | * agg block failed in previous agg block(s). | ||
406 | * | ||
407 | * Note that, for aggregation, ACK (block-ack) status is not delivered | ||
408 | * here; block-ack has not been received by the time the device records | ||
409 | * this status. | ||
410 | * This status relates to reasons the tx might have been blocked or aborted | ||
411 | * within the device, rather than whether it was received successfully by | ||
412 | * the destination station. | ||
413 | */ | ||
414 | |||
415 | /** | ||
416 | * struct agg_tx_status - per packet TX aggregation status | ||
417 | * @status: enum iwl_tx_agg_status | ||
418 | * @sequence: Sequence # for this frame's Tx cmd (not SSN!) | ||
419 | */ | ||
420 | struct agg_tx_status { | ||
421 | __le16 status; | ||
422 | __le16 sequence; | ||
423 | } __packed; | ||
424 | |||
425 | /* | ||
426 | * definitions for initial rate index field | ||
427 | * bits [3:0] initial rate index | ||
428 | * bits [6:4] rate table color, used for the initial rate | ||
429 | * bit-7 invalid rate indication | ||
430 | */ | ||
431 | #define TX_RES_INIT_RATE_INDEX_MSK 0x0f | ||
432 | #define TX_RES_RATE_TABLE_COLOR_MSK 0x70 | ||
433 | #define TX_RES_INV_RATE_INDEX_MSK 0x80 | ||
434 | |||
435 | #define IWL_MVM_TX_RES_GET_TID(_ra_tid) ((_ra_tid) & 0x0f) | ||
436 | #define IWL_MVM_TX_RES_GET_RA(_ra_tid) ((_ra_tid) >> 4) | ||
437 | |||
438 | /** | ||
439 | * struct iwl_mvm_tx_resp - notifies that fw is TXing a packet | ||
440 | * ( REPLY_TX = 0x1c ) | ||
441 | * @frame_count: 1 no aggregation, >1 aggregation | ||
442 | * @bt_kill_count: num of times blocked by bluetooth (unused for agg) | ||
443 | * @failure_rts: num of failures due to unsuccessful RTS | ||
444 | * @failure_frame: num failures due to no ACK (unused for agg) | ||
445 | * @initial_rate: for non-agg: rate of the successful Tx. For agg: rate of the | ||
446 | * Tx of all the batch. RATE_MCS_* | ||
447 | * @wireless_media_time: for non-agg: RTS + CTS + frame tx attempts time + ACK. | ||
448 | * for agg: RTS + CTS + aggregation tx time + block-ack time. | ||
449 | * in usec. | ||
450 | * @pa_status: tx power info | ||
451 | * @pa_integ_res_a: tx power info | ||
452 | * @pa_integ_res_b: tx power info | ||
453 | * @pa_integ_res_c: tx power info | ||
454 | * @measurement_req_id: tx power info | ||
455 | * @tfd_info: TFD information set by the FH | ||
456 | * @seq_ctl: sequence control from the Tx cmd | ||
457 | * @byte_cnt: byte count from the Tx cmd | ||
458 | * @tlc_info: TLC rate info | ||
459 | * @ra_tid: bits [3:0] = ra, bits [7:4] = tid | ||
460 | * @frame_ctrl: frame control | ||
461 | * @status: for non-agg: frame status TX_STATUS_* | ||
462 | * for agg: status of 1st frame, AGG_TX_STATE_*; other frame status fields | ||
463 | * follow this one, up to frame_count. | ||
464 | * | ||
465 | * After the array of statuses comes the SSN of the SCD. Look at | ||
466 | * %iwl_mvm_get_scd_ssn for more details. | ||
467 | */ | ||
468 | struct iwl_mvm_tx_resp { | ||
469 | u8 frame_count; | ||
470 | u8 bt_kill_count; | ||
471 | u8 failure_rts; | ||
472 | u8 failure_frame; | ||
473 | __le32 initial_rate; | ||
474 | __le16 wireless_media_time; | ||
475 | |||
476 | u8 pa_status; | ||
477 | u8 pa_integ_res_a[3]; | ||
478 | u8 pa_integ_res_b[3]; | ||
479 | u8 pa_integ_res_c[3]; | ||
480 | __le16 measurement_req_id; | ||
481 | __le16 reserved; | ||
482 | |||
483 | __le32 tfd_info; | ||
484 | __le16 seq_ctl; | ||
485 | __le16 byte_cnt; | ||
486 | u8 tlc_info; | ||
487 | u8 ra_tid; | ||
488 | __le16 frame_ctrl; | ||
489 | |||
490 | struct agg_tx_status status; | ||
491 | } __packed; /* TX_RSP_API_S_VER_3 */ | ||
492 | |||
493 | /** | ||
494 | * struct iwl_mvm_ba_notif - notifies about reception of BA | ||
495 | * ( BA_NOTIF = 0xc5 ) | ||
496 | * @sta_addr_lo32: lower 32 bits of the MAC address | ||
497 | * @sta_addr_hi16: upper 16 bits of the MAC address | ||
498 | * @sta_id: Index of recipient (BA-sending) station in fw's station table | ||
499 | * @tid: tid of the session | ||
500 | * @seq_ctl: | ||
501 | * @bitmap: the bitmap of the BA notification as seen in the air | ||
502 | * @scd_flow: the tx queue this BA relates to | ||
503 | * @scd_ssn: the index of the last contiguously sent packet | ||
504 | * @txed: number of Txed frames in this batch | ||
505 | * @txed_2_done: number of Acked frames in this batch | ||
506 | */ | ||
507 | struct iwl_mvm_ba_notif { | ||
508 | __le32 sta_addr_lo32; | ||
509 | __le16 sta_addr_hi16; | ||
510 | __le16 reserved; | ||
511 | |||
512 | u8 sta_id; | ||
513 | u8 tid; | ||
514 | __le16 seq_ctl; | ||
515 | __le64 bitmap; | ||
516 | __le16 scd_flow; | ||
517 | __le16 scd_ssn; | ||
518 | u8 txed; | ||
519 | u8 txed_2_done; | ||
520 | __le16 reserved1; | ||
521 | } __packed; | ||
522 | |||
523 | /* | ||
524 | * struct iwl_mac_beacon_cmd - beacon template command | ||
525 | * @tx: the tx commands associated with the beacon frame | ||
526 | * @template_id: currently equal to the mac context id of the coresponding | ||
527 | * mac. | ||
528 | * @tim_idx: the offset of the tim IE in the beacon | ||
529 | * @tim_size: the length of the tim IE | ||
530 | * @frame: the template of the beacon frame | ||
531 | */ | ||
532 | struct iwl_mac_beacon_cmd { | ||
533 | struct iwl_tx_cmd tx; | ||
534 | __le32 template_id; | ||
535 | __le32 tim_idx; | ||
536 | __le32 tim_size; | ||
537 | struct ieee80211_hdr frame[0]; | ||
538 | } __packed; | ||
539 | |||
540 | /** | ||
541 | * enum iwl_dump_control - dump (flush) control flags | ||
542 | * @DUMP_TX_FIFO_FLUSH: Dump MSDUs until the the FIFO is empty | ||
543 | * and the TFD queues are empty. | ||
544 | */ | ||
545 | enum iwl_dump_control { | ||
546 | DUMP_TX_FIFO_FLUSH = BIT(1), | ||
547 | }; | ||
548 | |||
549 | /** | ||
550 | * struct iwl_tx_path_flush_cmd -- queue/FIFO flush command | ||
551 | * @queues_ctl: bitmap of queues to flush | ||
552 | * @flush_ctl: control flags | ||
553 | * @reserved: reserved | ||
554 | */ | ||
555 | struct iwl_tx_path_flush_cmd { | ||
556 | __le32 queues_ctl; | ||
557 | __le16 flush_ctl; | ||
558 | __le16 reserved; | ||
559 | } __packed; /* TX_PATH_FLUSH_CMD_API_S_VER_1 */ | ||
560 | |||
561 | /** | ||
562 | * iwl_mvm_get_scd_ssn - returns the SSN of the SCD | ||
563 | * @tx_resp: the Tx response from the fw (agg or non-agg) | ||
564 | * | ||
565 | * When the fw sends an AMPDU, it fetches the MPDUs one after the other. Since | ||
566 | * it can't know that everything will go well until the end of the AMPDU, it | ||
567 | * can't know in advance the number of MPDUs that will be sent in the current | ||
568 | * batch. This is why it writes the agg Tx response while it fetches the MPDUs. | ||
569 | * Hence, it can't know in advance what the SSN of the SCD will be at the end | ||
570 | * of the batch. This is why the SSN of the SCD is written at the end of the | ||
571 | * whole struct at a variable offset. This function knows how to cope with the | ||
572 | * variable offset and returns the SSN of the SCD. | ||
573 | */ | ||
574 | static inline u32 iwl_mvm_get_scd_ssn(struct iwl_mvm_tx_resp *tx_resp) | ||
575 | { | ||
576 | return le32_to_cpup((__le32 *)&tx_resp->status + | ||
577 | tx_resp->frame_count) & 0xfff; | ||
578 | } | ||
579 | |||
580 | #endif /* __fw_api_tx_h__ */ | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h new file mode 100644 index 000000000000..9fd49db32a32 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h | |||
@@ -0,0 +1,949 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called LICENSE.GPL. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | * | ||
62 | *****************************************************************************/ | ||
63 | |||
64 | #ifndef __fw_api_h__ | ||
65 | #define __fw_api_h__ | ||
66 | |||
67 | #include "fw-api-rs.h" | ||
68 | #include "fw-api-tx.h" | ||
69 | #include "fw-api-sta.h" | ||
70 | #include "fw-api-mac.h" | ||
71 | #include "fw-api-power.h" | ||
72 | #include "fw-api-d3.h" | ||
73 | |||
74 | /* queue and FIFO numbers by usage */ | ||
75 | enum { | ||
76 | IWL_MVM_OFFCHANNEL_QUEUE = 8, | ||
77 | IWL_MVM_CMD_QUEUE = 9, | ||
78 | IWL_MVM_AUX_QUEUE = 15, | ||
79 | IWL_MVM_FIRST_AGG_QUEUE = 16, | ||
80 | IWL_MVM_NUM_QUEUES = 20, | ||
81 | IWL_MVM_LAST_AGG_QUEUE = IWL_MVM_NUM_QUEUES - 1, | ||
82 | IWL_MVM_CMD_FIFO = 7 | ||
83 | }; | ||
84 | |||
85 | #define IWL_MVM_STATION_COUNT 16 | ||
86 | |||
87 | /* commands */ | ||
88 | enum { | ||
89 | MVM_ALIVE = 0x1, | ||
90 | REPLY_ERROR = 0x2, | ||
91 | |||
92 | INIT_COMPLETE_NOTIF = 0x4, | ||
93 | |||
94 | /* PHY context commands */ | ||
95 | PHY_CONTEXT_CMD = 0x8, | ||
96 | DBG_CFG = 0x9, | ||
97 | |||
98 | /* station table */ | ||
99 | ADD_STA = 0x18, | ||
100 | REMOVE_STA = 0x19, | ||
101 | |||
102 | /* TX */ | ||
103 | TX_CMD = 0x1c, | ||
104 | TXPATH_FLUSH = 0x1e, | ||
105 | MGMT_MCAST_KEY = 0x1f, | ||
106 | |||
107 | /* global key */ | ||
108 | WEP_KEY = 0x20, | ||
109 | |||
110 | /* MAC and Binding commands */ | ||
111 | MAC_CONTEXT_CMD = 0x28, | ||
112 | TIME_EVENT_CMD = 0x29, /* both CMD and response */ | ||
113 | TIME_EVENT_NOTIFICATION = 0x2a, | ||
114 | BINDING_CONTEXT_CMD = 0x2b, | ||
115 | TIME_QUOTA_CMD = 0x2c, | ||
116 | |||
117 | LQ_CMD = 0x4e, | ||
118 | |||
119 | /* Calibration */ | ||
120 | TEMPERATURE_NOTIFICATION = 0x62, | ||
121 | CALIBRATION_CFG_CMD = 0x65, | ||
122 | CALIBRATION_RES_NOTIFICATION = 0x66, | ||
123 | CALIBRATION_COMPLETE_NOTIFICATION = 0x67, | ||
124 | RADIO_VERSION_NOTIFICATION = 0x68, | ||
125 | |||
126 | /* Scan offload */ | ||
127 | SCAN_OFFLOAD_REQUEST_CMD = 0x51, | ||
128 | SCAN_OFFLOAD_ABORT_CMD = 0x52, | ||
129 | SCAN_OFFLOAD_COMPLETE = 0x6D, | ||
130 | SCAN_OFFLOAD_UPDATE_PROFILES_CMD = 0x6E, | ||
131 | SCAN_OFFLOAD_CONFIG_CMD = 0x6f, | ||
132 | |||
133 | /* Phy */ | ||
134 | PHY_CONFIGURATION_CMD = 0x6a, | ||
135 | CALIB_RES_NOTIF_PHY_DB = 0x6b, | ||
136 | /* PHY_DB_CMD = 0x6c, */ | ||
137 | |||
138 | /* Power */ | ||
139 | POWER_TABLE_CMD = 0x77, | ||
140 | |||
141 | /* Scanning */ | ||
142 | SCAN_REQUEST_CMD = 0x80, | ||
143 | SCAN_ABORT_CMD = 0x81, | ||
144 | SCAN_START_NOTIFICATION = 0x82, | ||
145 | SCAN_RESULTS_NOTIFICATION = 0x83, | ||
146 | SCAN_COMPLETE_NOTIFICATION = 0x84, | ||
147 | |||
148 | /* NVM */ | ||
149 | NVM_ACCESS_CMD = 0x88, | ||
150 | |||
151 | SET_CALIB_DEFAULT_CMD = 0x8e, | ||
152 | |||
153 | BEACON_TEMPLATE_CMD = 0x91, | ||
154 | TX_ANT_CONFIGURATION_CMD = 0x98, | ||
155 | STATISTICS_NOTIFICATION = 0x9d, | ||
156 | |||
157 | /* RF-KILL commands and notifications */ | ||
158 | CARD_STATE_CMD = 0xa0, | ||
159 | CARD_STATE_NOTIFICATION = 0xa1, | ||
160 | |||
161 | REPLY_RX_PHY_CMD = 0xc0, | ||
162 | REPLY_RX_MPDU_CMD = 0xc1, | ||
163 | BA_NOTIF = 0xc5, | ||
164 | |||
165 | REPLY_DEBUG_CMD = 0xf0, | ||
166 | DEBUG_LOG_MSG = 0xf7, | ||
167 | |||
168 | /* D3 commands/notifications */ | ||
169 | D3_CONFIG_CMD = 0xd3, | ||
170 | PROT_OFFLOAD_CONFIG_CMD = 0xd4, | ||
171 | OFFLOADS_QUERY_CMD = 0xd5, | ||
172 | REMOTE_WAKE_CONFIG_CMD = 0xd6, | ||
173 | |||
174 | /* for WoWLAN in particular */ | ||
175 | WOWLAN_PATTERNS = 0xe0, | ||
176 | WOWLAN_CONFIGURATION = 0xe1, | ||
177 | WOWLAN_TSC_RSC_PARAM = 0xe2, | ||
178 | WOWLAN_TKIP_PARAM = 0xe3, | ||
179 | WOWLAN_KEK_KCK_MATERIAL = 0xe4, | ||
180 | WOWLAN_GET_STATUSES = 0xe5, | ||
181 | WOWLAN_TX_POWER_PER_DB = 0xe6, | ||
182 | |||
183 | /* and for NetDetect */ | ||
184 | NET_DETECT_CONFIG_CMD = 0x54, | ||
185 | NET_DETECT_PROFILES_QUERY_CMD = 0x56, | ||
186 | NET_DETECT_PROFILES_CMD = 0x57, | ||
187 | NET_DETECT_HOTSPOTS_CMD = 0x58, | ||
188 | NET_DETECT_HOTSPOTS_QUERY_CMD = 0x59, | ||
189 | |||
190 | REPLY_MAX = 0xff, | ||
191 | }; | ||
192 | |||
193 | /** | ||
194 | * struct iwl_cmd_response - generic response struct for most commands | ||
195 | * @status: status of the command asked, changes for each one | ||
196 | */ | ||
197 | struct iwl_cmd_response { | ||
198 | __le32 status; | ||
199 | }; | ||
200 | |||
201 | /* | ||
202 | * struct iwl_tx_ant_cfg_cmd | ||
203 | * @valid: valid antenna configuration | ||
204 | */ | ||
205 | struct iwl_tx_ant_cfg_cmd { | ||
206 | __le32 valid; | ||
207 | } __packed; | ||
208 | |||
209 | /* | ||
210 | * Calibration control struct. | ||
211 | * Sent as part of the phy configuration command. | ||
212 | * @flow_trigger: bitmap for which calibrations to perform according to | ||
213 | * flow triggers. | ||
214 | * @event_trigger: bitmap for which calibrations to perform according to | ||
215 | * event triggers. | ||
216 | */ | ||
217 | struct iwl_calib_ctrl { | ||
218 | __le32 flow_trigger; | ||
219 | __le32 event_trigger; | ||
220 | } __packed; | ||
221 | |||
222 | /* This enum defines the bitmap of various calibrations to enable in both | ||
223 | * init ucode and runtime ucode through CALIBRATION_CFG_CMD. | ||
224 | */ | ||
225 | enum iwl_calib_cfg { | ||
226 | IWL_CALIB_CFG_XTAL_IDX = BIT(0), | ||
227 | IWL_CALIB_CFG_TEMPERATURE_IDX = BIT(1), | ||
228 | IWL_CALIB_CFG_VOLTAGE_READ_IDX = BIT(2), | ||
229 | IWL_CALIB_CFG_PAPD_IDX = BIT(3), | ||
230 | IWL_CALIB_CFG_TX_PWR_IDX = BIT(4), | ||
231 | IWL_CALIB_CFG_DC_IDX = BIT(5), | ||
232 | IWL_CALIB_CFG_BB_FILTER_IDX = BIT(6), | ||
233 | IWL_CALIB_CFG_LO_LEAKAGE_IDX = BIT(7), | ||
234 | IWL_CALIB_CFG_TX_IQ_IDX = BIT(8), | ||
235 | IWL_CALIB_CFG_TX_IQ_SKEW_IDX = BIT(9), | ||
236 | IWL_CALIB_CFG_RX_IQ_IDX = BIT(10), | ||
237 | IWL_CALIB_CFG_RX_IQ_SKEW_IDX = BIT(11), | ||
238 | IWL_CALIB_CFG_SENSITIVITY_IDX = BIT(12), | ||
239 | IWL_CALIB_CFG_CHAIN_NOISE_IDX = BIT(13), | ||
240 | IWL_CALIB_CFG_DISCONNECTED_ANT_IDX = BIT(14), | ||
241 | IWL_CALIB_CFG_ANT_COUPLING_IDX = BIT(15), | ||
242 | IWL_CALIB_CFG_DAC_IDX = BIT(16), | ||
243 | IWL_CALIB_CFG_ABS_IDX = BIT(17), | ||
244 | IWL_CALIB_CFG_AGC_IDX = BIT(18), | ||
245 | }; | ||
246 | |||
247 | /* | ||
248 | * Phy configuration command. | ||
249 | */ | ||
250 | struct iwl_phy_cfg_cmd { | ||
251 | __le32 phy_cfg; | ||
252 | struct iwl_calib_ctrl calib_control; | ||
253 | } __packed; | ||
254 | |||
255 | #define PHY_CFG_RADIO_TYPE (BIT(0) | BIT(1)) | ||
256 | #define PHY_CFG_RADIO_STEP (BIT(2) | BIT(3)) | ||
257 | #define PHY_CFG_RADIO_DASH (BIT(4) | BIT(5)) | ||
258 | #define PHY_CFG_PRODUCT_NUMBER (BIT(6) | BIT(7)) | ||
259 | #define PHY_CFG_TX_CHAIN_A BIT(8) | ||
260 | #define PHY_CFG_TX_CHAIN_B BIT(9) | ||
261 | #define PHY_CFG_TX_CHAIN_C BIT(10) | ||
262 | #define PHY_CFG_RX_CHAIN_A BIT(12) | ||
263 | #define PHY_CFG_RX_CHAIN_B BIT(13) | ||
264 | #define PHY_CFG_RX_CHAIN_C BIT(14) | ||
265 | |||
266 | |||
267 | /* Target of the NVM_ACCESS_CMD */ | ||
268 | enum { | ||
269 | NVM_ACCESS_TARGET_CACHE = 0, | ||
270 | NVM_ACCESS_TARGET_OTP = 1, | ||
271 | NVM_ACCESS_TARGET_EEPROM = 2, | ||
272 | }; | ||
273 | |||
274 | /** | ||
275 | * struct iwl_nvm_access_cmd_ver1 - Request the device to send the NVM. | ||
276 | * @op_code: 0 - read, 1 - write. | ||
277 | * @target: NVM_ACCESS_TARGET_*. should be 0 for read. | ||
278 | * @cache_refresh: 0 - None, 1- NVM. | ||
279 | * @offset: offset in the nvm data. | ||
280 | * @length: of the chunk. | ||
281 | * @data: empty on read, the NVM chunk on write | ||
282 | */ | ||
283 | struct iwl_nvm_access_cmd_ver1 { | ||
284 | u8 op_code; | ||
285 | u8 target; | ||
286 | u8 cache_refresh; | ||
287 | u8 reserved; | ||
288 | __le16 offset; | ||
289 | __le16 length; | ||
290 | u8 data[]; | ||
291 | } __packed; /* NVM_ACCESS_CMD_API_S_VER_1 */ | ||
292 | |||
293 | /** | ||
294 | * struct iwl_nvm_access_resp_ver1 - response to NVM_ACCESS_CMD | ||
295 | * @offset: the offset in the nvm data | ||
296 | * @length: of the chunk | ||
297 | * @data: the nvm chunk on when NVM_ACCESS_CMD was read, nothing on write | ||
298 | */ | ||
299 | struct iwl_nvm_access_resp_ver1 { | ||
300 | __le16 offset; | ||
301 | __le16 length; | ||
302 | u8 data[]; | ||
303 | } __packed; /* NVM_ACCESS_CMD_RESP_API_S_VER_1 */ | ||
304 | |||
305 | /* Section types for NVM_ACCESS_CMD version 2 */ | ||
306 | enum { | ||
307 | NVM_SECTION_TYPE_HW = 0, | ||
308 | NVM_SECTION_TYPE_SW, | ||
309 | NVM_SECTION_TYPE_PAPD, | ||
310 | NVM_SECTION_TYPE_BT, | ||
311 | NVM_SECTION_TYPE_CALIBRATION, | ||
312 | NVM_SECTION_TYPE_PRODUCTION, | ||
313 | NVM_SECTION_TYPE_POST_FCS_CALIB, | ||
314 | NVM_NUM_OF_SECTIONS, | ||
315 | }; | ||
316 | |||
317 | /** | ||
318 | * struct iwl_nvm_access_cmd_ver2 - Request the device to send an NVM section | ||
319 | * @op_code: 0 - read, 1 - write | ||
320 | * @target: NVM_ACCESS_TARGET_* | ||
321 | * @type: NVM_SECTION_TYPE_* | ||
322 | * @offset: offset in bytes into the section | ||
323 | * @length: in bytes, to read/write | ||
324 | * @data: if write operation, the data to write. On read its empty | ||
325 | */ | ||
326 | struct iwl_nvm_access_cmd_ver2 { | ||
327 | u8 op_code; | ||
328 | u8 target; | ||
329 | __le16 type; | ||
330 | __le16 offset; | ||
331 | __le16 length; | ||
332 | u8 data[]; | ||
333 | } __packed; /* NVM_ACCESS_CMD_API_S_VER_2 */ | ||
334 | |||
335 | /** | ||
336 | * struct iwl_nvm_access_resp_ver2 - response to NVM_ACCESS_CMD | ||
337 | * @offset: offset in bytes into the section | ||
338 | * @length: in bytes, either how much was written or read | ||
339 | * @type: NVM_SECTION_TYPE_* | ||
340 | * @status: 0 for success, fail otherwise | ||
341 | * @data: if read operation, the data returned. Empty on write. | ||
342 | */ | ||
343 | struct iwl_nvm_access_resp_ver2 { | ||
344 | __le16 offset; | ||
345 | __le16 length; | ||
346 | __le16 type; | ||
347 | __le16 status; | ||
348 | u8 data[]; | ||
349 | } __packed; /* NVM_ACCESS_CMD_RESP_API_S_VER_2 */ | ||
350 | |||
351 | /* MVM_ALIVE 0x1 */ | ||
352 | |||
353 | /* alive response is_valid values */ | ||
354 | #define ALIVE_RESP_UCODE_OK BIT(0) | ||
355 | #define ALIVE_RESP_RFKILL BIT(1) | ||
356 | |||
357 | /* alive response ver_type values */ | ||
358 | enum { | ||
359 | FW_TYPE_HW = 0, | ||
360 | FW_TYPE_PROT = 1, | ||
361 | FW_TYPE_AP = 2, | ||
362 | FW_TYPE_WOWLAN = 3, | ||
363 | FW_TYPE_TIMING = 4, | ||
364 | FW_TYPE_WIPAN = 5 | ||
365 | }; | ||
366 | |||
367 | /* alive response ver_subtype values */ | ||
368 | enum { | ||
369 | FW_SUBTYPE_FULL_FEATURE = 0, | ||
370 | FW_SUBTYPE_BOOTSRAP = 1, /* Not valid */ | ||
371 | FW_SUBTYPE_REDUCED = 2, | ||
372 | FW_SUBTYPE_ALIVE_ONLY = 3, | ||
373 | FW_SUBTYPE_WOWLAN = 4, | ||
374 | FW_SUBTYPE_AP_SUBTYPE = 5, | ||
375 | FW_SUBTYPE_WIPAN = 6, | ||
376 | FW_SUBTYPE_INITIALIZE = 9 | ||
377 | }; | ||
378 | |||
379 | #define IWL_ALIVE_STATUS_ERR 0xDEAD | ||
380 | #define IWL_ALIVE_STATUS_OK 0xCAFE | ||
381 | |||
382 | #define IWL_ALIVE_FLG_RFKILL BIT(0) | ||
383 | |||
384 | struct mvm_alive_resp { | ||
385 | __le16 status; | ||
386 | __le16 flags; | ||
387 | u8 ucode_minor; | ||
388 | u8 ucode_major; | ||
389 | __le16 id; | ||
390 | u8 api_minor; | ||
391 | u8 api_major; | ||
392 | u8 ver_subtype; | ||
393 | u8 ver_type; | ||
394 | u8 mac; | ||
395 | u8 opt; | ||
396 | __le16 reserved2; | ||
397 | __le32 timestamp; | ||
398 | __le32 error_event_table_ptr; /* SRAM address for error log */ | ||
399 | __le32 log_event_table_ptr; /* SRAM address for event log */ | ||
400 | __le32 cpu_register_ptr; | ||
401 | __le32 dbgm_config_ptr; | ||
402 | __le32 alive_counter_ptr; | ||
403 | __le32 scd_base_ptr; /* SRAM address for SCD */ | ||
404 | } __packed; /* ALIVE_RES_API_S_VER_1 */ | ||
405 | |||
406 | /* Error response/notification */ | ||
407 | enum { | ||
408 | FW_ERR_UNKNOWN_CMD = 0x0, | ||
409 | FW_ERR_INVALID_CMD_PARAM = 0x1, | ||
410 | FW_ERR_SERVICE = 0x2, | ||
411 | FW_ERR_ARC_MEMORY = 0x3, | ||
412 | FW_ERR_ARC_CODE = 0x4, | ||
413 | FW_ERR_WATCH_DOG = 0x5, | ||
414 | FW_ERR_WEP_GRP_KEY_INDX = 0x10, | ||
415 | FW_ERR_WEP_KEY_SIZE = 0x11, | ||
416 | FW_ERR_OBSOLETE_FUNC = 0x12, | ||
417 | FW_ERR_UNEXPECTED = 0xFE, | ||
418 | FW_ERR_FATAL = 0xFF | ||
419 | }; | ||
420 | |||
421 | /** | ||
422 | * struct iwl_error_resp - FW error indication | ||
423 | * ( REPLY_ERROR = 0x2 ) | ||
424 | * @error_type: one of FW_ERR_* | ||
425 | * @cmd_id: the command ID for which the error occured | ||
426 | * @bad_cmd_seq_num: sequence number of the erroneous command | ||
427 | * @error_service: which service created the error, applicable only if | ||
428 | * error_type = 2, otherwise 0 | ||
429 | * @timestamp: TSF in usecs. | ||
430 | */ | ||
431 | struct iwl_error_resp { | ||
432 | __le32 error_type; | ||
433 | u8 cmd_id; | ||
434 | u8 reserved1; | ||
435 | __le16 bad_cmd_seq_num; | ||
436 | __le32 error_service; | ||
437 | __le64 timestamp; | ||
438 | } __packed; | ||
439 | |||
440 | |||
441 | /* Common PHY, MAC and Bindings definitions */ | ||
442 | |||
443 | #define MAX_MACS_IN_BINDING (3) | ||
444 | #define MAX_BINDINGS (4) | ||
445 | #define AUX_BINDING_INDEX (3) | ||
446 | #define MAX_PHYS (4) | ||
447 | |||
448 | /* Used to extract ID and color from the context dword */ | ||
449 | #define FW_CTXT_ID_POS (0) | ||
450 | #define FW_CTXT_ID_MSK (0xff << FW_CTXT_ID_POS) | ||
451 | #define FW_CTXT_COLOR_POS (8) | ||
452 | #define FW_CTXT_COLOR_MSK (0xff << FW_CTXT_COLOR_POS) | ||
453 | #define FW_CTXT_INVALID (0xffffffff) | ||
454 | |||
455 | #define FW_CMD_ID_AND_COLOR(_id, _color) ((_id << FW_CTXT_ID_POS) |\ | ||
456 | (_color << FW_CTXT_COLOR_POS)) | ||
457 | |||
458 | /* Possible actions on PHYs, MACs and Bindings */ | ||
459 | enum { | ||
460 | FW_CTXT_ACTION_STUB = 0, | ||
461 | FW_CTXT_ACTION_ADD, | ||
462 | FW_CTXT_ACTION_MODIFY, | ||
463 | FW_CTXT_ACTION_REMOVE, | ||
464 | FW_CTXT_ACTION_NUM | ||
465 | }; /* COMMON_CONTEXT_ACTION_API_E_VER_1 */ | ||
466 | |||
467 | /* Time Events */ | ||
468 | |||
469 | /* Time Event types, according to MAC type */ | ||
470 | enum iwl_time_event_type { | ||
471 | /* BSS Station Events */ | ||
472 | TE_BSS_STA_AGGRESSIVE_ASSOC, | ||
473 | TE_BSS_STA_ASSOC, | ||
474 | TE_BSS_EAP_DHCP_PROT, | ||
475 | TE_BSS_QUIET_PERIOD, | ||
476 | |||
477 | /* P2P Device Events */ | ||
478 | TE_P2P_DEVICE_DISCOVERABLE, | ||
479 | TE_P2P_DEVICE_LISTEN, | ||
480 | TE_P2P_DEVICE_ACTION_SCAN, | ||
481 | TE_P2P_DEVICE_FULL_SCAN, | ||
482 | |||
483 | /* P2P Client Events */ | ||
484 | TE_P2P_CLIENT_AGGRESSIVE_ASSOC, | ||
485 | TE_P2P_CLIENT_ASSOC, | ||
486 | TE_P2P_CLIENT_QUIET_PERIOD, | ||
487 | |||
488 | /* P2P GO Events */ | ||
489 | TE_P2P_GO_ASSOC_PROT, | ||
490 | TE_P2P_GO_REPETITIVE_NOA, | ||
491 | TE_P2P_GO_CT_WINDOW, | ||
492 | |||
493 | /* WiDi Sync Events */ | ||
494 | TE_WIDI_TX_SYNC, | ||
495 | |||
496 | TE_MAX | ||
497 | }; /* MAC_EVENT_TYPE_API_E_VER_1 */ | ||
498 | |||
499 | /* Time Event dependencies: none, on another TE, or in a specific time */ | ||
500 | enum { | ||
501 | TE_INDEPENDENT = 0, | ||
502 | TE_DEP_OTHER = 1, | ||
503 | TE_DEP_TSF = 2, | ||
504 | TE_EVENT_SOCIOPATHIC = 4, | ||
505 | }; /* MAC_EVENT_DEPENDENCY_POLICY_API_E_VER_2 */ | ||
506 | |||
507 | /* When to send Time Event notifications and to whom (internal = FW) */ | ||
508 | enum { | ||
509 | TE_NOTIF_NONE = 0, | ||
510 | TE_NOTIF_HOST_START = 0x1, | ||
511 | TE_NOTIF_HOST_END = 0x2, | ||
512 | TE_NOTIF_INTERNAL_START = 0x4, | ||
513 | TE_NOTIF_INTERNAL_END = 0x8 | ||
514 | }; /* MAC_EVENT_ACTION_API_E_VER_1 */ | ||
515 | |||
516 | /* | ||
517 | * @TE_FRAG_NONE: fragmentation of the time event is NOT allowed. | ||
518 | * @TE_FRAG_SINGLE: fragmentation of the time event is allowed, but only | ||
519 | * the first fragment is scheduled. | ||
520 | * @TE_FRAG_DUAL: fragmentation of the time event is allowed, but only | ||
521 | * the first 2 fragments are scheduled. | ||
522 | * @TE_FRAG_ENDLESS: fragmentation of the time event is allowed, and any number | ||
523 | * of fragments are valid. | ||
524 | * | ||
525 | * Other than the constant defined above, specifying a fragmentation value 'x' | ||
526 | * means that the event can be fragmented but only the first 'x' will be | ||
527 | * scheduled. | ||
528 | */ | ||
529 | enum { | ||
530 | TE_FRAG_NONE = 0, | ||
531 | TE_FRAG_SINGLE = 1, | ||
532 | TE_FRAG_DUAL = 2, | ||
533 | TE_FRAG_ENDLESS = 0xffffffff | ||
534 | }; | ||
535 | |||
536 | /* Repeat the time event endlessly (until removed) */ | ||
537 | #define TE_REPEAT_ENDLESS (0xffffffff) | ||
538 | /* If a Time Event has bounded repetitions, this is the maximal value */ | ||
539 | #define TE_REPEAT_MAX_MSK (0x0fffffff) | ||
540 | /* If a Time Event can be fragmented, this is the max number of fragments */ | ||
541 | #define TE_FRAG_MAX_MSK (0x0fffffff) | ||
542 | |||
543 | /** | ||
544 | * struct iwl_time_event_cmd - configuring Time Events | ||
545 | * ( TIME_EVENT_CMD = 0x29 ) | ||
546 | * @id_and_color: ID and color of the relevant MAC | ||
547 | * @action: action to perform, one of FW_CTXT_ACTION_* | ||
548 | * @id: this field has two meanings, depending on the action: | ||
549 | * If the action is ADD, then it means the type of event to add. | ||
550 | * For all other actions it is the unique event ID assigned when the | ||
551 | * event was added by the FW. | ||
552 | * @apply_time: When to start the Time Event (in GP2) | ||
553 | * @max_delay: maximum delay to event's start (apply time), in TU | ||
554 | * @depends_on: the unique ID of the event we depend on (if any) | ||
555 | * @interval: interval between repetitions, in TU | ||
556 | * @interval_reciprocal: 2^32 / interval | ||
557 | * @duration: duration of event in TU | ||
558 | * @repeat: how many repetitions to do, can be TE_REPEAT_ENDLESS | ||
559 | * @dep_policy: one of TE_INDEPENDENT, TE_DEP_OTHER, TE_DEP_TSF | ||
560 | * @is_present: 0 or 1, are we present or absent during the Time Event | ||
561 | * @max_frags: maximal number of fragments the Time Event can be divided to | ||
562 | * @notify: notifications using TE_NOTIF_* (whom to notify when) | ||
563 | */ | ||
564 | struct iwl_time_event_cmd { | ||
565 | /* COMMON_INDEX_HDR_API_S_VER_1 */ | ||
566 | __le32 id_and_color; | ||
567 | __le32 action; | ||
568 | __le32 id; | ||
569 | /* MAC_TIME_EVENT_DATA_API_S_VER_1 */ | ||
570 | __le32 apply_time; | ||
571 | __le32 max_delay; | ||
572 | __le32 dep_policy; | ||
573 | __le32 depends_on; | ||
574 | __le32 is_present; | ||
575 | __le32 max_frags; | ||
576 | __le32 interval; | ||
577 | __le32 interval_reciprocal; | ||
578 | __le32 duration; | ||
579 | __le32 repeat; | ||
580 | __le32 notify; | ||
581 | } __packed; /* MAC_TIME_EVENT_CMD_API_S_VER_1 */ | ||
582 | |||
583 | /** | ||
584 | * struct iwl_time_event_resp - response structure to iwl_time_event_cmd | ||
585 | * @status: bit 0 indicates success, all others specify errors | ||
586 | * @id: the Time Event type | ||
587 | * @unique_id: the unique ID assigned (in ADD) or given (others) to the TE | ||
588 | * @id_and_color: ID and color of the relevant MAC | ||
589 | */ | ||
590 | struct iwl_time_event_resp { | ||
591 | __le32 status; | ||
592 | __le32 id; | ||
593 | __le32 unique_id; | ||
594 | __le32 id_and_color; | ||
595 | } __packed; /* MAC_TIME_EVENT_RSP_API_S_VER_1 */ | ||
596 | |||
597 | /** | ||
598 | * struct iwl_time_event_notif - notifications of time event start/stop | ||
599 | * ( TIME_EVENT_NOTIFICATION = 0x2a ) | ||
600 | * @timestamp: action timestamp in GP2 | ||
601 | * @session_id: session's unique id | ||
602 | * @unique_id: unique id of the Time Event itself | ||
603 | * @id_and_color: ID and color of the relevant MAC | ||
604 | * @action: one of TE_NOTIF_START or TE_NOTIF_END | ||
605 | * @status: true if scheduled, false otherwise (not executed) | ||
606 | */ | ||
607 | struct iwl_time_event_notif { | ||
608 | __le32 timestamp; | ||
609 | __le32 session_id; | ||
610 | __le32 unique_id; | ||
611 | __le32 id_and_color; | ||
612 | __le32 action; | ||
613 | __le32 status; | ||
614 | } __packed; /* MAC_TIME_EVENT_NTFY_API_S_VER_1 */ | ||
615 | |||
616 | |||
617 | /* Bindings and Time Quota */ | ||
618 | |||
619 | /** | ||
620 | * struct iwl_binding_cmd - configuring bindings | ||
621 | * ( BINDING_CONTEXT_CMD = 0x2b ) | ||
622 | * @id_and_color: ID and color of the relevant Binding | ||
623 | * @action: action to perform, one of FW_CTXT_ACTION_* | ||
624 | * @macs: array of MAC id and colors which belong to the binding | ||
625 | * @phy: PHY id and color which belongs to the binding | ||
626 | */ | ||
627 | struct iwl_binding_cmd { | ||
628 | /* COMMON_INDEX_HDR_API_S_VER_1 */ | ||
629 | __le32 id_and_color; | ||
630 | __le32 action; | ||
631 | /* BINDING_DATA_API_S_VER_1 */ | ||
632 | __le32 macs[MAX_MACS_IN_BINDING]; | ||
633 | __le32 phy; | ||
634 | } __packed; /* BINDING_CMD_API_S_VER_1 */ | ||
635 | |||
636 | /** | ||
637 | * struct iwl_time_quota_data - configuration of time quota per binding | ||
638 | * @id_and_color: ID and color of the relevant Binding | ||
639 | * @quota: absolute time quota in TU. The scheduler will try to divide the | ||
640 | * remainig quota (after Time Events) according to this quota. | ||
641 | * @max_duration: max uninterrupted context duration in TU | ||
642 | */ | ||
643 | struct iwl_time_quota_data { | ||
644 | __le32 id_and_color; | ||
645 | __le32 quota; | ||
646 | __le32 max_duration; | ||
647 | } __packed; /* TIME_QUOTA_DATA_API_S_VER_1 */ | ||
648 | |||
649 | /** | ||
650 | * struct iwl_time_quota_cmd - configuration of time quota between bindings | ||
651 | * ( TIME_QUOTA_CMD = 0x2c ) | ||
652 | * @quotas: allocations per binding | ||
653 | */ | ||
654 | struct iwl_time_quota_cmd { | ||
655 | struct iwl_time_quota_data quotas[MAX_BINDINGS]; | ||
656 | } __packed; /* TIME_QUOTA_ALLOCATION_CMD_API_S_VER_1 */ | ||
657 | |||
658 | |||
659 | /* PHY context */ | ||
660 | |||
661 | /* Supported bands */ | ||
662 | #define PHY_BAND_5 (0) | ||
663 | #define PHY_BAND_24 (1) | ||
664 | |||
665 | /* Supported channel width, vary if there is VHT support */ | ||
666 | #define PHY_VHT_CHANNEL_MODE20 (0x0) | ||
667 | #define PHY_VHT_CHANNEL_MODE40 (0x1) | ||
668 | #define PHY_VHT_CHANNEL_MODE80 (0x2) | ||
669 | #define PHY_VHT_CHANNEL_MODE160 (0x3) | ||
670 | |||
671 | /* | ||
672 | * Control channel position: | ||
673 | * For legacy set bit means upper channel, otherwise lower. | ||
674 | * For VHT - bit-2 marks if the control is lower/upper relative to center-freq | ||
675 | * bits-1:0 mark the distance from the center freq. for 20Mhz, offset is 0. | ||
676 | * center_freq | ||
677 | * | | ||
678 | * 40Mhz |_______|_______| | ||
679 | * 80Mhz |_______|_______|_______|_______| | ||
680 | * 160Mhz |_______|_______|_______|_______|_______|_______|_______|_______| | ||
681 | * code 011 010 001 000 | 100 101 110 111 | ||
682 | */ | ||
683 | #define PHY_VHT_CTRL_POS_1_BELOW (0x0) | ||
684 | #define PHY_VHT_CTRL_POS_2_BELOW (0x1) | ||
685 | #define PHY_VHT_CTRL_POS_3_BELOW (0x2) | ||
686 | #define PHY_VHT_CTRL_POS_4_BELOW (0x3) | ||
687 | #define PHY_VHT_CTRL_POS_1_ABOVE (0x4) | ||
688 | #define PHY_VHT_CTRL_POS_2_ABOVE (0x5) | ||
689 | #define PHY_VHT_CTRL_POS_3_ABOVE (0x6) | ||
690 | #define PHY_VHT_CTRL_POS_4_ABOVE (0x7) | ||
691 | |||
692 | /* | ||
693 | * @band: PHY_BAND_* | ||
694 | * @channel: channel number | ||
695 | * @width: PHY_[VHT|LEGACY]_CHANNEL_* | ||
696 | * @ctrl channel: PHY_[VHT|LEGACY]_CTRL_* | ||
697 | */ | ||
698 | struct iwl_fw_channel_info { | ||
699 | u8 band; | ||
700 | u8 channel; | ||
701 | u8 width; | ||
702 | u8 ctrl_pos; | ||
703 | } __packed; | ||
704 | |||
705 | #define PHY_RX_CHAIN_DRIVER_FORCE_POS (0) | ||
706 | #define PHY_RX_CHAIN_DRIVER_FORCE_MSK \ | ||
707 | (0x1 << PHY_RX_CHAIN_DRIVER_FORCE_POS) | ||
708 | #define PHY_RX_CHAIN_VALID_POS (1) | ||
709 | #define PHY_RX_CHAIN_VALID_MSK \ | ||
710 | (0x7 << PHY_RX_CHAIN_VALID_POS) | ||
711 | #define PHY_RX_CHAIN_FORCE_SEL_POS (4) | ||
712 | #define PHY_RX_CHAIN_FORCE_SEL_MSK \ | ||
713 | (0x7 << PHY_RX_CHAIN_FORCE_SEL_POS) | ||
714 | #define PHY_RX_CHAIN_FORCE_MIMO_SEL_POS (7) | ||
715 | #define PHY_RX_CHAIN_FORCE_MIMO_SEL_MSK \ | ||
716 | (0x7 << PHY_RX_CHAIN_FORCE_MIMO_SEL_POS) | ||
717 | #define PHY_RX_CHAIN_CNT_POS (10) | ||
718 | #define PHY_RX_CHAIN_CNT_MSK \ | ||
719 | (0x3 << PHY_RX_CHAIN_CNT_POS) | ||
720 | #define PHY_RX_CHAIN_MIMO_CNT_POS (12) | ||
721 | #define PHY_RX_CHAIN_MIMO_CNT_MSK \ | ||
722 | (0x3 << PHY_RX_CHAIN_MIMO_CNT_POS) | ||
723 | #define PHY_RX_CHAIN_MIMO_FORCE_POS (14) | ||
724 | #define PHY_RX_CHAIN_MIMO_FORCE_MSK \ | ||
725 | (0x1 << PHY_RX_CHAIN_MIMO_FORCE_POS) | ||
726 | |||
727 | /* TODO: fix the value, make it depend on firmware at runtime? */ | ||
728 | #define NUM_PHY_CTX 3 | ||
729 | |||
730 | /* TODO: complete missing documentation */ | ||
731 | /** | ||
732 | * struct iwl_phy_context_cmd - config of the PHY context | ||
733 | * ( PHY_CONTEXT_CMD = 0x8 ) | ||
734 | * @id_and_color: ID and color of the relevant Binding | ||
735 | * @action: action to perform, one of FW_CTXT_ACTION_* | ||
736 | * @apply_time: 0 means immediate apply and context switch. | ||
737 | * other value means apply new params after X usecs | ||
738 | * @tx_param_color: ??? | ||
739 | * @channel_info: | ||
740 | * @txchain_info: ??? | ||
741 | * @rxchain_info: ??? | ||
742 | * @acquisition_data: ??? | ||
743 | * @dsp_cfg_flags: set to 0 | ||
744 | */ | ||
745 | struct iwl_phy_context_cmd { | ||
746 | /* COMMON_INDEX_HDR_API_S_VER_1 */ | ||
747 | __le32 id_and_color; | ||
748 | __le32 action; | ||
749 | /* PHY_CONTEXT_DATA_API_S_VER_1 */ | ||
750 | __le32 apply_time; | ||
751 | __le32 tx_param_color; | ||
752 | struct iwl_fw_channel_info ci; | ||
753 | __le32 txchain_info; | ||
754 | __le32 rxchain_info; | ||
755 | __le32 acquisition_data; | ||
756 | __le32 dsp_cfg_flags; | ||
757 | } __packed; /* PHY_CONTEXT_CMD_API_VER_1 */ | ||
758 | |||
759 | #define IWL_RX_INFO_PHY_CNT 8 | ||
760 | #define IWL_RX_INFO_AGC_IDX 1 | ||
761 | #define IWL_RX_INFO_RSSI_AB_IDX 2 | ||
762 | #define IWL_RX_INFO_RSSI_C_IDX 3 | ||
763 | #define IWL_OFDM_AGC_DB_MSK 0xfe00 | ||
764 | #define IWL_OFDM_AGC_DB_POS 9 | ||
765 | #define IWL_OFDM_RSSI_INBAND_A_MSK 0x00ff | ||
766 | #define IWL_OFDM_RSSI_ALLBAND_A_MSK 0xff00 | ||
767 | #define IWL_OFDM_RSSI_A_POS 0 | ||
768 | #define IWL_OFDM_RSSI_INBAND_B_MSK 0xff0000 | ||
769 | #define IWL_OFDM_RSSI_ALLBAND_B_MSK 0xff000000 | ||
770 | #define IWL_OFDM_RSSI_B_POS 16 | ||
771 | #define IWL_OFDM_RSSI_INBAND_C_MSK 0x00ff | ||
772 | #define IWL_OFDM_RSSI_ALLBAND_C_MSK 0xff00 | ||
773 | #define IWL_OFDM_RSSI_C_POS 0 | ||
774 | |||
775 | /** | ||
776 | * struct iwl_rx_phy_info - phy info | ||
777 | * (REPLY_RX_PHY_CMD = 0xc0) | ||
778 | * @non_cfg_phy_cnt: non configurable DSP phy data byte count | ||
779 | * @cfg_phy_cnt: configurable DSP phy data byte count | ||
780 | * @stat_id: configurable DSP phy data set ID | ||
781 | * @reserved1: | ||
782 | * @system_timestamp: GP2 at on air rise | ||
783 | * @timestamp: TSF at on air rise | ||
784 | * @beacon_time_stamp: beacon at on-air rise | ||
785 | * @phy_flags: general phy flags: band, modulation, ... | ||
786 | * @channel: channel number | ||
787 | * @non_cfg_phy_buf: for various implementations of non_cfg_phy | ||
788 | * @rate_n_flags: RATE_MCS_* | ||
789 | * @byte_count: frame's byte-count | ||
790 | * @frame_time: frame's time on the air, based on byte count and frame rate | ||
791 | * calculation | ||
792 | * | ||
793 | * Before each Rx, the device sends this data. It contains PHY information | ||
794 | * about the reception of the packet. | ||
795 | */ | ||
796 | struct iwl_rx_phy_info { | ||
797 | u8 non_cfg_phy_cnt; | ||
798 | u8 cfg_phy_cnt; | ||
799 | u8 stat_id; | ||
800 | u8 reserved1; | ||
801 | __le32 system_timestamp; | ||
802 | __le64 timestamp; | ||
803 | __le32 beacon_time_stamp; | ||
804 | __le16 phy_flags; | ||
805 | __le16 channel; | ||
806 | __le32 non_cfg_phy[IWL_RX_INFO_PHY_CNT]; | ||
807 | __le32 rate_n_flags; | ||
808 | __le32 byte_count; | ||
809 | __le16 reserved2; | ||
810 | __le16 frame_time; | ||
811 | } __packed; | ||
812 | |||
813 | struct iwl_rx_mpdu_res_start { | ||
814 | __le16 byte_count; | ||
815 | __le16 reserved; | ||
816 | } __packed; | ||
817 | |||
818 | /** | ||
819 | * enum iwl_rx_phy_flags - to parse %iwl_rx_phy_info phy_flags | ||
820 | * @RX_RES_PHY_FLAGS_BAND_24: true if the packet was received on 2.4 band | ||
821 | * @RX_RES_PHY_FLAGS_MOD_CCK: | ||
822 | * @RX_RES_PHY_FLAGS_SHORT_PREAMBLE: true if packet's preamble was short | ||
823 | * @RX_RES_PHY_FLAGS_NARROW_BAND: | ||
824 | * @RX_RES_PHY_FLAGS_ANTENNA: antenna on which the packet was received | ||
825 | * @RX_RES_PHY_FLAGS_AGG: set if the packet was part of an A-MPDU | ||
826 | * @RX_RES_PHY_FLAGS_OFDM_HT: The frame was an HT frame | ||
827 | * @RX_RES_PHY_FLAGS_OFDM_GF: The frame used GF preamble | ||
828 | * @RX_RES_PHY_FLAGS_OFDM_VHT: The frame was a VHT frame | ||
829 | */ | ||
830 | enum iwl_rx_phy_flags { | ||
831 | RX_RES_PHY_FLAGS_BAND_24 = BIT(0), | ||
832 | RX_RES_PHY_FLAGS_MOD_CCK = BIT(1), | ||
833 | RX_RES_PHY_FLAGS_SHORT_PREAMBLE = BIT(2), | ||
834 | RX_RES_PHY_FLAGS_NARROW_BAND = BIT(3), | ||
835 | RX_RES_PHY_FLAGS_ANTENNA = (0x7 << 4), | ||
836 | RX_RES_PHY_FLAGS_ANTENNA_POS = 4, | ||
837 | RX_RES_PHY_FLAGS_AGG = BIT(7), | ||
838 | RX_RES_PHY_FLAGS_OFDM_HT = BIT(8), | ||
839 | RX_RES_PHY_FLAGS_OFDM_GF = BIT(9), | ||
840 | RX_RES_PHY_FLAGS_OFDM_VHT = BIT(10), | ||
841 | }; | ||
842 | |||
843 | /** | ||
844 | * enum iwl_mvm_rx_status - written by fw for each Rx packet | ||
845 | * @RX_MPDU_RES_STATUS_CRC_OK: CRC is fine | ||
846 | * @RX_MPDU_RES_STATUS_OVERRUN_OK: there was no RXE overflow | ||
847 | * @RX_MPDU_RES_STATUS_SRC_STA_FOUND: | ||
848 | * @RX_MPDU_RES_STATUS_KEY_VALID: | ||
849 | * @RX_MPDU_RES_STATUS_KEY_PARAM_OK: | ||
850 | * @RX_MPDU_RES_STATUS_ICV_OK: ICV is fine, if not, the packet is destroyed | ||
851 | * @RX_MPDU_RES_STATUS_MIC_OK: used for CCM alg only. TKIP MIC is checked | ||
852 | * in the driver. | ||
853 | * @RX_MPDU_RES_STATUS_TTAK_OK: TTAK is fine | ||
854 | * @RX_MPDU_RES_STATUS_MNG_FRAME_REPLAY_ERR: valid for alg = CCM_CMAC or | ||
855 | * alg = CCM only. Checks replay attack for 11w frames. Relevant only if | ||
856 | * %RX_MPDU_RES_STATUS_ROBUST_MNG_FRAME is set. | ||
857 | * @RX_MPDU_RES_STATUS_SEC_NO_ENC: this frame is not encrypted | ||
858 | * @RX_MPDU_RES_STATUS_SEC_WEP_ENC: this frame is encrypted using WEP | ||
859 | * @RX_MPDU_RES_STATUS_SEC_CCM_ENC: this frame is encrypted using CCM | ||
860 | * @RX_MPDU_RES_STATUS_SEC_TKIP_ENC: this frame is encrypted using TKIP | ||
861 | * @RX_MPDU_RES_STATUS_SEC_CCM_CMAC_ENC: this frame is encrypted using CCM_CMAC | ||
862 | * @RX_MPDU_RES_STATUS_SEC_ENC_ERR: this frame couldn't be decrypted | ||
863 | * @RX_MPDU_RES_STATUS_SEC_ENC_MSK: bitmask of the encryption algorithm | ||
864 | * @RX_MPDU_RES_STATUS_DEC_DONE: this frame has been successfully decrypted | ||
865 | * @RX_MPDU_RES_STATUS_PROTECT_FRAME_BIT_CMP: | ||
866 | * @RX_MPDU_RES_STATUS_EXT_IV_BIT_CMP: | ||
867 | * @RX_MPDU_RES_STATUS_KEY_ID_CMP_BIT: | ||
868 | * @RX_MPDU_RES_STATUS_ROBUST_MNG_FRAME: this frame is an 11w management frame | ||
869 | * @RX_MPDU_RES_STATUS_HASH_INDEX_MSK: | ||
870 | * @RX_MPDU_RES_STATUS_STA_ID_MSK: | ||
871 | * @RX_MPDU_RES_STATUS_RRF_KILL: | ||
872 | * @RX_MPDU_RES_STATUS_FILTERING_MSK: | ||
873 | * @RX_MPDU_RES_STATUS2_FILTERING_MSK: | ||
874 | */ | ||
875 | enum iwl_mvm_rx_status { | ||
876 | RX_MPDU_RES_STATUS_CRC_OK = BIT(0), | ||
877 | RX_MPDU_RES_STATUS_OVERRUN_OK = BIT(1), | ||
878 | RX_MPDU_RES_STATUS_SRC_STA_FOUND = BIT(2), | ||
879 | RX_MPDU_RES_STATUS_KEY_VALID = BIT(3), | ||
880 | RX_MPDU_RES_STATUS_KEY_PARAM_OK = BIT(4), | ||
881 | RX_MPDU_RES_STATUS_ICV_OK = BIT(5), | ||
882 | RX_MPDU_RES_STATUS_MIC_OK = BIT(6), | ||
883 | RX_MPDU_RES_STATUS_TTAK_OK = BIT(7), | ||
884 | RX_MPDU_RES_STATUS_MNG_FRAME_REPLAY_ERR = BIT(7), | ||
885 | RX_MPDU_RES_STATUS_SEC_NO_ENC = (0 << 8), | ||
886 | RX_MPDU_RES_STATUS_SEC_WEP_ENC = (1 << 8), | ||
887 | RX_MPDU_RES_STATUS_SEC_CCM_ENC = (2 << 8), | ||
888 | RX_MPDU_RES_STATUS_SEC_TKIP_ENC = (3 << 8), | ||
889 | RX_MPDU_RES_STATUS_SEC_CCM_CMAC_ENC = (6 << 8), | ||
890 | RX_MPDU_RES_STATUS_SEC_ENC_ERR = (7 << 8), | ||
891 | RX_MPDU_RES_STATUS_SEC_ENC_MSK = (7 << 8), | ||
892 | RX_MPDU_RES_STATUS_DEC_DONE = BIT(11), | ||
893 | RX_MPDU_RES_STATUS_PROTECT_FRAME_BIT_CMP = BIT(12), | ||
894 | RX_MPDU_RES_STATUS_EXT_IV_BIT_CMP = BIT(13), | ||
895 | RX_MPDU_RES_STATUS_KEY_ID_CMP_BIT = BIT(14), | ||
896 | RX_MPDU_RES_STATUS_ROBUST_MNG_FRAME = BIT(15), | ||
897 | RX_MPDU_RES_STATUS_HASH_INDEX_MSK = (0x3F0000), | ||
898 | RX_MPDU_RES_STATUS_STA_ID_MSK = (0x1f000000), | ||
899 | RX_MPDU_RES_STATUS_RRF_KILL = BIT(29), | ||
900 | RX_MPDU_RES_STATUS_FILTERING_MSK = (0xc00000), | ||
901 | RX_MPDU_RES_STATUS2_FILTERING_MSK = (0xc0000000), | ||
902 | }; | ||
903 | |||
904 | /** | ||
905 | * struct iwl_radio_version_notif - information on the radio version | ||
906 | * ( RADIO_VERSION_NOTIFICATION = 0x68 ) | ||
907 | * @radio_flavor: | ||
908 | * @radio_step: | ||
909 | * @radio_dash: | ||
910 | */ | ||
911 | struct iwl_radio_version_notif { | ||
912 | __le32 radio_flavor; | ||
913 | __le32 radio_step; | ||
914 | __le32 radio_dash; | ||
915 | } __packed; /* RADIO_VERSION_NOTOFICATION_S_VER_1 */ | ||
916 | |||
917 | enum iwl_card_state_flags { | ||
918 | CARD_ENABLED = 0x00, | ||
919 | HW_CARD_DISABLED = 0x01, | ||
920 | SW_CARD_DISABLED = 0x02, | ||
921 | CT_KILL_CARD_DISABLED = 0x04, | ||
922 | HALT_CARD_DISABLED = 0x08, | ||
923 | CARD_DISABLED_MSK = 0x0f, | ||
924 | CARD_IS_RX_ON = 0x10, | ||
925 | }; | ||
926 | |||
927 | /** | ||
928 | * struct iwl_radio_version_notif - information on the radio version | ||
929 | * ( CARD_STATE_NOTIFICATION = 0xa1 ) | ||
930 | * @flags: %iwl_card_state_flags | ||
931 | */ | ||
932 | struct iwl_card_state_notif { | ||
933 | __le32 flags; | ||
934 | } __packed; /* CARD_STATE_NTFY_API_S_VER_1 */ | ||
935 | |||
936 | /** | ||
937 | * struct iwl_set_calib_default_cmd - set default value for calibration. | ||
938 | * ( SET_CALIB_DEFAULT_CMD = 0x8e ) | ||
939 | * @calib_index: the calibration to set value for | ||
940 | * @length: of data | ||
941 | * @data: the value to set for the calibration result | ||
942 | */ | ||
943 | struct iwl_set_calib_default_cmd { | ||
944 | __le16 calib_index; | ||
945 | __le16 length; | ||
946 | u8 data[0]; | ||
947 | } __packed; /* PHY_CALIB_OVERRIDE_VALUES_S */ | ||
948 | |||
949 | #endif /* __fw_api_h__ */ | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c new file mode 100644 index 000000000000..90473c2ba1c7 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c | |||
@@ -0,0 +1,644 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called LICENSE.GPL. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | * | ||
62 | *****************************************************************************/ | ||
63 | #include <net/mac80211.h> | ||
64 | |||
65 | #include "iwl-trans.h" | ||
66 | #include "iwl-op-mode.h" | ||
67 | #include "iwl-fw.h" | ||
68 | #include "iwl-debug.h" | ||
69 | #include "iwl-csr.h" /* for iwl_mvm_rx_card_state_notif */ | ||
70 | #include "iwl-io.h" /* for iwl_mvm_rx_card_state_notif */ | ||
71 | #include "iwl-eeprom-parse.h" | ||
72 | |||
73 | #include "mvm.h" | ||
74 | #include "iwl-phy-db.h" | ||
75 | |||
76 | #define MVM_UCODE_ALIVE_TIMEOUT HZ | ||
77 | #define MVM_UCODE_CALIB_TIMEOUT (2*HZ) | ||
78 | |||
79 | #define UCODE_VALID_OK cpu_to_le32(0x1) | ||
80 | |||
81 | /* Default calibration values for WkP - set to INIT image w/o running */ | ||
82 | static const u8 wkp_calib_values_bb_filter[] = { 0xbf, 0x00, 0x5f, 0x00, 0x2f, | ||
83 | 0x00, 0x18, 0x00 }; | ||
84 | static const u8 wkp_calib_values_rx_dc[] = { 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, | ||
85 | 0x7f, 0x7f, 0x7f }; | ||
86 | static const u8 wkp_calib_values_tx_lo[] = { 0x00, 0x00, 0x00, 0x00 }; | ||
87 | static const u8 wkp_calib_values_tx_iq[] = { 0xff, 0x00, 0xff, 0x00, 0x00, | ||
88 | 0x00 }; | ||
89 | static const u8 wkp_calib_values_rx_iq[] = { 0xff, 0x00, 0x00, 0x00 }; | ||
90 | static const u8 wkp_calib_values_rx_iq_skew[] = { 0x00, 0x00, 0x01, 0x00 }; | ||
91 | static const u8 wkp_calib_values_tx_iq_skew[] = { 0x01, 0x00, 0x00, 0x00 }; | ||
92 | static const u8 wkp_calib_values_xtal[] = { 0xd2, 0xd2 }; | ||
93 | |||
94 | struct iwl_calib_default_data { | ||
95 | u16 size; | ||
96 | void *data; | ||
97 | }; | ||
98 | |||
99 | #define CALIB_SIZE_N_DATA(_buf) {.size = sizeof(_buf), .data = &_buf} | ||
100 | |||
101 | static const struct iwl_calib_default_data wkp_calib_default_data[12] = { | ||
102 | [5] = CALIB_SIZE_N_DATA(wkp_calib_values_rx_dc), | ||
103 | [6] = CALIB_SIZE_N_DATA(wkp_calib_values_bb_filter), | ||
104 | [7] = CALIB_SIZE_N_DATA(wkp_calib_values_tx_lo), | ||
105 | [8] = CALIB_SIZE_N_DATA(wkp_calib_values_tx_iq), | ||
106 | [9] = CALIB_SIZE_N_DATA(wkp_calib_values_tx_iq_skew), | ||
107 | [10] = CALIB_SIZE_N_DATA(wkp_calib_values_rx_iq), | ||
108 | [11] = CALIB_SIZE_N_DATA(wkp_calib_values_rx_iq_skew), | ||
109 | }; | ||
110 | |||
111 | struct iwl_mvm_alive_data { | ||
112 | bool valid; | ||
113 | u32 scd_base_addr; | ||
114 | }; | ||
115 | |||
116 | static inline const struct fw_img * | ||
117 | iwl_get_ucode_image(struct iwl_mvm *mvm, enum iwl_ucode_type ucode_type) | ||
118 | { | ||
119 | if (ucode_type >= IWL_UCODE_TYPE_MAX) | ||
120 | return NULL; | ||
121 | |||
122 | return &mvm->fw->img[ucode_type]; | ||
123 | } | ||
124 | |||
125 | static int iwl_send_tx_ant_cfg(struct iwl_mvm *mvm, u8 valid_tx_ant) | ||
126 | { | ||
127 | struct iwl_tx_ant_cfg_cmd tx_ant_cmd = { | ||
128 | .valid = cpu_to_le32(valid_tx_ant), | ||
129 | }; | ||
130 | |||
131 | IWL_DEBUG_HC(mvm, "select valid tx ant: %u\n", valid_tx_ant); | ||
132 | return iwl_mvm_send_cmd_pdu(mvm, TX_ANT_CONFIGURATION_CMD, CMD_SYNC, | ||
133 | sizeof(tx_ant_cmd), &tx_ant_cmd); | ||
134 | } | ||
135 | |||
136 | static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait, | ||
137 | struct iwl_rx_packet *pkt, void *data) | ||
138 | { | ||
139 | struct iwl_mvm *mvm = | ||
140 | container_of(notif_wait, struct iwl_mvm, notif_wait); | ||
141 | struct iwl_mvm_alive_data *alive_data = data; | ||
142 | struct mvm_alive_resp *palive; | ||
143 | |||
144 | palive = (void *)pkt->data; | ||
145 | |||
146 | mvm->error_event_table = le32_to_cpu(palive->error_event_table_ptr); | ||
147 | mvm->log_event_table = le32_to_cpu(palive->log_event_table_ptr); | ||
148 | alive_data->scd_base_addr = le32_to_cpu(palive->scd_base_ptr); | ||
149 | |||
150 | alive_data->valid = le16_to_cpu(palive->status) == IWL_ALIVE_STATUS_OK; | ||
151 | IWL_DEBUG_FW(mvm, "Alive ucode status 0x%04x revision 0x%01X 0x%01X\n", | ||
152 | le16_to_cpu(palive->status), palive->ver_type, | ||
153 | palive->ver_subtype); | ||
154 | |||
155 | return true; | ||
156 | } | ||
157 | |||
158 | static bool iwl_wait_phy_db_entry(struct iwl_notif_wait_data *notif_wait, | ||
159 | struct iwl_rx_packet *pkt, void *data) | ||
160 | { | ||
161 | struct iwl_phy_db *phy_db = data; | ||
162 | |||
163 | if (pkt->hdr.cmd != CALIB_RES_NOTIF_PHY_DB) { | ||
164 | WARN_ON(pkt->hdr.cmd != INIT_COMPLETE_NOTIF); | ||
165 | return true; | ||
166 | } | ||
167 | |||
168 | WARN_ON(iwl_phy_db_set_section(phy_db, pkt, GFP_ATOMIC)); | ||
169 | |||
170 | return false; | ||
171 | } | ||
172 | |||
173 | static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, | ||
174 | enum iwl_ucode_type ucode_type) | ||
175 | { | ||
176 | struct iwl_notification_wait alive_wait; | ||
177 | struct iwl_mvm_alive_data alive_data; | ||
178 | const struct fw_img *fw; | ||
179 | int ret, i; | ||
180 | enum iwl_ucode_type old_type = mvm->cur_ucode; | ||
181 | static const u8 alive_cmd[] = { MVM_ALIVE }; | ||
182 | |||
183 | mvm->cur_ucode = ucode_type; | ||
184 | fw = iwl_get_ucode_image(mvm, ucode_type); | ||
185 | |||
186 | mvm->ucode_loaded = false; | ||
187 | |||
188 | if (!fw) | ||
189 | return -EINVAL; | ||
190 | |||
191 | iwl_init_notification_wait(&mvm->notif_wait, &alive_wait, | ||
192 | alive_cmd, ARRAY_SIZE(alive_cmd), | ||
193 | iwl_alive_fn, &alive_data); | ||
194 | |||
195 | ret = iwl_trans_start_fw(mvm->trans, fw, ucode_type == IWL_UCODE_INIT); | ||
196 | if (ret) { | ||
197 | mvm->cur_ucode = old_type; | ||
198 | iwl_remove_notification(&mvm->notif_wait, &alive_wait); | ||
199 | return ret; | ||
200 | } | ||
201 | |||
202 | /* | ||
203 | * Some things may run in the background now, but we | ||
204 | * just wait for the ALIVE notification here. | ||
205 | */ | ||
206 | ret = iwl_wait_notification(&mvm->notif_wait, &alive_wait, | ||
207 | MVM_UCODE_ALIVE_TIMEOUT); | ||
208 | if (ret) { | ||
209 | mvm->cur_ucode = old_type; | ||
210 | return ret; | ||
211 | } | ||
212 | |||
213 | if (!alive_data.valid) { | ||
214 | IWL_ERR(mvm, "Loaded ucode is not valid!\n"); | ||
215 | mvm->cur_ucode = old_type; | ||
216 | return -EIO; | ||
217 | } | ||
218 | |||
219 | iwl_trans_fw_alive(mvm->trans, alive_data.scd_base_addr); | ||
220 | |||
221 | /* | ||
222 | * Note: all the queues are enabled as part of the interface | ||
223 | * initialization, but in firmware restart scenarios they | ||
224 | * could be stopped, so wake them up. In firmware restart, | ||
225 | * mac80211 will have the queues stopped as well until the | ||
226 | * reconfiguration completes. During normal startup, they | ||
227 | * will be empty. | ||
228 | */ | ||
229 | |||
230 | for (i = 0; i < IWL_MAX_HW_QUEUES; i++) { | ||
231 | if (i < IWL_MVM_FIRST_AGG_QUEUE && i != IWL_MVM_CMD_QUEUE) | ||
232 | mvm->queue_to_mac80211[i] = i; | ||
233 | else | ||
234 | mvm->queue_to_mac80211[i] = IWL_INVALID_MAC80211_QUEUE; | ||
235 | atomic_set(&mvm->queue_stop_count[i], 0); | ||
236 | } | ||
237 | |||
238 | mvm->transport_queue_stop = 0; | ||
239 | |||
240 | mvm->ucode_loaded = true; | ||
241 | |||
242 | return 0; | ||
243 | } | ||
244 | #define IWL_HW_REV_ID_RAINBOW 0x2 | ||
245 | #define IWL_PROJ_TYPE_LHP 0x5 | ||
246 | |||
247 | static u32 iwl_mvm_build_phy_cfg(struct iwl_mvm *mvm) | ||
248 | { | ||
249 | struct iwl_nvm_data *data = mvm->nvm_data; | ||
250 | /* Temp calls to static definitions, will be changed to CSR calls */ | ||
251 | u8 hw_rev_id = IWL_HW_REV_ID_RAINBOW; | ||
252 | u8 project_type = IWL_PROJ_TYPE_LHP; | ||
253 | |||
254 | return data->radio_cfg_dash | (data->radio_cfg_step << 2) | | ||
255 | (hw_rev_id << 4) | ((project_type & 0x7f) << 6) | | ||
256 | (data->valid_tx_ant << 16) | (data->valid_rx_ant << 20); | ||
257 | } | ||
258 | |||
259 | static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm) | ||
260 | { | ||
261 | struct iwl_phy_cfg_cmd phy_cfg_cmd; | ||
262 | enum iwl_ucode_type ucode_type = mvm->cur_ucode; | ||
263 | |||
264 | /* Set parameters */ | ||
265 | phy_cfg_cmd.phy_cfg = cpu_to_le32(iwl_mvm_build_phy_cfg(mvm)); | ||
266 | phy_cfg_cmd.calib_control.event_trigger = | ||
267 | mvm->fw->default_calib[ucode_type].event_trigger; | ||
268 | phy_cfg_cmd.calib_control.flow_trigger = | ||
269 | mvm->fw->default_calib[ucode_type].flow_trigger; | ||
270 | |||
271 | IWL_DEBUG_INFO(mvm, "Sending Phy CFG command: 0x%x\n", | ||
272 | phy_cfg_cmd.phy_cfg); | ||
273 | |||
274 | return iwl_mvm_send_cmd_pdu(mvm, PHY_CONFIGURATION_CMD, CMD_SYNC, | ||
275 | sizeof(phy_cfg_cmd), &phy_cfg_cmd); | ||
276 | } | ||
277 | |||
278 | /* Starting with the new PHY DB implementation - New calibs are enabled */ | ||
279 | /* Value - 0x405e7 */ | ||
280 | #define IWL_CALIB_DEFAULT_FLOW_INIT (IWL_CALIB_CFG_XTAL_IDX |\ | ||
281 | IWL_CALIB_CFG_TEMPERATURE_IDX |\ | ||
282 | IWL_CALIB_CFG_VOLTAGE_READ_IDX |\ | ||
283 | IWL_CALIB_CFG_DC_IDX |\ | ||
284 | IWL_CALIB_CFG_BB_FILTER_IDX |\ | ||
285 | IWL_CALIB_CFG_LO_LEAKAGE_IDX |\ | ||
286 | IWL_CALIB_CFG_TX_IQ_IDX |\ | ||
287 | IWL_CALIB_CFG_RX_IQ_IDX |\ | ||
288 | IWL_CALIB_CFG_AGC_IDX) | ||
289 | |||
290 | #define IWL_CALIB_DEFAULT_EVENT_INIT 0x0 | ||
291 | |||
292 | /* Value 0x41567 */ | ||
293 | #define IWL_CALIB_DEFAULT_FLOW_RUN (IWL_CALIB_CFG_XTAL_IDX |\ | ||
294 | IWL_CALIB_CFG_TEMPERATURE_IDX |\ | ||
295 | IWL_CALIB_CFG_VOLTAGE_READ_IDX |\ | ||
296 | IWL_CALIB_CFG_BB_FILTER_IDX |\ | ||
297 | IWL_CALIB_CFG_DC_IDX |\ | ||
298 | IWL_CALIB_CFG_TX_IQ_IDX |\ | ||
299 | IWL_CALIB_CFG_RX_IQ_IDX |\ | ||
300 | IWL_CALIB_CFG_SENSITIVITY_IDX |\ | ||
301 | IWL_CALIB_CFG_AGC_IDX) | ||
302 | |||
303 | #define IWL_CALIB_DEFAULT_EVENT_RUN (IWL_CALIB_CFG_XTAL_IDX |\ | ||
304 | IWL_CALIB_CFG_TEMPERATURE_IDX |\ | ||
305 | IWL_CALIB_CFG_VOLTAGE_READ_IDX |\ | ||
306 | IWL_CALIB_CFG_TX_PWR_IDX |\ | ||
307 | IWL_CALIB_CFG_DC_IDX |\ | ||
308 | IWL_CALIB_CFG_TX_IQ_IDX |\ | ||
309 | IWL_CALIB_CFG_SENSITIVITY_IDX) | ||
310 | |||
311 | /* | ||
312 | * Sets the calibrations trigger values that will be sent to the FW for runtime | ||
313 | * and init calibrations. | ||
314 | * The ones given in the FW TLV are not correct. | ||
315 | */ | ||
316 | static void iwl_set_default_calib_trigger(struct iwl_mvm *mvm) | ||
317 | { | ||
318 | struct iwl_tlv_calib_ctrl default_calib; | ||
319 | |||
320 | /* | ||
321 | * WkP FW TLV calib bits are wrong, overwrite them. | ||
322 | * This defines the dynamic calibrations which are implemented in the | ||
323 | * uCode both for init(flow) calculation and event driven calibs. | ||
324 | */ | ||
325 | |||
326 | /* Init Image */ | ||
327 | default_calib.event_trigger = cpu_to_le32(IWL_CALIB_DEFAULT_EVENT_INIT); | ||
328 | default_calib.flow_trigger = cpu_to_le32(IWL_CALIB_DEFAULT_FLOW_INIT); | ||
329 | |||
330 | if (default_calib.event_trigger != | ||
331 | mvm->fw->default_calib[IWL_UCODE_INIT].event_trigger) | ||
332 | IWL_ERR(mvm, | ||
333 | "Updating the event calib for INIT image: 0x%x -> 0x%x\n", | ||
334 | mvm->fw->default_calib[IWL_UCODE_INIT].event_trigger, | ||
335 | default_calib.event_trigger); | ||
336 | if (default_calib.flow_trigger != | ||
337 | mvm->fw->default_calib[IWL_UCODE_INIT].flow_trigger) | ||
338 | IWL_ERR(mvm, | ||
339 | "Updating the flow calib for INIT image: 0x%x -> 0x%x\n", | ||
340 | mvm->fw->default_calib[IWL_UCODE_INIT].flow_trigger, | ||
341 | default_calib.flow_trigger); | ||
342 | |||
343 | memcpy((void *)&mvm->fw->default_calib[IWL_UCODE_INIT], | ||
344 | &default_calib, sizeof(struct iwl_tlv_calib_ctrl)); | ||
345 | IWL_ERR(mvm, | ||
346 | "Setting uCode init calibrations event 0x%x, trigger 0x%x\n", | ||
347 | default_calib.event_trigger, | ||
348 | default_calib.flow_trigger); | ||
349 | |||
350 | /* Run time image */ | ||
351 | default_calib.event_trigger = cpu_to_le32(IWL_CALIB_DEFAULT_EVENT_RUN); | ||
352 | default_calib.flow_trigger = cpu_to_le32(IWL_CALIB_DEFAULT_FLOW_RUN); | ||
353 | |||
354 | if (default_calib.event_trigger != | ||
355 | mvm->fw->default_calib[IWL_UCODE_REGULAR].event_trigger) | ||
356 | IWL_ERR(mvm, | ||
357 | "Updating the event calib for RT image: 0x%x -> 0x%x\n", | ||
358 | mvm->fw->default_calib[IWL_UCODE_REGULAR].event_trigger, | ||
359 | default_calib.event_trigger); | ||
360 | if (default_calib.flow_trigger != | ||
361 | mvm->fw->default_calib[IWL_UCODE_REGULAR].flow_trigger) | ||
362 | IWL_ERR(mvm, | ||
363 | "Updating the flow calib for RT image: 0x%x -> 0x%x\n", | ||
364 | mvm->fw->default_calib[IWL_UCODE_REGULAR].flow_trigger, | ||
365 | default_calib.flow_trigger); | ||
366 | |||
367 | memcpy((void *)&mvm->fw->default_calib[IWL_UCODE_REGULAR], | ||
368 | &default_calib, sizeof(struct iwl_tlv_calib_ctrl)); | ||
369 | IWL_ERR(mvm, | ||
370 | "Setting uCode runtime calibs event 0x%x, trigger 0x%x\n", | ||
371 | default_calib.event_trigger, | ||
372 | default_calib.flow_trigger); | ||
373 | } | ||
374 | |||
375 | static int iwl_set_default_calibrations(struct iwl_mvm *mvm) | ||
376 | { | ||
377 | u8 cmd_raw[16]; /* holds the variable size commands */ | ||
378 | struct iwl_set_calib_default_cmd *cmd = | ||
379 | (struct iwl_set_calib_default_cmd *)cmd_raw; | ||
380 | int ret, i; | ||
381 | |||
382 | /* Setting default values for calibrations we don't run */ | ||
383 | for (i = 0; i < ARRAY_SIZE(wkp_calib_default_data); i++) { | ||
384 | u16 cmd_len; | ||
385 | |||
386 | if (wkp_calib_default_data[i].size == 0) | ||
387 | continue; | ||
388 | |||
389 | memset(cmd_raw, 0, sizeof(cmd_raw)); | ||
390 | cmd_len = wkp_calib_default_data[i].size + sizeof(cmd); | ||
391 | cmd->calib_index = cpu_to_le16(i); | ||
392 | cmd->length = cpu_to_le16(wkp_calib_default_data[i].size); | ||
393 | if (WARN_ONCE(cmd_len > sizeof(cmd_raw), | ||
394 | "Need to enlarge cmd_raw to %d\n", cmd_len)) | ||
395 | break; | ||
396 | memcpy(cmd->data, wkp_calib_default_data[i].data, | ||
397 | wkp_calib_default_data[i].size); | ||
398 | ret = iwl_mvm_send_cmd_pdu(mvm, SET_CALIB_DEFAULT_CMD, 0, | ||
399 | sizeof(*cmd) + | ||
400 | wkp_calib_default_data[i].size, | ||
401 | cmd); | ||
402 | if (ret) | ||
403 | return ret; | ||
404 | } | ||
405 | |||
406 | return 0; | ||
407 | } | ||
408 | |||
409 | int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) | ||
410 | { | ||
411 | struct iwl_notification_wait calib_wait; | ||
412 | static const u8 init_complete[] = { | ||
413 | INIT_COMPLETE_NOTIF, | ||
414 | CALIB_RES_NOTIF_PHY_DB | ||
415 | }; | ||
416 | int ret; | ||
417 | |||
418 | lockdep_assert_held(&mvm->mutex); | ||
419 | |||
420 | if (mvm->init_ucode_run) | ||
421 | return 0; | ||
422 | |||
423 | iwl_init_notification_wait(&mvm->notif_wait, | ||
424 | &calib_wait, | ||
425 | init_complete, | ||
426 | ARRAY_SIZE(init_complete), | ||
427 | iwl_wait_phy_db_entry, | ||
428 | mvm->phy_db); | ||
429 | |||
430 | /* Will also start the device */ | ||
431 | ret = iwl_mvm_load_ucode_wait_alive(mvm, IWL_UCODE_INIT); | ||
432 | if (ret) { | ||
433 | IWL_ERR(mvm, "Failed to start INIT ucode: %d\n", ret); | ||
434 | goto error; | ||
435 | } | ||
436 | |||
437 | if (read_nvm) { | ||
438 | /* Read nvm */ | ||
439 | ret = iwl_nvm_init(mvm); | ||
440 | if (ret) { | ||
441 | IWL_ERR(mvm, "Failed to read NVM: %d\n", ret); | ||
442 | goto error; | ||
443 | } | ||
444 | } | ||
445 | |||
446 | ret = iwl_nvm_check_version(mvm->nvm_data, mvm->trans); | ||
447 | WARN_ON(ret); | ||
448 | |||
449 | /* Override the calibrations from TLV and the const of fw */ | ||
450 | iwl_set_default_calib_trigger(mvm); | ||
451 | |||
452 | /* WkP doesn't have all calibrations, need to set default values */ | ||
453 | if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) { | ||
454 | ret = iwl_set_default_calibrations(mvm); | ||
455 | if (ret) | ||
456 | goto error; | ||
457 | } | ||
458 | |||
459 | /* | ||
460 | * Send phy configurations command to init uCode | ||
461 | * to start the 16.0 uCode init image internal calibrations. | ||
462 | */ | ||
463 | ret = iwl_send_phy_cfg_cmd(mvm); | ||
464 | if (ret) { | ||
465 | IWL_ERR(mvm, "Failed to run INIT calibrations: %d\n", | ||
466 | ret); | ||
467 | goto error; | ||
468 | } | ||
469 | |||
470 | /* | ||
471 | * Some things may run in the background now, but we | ||
472 | * just wait for the calibration complete notification. | ||
473 | */ | ||
474 | ret = iwl_wait_notification(&mvm->notif_wait, &calib_wait, | ||
475 | MVM_UCODE_CALIB_TIMEOUT); | ||
476 | if (!ret) | ||
477 | mvm->init_ucode_run = true; | ||
478 | goto out; | ||
479 | |||
480 | error: | ||
481 | iwl_remove_notification(&mvm->notif_wait, &calib_wait); | ||
482 | out: | ||
483 | if (!iwlmvm_mod_params.init_dbg) { | ||
484 | iwl_trans_stop_device(mvm->trans); | ||
485 | } else if (!mvm->nvm_data) { | ||
486 | /* we want to debug INIT and we have no NVM - fake */ | ||
487 | mvm->nvm_data = kzalloc(sizeof(struct iwl_nvm_data) + | ||
488 | sizeof(struct ieee80211_channel) + | ||
489 | sizeof(struct ieee80211_rate), | ||
490 | GFP_KERNEL); | ||
491 | if (!mvm->nvm_data) | ||
492 | return -ENOMEM; | ||
493 | mvm->nvm_data->valid_rx_ant = 1; | ||
494 | mvm->nvm_data->valid_tx_ant = 1; | ||
495 | mvm->nvm_data->bands[0].channels = mvm->nvm_data->channels; | ||
496 | mvm->nvm_data->bands[0].n_channels = 1; | ||
497 | mvm->nvm_data->bands[0].n_bitrates = 1; | ||
498 | mvm->nvm_data->bands[0].bitrates = | ||
499 | (void *)mvm->nvm_data->channels + 1; | ||
500 | mvm->nvm_data->bands[0].bitrates->hw_value = 10; | ||
501 | } | ||
502 | |||
503 | return ret; | ||
504 | } | ||
505 | |||
506 | #define UCODE_CALIB_TIMEOUT (2*HZ) | ||
507 | |||
508 | int iwl_mvm_up(struct iwl_mvm *mvm) | ||
509 | { | ||
510 | int ret, i; | ||
511 | |||
512 | lockdep_assert_held(&mvm->mutex); | ||
513 | |||
514 | ret = iwl_trans_start_hw(mvm->trans); | ||
515 | if (ret) | ||
516 | return ret; | ||
517 | |||
518 | /* If we were in RFKILL during module loading, load init ucode now */ | ||
519 | if (!mvm->init_ucode_run) { | ||
520 | ret = iwl_run_init_mvm_ucode(mvm, false); | ||
521 | if (ret && !iwlmvm_mod_params.init_dbg) { | ||
522 | IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", ret); | ||
523 | goto error; | ||
524 | } | ||
525 | } | ||
526 | |||
527 | if (iwlmvm_mod_params.init_dbg) | ||
528 | return 0; | ||
529 | |||
530 | ret = iwl_mvm_load_ucode_wait_alive(mvm, IWL_UCODE_REGULAR); | ||
531 | if (ret) { | ||
532 | IWL_ERR(mvm, "Failed to start RT ucode: %d\n", ret); | ||
533 | goto error; | ||
534 | } | ||
535 | |||
536 | ret = iwl_send_tx_ant_cfg(mvm, mvm->nvm_data->valid_tx_ant); | ||
537 | if (ret) | ||
538 | goto error; | ||
539 | |||
540 | /* Send phy db control command and then phy db calibration*/ | ||
541 | ret = iwl_send_phy_db_data(mvm->phy_db); | ||
542 | if (ret) | ||
543 | goto error; | ||
544 | |||
545 | ret = iwl_send_phy_cfg_cmd(mvm); | ||
546 | if (ret) | ||
547 | goto error; | ||
548 | |||
549 | /* init the fw <-> mac80211 STA mapping */ | ||
550 | for (i = 0; i < IWL_MVM_STATION_COUNT; i++) | ||
551 | RCU_INIT_POINTER(mvm->fw_id_to_mac_id[i], NULL); | ||
552 | |||
553 | /* Add auxiliary station for scanning */ | ||
554 | ret = iwl_mvm_add_aux_sta(mvm); | ||
555 | if (ret) | ||
556 | goto error; | ||
557 | |||
558 | IWL_DEBUG_INFO(mvm, "RT uCode started.\n"); | ||
559 | |||
560 | return 0; | ||
561 | error: | ||
562 | iwl_trans_stop_device(mvm->trans); | ||
563 | return ret; | ||
564 | } | ||
565 | |||
566 | int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm) | ||
567 | { | ||
568 | int ret, i; | ||
569 | |||
570 | lockdep_assert_held(&mvm->mutex); | ||
571 | |||
572 | ret = iwl_trans_start_hw(mvm->trans); | ||
573 | if (ret) | ||
574 | return ret; | ||
575 | |||
576 | ret = iwl_mvm_load_ucode_wait_alive(mvm, IWL_UCODE_WOWLAN); | ||
577 | if (ret) { | ||
578 | IWL_ERR(mvm, "Failed to start WoWLAN firmware: %d\n", ret); | ||
579 | goto error; | ||
580 | } | ||
581 | |||
582 | ret = iwl_send_tx_ant_cfg(mvm, mvm->nvm_data->valid_tx_ant); | ||
583 | if (ret) | ||
584 | goto error; | ||
585 | |||
586 | /* Send phy db control command and then phy db calibration*/ | ||
587 | ret = iwl_send_phy_db_data(mvm->phy_db); | ||
588 | if (ret) | ||
589 | goto error; | ||
590 | |||
591 | ret = iwl_send_phy_cfg_cmd(mvm); | ||
592 | if (ret) | ||
593 | goto error; | ||
594 | |||
595 | /* init the fw <-> mac80211 STA mapping */ | ||
596 | for (i = 0; i < IWL_MVM_STATION_COUNT; i++) | ||
597 | RCU_INIT_POINTER(mvm->fw_id_to_mac_id[i], NULL); | ||
598 | |||
599 | /* Add auxiliary station for scanning */ | ||
600 | ret = iwl_mvm_add_aux_sta(mvm); | ||
601 | if (ret) | ||
602 | goto error; | ||
603 | |||
604 | return 0; | ||
605 | error: | ||
606 | iwl_trans_stop_device(mvm->trans); | ||
607 | return ret; | ||
608 | } | ||
609 | |||
610 | int iwl_mvm_rx_card_state_notif(struct iwl_mvm *mvm, | ||
611 | struct iwl_rx_cmd_buffer *rxb, | ||
612 | struct iwl_device_cmd *cmd) | ||
613 | { | ||
614 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
615 | struct iwl_card_state_notif *card_state_notif = (void *)pkt->data; | ||
616 | u32 flags = le32_to_cpu(card_state_notif->flags); | ||
617 | |||
618 | IWL_DEBUG_RF_KILL(mvm, "Card state received: HW:%s SW:%s CT:%s\n", | ||
619 | (flags & HW_CARD_DISABLED) ? "Kill" : "On", | ||
620 | (flags & SW_CARD_DISABLED) ? "Kill" : "On", | ||
621 | (flags & CT_KILL_CARD_DISABLED) ? | ||
622 | "Reached" : "Not reached"); | ||
623 | |||
624 | if (flags & CARD_DISABLED_MSK) | ||
625 | iwl_write32(mvm->trans, CSR_UCODE_DRV_GP1_SET, | ||
626 | CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); | ||
627 | |||
628 | return 0; | ||
629 | } | ||
630 | |||
631 | int iwl_mvm_rx_radio_ver(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | ||
632 | struct iwl_device_cmd *cmd) | ||
633 | { | ||
634 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
635 | struct iwl_radio_version_notif *radio_version = (void *)pkt->data; | ||
636 | |||
637 | /* TODO: what to do with that? */ | ||
638 | IWL_DEBUG_INFO(mvm, | ||
639 | "Radio version: flavor: 0x%08x, step 0x%08x, dash 0x%08x\n", | ||
640 | le32_to_cpu(radio_version->radio_flavor), | ||
641 | le32_to_cpu(radio_version->radio_step), | ||
642 | le32_to_cpu(radio_version->radio_dash)); | ||
643 | return 0; | ||
644 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/led.c b/drivers/net/wireless/iwlwifi/mvm/led.c new file mode 100644 index 000000000000..011906e73a05 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/led.c | |||
@@ -0,0 +1,134 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called LICENSE.GPL. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | * | ||
62 | *****************************************************************************/ | ||
63 | |||
64 | #include <linux/leds.h> | ||
65 | #include "iwl-io.h" | ||
66 | #include "iwl-csr.h" | ||
67 | #include "mvm.h" | ||
68 | |||
69 | /* Set led register on */ | ||
70 | static void iwl_mvm_led_enable(struct iwl_mvm *mvm) | ||
71 | { | ||
72 | iwl_write32(mvm->trans, CSR_LED_REG, CSR_LED_REG_TURN_ON); | ||
73 | } | ||
74 | |||
75 | /* Set led register off */ | ||
76 | static void iwl_mvm_led_disable(struct iwl_mvm *mvm) | ||
77 | { | ||
78 | iwl_write32(mvm->trans, CSR_LED_REG, CSR_LED_REG_TURN_OFF); | ||
79 | } | ||
80 | |||
81 | static void iwl_led_brightness_set(struct led_classdev *led_cdev, | ||
82 | enum led_brightness brightness) | ||
83 | { | ||
84 | struct iwl_mvm *mvm = container_of(led_cdev, struct iwl_mvm, led); | ||
85 | if (brightness > 0) | ||
86 | iwl_mvm_led_enable(mvm); | ||
87 | else | ||
88 | iwl_mvm_led_disable(mvm); | ||
89 | } | ||
90 | |||
91 | int iwl_mvm_leds_init(struct iwl_mvm *mvm) | ||
92 | { | ||
93 | int mode = iwlwifi_mod_params.led_mode; | ||
94 | int ret; | ||
95 | |||
96 | switch (mode) { | ||
97 | case IWL_LED_DEFAULT: | ||
98 | case IWL_LED_RF_STATE: | ||
99 | mode = IWL_LED_RF_STATE; | ||
100 | break; | ||
101 | case IWL_LED_DISABLE: | ||
102 | IWL_INFO(mvm, "Led disabled\n"); | ||
103 | return 0; | ||
104 | default: | ||
105 | return -EINVAL; | ||
106 | }; | ||
107 | |||
108 | mvm->led.name = kasprintf(GFP_KERNEL, "%s-led", | ||
109 | wiphy_name(mvm->hw->wiphy)); | ||
110 | mvm->led.brightness_set = iwl_led_brightness_set; | ||
111 | mvm->led.max_brightness = 1; | ||
112 | |||
113 | if (mode == IWL_LED_RF_STATE) | ||
114 | mvm->led.default_trigger = | ||
115 | ieee80211_get_radio_led_name(mvm->hw); | ||
116 | |||
117 | ret = led_classdev_register(mvm->trans->dev, &mvm->led); | ||
118 | if (ret) { | ||
119 | kfree(mvm->led.name); | ||
120 | IWL_INFO(mvm, "Failed to enable led\n"); | ||
121 | return ret; | ||
122 | } | ||
123 | |||
124 | return 0; | ||
125 | } | ||
126 | |||
127 | void iwl_mvm_leds_exit(struct iwl_mvm *mvm) | ||
128 | { | ||
129 | if (iwlwifi_mod_params.led_mode == IWL_LED_DISABLE) | ||
130 | return; | ||
131 | |||
132 | led_classdev_unregister(&mvm->led); | ||
133 | kfree(mvm->led.name); | ||
134 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c new file mode 100644 index 000000000000..c08a17a3cab9 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | |||
@@ -0,0 +1,951 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called LICENSE.GPL. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | * | ||
62 | *****************************************************************************/ | ||
63 | |||
64 | #include <linux/etherdevice.h> | ||
65 | #include <net/mac80211.h> | ||
66 | #include "iwl-io.h" | ||
67 | #include "iwl-prph.h" | ||
68 | #include "fw-api.h" | ||
69 | #include "mvm.h" | ||
70 | |||
71 | const u8 iwl_mvm_ac_to_tx_fifo[] = { | ||
72 | IWL_MVM_TX_FIFO_BK, | ||
73 | IWL_MVM_TX_FIFO_BE, | ||
74 | IWL_MVM_TX_FIFO_VI, | ||
75 | IWL_MVM_TX_FIFO_VO, | ||
76 | }; | ||
77 | |||
78 | struct iwl_mvm_mac_iface_iterator_data { | ||
79 | struct iwl_mvm *mvm; | ||
80 | struct ieee80211_vif *vif; | ||
81 | unsigned long available_mac_ids[BITS_TO_LONGS(NUM_MAC_INDEX_DRIVER)]; | ||
82 | unsigned long available_tsf_ids[BITS_TO_LONGS(NUM_TSF_IDS)]; | ||
83 | unsigned long used_hw_queues[BITS_TO_LONGS(IWL_MVM_FIRST_AGG_QUEUE)]; | ||
84 | enum iwl_tsf_id preferred_tsf; | ||
85 | bool found_vif; | ||
86 | }; | ||
87 | |||
88 | static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac, | ||
89 | struct ieee80211_vif *vif) | ||
90 | { | ||
91 | struct iwl_mvm_mac_iface_iterator_data *data = _data; | ||
92 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
93 | u32 ac; | ||
94 | |||
95 | /* Iterator may already find the interface being added -- skip it */ | ||
96 | if (vif == data->vif) { | ||
97 | data->found_vif = true; | ||
98 | return; | ||
99 | } | ||
100 | |||
101 | /* Mark the queues used by the vif */ | ||
102 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) | ||
103 | if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE) | ||
104 | __set_bit(vif->hw_queue[ac], data->used_hw_queues); | ||
105 | |||
106 | if (vif->cab_queue != IEEE80211_INVAL_HW_QUEUE) | ||
107 | __set_bit(vif->cab_queue, data->used_hw_queues); | ||
108 | |||
109 | /* | ||
110 | * Mark MAC IDs as used by clearing the available bit, and | ||
111 | * (below) mark TSFs as used if their existing use is not | ||
112 | * compatible with the new interface type. | ||
113 | * No locking or atomic bit operations are needed since the | ||
114 | * data is on the stack of the caller function. | ||
115 | */ | ||
116 | __clear_bit(mvmvif->id, data->available_mac_ids); | ||
117 | |||
118 | /* | ||
119 | * The TSF is a hardware/firmware resource, there are 4 and | ||
120 | * the driver should assign and free them as needed. However, | ||
121 | * there are cases where 2 MACs should share the same TSF ID | ||
122 | * for the purpose of clock sync, an optimization to avoid | ||
123 | * clock drift causing overlapping TBTTs/DTIMs for a GO and | ||
124 | * client in the system. | ||
125 | * | ||
126 | * The firmware will decide according to the MAC type which | ||
127 | * will be the master and slave. Clients that need to sync | ||
128 | * with a remote station will be the master, and an AP or GO | ||
129 | * will be the slave. | ||
130 | * | ||
131 | * Depending on the new interface type it can be slaved to | ||
132 | * or become the master of an existing interface. | ||
133 | */ | ||
134 | switch (data->vif->type) { | ||
135 | case NL80211_IFTYPE_STATION: | ||
136 | /* | ||
137 | * The new interface is client, so if the existing one | ||
138 | * we're iterating is an AP, the TSF should be used to | ||
139 | * avoid drift between the new client and existing AP, | ||
140 | * the existing AP will get drift updates from the new | ||
141 | * client context in this case | ||
142 | */ | ||
143 | if (vif->type == NL80211_IFTYPE_AP) { | ||
144 | if (data->preferred_tsf == NUM_TSF_IDS && | ||
145 | test_bit(mvmvif->tsf_id, data->available_tsf_ids)) | ||
146 | data->preferred_tsf = mvmvif->tsf_id; | ||
147 | return; | ||
148 | } | ||
149 | break; | ||
150 | case NL80211_IFTYPE_AP: | ||
151 | /* | ||
152 | * The new interface is AP/GO, so should get drift | ||
153 | * updates from an existing client or use the same | ||
154 | * TSF as an existing GO. There's no drift between | ||
155 | * TSFs internally but if they used different TSFs | ||
156 | * then a new client MAC could update one of them | ||
157 | * and cause drift that way. | ||
158 | */ | ||
159 | if (vif->type == NL80211_IFTYPE_STATION || | ||
160 | vif->type == NL80211_IFTYPE_AP) { | ||
161 | if (data->preferred_tsf == NUM_TSF_IDS && | ||
162 | test_bit(mvmvif->tsf_id, data->available_tsf_ids)) | ||
163 | data->preferred_tsf = mvmvif->tsf_id; | ||
164 | return; | ||
165 | } | ||
166 | break; | ||
167 | default: | ||
168 | /* | ||
169 | * For all other interface types there's no need to | ||
170 | * take drift into account. Either they're exclusive | ||
171 | * like IBSS and monitor, or we don't care much about | ||
172 | * their TSF (like P2P Device), but we won't be able | ||
173 | * to share the TSF resource. | ||
174 | */ | ||
175 | break; | ||
176 | } | ||
177 | |||
178 | /* | ||
179 | * Unless we exited above, we can't share the TSF resource | ||
180 | * that the virtual interface we're iterating over is using | ||
181 | * with the new one, so clear the available bit and if this | ||
182 | * was the preferred one, reset that as well. | ||
183 | */ | ||
184 | __clear_bit(mvmvif->tsf_id, data->available_tsf_ids); | ||
185 | |||
186 | if (data->preferred_tsf == mvmvif->tsf_id) | ||
187 | data->preferred_tsf = NUM_TSF_IDS; | ||
188 | } | ||
189 | |||
190 | /* | ||
191 | * Get the mask of the queus used by the vif | ||
192 | */ | ||
193 | u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm, | ||
194 | struct ieee80211_vif *vif) | ||
195 | { | ||
196 | u32 qmask, ac; | ||
197 | |||
198 | if (vif->type == NL80211_IFTYPE_P2P_DEVICE) | ||
199 | return BIT(IWL_OFFCHANNEL_QUEUE); | ||
200 | |||
201 | qmask = (vif->cab_queue != IEEE80211_INVAL_HW_QUEUE) ? | ||
202 | BIT(vif->cab_queue) : 0; | ||
203 | |||
204 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) | ||
205 | if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE) | ||
206 | qmask |= BIT(vif->hw_queue[ac]); | ||
207 | |||
208 | return qmask; | ||
209 | } | ||
210 | |||
211 | static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm, | ||
212 | struct ieee80211_vif *vif) | ||
213 | { | ||
214 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
215 | struct iwl_mvm_mac_iface_iterator_data data = { | ||
216 | .mvm = mvm, | ||
217 | .vif = vif, | ||
218 | .available_mac_ids = { (1 << NUM_MAC_INDEX_DRIVER) - 1 }, | ||
219 | .available_tsf_ids = { (1 << NUM_TSF_IDS) - 1 }, | ||
220 | /* no preference yet */ | ||
221 | .preferred_tsf = NUM_TSF_IDS, | ||
222 | .used_hw_queues = { | ||
223 | BIT(IWL_MVM_OFFCHANNEL_QUEUE) | | ||
224 | BIT(IWL_MVM_AUX_QUEUE) | | ||
225 | BIT(IWL_MVM_CMD_QUEUE) | ||
226 | }, | ||
227 | .found_vif = false, | ||
228 | }; | ||
229 | u32 ac; | ||
230 | int ret; | ||
231 | |||
232 | /* | ||
233 | * Allocate a MAC ID and a TSF for this MAC, along with the queues | ||
234 | * and other resources. | ||
235 | */ | ||
236 | |||
237 | /* | ||
238 | * Before the iterator, we start with all MAC IDs and TSFs available. | ||
239 | * | ||
240 | * During iteration, all MAC IDs are cleared that are in use by other | ||
241 | * virtual interfaces, and all TSF IDs are cleared that can't be used | ||
242 | * by this new virtual interface because they're used by an interface | ||
243 | * that can't share it with the new one. | ||
244 | * At the same time, we check if there's a preferred TSF in the case | ||
245 | * that we should share it with another interface. | ||
246 | */ | ||
247 | |||
248 | ieee80211_iterate_active_interfaces_atomic( | ||
249 | mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL, | ||
250 | iwl_mvm_mac_iface_iterator, &data); | ||
251 | |||
252 | /* | ||
253 | * In the case we're getting here during resume, it's similar to | ||
254 | * firmware restart, and with RESUME_ALL the iterator will find | ||
255 | * the vif being added already. | ||
256 | * We don't want to reassign any IDs in either case since doing | ||
257 | * so would probably assign different IDs (as interfaces aren't | ||
258 | * necessarily added in the same order), but the old IDs were | ||
259 | * preserved anyway, so skip ID assignment for both resume and | ||
260 | * recovery. | ||
261 | */ | ||
262 | if (data.found_vif) | ||
263 | return 0; | ||
264 | |||
265 | /* Therefore, in recovery, we can't get here */ | ||
266 | WARN_ON_ONCE(test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)); | ||
267 | |||
268 | mvmvif->id = find_first_bit(data.available_mac_ids, | ||
269 | NUM_MAC_INDEX_DRIVER); | ||
270 | if (mvmvif->id == NUM_MAC_INDEX_DRIVER) { | ||
271 | IWL_ERR(mvm, "Failed to init MAC context - no free ID!\n"); | ||
272 | ret = -EIO; | ||
273 | goto exit_fail; | ||
274 | } | ||
275 | |||
276 | if (data.preferred_tsf != NUM_TSF_IDS) | ||
277 | mvmvif->tsf_id = data.preferred_tsf; | ||
278 | else | ||
279 | mvmvif->tsf_id = find_first_bit(data.available_tsf_ids, | ||
280 | NUM_TSF_IDS); | ||
281 | if (mvmvif->tsf_id == NUM_TSF_IDS) { | ||
282 | IWL_ERR(mvm, "Failed to init MAC context - no free TSF!\n"); | ||
283 | ret = -EIO; | ||
284 | goto exit_fail; | ||
285 | } | ||
286 | |||
287 | mvmvif->color = 0; | ||
288 | |||
289 | /* No need to allocate data queues to P2P Device MAC.*/ | ||
290 | if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { | ||
291 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) | ||
292 | vif->hw_queue[ac] = IEEE80211_INVAL_HW_QUEUE; | ||
293 | |||
294 | return 0; | ||
295 | } | ||
296 | |||
297 | /* Find available queues, and allocate them to the ACs */ | ||
298 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | ||
299 | u8 queue = find_first_zero_bit(data.used_hw_queues, | ||
300 | IWL_MVM_FIRST_AGG_QUEUE); | ||
301 | |||
302 | if (queue >= IWL_MVM_FIRST_AGG_QUEUE) { | ||
303 | IWL_ERR(mvm, "Failed to allocate queue\n"); | ||
304 | ret = -EIO; | ||
305 | goto exit_fail; | ||
306 | } | ||
307 | |||
308 | __set_bit(queue, data.used_hw_queues); | ||
309 | vif->hw_queue[ac] = queue; | ||
310 | } | ||
311 | |||
312 | /* Allocate the CAB queue for softAP and GO interfaces */ | ||
313 | if (vif->type == NL80211_IFTYPE_AP) { | ||
314 | u8 queue = find_first_zero_bit(data.used_hw_queues, | ||
315 | IWL_MVM_FIRST_AGG_QUEUE); | ||
316 | |||
317 | if (queue >= IWL_MVM_FIRST_AGG_QUEUE) { | ||
318 | IWL_ERR(mvm, "Failed to allocate cab queue\n"); | ||
319 | ret = -EIO; | ||
320 | goto exit_fail; | ||
321 | } | ||
322 | |||
323 | vif->cab_queue = queue; | ||
324 | } else { | ||
325 | vif->cab_queue = IEEE80211_INVAL_HW_QUEUE; | ||
326 | } | ||
327 | |||
328 | mvmvif->bcast_sta.sta_id = IWL_MVM_STATION_COUNT; | ||
329 | mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; | ||
330 | |||
331 | INIT_LIST_HEAD(&mvmvif->time_event_data.list); | ||
332 | mvmvif->time_event_data.id = TE_MAX; | ||
333 | |||
334 | return 0; | ||
335 | |||
336 | exit_fail: | ||
337 | memset(mvmvif, 0, sizeof(struct iwl_mvm_vif)); | ||
338 | memset(vif->hw_queue, IEEE80211_INVAL_HW_QUEUE, sizeof(vif->hw_queue)); | ||
339 | vif->cab_queue = IEEE80211_INVAL_HW_QUEUE; | ||
340 | return ret; | ||
341 | } | ||
342 | |||
343 | int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | ||
344 | { | ||
345 | u32 ac; | ||
346 | int ret; | ||
347 | |||
348 | lockdep_assert_held(&mvm->mutex); | ||
349 | |||
350 | ret = iwl_mvm_mac_ctxt_allocate_resources(mvm, vif); | ||
351 | if (ret) | ||
352 | return ret; | ||
353 | |||
354 | switch (vif->type) { | ||
355 | case NL80211_IFTYPE_P2P_DEVICE: | ||
356 | iwl_trans_ac_txq_enable(mvm->trans, IWL_MVM_OFFCHANNEL_QUEUE, | ||
357 | IWL_MVM_TX_FIFO_VO); | ||
358 | break; | ||
359 | case NL80211_IFTYPE_AP: | ||
360 | iwl_trans_ac_txq_enable(mvm->trans, vif->cab_queue, | ||
361 | IWL_MVM_TX_FIFO_VO); | ||
362 | /* fall through */ | ||
363 | default: | ||
364 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) | ||
365 | iwl_trans_ac_txq_enable(mvm->trans, vif->hw_queue[ac], | ||
366 | iwl_mvm_ac_to_tx_fifo[ac]); | ||
367 | break; | ||
368 | } | ||
369 | |||
370 | return 0; | ||
371 | } | ||
372 | |||
373 | void iwl_mvm_mac_ctxt_release(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | ||
374 | { | ||
375 | int ac; | ||
376 | |||
377 | lockdep_assert_held(&mvm->mutex); | ||
378 | |||
379 | switch (vif->type) { | ||
380 | case NL80211_IFTYPE_P2P_DEVICE: | ||
381 | iwl_trans_txq_disable(mvm->trans, IWL_MVM_OFFCHANNEL_QUEUE); | ||
382 | break; | ||
383 | case NL80211_IFTYPE_AP: | ||
384 | iwl_trans_txq_disable(mvm->trans, vif->cab_queue); | ||
385 | /* fall through */ | ||
386 | default: | ||
387 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) | ||
388 | iwl_trans_txq_disable(mvm->trans, vif->hw_queue[ac]); | ||
389 | } | ||
390 | } | ||
391 | |||
392 | static void iwl_mvm_ack_rates(struct iwl_mvm *mvm, | ||
393 | struct ieee80211_vif *vif, | ||
394 | enum ieee80211_band band, | ||
395 | u8 *cck_rates, u8 *ofdm_rates) | ||
396 | { | ||
397 | struct ieee80211_supported_band *sband; | ||
398 | unsigned long basic = vif->bss_conf.basic_rates; | ||
399 | int lowest_present_ofdm = 100; | ||
400 | int lowest_present_cck = 100; | ||
401 | u8 cck = 0; | ||
402 | u8 ofdm = 0; | ||
403 | int i; | ||
404 | |||
405 | sband = mvm->hw->wiphy->bands[band]; | ||
406 | |||
407 | for_each_set_bit(i, &basic, BITS_PER_LONG) { | ||
408 | int hw = sband->bitrates[i].hw_value; | ||
409 | if (hw >= IWL_FIRST_OFDM_RATE) { | ||
410 | ofdm |= BIT(hw - IWL_FIRST_OFDM_RATE); | ||
411 | if (lowest_present_ofdm > hw) | ||
412 | lowest_present_ofdm = hw; | ||
413 | } else { | ||
414 | BUILD_BUG_ON(IWL_FIRST_CCK_RATE != 0); | ||
415 | |||
416 | cck |= BIT(hw); | ||
417 | if (lowest_present_cck > hw) | ||
418 | lowest_present_cck = hw; | ||
419 | } | ||
420 | } | ||
421 | |||
422 | /* | ||
423 | * Now we've got the basic rates as bitmaps in the ofdm and cck | ||
424 | * variables. This isn't sufficient though, as there might not | ||
425 | * be all the right rates in the bitmap. E.g. if the only basic | ||
426 | * rates are 5.5 Mbps and 11 Mbps, we still need to add 1 Mbps | ||
427 | * and 6 Mbps because the 802.11-2007 standard says in 9.6: | ||
428 | * | ||
429 | * [...] a STA responding to a received frame shall transmit | ||
430 | * its Control Response frame [...] at the highest rate in the | ||
431 | * BSSBasicRateSet parameter that is less than or equal to the | ||
432 | * rate of the immediately previous frame in the frame exchange | ||
433 | * sequence ([...]) and that is of the same modulation class | ||
434 | * ([...]) as the received frame. If no rate contained in the | ||
435 | * BSSBasicRateSet parameter meets these conditions, then the | ||
436 | * control frame sent in response to a received frame shall be | ||
437 | * transmitted at the highest mandatory rate of the PHY that is | ||
438 | * less than or equal to the rate of the received frame, and | ||
439 | * that is of the same modulation class as the received frame. | ||
440 | * | ||
441 | * As a consequence, we need to add all mandatory rates that are | ||
442 | * lower than all of the basic rates to these bitmaps. | ||
443 | */ | ||
444 | |||
445 | if (IWL_RATE_24M_INDEX < lowest_present_ofdm) | ||
446 | ofdm |= IWL_RATE_BIT_MSK(24) >> IWL_FIRST_OFDM_RATE; | ||
447 | if (IWL_RATE_12M_INDEX < lowest_present_ofdm) | ||
448 | ofdm |= IWL_RATE_BIT_MSK(12) >> IWL_FIRST_OFDM_RATE; | ||
449 | /* 6M already there or needed so always add */ | ||
450 | ofdm |= IWL_RATE_BIT_MSK(6) >> IWL_FIRST_OFDM_RATE; | ||
451 | |||
452 | /* | ||
453 | * CCK is a bit more complex with DSSS vs. HR/DSSS vs. ERP. | ||
454 | * Note, however: | ||
455 | * - if no CCK rates are basic, it must be ERP since there must | ||
456 | * be some basic rates at all, so they're OFDM => ERP PHY | ||
457 | * (or we're in 5 GHz, and the cck bitmap will never be used) | ||
458 | * - if 11M is a basic rate, it must be ERP as well, so add 5.5M | ||
459 | * - if 5.5M is basic, 1M and 2M are mandatory | ||
460 | * - if 2M is basic, 1M is mandatory | ||
461 | * - if 1M is basic, that's the only valid ACK rate. | ||
462 | * As a consequence, it's not as complicated as it sounds, just add | ||
463 | * any lower rates to the ACK rate bitmap. | ||
464 | */ | ||
465 | if (IWL_RATE_11M_INDEX < lowest_present_cck) | ||
466 | cck |= IWL_RATE_BIT_MSK(11) >> IWL_FIRST_CCK_RATE; | ||
467 | if (IWL_RATE_5M_INDEX < lowest_present_cck) | ||
468 | cck |= IWL_RATE_BIT_MSK(5) >> IWL_FIRST_CCK_RATE; | ||
469 | if (IWL_RATE_2M_INDEX < lowest_present_cck) | ||
470 | cck |= IWL_RATE_BIT_MSK(2) >> IWL_FIRST_CCK_RATE; | ||
471 | /* 1M already there or needed so always add */ | ||
472 | cck |= IWL_RATE_BIT_MSK(1) >> IWL_FIRST_CCK_RATE; | ||
473 | |||
474 | *cck_rates = cck; | ||
475 | *ofdm_rates = ofdm; | ||
476 | } | ||
477 | |||
478 | static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm, | ||
479 | struct ieee80211_vif *vif, | ||
480 | struct iwl_mac_ctx_cmd *cmd, | ||
481 | u32 action) | ||
482 | { | ||
483 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
484 | struct ieee80211_chanctx_conf *chanctx; | ||
485 | u8 cck_ack_rates, ofdm_ack_rates; | ||
486 | int i; | ||
487 | |||
488 | cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, | ||
489 | mvmvif->color)); | ||
490 | cmd->action = cpu_to_le32(action); | ||
491 | |||
492 | switch (vif->type) { | ||
493 | case NL80211_IFTYPE_STATION: | ||
494 | if (vif->p2p) | ||
495 | cmd->mac_type = cpu_to_le32(FW_MAC_TYPE_P2P_STA); | ||
496 | else | ||
497 | cmd->mac_type = cpu_to_le32(FW_MAC_TYPE_BSS_STA); | ||
498 | break; | ||
499 | case NL80211_IFTYPE_AP: | ||
500 | cmd->mac_type = cpu_to_le32(FW_MAC_TYPE_GO); | ||
501 | break; | ||
502 | case NL80211_IFTYPE_MONITOR: | ||
503 | cmd->mac_type = cpu_to_le32(FW_MAC_TYPE_LISTENER); | ||
504 | break; | ||
505 | case NL80211_IFTYPE_P2P_DEVICE: | ||
506 | cmd->mac_type = cpu_to_le32(FW_MAC_TYPE_P2P_DEVICE); | ||
507 | break; | ||
508 | case NL80211_IFTYPE_ADHOC: | ||
509 | cmd->mac_type = cpu_to_le32(FW_MAC_TYPE_IBSS); | ||
510 | break; | ||
511 | default: | ||
512 | WARN_ON_ONCE(1); | ||
513 | } | ||
514 | |||
515 | cmd->tsf_id = cpu_to_le32(mvmvif->tsf_id); | ||
516 | |||
517 | memcpy(cmd->node_addr, vif->addr, ETH_ALEN); | ||
518 | if (vif->bss_conf.bssid) | ||
519 | memcpy(cmd->bssid_addr, vif->bss_conf.bssid, ETH_ALEN); | ||
520 | else | ||
521 | eth_broadcast_addr(cmd->bssid_addr); | ||
522 | |||
523 | rcu_read_lock(); | ||
524 | chanctx = rcu_dereference(vif->chanctx_conf); | ||
525 | iwl_mvm_ack_rates(mvm, vif, chanctx ? chanctx->def.chan->band | ||
526 | : IEEE80211_BAND_2GHZ, | ||
527 | &cck_ack_rates, &ofdm_ack_rates); | ||
528 | rcu_read_unlock(); | ||
529 | |||
530 | cmd->cck_rates = cpu_to_le32((u32)cck_ack_rates); | ||
531 | cmd->ofdm_rates = cpu_to_le32((u32)ofdm_ack_rates); | ||
532 | |||
533 | cmd->cck_short_preamble = | ||
534 | cpu_to_le32(vif->bss_conf.use_short_preamble ? | ||
535 | MAC_FLG_SHORT_PREAMBLE : 0); | ||
536 | cmd->short_slot = | ||
537 | cpu_to_le32(vif->bss_conf.use_short_slot ? | ||
538 | MAC_FLG_SHORT_SLOT : 0); | ||
539 | |||
540 | for (i = 0; i < AC_NUM; i++) { | ||
541 | cmd->ac[i].cw_min = cpu_to_le16(mvmvif->queue_params[i].cw_min); | ||
542 | cmd->ac[i].cw_max = cpu_to_le16(mvmvif->queue_params[i].cw_max); | ||
543 | cmd->ac[i].aifsn = mvmvif->queue_params[i].aifs; | ||
544 | cmd->ac[i].edca_txop = | ||
545 | cpu_to_le16(mvmvif->queue_params[i].txop * 32); | ||
546 | cmd->ac[i].fifos_mask = BIT(iwl_mvm_ac_to_tx_fifo[i]); | ||
547 | } | ||
548 | |||
549 | if (vif->bss_conf.qos) | ||
550 | cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_UPDATE_EDCA); | ||
551 | |||
552 | if (vif->bss_conf.use_cts_prot) | ||
553 | cmd->protection_flags |= cpu_to_le32(MAC_PROT_FLG_TGG_PROTECT | | ||
554 | MAC_PROT_FLG_SELF_CTS_EN); | ||
555 | |||
556 | /* | ||
557 | * I think that we should enable these 2 flags regardless the HT PROT | ||
558 | * fields in the HT IE, but I am not sure. Someone knows whom to ask?... | ||
559 | */ | ||
560 | if (vif->bss_conf.chandef.width != NL80211_CHAN_WIDTH_20_NOHT) { | ||
561 | cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_TGN); | ||
562 | cmd->protection_flags |= cpu_to_le32(MAC_PROT_FLG_HT_PROT | | ||
563 | MAC_PROT_FLG_FAT_PROT); | ||
564 | } | ||
565 | |||
566 | cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP); | ||
567 | } | ||
568 | |||
569 | static int iwl_mvm_mac_ctxt_send_cmd(struct iwl_mvm *mvm, | ||
570 | struct iwl_mac_ctx_cmd *cmd) | ||
571 | { | ||
572 | int ret = iwl_mvm_send_cmd_pdu(mvm, MAC_CONTEXT_CMD, CMD_SYNC, | ||
573 | sizeof(*cmd), cmd); | ||
574 | if (ret) | ||
575 | IWL_ERR(mvm, "Failed to send MAC context (action:%d): %d\n", | ||
576 | le32_to_cpu(cmd->action), ret); | ||
577 | return ret; | ||
578 | } | ||
579 | |||
580 | /* | ||
581 | * Fill the specific data for mac context of type station or p2p client | ||
582 | */ | ||
583 | static void iwl_mvm_mac_ctxt_cmd_fill_sta(struct iwl_mvm *mvm, | ||
584 | struct ieee80211_vif *vif, | ||
585 | struct iwl_mac_data_sta *ctxt_sta) | ||
586 | { | ||
587 | ctxt_sta->is_assoc = cpu_to_le32(vif->bss_conf.assoc ? 1 : 0); | ||
588 | |||
589 | ctxt_sta->bi = cpu_to_le32(vif->bss_conf.beacon_int); | ||
590 | ctxt_sta->bi_reciprocal = | ||
591 | cpu_to_le32(iwl_mvm_reciprocal(vif->bss_conf.beacon_int)); | ||
592 | ctxt_sta->dtim_interval = cpu_to_le32(vif->bss_conf.beacon_int * | ||
593 | vif->bss_conf.dtim_period); | ||
594 | ctxt_sta->dtim_reciprocal = | ||
595 | cpu_to_le32(iwl_mvm_reciprocal(vif->bss_conf.beacon_int * | ||
596 | vif->bss_conf.dtim_period)); | ||
597 | |||
598 | ctxt_sta->listen_interval = cpu_to_le32(mvm->hw->conf.listen_interval); | ||
599 | ctxt_sta->assoc_id = cpu_to_le32(vif->bss_conf.aid); | ||
600 | } | ||
601 | |||
602 | static int iwl_mvm_mac_ctxt_cmd_station(struct iwl_mvm *mvm, | ||
603 | struct ieee80211_vif *vif, | ||
604 | u32 action) | ||
605 | { | ||
606 | struct iwl_mac_ctx_cmd cmd = {}; | ||
607 | |||
608 | WARN_ON(vif->type != NL80211_IFTYPE_STATION || vif->p2p); | ||
609 | |||
610 | /* Fill the common data for all mac context types */ | ||
611 | iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); | ||
612 | |||
613 | /* Fill the data specific for station mode */ | ||
614 | iwl_mvm_mac_ctxt_cmd_fill_sta(mvm, vif, &cmd.sta); | ||
615 | |||
616 | return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd); | ||
617 | } | ||
618 | |||
619 | static int iwl_mvm_mac_ctxt_cmd_p2p_client(struct iwl_mvm *mvm, | ||
620 | struct ieee80211_vif *vif, | ||
621 | u32 action) | ||
622 | { | ||
623 | struct iwl_mac_ctx_cmd cmd = {}; | ||
624 | |||
625 | WARN_ON(vif->type != NL80211_IFTYPE_STATION || !vif->p2p); | ||
626 | |||
627 | /* Fill the common data for all mac context types */ | ||
628 | iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); | ||
629 | |||
630 | /* Fill the data specific for station mode */ | ||
631 | iwl_mvm_mac_ctxt_cmd_fill_sta(mvm, vif, &cmd.p2p_sta.sta); | ||
632 | |||
633 | cmd.p2p_sta.ctwin = cpu_to_le32(vif->bss_conf.p2p_ctwindow); | ||
634 | |||
635 | return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd); | ||
636 | } | ||
637 | |||
638 | static int iwl_mvm_mac_ctxt_cmd_listener(struct iwl_mvm *mvm, | ||
639 | struct ieee80211_vif *vif, | ||
640 | u32 action) | ||
641 | { | ||
642 | struct iwl_mac_ctx_cmd cmd = {}; | ||
643 | |||
644 | WARN_ON(vif->type != NL80211_IFTYPE_MONITOR); | ||
645 | |||
646 | iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); | ||
647 | /* No other data to be filled */ | ||
648 | return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd); | ||
649 | } | ||
650 | |||
651 | struct iwl_mvm_go_iterator_data { | ||
652 | bool go_active; | ||
653 | }; | ||
654 | |||
655 | static void iwl_mvm_go_iterator(void *_data, u8 *mac, struct ieee80211_vif *vif) | ||
656 | { | ||
657 | struct iwl_mvm_go_iterator_data *data = _data; | ||
658 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
659 | |||
660 | if (vif->type == NL80211_IFTYPE_AP && vif->p2p && mvmvif->ap_active) | ||
661 | data->go_active = true; | ||
662 | } | ||
663 | |||
664 | static int iwl_mvm_mac_ctxt_cmd_p2p_device(struct iwl_mvm *mvm, | ||
665 | struct ieee80211_vif *vif, | ||
666 | u32 action) | ||
667 | { | ||
668 | struct iwl_mac_ctx_cmd cmd = {}; | ||
669 | struct iwl_mvm_go_iterator_data data = {}; | ||
670 | |||
671 | WARN_ON(vif->type != NL80211_IFTYPE_P2P_DEVICE); | ||
672 | |||
673 | iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); | ||
674 | |||
675 | cmd.protection_flags |= cpu_to_le32(MAC_PROT_FLG_TGG_PROTECT); | ||
676 | cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_PROMISC); | ||
677 | |||
678 | /* | ||
679 | * This flag should be set to true when the P2P Device is | ||
680 | * discoverable and there is at least another active P2P GO. Settings | ||
681 | * this flag will allow the P2P Device to be discoverable on other | ||
682 | * channels in addition to its listen channel. | ||
683 | * Note that this flag should not be set in other cases as it opens the | ||
684 | * Rx filters on all MAC and increases the number of interrupts. | ||
685 | */ | ||
686 | ieee80211_iterate_active_interfaces_atomic( | ||
687 | mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL, | ||
688 | iwl_mvm_go_iterator, &data); | ||
689 | |||
690 | cmd.p2p_dev.is_disc_extended = cpu_to_le32(data.go_active ? 1 : 0); | ||
691 | return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd); | ||
692 | } | ||
693 | |||
694 | static void iwl_mvm_mac_ctxt_set_tim(struct iwl_mvm *mvm, | ||
695 | struct iwl_mac_beacon_cmd *beacon_cmd, | ||
696 | u8 *beacon, u32 frame_size) | ||
697 | { | ||
698 | u32 tim_idx; | ||
699 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)beacon; | ||
700 | |||
701 | /* The index is relative to frame start but we start looking at the | ||
702 | * variable-length part of the beacon. */ | ||
703 | tim_idx = mgmt->u.beacon.variable - beacon; | ||
704 | |||
705 | /* Parse variable-length elements of beacon to find WLAN_EID_TIM */ | ||
706 | while ((tim_idx < (frame_size - 2)) && | ||
707 | (beacon[tim_idx] != WLAN_EID_TIM)) | ||
708 | tim_idx += beacon[tim_idx+1] + 2; | ||
709 | |||
710 | /* If TIM field was found, set variables */ | ||
711 | if ((tim_idx < (frame_size - 1)) && (beacon[tim_idx] == WLAN_EID_TIM)) { | ||
712 | beacon_cmd->tim_idx = cpu_to_le32(tim_idx); | ||
713 | beacon_cmd->tim_size = cpu_to_le32((u32)beacon[tim_idx+1]); | ||
714 | } else { | ||
715 | IWL_WARN(mvm, "Unable to find TIM Element in beacon\n"); | ||
716 | } | ||
717 | } | ||
718 | |||
719 | static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm, | ||
720 | struct ieee80211_vif *vif, | ||
721 | struct sk_buff *beacon) | ||
722 | { | ||
723 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
724 | struct iwl_host_cmd cmd = { | ||
725 | .id = BEACON_TEMPLATE_CMD, | ||
726 | .flags = CMD_ASYNC, | ||
727 | }; | ||
728 | struct iwl_mac_beacon_cmd beacon_cmd = {}; | ||
729 | struct ieee80211_tx_info *info; | ||
730 | u32 beacon_skb_len; | ||
731 | u32 rate; | ||
732 | |||
733 | if (WARN_ON(!beacon)) | ||
734 | return -EINVAL; | ||
735 | |||
736 | beacon_skb_len = beacon->len; | ||
737 | |||
738 | /* TODO: for now the beacon template id is set to be the mac context id. | ||
739 | * Might be better to handle it as another resource ... */ | ||
740 | beacon_cmd.template_id = cpu_to_le32((u32)mvmvif->id); | ||
741 | |||
742 | /* Set up TX command fields */ | ||
743 | beacon_cmd.tx.len = cpu_to_le16((u16)beacon_skb_len); | ||
744 | beacon_cmd.tx.sta_id = mvmvif->bcast_sta.sta_id; | ||
745 | beacon_cmd.tx.life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE); | ||
746 | beacon_cmd.tx.tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL | | ||
747 | TX_CMD_FLG_BT_DIS | | ||
748 | TX_CMD_FLG_TSF); | ||
749 | |||
750 | mvm->mgmt_last_antenna_idx = | ||
751 | iwl_mvm_next_antenna(mvm, mvm->nvm_data->valid_tx_ant, | ||
752 | mvm->mgmt_last_antenna_idx); | ||
753 | |||
754 | beacon_cmd.tx.rate_n_flags = | ||
755 | cpu_to_le32(BIT(mvm->mgmt_last_antenna_idx) << | ||
756 | RATE_MCS_ANT_POS); | ||
757 | |||
758 | info = IEEE80211_SKB_CB(beacon); | ||
759 | |||
760 | if (info->band == IEEE80211_BAND_5GHZ || vif->p2p) { | ||
761 | rate = IWL_FIRST_OFDM_RATE; | ||
762 | } else { | ||
763 | rate = IWL_FIRST_CCK_RATE; | ||
764 | beacon_cmd.tx.rate_n_flags |= cpu_to_le32(RATE_MCS_CCK_MSK); | ||
765 | } | ||
766 | beacon_cmd.tx.rate_n_flags |= | ||
767 | cpu_to_le32(iwl_mvm_mac80211_idx_to_hwrate(rate)); | ||
768 | |||
769 | /* Set up TX beacon command fields */ | ||
770 | iwl_mvm_mac_ctxt_set_tim(mvm, &beacon_cmd, | ||
771 | beacon->data, | ||
772 | beacon_skb_len); | ||
773 | |||
774 | /* Submit command */ | ||
775 | cmd.len[0] = sizeof(beacon_cmd); | ||
776 | cmd.data[0] = &beacon_cmd; | ||
777 | cmd.dataflags[0] = 0; | ||
778 | cmd.len[1] = beacon_skb_len; | ||
779 | cmd.data[1] = beacon->data; | ||
780 | cmd.dataflags[1] = IWL_HCMD_DFL_DUP; | ||
781 | |||
782 | return iwl_mvm_send_cmd(mvm, &cmd); | ||
783 | } | ||
784 | |||
785 | /* The beacon template for the AP/GO context has changed and needs update */ | ||
786 | int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm, | ||
787 | struct ieee80211_vif *vif) | ||
788 | { | ||
789 | struct sk_buff *beacon; | ||
790 | int ret; | ||
791 | |||
792 | WARN_ON(vif->type != NL80211_IFTYPE_AP); | ||
793 | |||
794 | beacon = ieee80211_beacon_get(mvm->hw, vif); | ||
795 | if (!beacon) | ||
796 | return -ENOMEM; | ||
797 | |||
798 | ret = iwl_mvm_mac_ctxt_send_beacon(mvm, vif, beacon); | ||
799 | dev_kfree_skb(beacon); | ||
800 | return ret; | ||
801 | } | ||
802 | |||
803 | /* | ||
804 | * Fill the specific data for mac context of type AP of P2P GO | ||
805 | */ | ||
806 | static void iwl_mvm_mac_ctxt_cmd_fill_ap(struct iwl_mvm *mvm, | ||
807 | struct ieee80211_vif *vif, | ||
808 | struct iwl_mac_data_ap *ctxt_ap) | ||
809 | { | ||
810 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
811 | u32 curr_dev_time; | ||
812 | |||
813 | ctxt_ap->bi = cpu_to_le32(vif->bss_conf.beacon_int); | ||
814 | ctxt_ap->bi_reciprocal = | ||
815 | cpu_to_le32(iwl_mvm_reciprocal(vif->bss_conf.beacon_int)); | ||
816 | ctxt_ap->dtim_interval = cpu_to_le32(vif->bss_conf.beacon_int * | ||
817 | vif->bss_conf.dtim_period); | ||
818 | ctxt_ap->dtim_reciprocal = | ||
819 | cpu_to_le32(iwl_mvm_reciprocal(vif->bss_conf.beacon_int * | ||
820 | vif->bss_conf.dtim_period)); | ||
821 | |||
822 | ctxt_ap->mcast_qid = cpu_to_le32(vif->cab_queue); | ||
823 | curr_dev_time = iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG); | ||
824 | ctxt_ap->beacon_time = cpu_to_le32(curr_dev_time); | ||
825 | |||
826 | ctxt_ap->beacon_tsf = cpu_to_le64(curr_dev_time); | ||
827 | |||
828 | /* TODO: Assume that the beacon id == mac context id */ | ||
829 | ctxt_ap->beacon_template = cpu_to_le32(mvmvif->id); | ||
830 | } | ||
831 | |||
832 | static int iwl_mvm_mac_ctxt_cmd_ap(struct iwl_mvm *mvm, | ||
833 | struct ieee80211_vif *vif, | ||
834 | u32 action) | ||
835 | { | ||
836 | struct iwl_mac_ctx_cmd cmd = {}; | ||
837 | |||
838 | WARN_ON(vif->type != NL80211_IFTYPE_AP || vif->p2p); | ||
839 | |||
840 | /* Fill the common data for all mac context types */ | ||
841 | iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); | ||
842 | |||
843 | /* Fill the data specific for ap mode */ | ||
844 | iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.ap); | ||
845 | |||
846 | return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd); | ||
847 | } | ||
848 | |||
849 | static int iwl_mvm_mac_ctxt_cmd_go(struct iwl_mvm *mvm, | ||
850 | struct ieee80211_vif *vif, | ||
851 | u32 action) | ||
852 | { | ||
853 | struct iwl_mac_ctx_cmd cmd = {}; | ||
854 | |||
855 | WARN_ON(vif->type != NL80211_IFTYPE_AP || !vif->p2p); | ||
856 | |||
857 | /* Fill the common data for all mac context types */ | ||
858 | iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); | ||
859 | |||
860 | /* Fill the data specific for GO mode */ | ||
861 | iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.go.ap); | ||
862 | |||
863 | cmd.go.ctwin = cpu_to_le32(vif->bss_conf.p2p_ctwindow); | ||
864 | cmd.go.opp_ps_enabled = cpu_to_le32(!!vif->bss_conf.p2p_oppps); | ||
865 | |||
866 | return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd); | ||
867 | } | ||
868 | |||
869 | static int iwl_mvm_mac_ctx_send(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
870 | u32 action) | ||
871 | { | ||
872 | switch (vif->type) { | ||
873 | case NL80211_IFTYPE_STATION: | ||
874 | if (!vif->p2p) | ||
875 | return iwl_mvm_mac_ctxt_cmd_station(mvm, vif, | ||
876 | action); | ||
877 | else | ||
878 | return iwl_mvm_mac_ctxt_cmd_p2p_client(mvm, vif, | ||
879 | action); | ||
880 | break; | ||
881 | case NL80211_IFTYPE_AP: | ||
882 | if (!vif->p2p) | ||
883 | return iwl_mvm_mac_ctxt_cmd_ap(mvm, vif, action); | ||
884 | else | ||
885 | return iwl_mvm_mac_ctxt_cmd_go(mvm, vif, action); | ||
886 | break; | ||
887 | case NL80211_IFTYPE_MONITOR: | ||
888 | return iwl_mvm_mac_ctxt_cmd_listener(mvm, vif, action); | ||
889 | case NL80211_IFTYPE_P2P_DEVICE: | ||
890 | return iwl_mvm_mac_ctxt_cmd_p2p_device(mvm, vif, action); | ||
891 | default: | ||
892 | break; | ||
893 | } | ||
894 | |||
895 | return -EOPNOTSUPP; | ||
896 | } | ||
897 | |||
898 | int iwl_mvm_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | ||
899 | { | ||
900 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
901 | int ret; | ||
902 | |||
903 | if (WARN_ONCE(mvmvif->uploaded, "Adding active MAC %pM/%d\n", | ||
904 | vif->addr, ieee80211_vif_type_p2p(vif))) | ||
905 | return -EIO; | ||
906 | |||
907 | ret = iwl_mvm_mac_ctx_send(mvm, vif, FW_CTXT_ACTION_ADD); | ||
908 | if (ret) | ||
909 | return ret; | ||
910 | |||
911 | mvmvif->uploaded = true; | ||
912 | return 0; | ||
913 | } | ||
914 | |||
915 | int iwl_mvm_mac_ctxt_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | ||
916 | { | ||
917 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
918 | |||
919 | if (WARN_ONCE(!mvmvif->uploaded, "Changing inactive MAC %pM/%d\n", | ||
920 | vif->addr, ieee80211_vif_type_p2p(vif))) | ||
921 | return -EIO; | ||
922 | |||
923 | return iwl_mvm_mac_ctx_send(mvm, vif, FW_CTXT_ACTION_MODIFY); | ||
924 | } | ||
925 | |||
926 | int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | ||
927 | { | ||
928 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
929 | struct iwl_mac_ctx_cmd cmd; | ||
930 | int ret; | ||
931 | |||
932 | if (WARN_ONCE(!mvmvif->uploaded, "Removing inactive MAC %pM/%d\n", | ||
933 | vif->addr, ieee80211_vif_type_p2p(vif))) | ||
934 | return -EIO; | ||
935 | |||
936 | memset(&cmd, 0, sizeof(cmd)); | ||
937 | |||
938 | cmd.id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, | ||
939 | mvmvif->color)); | ||
940 | cmd.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE); | ||
941 | |||
942 | ret = iwl_mvm_send_cmd_pdu(mvm, MAC_CONTEXT_CMD, CMD_SYNC, | ||
943 | sizeof(cmd), &cmd); | ||
944 | if (ret) { | ||
945 | IWL_ERR(mvm, "Failed to remove MAC context: %d\n", ret); | ||
946 | return ret; | ||
947 | } | ||
948 | |||
949 | mvmvif->uploaded = false; | ||
950 | return 0; | ||
951 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c new file mode 100644 index 000000000000..a6b05a02cfd4 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c | |||
@@ -0,0 +1,1310 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called LICENSE.GPL. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | * | ||
62 | *****************************************************************************/ | ||
63 | #include <linux/kernel.h> | ||
64 | #include <linux/slab.h> | ||
65 | #include <linux/skbuff.h> | ||
66 | #include <linux/netdevice.h> | ||
67 | #include <linux/etherdevice.h> | ||
68 | #include <net/mac80211.h> | ||
69 | |||
70 | #include "iwl-op-mode.h" | ||
71 | #include "iwl-io.h" | ||
72 | #include "mvm.h" | ||
73 | #include "sta.h" | ||
74 | #include "time-event.h" | ||
75 | #include "iwl-eeprom-parse.h" | ||
76 | #include "fw-api-scan.h" | ||
77 | #include "iwl-phy-db.h" | ||
78 | |||
79 | static const struct ieee80211_iface_limit iwl_mvm_limits[] = { | ||
80 | { | ||
81 | .max = 1, | ||
82 | .types = BIT(NL80211_IFTYPE_STATION) | | ||
83 | BIT(NL80211_IFTYPE_AP), | ||
84 | }, | ||
85 | { | ||
86 | .max = 1, | ||
87 | .types = BIT(NL80211_IFTYPE_P2P_CLIENT) | | ||
88 | BIT(NL80211_IFTYPE_P2P_GO), | ||
89 | }, | ||
90 | { | ||
91 | .max = 1, | ||
92 | .types = BIT(NL80211_IFTYPE_P2P_DEVICE), | ||
93 | }, | ||
94 | }; | ||
95 | |||
96 | static const struct ieee80211_iface_combination iwl_mvm_iface_combinations[] = { | ||
97 | { | ||
98 | .num_different_channels = 1, | ||
99 | .max_interfaces = 3, | ||
100 | .limits = iwl_mvm_limits, | ||
101 | .n_limits = ARRAY_SIZE(iwl_mvm_limits), | ||
102 | }, | ||
103 | }; | ||
104 | |||
105 | int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | ||
106 | { | ||
107 | struct ieee80211_hw *hw = mvm->hw; | ||
108 | int num_mac, ret; | ||
109 | |||
110 | /* Tell mac80211 our characteristics */ | ||
111 | hw->flags = IEEE80211_HW_SIGNAL_DBM | | ||
112 | IEEE80211_HW_SPECTRUM_MGMT | | ||
113 | IEEE80211_HW_REPORTS_TX_ACK_STATUS | | ||
114 | IEEE80211_HW_QUEUE_CONTROL | | ||
115 | IEEE80211_HW_WANT_MONITOR_VIF | | ||
116 | IEEE80211_HW_SCAN_WHILE_IDLE | | ||
117 | IEEE80211_HW_NEED_DTIM_PERIOD | | ||
118 | IEEE80211_HW_SUPPORTS_PS | | ||
119 | IEEE80211_HW_SUPPORTS_DYNAMIC_PS | | ||
120 | IEEE80211_HW_AMPDU_AGGREGATION; | ||
121 | |||
122 | hw->queues = IWL_FIRST_AMPDU_QUEUE; | ||
123 | hw->offchannel_tx_hw_queue = IWL_OFFCHANNEL_QUEUE; | ||
124 | hw->rate_control_algorithm = "iwl-mvm-rs"; | ||
125 | |||
126 | /* | ||
127 | * Enable 11w if advertised by firmware and software crypto | ||
128 | * is not enabled (as the firmware will interpret some mgmt | ||
129 | * packets, so enabling it with software crypto isn't safe) | ||
130 | */ | ||
131 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_MFP && | ||
132 | !iwlwifi_mod_params.sw_crypto) | ||
133 | hw->flags |= IEEE80211_HW_MFP_CAPABLE; | ||
134 | |||
135 | hw->sta_data_size = sizeof(struct iwl_mvm_sta); | ||
136 | hw->vif_data_size = sizeof(struct iwl_mvm_vif); | ||
137 | hw->chanctx_data_size = sizeof(struct iwl_mvm_phy_ctxt); | ||
138 | |||
139 | hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | | ||
140 | BIT(NL80211_IFTYPE_P2P_CLIENT) | | ||
141 | BIT(NL80211_IFTYPE_AP) | | ||
142 | BIT(NL80211_IFTYPE_P2P_GO) | | ||
143 | BIT(NL80211_IFTYPE_P2P_DEVICE); | ||
144 | |||
145 | hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY | | ||
146 | WIPHY_FLAG_DISABLE_BEACON_HINTS | | ||
147 | WIPHY_FLAG_IBSS_RSN; | ||
148 | |||
149 | hw->wiphy->iface_combinations = iwl_mvm_iface_combinations; | ||
150 | hw->wiphy->n_iface_combinations = | ||
151 | ARRAY_SIZE(iwl_mvm_iface_combinations); | ||
152 | |||
153 | hw->wiphy->max_remain_on_channel_duration = 500; | ||
154 | hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL; | ||
155 | |||
156 | /* Extract MAC address */ | ||
157 | memcpy(mvm->addresses[0].addr, mvm->nvm_data->hw_addr, ETH_ALEN); | ||
158 | hw->wiphy->addresses = mvm->addresses; | ||
159 | hw->wiphy->n_addresses = 1; | ||
160 | num_mac = mvm->nvm_data->n_hw_addrs; | ||
161 | if (num_mac > 1) { | ||
162 | memcpy(mvm->addresses[1].addr, mvm->addresses[0].addr, | ||
163 | ETH_ALEN); | ||
164 | mvm->addresses[1].addr[5]++; | ||
165 | hw->wiphy->n_addresses++; | ||
166 | } | ||
167 | |||
168 | /* we create the 802.11 header and a max-length SSID element */ | ||
169 | hw->wiphy->max_scan_ie_len = | ||
170 | mvm->fw->ucode_capa.max_probe_length - 24 - 34; | ||
171 | hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX; | ||
172 | |||
173 | if (mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels) | ||
174 | hw->wiphy->bands[IEEE80211_BAND_2GHZ] = | ||
175 | &mvm->nvm_data->bands[IEEE80211_BAND_2GHZ]; | ||
176 | if (mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels) | ||
177 | hw->wiphy->bands[IEEE80211_BAND_5GHZ] = | ||
178 | &mvm->nvm_data->bands[IEEE80211_BAND_5GHZ]; | ||
179 | |||
180 | hw->wiphy->hw_version = mvm->trans->hw_id; | ||
181 | |||
182 | if (iwlwifi_mod_params.power_save) | ||
183 | hw->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; | ||
184 | else | ||
185 | hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; | ||
186 | |||
187 | hw->wiphy->features |= NL80211_FEATURE_P2P_GO_CTWIN | | ||
188 | NL80211_FEATURE_P2P_GO_OPPPS; | ||
189 | |||
190 | mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; | ||
191 | |||
192 | #ifdef CONFIG_PM_SLEEP | ||
193 | if (mvm->fw->img[IWL_UCODE_WOWLAN].sec[0].len && | ||
194 | mvm->trans->ops->d3_suspend && | ||
195 | mvm->trans->ops->d3_resume && | ||
196 | device_can_wakeup(mvm->trans->dev)) { | ||
197 | hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT | | ||
198 | WIPHY_WOWLAN_DISCONNECT | | ||
199 | WIPHY_WOWLAN_EAP_IDENTITY_REQ | | ||
200 | WIPHY_WOWLAN_RFKILL_RELEASE; | ||
201 | if (!iwlwifi_mod_params.sw_crypto) | ||
202 | hw->wiphy->wowlan.flags |= | ||
203 | WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | | ||
204 | WIPHY_WOWLAN_GTK_REKEY_FAILURE | | ||
205 | WIPHY_WOWLAN_4WAY_HANDSHAKE; | ||
206 | |||
207 | hw->wiphy->wowlan.n_patterns = IWL_WOWLAN_MAX_PATTERNS; | ||
208 | hw->wiphy->wowlan.pattern_min_len = IWL_WOWLAN_MIN_PATTERN_LEN; | ||
209 | hw->wiphy->wowlan.pattern_max_len = IWL_WOWLAN_MAX_PATTERN_LEN; | ||
210 | } | ||
211 | #endif | ||
212 | |||
213 | ret = iwl_mvm_leds_init(mvm); | ||
214 | if (ret) | ||
215 | return ret; | ||
216 | |||
217 | return ieee80211_register_hw(mvm->hw); | ||
218 | } | ||
219 | |||
220 | static void iwl_mvm_mac_tx(struct ieee80211_hw *hw, | ||
221 | struct ieee80211_tx_control *control, | ||
222 | struct sk_buff *skb) | ||
223 | { | ||
224 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
225 | |||
226 | if (test_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status)) { | ||
227 | IWL_DEBUG_DROP(mvm, "Dropping - RF KILL\n"); | ||
228 | goto drop; | ||
229 | } | ||
230 | |||
231 | if (IEEE80211_SKB_CB(skb)->hw_queue == IWL_OFFCHANNEL_QUEUE && | ||
232 | !test_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status)) | ||
233 | goto drop; | ||
234 | |||
235 | if (control->sta) { | ||
236 | if (iwl_mvm_tx_skb(mvm, skb, control->sta)) | ||
237 | goto drop; | ||
238 | return; | ||
239 | } | ||
240 | |||
241 | if (iwl_mvm_tx_skb_non_sta(mvm, skb)) | ||
242 | goto drop; | ||
243 | return; | ||
244 | drop: | ||
245 | ieee80211_free_txskb(hw, skb); | ||
246 | } | ||
247 | |||
248 | static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw, | ||
249 | struct ieee80211_vif *vif, | ||
250 | enum ieee80211_ampdu_mlme_action action, | ||
251 | struct ieee80211_sta *sta, u16 tid, | ||
252 | u16 *ssn, u8 buf_size) | ||
253 | { | ||
254 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
255 | int ret; | ||
256 | |||
257 | IWL_DEBUG_HT(mvm, "A-MPDU action on addr %pM tid %d: action %d\n", | ||
258 | sta->addr, tid, action); | ||
259 | |||
260 | if (!(mvm->nvm_data->sku_cap_11n_enable)) | ||
261 | return -EACCES; | ||
262 | |||
263 | mutex_lock(&mvm->mutex); | ||
264 | |||
265 | switch (action) { | ||
266 | case IEEE80211_AMPDU_RX_START: | ||
267 | if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_RXAGG) { | ||
268 | ret = -EINVAL; | ||
269 | break; | ||
270 | } | ||
271 | ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, *ssn, true); | ||
272 | break; | ||
273 | case IEEE80211_AMPDU_RX_STOP: | ||
274 | ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, 0, false); | ||
275 | break; | ||
276 | case IEEE80211_AMPDU_TX_START: | ||
277 | ret = iwl_mvm_sta_tx_agg_start(mvm, vif, sta, tid, ssn); | ||
278 | break; | ||
279 | case IEEE80211_AMPDU_TX_STOP_CONT: | ||
280 | case IEEE80211_AMPDU_TX_STOP_FLUSH: | ||
281 | case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: | ||
282 | ret = iwl_mvm_sta_tx_agg_stop(mvm, vif, sta, tid); | ||
283 | break; | ||
284 | case IEEE80211_AMPDU_TX_OPERATIONAL: | ||
285 | ret = iwl_mvm_sta_tx_agg_oper(mvm, vif, sta, tid, buf_size); | ||
286 | break; | ||
287 | default: | ||
288 | WARN_ON_ONCE(1); | ||
289 | ret = -EINVAL; | ||
290 | break; | ||
291 | } | ||
292 | mutex_unlock(&mvm->mutex); | ||
293 | |||
294 | return ret; | ||
295 | } | ||
296 | |||
297 | static void iwl_mvm_cleanup_iterator(void *data, u8 *mac, | ||
298 | struct ieee80211_vif *vif) | ||
299 | { | ||
300 | struct iwl_mvm *mvm = data; | ||
301 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
302 | |||
303 | mvmvif->uploaded = false; | ||
304 | mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; | ||
305 | |||
306 | /* does this make sense at all? */ | ||
307 | mvmvif->color++; | ||
308 | |||
309 | spin_lock_bh(&mvm->time_event_lock); | ||
310 | iwl_mvm_te_clear_data(mvm, &mvmvif->time_event_data); | ||
311 | spin_unlock_bh(&mvm->time_event_lock); | ||
312 | |||
313 | if (vif->type != NL80211_IFTYPE_P2P_DEVICE) | ||
314 | mvmvif->phy_ctxt = NULL; | ||
315 | } | ||
316 | |||
317 | static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) | ||
318 | { | ||
319 | iwl_trans_stop_device(mvm->trans); | ||
320 | iwl_trans_stop_hw(mvm->trans, false); | ||
321 | |||
322 | mvm->scan_status = IWL_MVM_SCAN_NONE; | ||
323 | |||
324 | /* just in case one was running */ | ||
325 | ieee80211_remain_on_channel_expired(mvm->hw); | ||
326 | |||
327 | ieee80211_iterate_active_interfaces_atomic( | ||
328 | mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL, | ||
329 | iwl_mvm_cleanup_iterator, mvm); | ||
330 | |||
331 | memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table)); | ||
332 | memset(mvm->sta_drained, 0, sizeof(mvm->sta_drained)); | ||
333 | |||
334 | ieee80211_wake_queues(mvm->hw); | ||
335 | |||
336 | mvm->vif_count = 0; | ||
337 | } | ||
338 | |||
339 | static int iwl_mvm_mac_start(struct ieee80211_hw *hw) | ||
340 | { | ||
341 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
342 | int ret; | ||
343 | |||
344 | mutex_lock(&mvm->mutex); | ||
345 | |||
346 | /* Clean up some internal and mac80211 state on restart */ | ||
347 | if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) | ||
348 | iwl_mvm_restart_cleanup(mvm); | ||
349 | |||
350 | ret = iwl_mvm_up(mvm); | ||
351 | mutex_unlock(&mvm->mutex); | ||
352 | |||
353 | return ret; | ||
354 | } | ||
355 | |||
356 | static void iwl_mvm_mac_restart_complete(struct ieee80211_hw *hw) | ||
357 | { | ||
358 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
359 | int ret; | ||
360 | |||
361 | mutex_lock(&mvm->mutex); | ||
362 | |||
363 | clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); | ||
364 | ret = iwl_mvm_update_quotas(mvm, NULL); | ||
365 | if (ret) | ||
366 | IWL_ERR(mvm, "Failed to update quotas after restart (%d)\n", | ||
367 | ret); | ||
368 | |||
369 | mutex_unlock(&mvm->mutex); | ||
370 | } | ||
371 | |||
372 | static void iwl_mvm_mac_stop(struct ieee80211_hw *hw) | ||
373 | { | ||
374 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
375 | |||
376 | flush_work(&mvm->async_handlers_wk); | ||
377 | |||
378 | mutex_lock(&mvm->mutex); | ||
379 | /* async_handlers_wk is now blocked */ | ||
380 | |||
381 | /* | ||
382 | * The work item could be running or queued if the | ||
383 | * ROC time event stops just as we get here. | ||
384 | */ | ||
385 | cancel_work_sync(&mvm->roc_done_wk); | ||
386 | |||
387 | iwl_trans_stop_device(mvm->trans); | ||
388 | iwl_trans_stop_hw(mvm->trans, false); | ||
389 | |||
390 | iwl_mvm_async_handlers_purge(mvm); | ||
391 | /* async_handlers_list is empty and will stay empty: HW is stopped */ | ||
392 | |||
393 | /* the fw is stopped, the aux sta is dead: clean up driver state */ | ||
394 | iwl_mvm_dealloc_int_sta(mvm, &mvm->aux_sta); | ||
395 | |||
396 | mutex_unlock(&mvm->mutex); | ||
397 | |||
398 | /* | ||
399 | * The worker might have been waiting for the mutex, let it run and | ||
400 | * discover that its list is now empty. | ||
401 | */ | ||
402 | cancel_work_sync(&mvm->async_handlers_wk); | ||
403 | } | ||
404 | |||
405 | static void iwl_mvm_pm_disable_iterator(void *data, u8 *mac, | ||
406 | struct ieee80211_vif *vif) | ||
407 | { | ||
408 | struct iwl_mvm *mvm = data; | ||
409 | int ret; | ||
410 | |||
411 | ret = iwl_mvm_power_disable(mvm, vif); | ||
412 | if (ret) | ||
413 | IWL_ERR(mvm, "failed to disable power management\n"); | ||
414 | } | ||
415 | |||
416 | static void iwl_mvm_power_update_iterator(void *data, u8 *mac, | ||
417 | struct ieee80211_vif *vif) | ||
418 | { | ||
419 | struct iwl_mvm *mvm = data; | ||
420 | |||
421 | iwl_mvm_power_update_mode(mvm, vif); | ||
422 | } | ||
423 | |||
424 | static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, | ||
425 | struct ieee80211_vif *vif) | ||
426 | { | ||
427 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
428 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
429 | int ret; | ||
430 | |||
431 | /* | ||
432 | * Not much to do here. The stack will not allow interface | ||
433 | * types or combinations that we didn't advertise, so we | ||
434 | * don't really have to check the types. | ||
435 | */ | ||
436 | |||
437 | mutex_lock(&mvm->mutex); | ||
438 | |||
439 | /* Allocate resources for the MAC context, and add it the the fw */ | ||
440 | ret = iwl_mvm_mac_ctxt_init(mvm, vif); | ||
441 | if (ret) | ||
442 | goto out_unlock; | ||
443 | |||
444 | /* | ||
445 | * The AP binding flow can be done only after the beacon | ||
446 | * template is configured (which happens only in the mac80211 | ||
447 | * start_ap() flow), and adding the broadcast station can happen | ||
448 | * only after the binding. | ||
449 | * In addition, since modifying the MAC before adding a bcast | ||
450 | * station is not allowed by the FW, delay the adding of MAC context to | ||
451 | * the point where we can also add the bcast station. | ||
452 | * In short: there's not much we can do at this point, other than | ||
453 | * allocating resources :) | ||
454 | */ | ||
455 | if (vif->type == NL80211_IFTYPE_AP) { | ||
456 | u32 qmask = iwl_mvm_mac_get_queues_mask(mvm, vif); | ||
457 | ret = iwl_mvm_allocate_int_sta(mvm, &mvmvif->bcast_sta, | ||
458 | qmask); | ||
459 | if (ret) { | ||
460 | IWL_ERR(mvm, "Failed to allocate bcast sta\n"); | ||
461 | goto out_release; | ||
462 | } | ||
463 | |||
464 | goto out_unlock; | ||
465 | } | ||
466 | |||
467 | /* | ||
468 | * TODO: remove this temporary code. | ||
469 | * Currently MVM FW supports power management only on single MAC. | ||
470 | * Iterate and disable PM on all active interfaces. | ||
471 | * Note: the method below does not count the new interface being added | ||
472 | * at this moment. | ||
473 | */ | ||
474 | mvm->vif_count++; | ||
475 | if (mvm->vif_count > 1) { | ||
476 | IWL_DEBUG_MAC80211(mvm, | ||
477 | "Disable power on existing interfaces\n"); | ||
478 | ieee80211_iterate_active_interfaces( | ||
479 | mvm->hw, | ||
480 | IEEE80211_IFACE_ITER_NORMAL, | ||
481 | iwl_mvm_pm_disable_iterator, mvm); | ||
482 | } | ||
483 | |||
484 | ret = iwl_mvm_mac_ctxt_add(mvm, vif); | ||
485 | if (ret) | ||
486 | goto out_release; | ||
487 | |||
488 | /* | ||
489 | * Update power state on the new interface. Admittedly, based on | ||
490 | * mac80211 logics this power update will disable power management | ||
491 | */ | ||
492 | iwl_mvm_power_update_mode(mvm, vif); | ||
493 | |||
494 | /* | ||
495 | * P2P_DEVICE interface does not have a channel context assigned to it, | ||
496 | * so a dedicated PHY context is allocated to it and the corresponding | ||
497 | * MAC context is bound to it at this stage. | ||
498 | */ | ||
499 | if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { | ||
500 | struct ieee80211_channel *chan; | ||
501 | struct cfg80211_chan_def chandef; | ||
502 | |||
503 | mvmvif->phy_ctxt = &mvm->phy_ctxt_roc; | ||
504 | |||
505 | /* | ||
506 | * The channel used here isn't relevant as it's | ||
507 | * going to be overwritten as part of the ROC flow. | ||
508 | * For now use the first channel we have. | ||
509 | */ | ||
510 | chan = &mvm->hw->wiphy->bands[IEEE80211_BAND_2GHZ]->channels[0]; | ||
511 | cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT); | ||
512 | ret = iwl_mvm_phy_ctxt_add(mvm, mvmvif->phy_ctxt, | ||
513 | &chandef, 1, 1); | ||
514 | if (ret) | ||
515 | goto out_remove_mac; | ||
516 | |||
517 | ret = iwl_mvm_binding_add_vif(mvm, vif); | ||
518 | if (ret) | ||
519 | goto out_remove_phy; | ||
520 | |||
521 | ret = iwl_mvm_add_bcast_sta(mvm, vif, &mvmvif->bcast_sta); | ||
522 | if (ret) | ||
523 | goto out_unbind; | ||
524 | |||
525 | /* Save a pointer to p2p device vif, so it can later be used to | ||
526 | * update the p2p device MAC when a GO is started/stopped */ | ||
527 | mvm->p2p_device_vif = vif; | ||
528 | } | ||
529 | |||
530 | goto out_unlock; | ||
531 | |||
532 | out_unbind: | ||
533 | iwl_mvm_binding_remove_vif(mvm, vif); | ||
534 | out_remove_phy: | ||
535 | iwl_mvm_phy_ctxt_remove(mvm, mvmvif->phy_ctxt); | ||
536 | out_remove_mac: | ||
537 | mvmvif->phy_ctxt = NULL; | ||
538 | iwl_mvm_mac_ctxt_remove(mvm, vif); | ||
539 | out_release: | ||
540 | /* | ||
541 | * TODO: remove this temporary code. | ||
542 | * Currently MVM FW supports power management only on single MAC. | ||
543 | * Check if only one additional interface remains after rereasing | ||
544 | * current one. Update power mode on the remaining interface. | ||
545 | */ | ||
546 | mvm->vif_count--; | ||
547 | IWL_DEBUG_MAC80211(mvm, "Currently %d interfaces active\n", | ||
548 | mvm->vif_count); | ||
549 | if (mvm->vif_count == 1) { | ||
550 | ieee80211_iterate_active_interfaces( | ||
551 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, | ||
552 | iwl_mvm_power_update_iterator, mvm); | ||
553 | } | ||
554 | iwl_mvm_mac_ctxt_release(mvm, vif); | ||
555 | out_unlock: | ||
556 | mutex_unlock(&mvm->mutex); | ||
557 | |||
558 | return ret; | ||
559 | } | ||
560 | |||
561 | static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw, | ||
562 | struct ieee80211_vif *vif) | ||
563 | { | ||
564 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
565 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
566 | u32 tfd_msk = 0, ac; | ||
567 | |||
568 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) | ||
569 | if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE) | ||
570 | tfd_msk |= BIT(vif->hw_queue[ac]); | ||
571 | |||
572 | if (vif->cab_queue != IEEE80211_INVAL_HW_QUEUE) | ||
573 | tfd_msk |= BIT(vif->cab_queue); | ||
574 | |||
575 | if (tfd_msk) { | ||
576 | mutex_lock(&mvm->mutex); | ||
577 | iwl_mvm_flush_tx_path(mvm, tfd_msk, true); | ||
578 | mutex_unlock(&mvm->mutex); | ||
579 | } | ||
580 | |||
581 | if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { | ||
582 | /* | ||
583 | * Flush the ROC worker which will flush the OFFCHANNEL queue. | ||
584 | * We assume here that all the packets sent to the OFFCHANNEL | ||
585 | * queue are sent in ROC session. | ||
586 | */ | ||
587 | flush_work(&mvm->roc_done_wk); | ||
588 | } else { | ||
589 | /* | ||
590 | * By now, all the AC queues are empty. The AGG queues are | ||
591 | * empty too. We already got all the Tx responses for all the | ||
592 | * packets in the queues. The drain work can have been | ||
593 | * triggered. Flush it. This work item takes the mutex, so kill | ||
594 | * it before we take it. | ||
595 | */ | ||
596 | flush_work(&mvm->sta_drained_wk); | ||
597 | } | ||
598 | |||
599 | mutex_lock(&mvm->mutex); | ||
600 | |||
601 | /* | ||
602 | * For AP/GO interface, the tear down of the resources allocated to the | ||
603 | * interface should be handled as part of the bss_info_changed flow. | ||
604 | */ | ||
605 | if (vif->type == NL80211_IFTYPE_AP) { | ||
606 | iwl_mvm_dealloc_int_sta(mvm, &mvmvif->bcast_sta); | ||
607 | goto out_release; | ||
608 | } | ||
609 | |||
610 | if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { | ||
611 | mvm->p2p_device_vif = NULL; | ||
612 | iwl_mvm_rm_bcast_sta(mvm, &mvmvif->bcast_sta); | ||
613 | iwl_mvm_binding_remove_vif(mvm, vif); | ||
614 | iwl_mvm_phy_ctxt_remove(mvm, mvmvif->phy_ctxt); | ||
615 | mvmvif->phy_ctxt = NULL; | ||
616 | } | ||
617 | |||
618 | /* | ||
619 | * TODO: remove this temporary code. | ||
620 | * Currently MVM FW supports power management only on single MAC. | ||
621 | * Check if only one additional interface remains after removing | ||
622 | * current one. Update power mode on the remaining interface. | ||
623 | */ | ||
624 | if (mvm->vif_count) | ||
625 | mvm->vif_count--; | ||
626 | IWL_DEBUG_MAC80211(mvm, "Currently %d interfaces active\n", | ||
627 | mvm->vif_count); | ||
628 | if (mvm->vif_count == 1) { | ||
629 | ieee80211_iterate_active_interfaces( | ||
630 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, | ||
631 | iwl_mvm_power_update_iterator, mvm); | ||
632 | } | ||
633 | |||
634 | iwl_mvm_mac_ctxt_remove(mvm, vif); | ||
635 | |||
636 | out_release: | ||
637 | iwl_mvm_mac_ctxt_release(mvm, vif); | ||
638 | mutex_unlock(&mvm->mutex); | ||
639 | } | ||
640 | |||
641 | static int iwl_mvm_mac_config(struct ieee80211_hw *hw, u32 changed) | ||
642 | { | ||
643 | return 0; | ||
644 | } | ||
645 | |||
646 | static void iwl_mvm_configure_filter(struct ieee80211_hw *hw, | ||
647 | unsigned int changed_flags, | ||
648 | unsigned int *total_flags, | ||
649 | u64 multicast) | ||
650 | { | ||
651 | *total_flags = 0; | ||
652 | } | ||
653 | |||
654 | static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, | ||
655 | struct ieee80211_vif *vif, | ||
656 | struct ieee80211_bss_conf *bss_conf, | ||
657 | u32 changes) | ||
658 | { | ||
659 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
660 | int ret; | ||
661 | |||
662 | ret = iwl_mvm_mac_ctxt_changed(mvm, vif); | ||
663 | if (ret) | ||
664 | IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr); | ||
665 | |||
666 | if (changes & BSS_CHANGED_ASSOC) { | ||
667 | if (bss_conf->assoc) { | ||
668 | /* add quota for this interface */ | ||
669 | ret = iwl_mvm_update_quotas(mvm, vif); | ||
670 | if (ret) { | ||
671 | IWL_ERR(mvm, "failed to update quotas\n"); | ||
672 | return; | ||
673 | } | ||
674 | iwl_mvm_remove_time_event(mvm, mvmvif, | ||
675 | &mvmvif->time_event_data); | ||
676 | } else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) { | ||
677 | /* remove AP station now that the MAC is unassoc */ | ||
678 | ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id); | ||
679 | if (ret) | ||
680 | IWL_ERR(mvm, "failed to remove AP station\n"); | ||
681 | mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; | ||
682 | /* remove quota for this interface */ | ||
683 | ret = iwl_mvm_update_quotas(mvm, NULL); | ||
684 | if (ret) | ||
685 | IWL_ERR(mvm, "failed to update quotas\n"); | ||
686 | } | ||
687 | } else if (changes & BSS_CHANGED_PS) { | ||
688 | /* | ||
689 | * TODO: remove this temporary code. | ||
690 | * Currently MVM FW supports power management only on single | ||
691 | * MAC. Avoid power mode update if more than one interface | ||
692 | * is active. | ||
693 | */ | ||
694 | IWL_DEBUG_MAC80211(mvm, "Currently %d interfaces active\n", | ||
695 | mvm->vif_count); | ||
696 | if (mvm->vif_count == 1) { | ||
697 | ret = iwl_mvm_power_update_mode(mvm, vif); | ||
698 | if (ret) | ||
699 | IWL_ERR(mvm, "failed to update power mode\n"); | ||
700 | } | ||
701 | } | ||
702 | } | ||
703 | |||
704 | static int iwl_mvm_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) | ||
705 | { | ||
706 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
707 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
708 | int ret; | ||
709 | |||
710 | mutex_lock(&mvm->mutex); | ||
711 | |||
712 | /* Send the beacon template */ | ||
713 | ret = iwl_mvm_mac_ctxt_beacon_changed(mvm, vif); | ||
714 | if (ret) | ||
715 | goto out_unlock; | ||
716 | |||
717 | /* Add the mac context */ | ||
718 | ret = iwl_mvm_mac_ctxt_add(mvm, vif); | ||
719 | if (ret) | ||
720 | goto out_unlock; | ||
721 | |||
722 | /* Perform the binding */ | ||
723 | ret = iwl_mvm_binding_add_vif(mvm, vif); | ||
724 | if (ret) | ||
725 | goto out_remove; | ||
726 | |||
727 | mvmvif->ap_active = true; | ||
728 | |||
729 | /* Send the bcast station. At this stage the TBTT and DTIM time events | ||
730 | * are added and applied to the scheduler */ | ||
731 | ret = iwl_mvm_send_bcast_sta(mvm, vif, &mvmvif->bcast_sta); | ||
732 | if (ret) | ||
733 | goto out_unbind; | ||
734 | |||
735 | ret = iwl_mvm_update_quotas(mvm, vif); | ||
736 | if (ret) | ||
737 | goto out_rm_bcast; | ||
738 | |||
739 | /* Need to update the P2P Device MAC */ | ||
740 | if (vif->p2p && mvm->p2p_device_vif) | ||
741 | iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif); | ||
742 | |||
743 | mutex_unlock(&mvm->mutex); | ||
744 | return 0; | ||
745 | |||
746 | out_rm_bcast: | ||
747 | iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta); | ||
748 | out_unbind: | ||
749 | iwl_mvm_binding_remove_vif(mvm, vif); | ||
750 | out_remove: | ||
751 | iwl_mvm_mac_ctxt_remove(mvm, vif); | ||
752 | out_unlock: | ||
753 | mutex_unlock(&mvm->mutex); | ||
754 | return ret; | ||
755 | } | ||
756 | |||
757 | static void iwl_mvm_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) | ||
758 | { | ||
759 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
760 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
761 | |||
762 | mutex_lock(&mvm->mutex); | ||
763 | |||
764 | mvmvif->ap_active = false; | ||
765 | |||
766 | /* Need to update the P2P Device MAC */ | ||
767 | if (vif->p2p && mvm->p2p_device_vif) | ||
768 | iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif); | ||
769 | |||
770 | iwl_mvm_update_quotas(mvm, NULL); | ||
771 | iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta); | ||
772 | iwl_mvm_binding_remove_vif(mvm, vif); | ||
773 | iwl_mvm_mac_ctxt_remove(mvm, vif); | ||
774 | |||
775 | mutex_unlock(&mvm->mutex); | ||
776 | } | ||
777 | |||
778 | static void iwl_mvm_bss_info_changed_ap(struct iwl_mvm *mvm, | ||
779 | struct ieee80211_vif *vif, | ||
780 | struct ieee80211_bss_conf *bss_conf, | ||
781 | u32 changes) | ||
782 | { | ||
783 | /* Need to send a new beacon template to the FW */ | ||
784 | if (changes & BSS_CHANGED_BEACON) { | ||
785 | if (iwl_mvm_mac_ctxt_beacon_changed(mvm, vif)) | ||
786 | IWL_WARN(mvm, "Failed updating beacon data\n"); | ||
787 | } | ||
788 | } | ||
789 | |||
790 | static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw, | ||
791 | struct ieee80211_vif *vif, | ||
792 | struct ieee80211_bss_conf *bss_conf, | ||
793 | u32 changes) | ||
794 | { | ||
795 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
796 | |||
797 | mutex_lock(&mvm->mutex); | ||
798 | |||
799 | switch (vif->type) { | ||
800 | case NL80211_IFTYPE_STATION: | ||
801 | iwl_mvm_bss_info_changed_station(mvm, vif, bss_conf, changes); | ||
802 | break; | ||
803 | case NL80211_IFTYPE_AP: | ||
804 | iwl_mvm_bss_info_changed_ap(mvm, vif, bss_conf, changes); | ||
805 | break; | ||
806 | default: | ||
807 | /* shouldn't happen */ | ||
808 | WARN_ON_ONCE(1); | ||
809 | } | ||
810 | |||
811 | mutex_unlock(&mvm->mutex); | ||
812 | } | ||
813 | |||
814 | static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, | ||
815 | struct ieee80211_vif *vif, | ||
816 | struct cfg80211_scan_request *req) | ||
817 | { | ||
818 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
819 | int ret; | ||
820 | |||
821 | if (req->n_channels == 0 || req->n_channels > MAX_NUM_SCAN_CHANNELS) | ||
822 | return -EINVAL; | ||
823 | |||
824 | mutex_lock(&mvm->mutex); | ||
825 | |||
826 | if (mvm->scan_status == IWL_MVM_SCAN_NONE) | ||
827 | ret = iwl_mvm_scan_request(mvm, vif, req); | ||
828 | else | ||
829 | ret = -EBUSY; | ||
830 | |||
831 | mutex_unlock(&mvm->mutex); | ||
832 | |||
833 | return ret; | ||
834 | } | ||
835 | |||
836 | static void iwl_mvm_mac_cancel_hw_scan(struct ieee80211_hw *hw, | ||
837 | struct ieee80211_vif *vif) | ||
838 | { | ||
839 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
840 | |||
841 | mutex_lock(&mvm->mutex); | ||
842 | |||
843 | iwl_mvm_cancel_scan(mvm); | ||
844 | |||
845 | mutex_unlock(&mvm->mutex); | ||
846 | } | ||
847 | |||
848 | static void | ||
849 | iwl_mvm_mac_allow_buffered_frames(struct ieee80211_hw *hw, | ||
850 | struct ieee80211_sta *sta, u16 tid, | ||
851 | int num_frames, | ||
852 | enum ieee80211_frame_release_type reason, | ||
853 | bool more_data) | ||
854 | { | ||
855 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
856 | struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; | ||
857 | |||
858 | /* TODO: how do we tell the fw to send frames for a specific TID */ | ||
859 | |||
860 | /* | ||
861 | * The fw will send EOSP notification when the last frame will be | ||
862 | * transmitted. | ||
863 | */ | ||
864 | iwl_mvm_sta_modify_sleep_tx_count(mvm, mvmsta->sta_id, reason, | ||
865 | num_frames); | ||
866 | } | ||
867 | |||
868 | static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw, | ||
869 | struct ieee80211_vif *vif, | ||
870 | enum sta_notify_cmd cmd, | ||
871 | struct ieee80211_sta *sta) | ||
872 | { | ||
873 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
874 | struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; | ||
875 | |||
876 | switch (cmd) { | ||
877 | case STA_NOTIFY_SLEEP: | ||
878 | if (atomic_read(&mvmsta->pending_frames) > 0) | ||
879 | ieee80211_sta_block_awake(hw, sta, true); | ||
880 | /* | ||
881 | * The fw updates the STA to be asleep. Tx packets on the Tx | ||
882 | * queues to this station will not be transmitted. The fw will | ||
883 | * send a Tx response with TX_STATUS_FAIL_DEST_PS. | ||
884 | */ | ||
885 | break; | ||
886 | case STA_NOTIFY_AWAKE: | ||
887 | if (WARN_ON(mvmsta->sta_id == IWL_INVALID_STATION)) | ||
888 | break; | ||
889 | iwl_mvm_sta_modify_ps_wake(mvm, mvmsta->sta_id); | ||
890 | break; | ||
891 | default: | ||
892 | break; | ||
893 | } | ||
894 | } | ||
895 | |||
896 | static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, | ||
897 | struct ieee80211_vif *vif, | ||
898 | struct ieee80211_sta *sta, | ||
899 | enum ieee80211_sta_state old_state, | ||
900 | enum ieee80211_sta_state new_state) | ||
901 | { | ||
902 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
903 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
904 | int ret; | ||
905 | |||
906 | IWL_DEBUG_MAC80211(mvm, "station %pM state change %d->%d\n", | ||
907 | sta->addr, old_state, new_state); | ||
908 | |||
909 | /* this would be a mac80211 bug ... but don't crash */ | ||
910 | if (WARN_ON_ONCE(!mvmvif->phy_ctxt)) | ||
911 | return -EINVAL; | ||
912 | |||
913 | /* if a STA is being removed, reuse its ID */ | ||
914 | flush_work(&mvm->sta_drained_wk); | ||
915 | |||
916 | mutex_lock(&mvm->mutex); | ||
917 | if (old_state == IEEE80211_STA_NOTEXIST && | ||
918 | new_state == IEEE80211_STA_NONE) { | ||
919 | ret = iwl_mvm_add_sta(mvm, vif, sta); | ||
920 | } else if (old_state == IEEE80211_STA_NONE && | ||
921 | new_state == IEEE80211_STA_AUTH) { | ||
922 | ret = 0; | ||
923 | } else if (old_state == IEEE80211_STA_AUTH && | ||
924 | new_state == IEEE80211_STA_ASSOC) { | ||
925 | iwl_mvm_rs_rate_init(mvm, sta, mvmvif->phy_ctxt->channel->band); | ||
926 | ret = 0; | ||
927 | } else if (old_state == IEEE80211_STA_ASSOC && | ||
928 | new_state == IEEE80211_STA_AUTHORIZED) { | ||
929 | ret = 0; | ||
930 | } else if (old_state == IEEE80211_STA_AUTHORIZED && | ||
931 | new_state == IEEE80211_STA_ASSOC) { | ||
932 | ret = 0; | ||
933 | } else if (old_state == IEEE80211_STA_ASSOC && | ||
934 | new_state == IEEE80211_STA_AUTH) { | ||
935 | ret = 0; | ||
936 | } else if (old_state == IEEE80211_STA_AUTH && | ||
937 | new_state == IEEE80211_STA_NONE) { | ||
938 | ret = 0; | ||
939 | } else if (old_state == IEEE80211_STA_NONE && | ||
940 | new_state == IEEE80211_STA_NOTEXIST) { | ||
941 | ret = iwl_mvm_rm_sta(mvm, vif, sta); | ||
942 | } else { | ||
943 | ret = -EIO; | ||
944 | } | ||
945 | mutex_unlock(&mvm->mutex); | ||
946 | |||
947 | return ret; | ||
948 | } | ||
949 | |||
950 | static int iwl_mvm_mac_set_rts_threshold(struct ieee80211_hw *hw, u32 value) | ||
951 | { | ||
952 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
953 | |||
954 | mvm->rts_threshold = value; | ||
955 | |||
956 | return 0; | ||
957 | } | ||
958 | |||
959 | static int iwl_mvm_mac_conf_tx(struct ieee80211_hw *hw, | ||
960 | struct ieee80211_vif *vif, u16 ac, | ||
961 | const struct ieee80211_tx_queue_params *params) | ||
962 | { | ||
963 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
964 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
965 | |||
966 | mvmvif->queue_params[ac] = *params; | ||
967 | |||
968 | /* | ||
969 | * No need to update right away, we'll get BSS_CHANGED_QOS | ||
970 | * The exception is P2P_DEVICE interface which needs immediate update. | ||
971 | */ | ||
972 | if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { | ||
973 | int ret; | ||
974 | |||
975 | mutex_lock(&mvm->mutex); | ||
976 | ret = iwl_mvm_mac_ctxt_changed(mvm, vif); | ||
977 | mutex_unlock(&mvm->mutex); | ||
978 | return ret; | ||
979 | } | ||
980 | return 0; | ||
981 | } | ||
982 | |||
983 | static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw, | ||
984 | struct ieee80211_vif *vif) | ||
985 | { | ||
986 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
987 | u32 duration = min(IWL_MVM_TE_SESSION_PROTECTION_MAX_TIME_MS, | ||
988 | 200 + vif->bss_conf.beacon_int); | ||
989 | u32 min_duration = min(IWL_MVM_TE_SESSION_PROTECTION_MIN_TIME_MS, | ||
990 | 100 + vif->bss_conf.beacon_int); | ||
991 | |||
992 | if (WARN_ON_ONCE(vif->bss_conf.assoc)) | ||
993 | return; | ||
994 | |||
995 | mutex_lock(&mvm->mutex); | ||
996 | /* Try really hard to protect the session and hear a beacon */ | ||
997 | iwl_mvm_protect_session(mvm, vif, duration, min_duration); | ||
998 | mutex_unlock(&mvm->mutex); | ||
999 | } | ||
1000 | |||
1001 | static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, | ||
1002 | enum set_key_cmd cmd, | ||
1003 | struct ieee80211_vif *vif, | ||
1004 | struct ieee80211_sta *sta, | ||
1005 | struct ieee80211_key_conf *key) | ||
1006 | { | ||
1007 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
1008 | int ret; | ||
1009 | |||
1010 | if (iwlwifi_mod_params.sw_crypto) { | ||
1011 | IWL_DEBUG_MAC80211(mvm, "leave - hwcrypto disabled\n"); | ||
1012 | return -EOPNOTSUPP; | ||
1013 | } | ||
1014 | |||
1015 | switch (key->cipher) { | ||
1016 | case WLAN_CIPHER_SUITE_TKIP: | ||
1017 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; | ||
1018 | /* fall-through */ | ||
1019 | case WLAN_CIPHER_SUITE_CCMP: | ||
1020 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; | ||
1021 | break; | ||
1022 | case WLAN_CIPHER_SUITE_AES_CMAC: | ||
1023 | WARN_ON_ONCE(!(hw->flags & IEEE80211_HW_MFP_CAPABLE)); | ||
1024 | break; | ||
1025 | case WLAN_CIPHER_SUITE_WEP40: | ||
1026 | case WLAN_CIPHER_SUITE_WEP104: | ||
1027 | /* | ||
1028 | * Support for TX only, at least for now, so accept | ||
1029 | * the key and do nothing else. Then mac80211 will | ||
1030 | * pass it for TX but we don't have to use it for RX. | ||
1031 | */ | ||
1032 | return 0; | ||
1033 | default: | ||
1034 | return -EOPNOTSUPP; | ||
1035 | } | ||
1036 | |||
1037 | mutex_lock(&mvm->mutex); | ||
1038 | |||
1039 | switch (cmd) { | ||
1040 | case SET_KEY: | ||
1041 | IWL_DEBUG_MAC80211(mvm, "set hwcrypto key\n"); | ||
1042 | ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, false); | ||
1043 | if (ret) { | ||
1044 | IWL_WARN(mvm, "set key failed\n"); | ||
1045 | /* | ||
1046 | * can't add key for RX, but we don't need it | ||
1047 | * in the device for TX so still return 0 | ||
1048 | */ | ||
1049 | ret = 0; | ||
1050 | } | ||
1051 | |||
1052 | break; | ||
1053 | case DISABLE_KEY: | ||
1054 | IWL_DEBUG_MAC80211(mvm, "disable hwcrypto key\n"); | ||
1055 | ret = iwl_mvm_remove_sta_key(mvm, vif, sta, key); | ||
1056 | break; | ||
1057 | default: | ||
1058 | ret = -EINVAL; | ||
1059 | } | ||
1060 | |||
1061 | mutex_unlock(&mvm->mutex); | ||
1062 | return ret; | ||
1063 | } | ||
1064 | |||
1065 | static void iwl_mvm_mac_update_tkip_key(struct ieee80211_hw *hw, | ||
1066 | struct ieee80211_vif *vif, | ||
1067 | struct ieee80211_key_conf *keyconf, | ||
1068 | struct ieee80211_sta *sta, | ||
1069 | u32 iv32, u16 *phase1key) | ||
1070 | { | ||
1071 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
1072 | |||
1073 | iwl_mvm_update_tkip_key(mvm, vif, keyconf, sta, iv32, phase1key); | ||
1074 | } | ||
1075 | |||
1076 | |||
1077 | static int iwl_mvm_roc(struct ieee80211_hw *hw, | ||
1078 | struct ieee80211_vif *vif, | ||
1079 | struct ieee80211_channel *channel, | ||
1080 | int duration) | ||
1081 | { | ||
1082 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
1083 | struct cfg80211_chan_def chandef; | ||
1084 | int ret; | ||
1085 | |||
1086 | if (vif->type != NL80211_IFTYPE_P2P_DEVICE) { | ||
1087 | IWL_ERR(mvm, "vif isn't a P2P_DEVICE: %d\n", vif->type); | ||
1088 | return -EINVAL; | ||
1089 | } | ||
1090 | |||
1091 | IWL_DEBUG_MAC80211(mvm, "enter (%d, %d)\n", channel->hw_value, | ||
1092 | duration); | ||
1093 | |||
1094 | mutex_lock(&mvm->mutex); | ||
1095 | |||
1096 | cfg80211_chandef_create(&chandef, channel, NL80211_CHAN_NO_HT); | ||
1097 | ret = iwl_mvm_phy_ctxt_changed(mvm, &mvm->phy_ctxt_roc, | ||
1098 | &chandef, 1, 1); | ||
1099 | |||
1100 | /* Schedule the time events */ | ||
1101 | ret = iwl_mvm_start_p2p_roc(mvm, vif, duration); | ||
1102 | |||
1103 | mutex_unlock(&mvm->mutex); | ||
1104 | IWL_DEBUG_MAC80211(mvm, "leave\n"); | ||
1105 | |||
1106 | return ret; | ||
1107 | } | ||
1108 | |||
1109 | static int iwl_mvm_cancel_roc(struct ieee80211_hw *hw) | ||
1110 | { | ||
1111 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
1112 | |||
1113 | IWL_DEBUG_MAC80211(mvm, "enter\n"); | ||
1114 | |||
1115 | mutex_lock(&mvm->mutex); | ||
1116 | iwl_mvm_stop_p2p_roc(mvm); | ||
1117 | mutex_unlock(&mvm->mutex); | ||
1118 | |||
1119 | IWL_DEBUG_MAC80211(mvm, "leave\n"); | ||
1120 | return 0; | ||
1121 | } | ||
1122 | |||
1123 | static int iwl_mvm_add_chanctx(struct ieee80211_hw *hw, | ||
1124 | struct ieee80211_chanctx_conf *ctx) | ||
1125 | { | ||
1126 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
1127 | struct iwl_mvm_phy_ctxt *phy_ctxt = (void *)ctx->drv_priv; | ||
1128 | int ret; | ||
1129 | |||
1130 | mutex_lock(&mvm->mutex); | ||
1131 | |||
1132 | IWL_DEBUG_MAC80211(mvm, "Add PHY context\n"); | ||
1133 | ret = iwl_mvm_phy_ctxt_add(mvm, phy_ctxt, &ctx->def, | ||
1134 | ctx->rx_chains_static, | ||
1135 | ctx->rx_chains_dynamic); | ||
1136 | mutex_unlock(&mvm->mutex); | ||
1137 | return ret; | ||
1138 | } | ||
1139 | |||
1140 | static void iwl_mvm_remove_chanctx(struct ieee80211_hw *hw, | ||
1141 | struct ieee80211_chanctx_conf *ctx) | ||
1142 | { | ||
1143 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
1144 | struct iwl_mvm_phy_ctxt *phy_ctxt = (void *)ctx->drv_priv; | ||
1145 | |||
1146 | mutex_lock(&mvm->mutex); | ||
1147 | iwl_mvm_phy_ctxt_remove(mvm, phy_ctxt); | ||
1148 | mutex_unlock(&mvm->mutex); | ||
1149 | } | ||
1150 | |||
1151 | static void iwl_mvm_change_chanctx(struct ieee80211_hw *hw, | ||
1152 | struct ieee80211_chanctx_conf *ctx, | ||
1153 | u32 changed) | ||
1154 | { | ||
1155 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
1156 | struct iwl_mvm_phy_ctxt *phy_ctxt = (void *)ctx->drv_priv; | ||
1157 | |||
1158 | mutex_lock(&mvm->mutex); | ||
1159 | iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx->def, | ||
1160 | ctx->rx_chains_static, | ||
1161 | ctx->rx_chains_dynamic); | ||
1162 | mutex_unlock(&mvm->mutex); | ||
1163 | } | ||
1164 | |||
1165 | static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw, | ||
1166 | struct ieee80211_vif *vif, | ||
1167 | struct ieee80211_chanctx_conf *ctx) | ||
1168 | { | ||
1169 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
1170 | struct iwl_mvm_phy_ctxt *phyctx = (void *)ctx->drv_priv; | ||
1171 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
1172 | int ret; | ||
1173 | |||
1174 | mutex_lock(&mvm->mutex); | ||
1175 | |||
1176 | mvmvif->phy_ctxt = phyctx; | ||
1177 | |||
1178 | switch (vif->type) { | ||
1179 | case NL80211_IFTYPE_AP: | ||
1180 | /* | ||
1181 | * The AP binding flow is handled as part of the start_ap flow | ||
1182 | * (in bss_info_changed). | ||
1183 | */ | ||
1184 | ret = 0; | ||
1185 | goto out_unlock; | ||
1186 | case NL80211_IFTYPE_STATION: | ||
1187 | case NL80211_IFTYPE_ADHOC: | ||
1188 | case NL80211_IFTYPE_MONITOR: | ||
1189 | break; | ||
1190 | default: | ||
1191 | ret = -EINVAL; | ||
1192 | goto out_unlock; | ||
1193 | } | ||
1194 | |||
1195 | ret = iwl_mvm_binding_add_vif(mvm, vif); | ||
1196 | if (ret) | ||
1197 | goto out_unlock; | ||
1198 | |||
1199 | /* | ||
1200 | * Setting the quota at this stage is only required for monitor | ||
1201 | * interfaces. For the other types, the bss_info changed flow | ||
1202 | * will handle quota settings. | ||
1203 | */ | ||
1204 | if (vif->type == NL80211_IFTYPE_MONITOR) { | ||
1205 | ret = iwl_mvm_update_quotas(mvm, vif); | ||
1206 | if (ret) | ||
1207 | goto out_remove_binding; | ||
1208 | } | ||
1209 | |||
1210 | goto out_unlock; | ||
1211 | |||
1212 | out_remove_binding: | ||
1213 | iwl_mvm_binding_remove_vif(mvm, vif); | ||
1214 | out_unlock: | ||
1215 | mutex_unlock(&mvm->mutex); | ||
1216 | if (ret) | ||
1217 | mvmvif->phy_ctxt = NULL; | ||
1218 | return ret; | ||
1219 | } | ||
1220 | |||
1221 | static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw, | ||
1222 | struct ieee80211_vif *vif, | ||
1223 | struct ieee80211_chanctx_conf *ctx) | ||
1224 | { | ||
1225 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
1226 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
1227 | |||
1228 | mutex_lock(&mvm->mutex); | ||
1229 | |||
1230 | iwl_mvm_remove_time_event(mvm, mvmvif, &mvmvif->time_event_data); | ||
1231 | |||
1232 | if (vif->type == NL80211_IFTYPE_AP) | ||
1233 | goto out_unlock; | ||
1234 | |||
1235 | iwl_mvm_binding_remove_vif(mvm, vif); | ||
1236 | switch (vif->type) { | ||
1237 | case NL80211_IFTYPE_MONITOR: | ||
1238 | iwl_mvm_update_quotas(mvm, vif); | ||
1239 | break; | ||
1240 | default: | ||
1241 | break; | ||
1242 | } | ||
1243 | |||
1244 | out_unlock: | ||
1245 | mvmvif->phy_ctxt = NULL; | ||
1246 | mutex_unlock(&mvm->mutex); | ||
1247 | } | ||
1248 | |||
1249 | static int iwl_mvm_set_tim(struct ieee80211_hw *hw, | ||
1250 | struct ieee80211_sta *sta, | ||
1251 | bool set) | ||
1252 | { | ||
1253 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
1254 | struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; | ||
1255 | |||
1256 | if (!mvm_sta || !mvm_sta->vif) { | ||
1257 | IWL_ERR(mvm, "Station is not associated to a vif\n"); | ||
1258 | return -EINVAL; | ||
1259 | } | ||
1260 | |||
1261 | return iwl_mvm_mac_ctxt_beacon_changed(mvm, mvm_sta->vif); | ||
1262 | } | ||
1263 | |||
1264 | struct ieee80211_ops iwl_mvm_hw_ops = { | ||
1265 | .tx = iwl_mvm_mac_tx, | ||
1266 | .ampdu_action = iwl_mvm_mac_ampdu_action, | ||
1267 | .start = iwl_mvm_mac_start, | ||
1268 | .restart_complete = iwl_mvm_mac_restart_complete, | ||
1269 | .stop = iwl_mvm_mac_stop, | ||
1270 | .add_interface = iwl_mvm_mac_add_interface, | ||
1271 | .remove_interface = iwl_mvm_mac_remove_interface, | ||
1272 | .config = iwl_mvm_mac_config, | ||
1273 | .configure_filter = iwl_mvm_configure_filter, | ||
1274 | .bss_info_changed = iwl_mvm_bss_info_changed, | ||
1275 | .hw_scan = iwl_mvm_mac_hw_scan, | ||
1276 | .cancel_hw_scan = iwl_mvm_mac_cancel_hw_scan, | ||
1277 | .sta_state = iwl_mvm_mac_sta_state, | ||
1278 | .sta_notify = iwl_mvm_mac_sta_notify, | ||
1279 | .allow_buffered_frames = iwl_mvm_mac_allow_buffered_frames, | ||
1280 | .set_rts_threshold = iwl_mvm_mac_set_rts_threshold, | ||
1281 | .conf_tx = iwl_mvm_mac_conf_tx, | ||
1282 | .mgd_prepare_tx = iwl_mvm_mac_mgd_prepare_tx, | ||
1283 | .set_key = iwl_mvm_mac_set_key, | ||
1284 | .update_tkip_key = iwl_mvm_mac_update_tkip_key, | ||
1285 | .remain_on_channel = iwl_mvm_roc, | ||
1286 | .cancel_remain_on_channel = iwl_mvm_cancel_roc, | ||
1287 | |||
1288 | .add_chanctx = iwl_mvm_add_chanctx, | ||
1289 | .remove_chanctx = iwl_mvm_remove_chanctx, | ||
1290 | .change_chanctx = iwl_mvm_change_chanctx, | ||
1291 | .assign_vif_chanctx = iwl_mvm_assign_vif_chanctx, | ||
1292 | .unassign_vif_chanctx = iwl_mvm_unassign_vif_chanctx, | ||
1293 | |||
1294 | .start_ap = iwl_mvm_start_ap, | ||
1295 | .stop_ap = iwl_mvm_stop_ap, | ||
1296 | |||
1297 | .set_tim = iwl_mvm_set_tim, | ||
1298 | |||
1299 | #ifdef CONFIG_PM_SLEEP | ||
1300 | /* look at d3.c */ | ||
1301 | .suspend = iwl_mvm_suspend, | ||
1302 | .resume = iwl_mvm_resume, | ||
1303 | .set_wakeup = iwl_mvm_set_wakeup, | ||
1304 | .set_rekey_data = iwl_mvm_set_rekey_data, | ||
1305 | #if IS_ENABLED(CONFIG_IPV6) | ||
1306 | .ipv6_addr_change = iwl_mvm_ipv6_addr_change, | ||
1307 | #endif | ||
1308 | .set_default_unicast_key = iwl_mvm_set_default_unicast_key, | ||
1309 | #endif | ||
1310 | }; | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h new file mode 100644 index 000000000000..4e339ccfa800 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h | |||
@@ -0,0 +1,500 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called LICENSE.GPL. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | * | ||
62 | *****************************************************************************/ | ||
63 | |||
64 | #ifndef __IWL_MVM_H__ | ||
65 | #define __IWL_MVM_H__ | ||
66 | |||
67 | #include <linux/list.h> | ||
68 | #include <linux/spinlock.h> | ||
69 | #include <linux/leds.h> | ||
70 | #include <linux/in6.h> | ||
71 | |||
72 | #include "iwl-op-mode.h" | ||
73 | #include "iwl-trans.h" | ||
74 | #include "iwl-notif-wait.h" | ||
75 | #include "iwl-eeprom-parse.h" | ||
76 | #include "iwl-test.h" | ||
77 | #include "iwl-trans.h" | ||
78 | #include "sta.h" | ||
79 | #include "fw-api.h" | ||
80 | |||
81 | #define IWL_INVALID_MAC80211_QUEUE 0xff | ||
82 | #define IWL_MVM_MAX_ADDRESSES 2 | ||
83 | #define IWL_RSSI_OFFSET 44 | ||
84 | |||
85 | enum iwl_mvm_tx_fifo { | ||
86 | IWL_MVM_TX_FIFO_BK = 0, | ||
87 | IWL_MVM_TX_FIFO_BE, | ||
88 | IWL_MVM_TX_FIFO_VI, | ||
89 | IWL_MVM_TX_FIFO_VO, | ||
90 | }; | ||
91 | |||
92 | /* Placeholder */ | ||
93 | #define IWL_OFFCHANNEL_QUEUE 8 | ||
94 | #define IWL_FIRST_AMPDU_QUEUE 11 | ||
95 | |||
96 | extern struct ieee80211_ops iwl_mvm_hw_ops; | ||
97 | /** | ||
98 | * struct iwl_mvm_mod_params - module parameters for iwlmvm | ||
99 | * @init_dbg: if true, then the NIC won't be stopped if the INIT fw asserted. | ||
100 | * We will register to mac80211 to have testmode working. The NIC must not | ||
101 | * be up'ed after the INIT fw asserted. This is useful to be able to use | ||
102 | * proprietary tools over testmode to debug the INIT fw. | ||
103 | * @power_scheme: CAM(Continuous Active Mode)-1, BPS(Balanced Power | ||
104 | * Save)-2(default), LP(Low Power)-3 | ||
105 | */ | ||
106 | struct iwl_mvm_mod_params { | ||
107 | bool init_dbg; | ||
108 | int power_scheme; | ||
109 | }; | ||
110 | extern struct iwl_mvm_mod_params iwlmvm_mod_params; | ||
111 | |||
112 | struct iwl_mvm_phy_ctxt { | ||
113 | u16 id; | ||
114 | u16 color; | ||
115 | |||
116 | /* | ||
117 | * TODO: This should probably be removed. Currently here only for rate | ||
118 | * scaling algorithm | ||
119 | */ | ||
120 | struct ieee80211_channel *channel; | ||
121 | }; | ||
122 | |||
123 | struct iwl_mvm_time_event_data { | ||
124 | struct ieee80211_vif *vif; | ||
125 | struct list_head list; | ||
126 | unsigned long end_jiffies; | ||
127 | u32 duration; | ||
128 | bool running; | ||
129 | u32 uid; | ||
130 | |||
131 | /* | ||
132 | * The access to the 'id' field must be done when the | ||
133 | * mvm->time_event_lock is held, as it value is used to indicate | ||
134 | * if the te is in the time event list or not (when id == TE_MAX) | ||
135 | */ | ||
136 | u32 id; | ||
137 | }; | ||
138 | |||
139 | /* Power management */ | ||
140 | |||
141 | /** | ||
142 | * enum iwl_power_scheme | ||
143 | * @IWL_POWER_LEVEL_CAM - Continuously Active Mode | ||
144 | * @IWL_POWER_LEVEL_BPS - Balanced Power Save (default) | ||
145 | * @IWL_POWER_LEVEL_LP - Low Power | ||
146 | */ | ||
147 | enum iwl_power_scheme { | ||
148 | IWL_POWER_SCHEME_CAM = 1, | ||
149 | IWL_POWER_SCHEME_BPS, | ||
150 | IWL_POWER_SCHEME_LP | ||
151 | }; | ||
152 | |||
153 | #define IWL_CONN_MAX_LISTEN_INTERVAL 70 | ||
154 | |||
155 | /** | ||
156 | * struct iwl_mvm_vif - data per Virtual Interface, it is a MAC context | ||
157 | * @id: between 0 and 3 | ||
158 | * @color: to solve races upon MAC addition and removal | ||
159 | * @ap_sta_id: the sta_id of the AP - valid only if VIF type is STA | ||
160 | * @uploaded: indicates the MAC context has been added to the device | ||
161 | * @ap_active: indicates that ap context is configured, and that the interface | ||
162 | * should get quota etc. | ||
163 | * @queue_params: QoS params for this MAC | ||
164 | * @bcast_sta: station used for broadcast packets. Used by the following | ||
165 | * vifs: P2P_DEVICE, GO and AP. | ||
166 | * @beacon_skb: the skb used to hold the AP/GO beacon template | ||
167 | */ | ||
168 | struct iwl_mvm_vif { | ||
169 | u16 id; | ||
170 | u16 color; | ||
171 | u8 ap_sta_id; | ||
172 | |||
173 | bool uploaded; | ||
174 | bool ap_active; | ||
175 | |||
176 | enum iwl_tsf_id tsf_id; | ||
177 | |||
178 | /* | ||
179 | * QoS data from mac80211, need to store this here | ||
180 | * as mac80211 has a separate callback but we need | ||
181 | * to have the data for the MAC context | ||
182 | */ | ||
183 | struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS]; | ||
184 | struct iwl_mvm_time_event_data time_event_data; | ||
185 | |||
186 | struct iwl_mvm_int_sta bcast_sta; | ||
187 | |||
188 | /* | ||
189 | * Assigned while mac80211 has the interface in a channel context, | ||
190 | * or, for P2P Device, while it exists. | ||
191 | */ | ||
192 | struct iwl_mvm_phy_ctxt *phy_ctxt; | ||
193 | |||
194 | #ifdef CONFIG_PM_SLEEP | ||
195 | /* WoWLAN GTK rekey data */ | ||
196 | struct { | ||
197 | u8 kck[NL80211_KCK_LEN], kek[NL80211_KEK_LEN]; | ||
198 | __le64 replay_ctr; | ||
199 | bool valid; | ||
200 | } rekey_data; | ||
201 | |||
202 | int tx_key_idx; | ||
203 | |||
204 | #if IS_ENABLED(CONFIG_IPV6) | ||
205 | /* IPv6 addresses for WoWLAN */ | ||
206 | struct in6_addr target_ipv6_addrs[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS]; | ||
207 | int num_target_ipv6_addrs; | ||
208 | #endif | ||
209 | #endif | ||
210 | |||
211 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
212 | struct dentry *dbgfs_dir; | ||
213 | void *dbgfs_data; | ||
214 | #endif | ||
215 | }; | ||
216 | |||
217 | static inline struct iwl_mvm_vif * | ||
218 | iwl_mvm_vif_from_mac80211(struct ieee80211_vif *vif) | ||
219 | { | ||
220 | return (void *)vif->drv_priv; | ||
221 | } | ||
222 | |||
223 | enum iwl_mvm_status { | ||
224 | IWL_MVM_STATUS_HW_RFKILL, | ||
225 | IWL_MVM_STATUS_ROC_RUNNING, | ||
226 | IWL_MVM_STATUS_IN_HW_RESTART, | ||
227 | }; | ||
228 | |||
229 | enum iwl_scan_status { | ||
230 | IWL_MVM_SCAN_NONE, | ||
231 | IWL_MVM_SCAN_OS, | ||
232 | }; | ||
233 | |||
234 | /** | ||
235 | * struct iwl_nvm_section - describes an NVM section in memory. | ||
236 | * | ||
237 | * This struct holds an NVM section read from the NIC using NVM_ACCESS_CMD, | ||
238 | * and saved for later use by the driver. Not all NVM sections are saved | ||
239 | * this way, only the needed ones. | ||
240 | */ | ||
241 | struct iwl_nvm_section { | ||
242 | u16 length; | ||
243 | const u8 *data; | ||
244 | }; | ||
245 | |||
246 | struct iwl_mvm { | ||
247 | /* for logger access */ | ||
248 | struct device *dev; | ||
249 | |||
250 | struct iwl_trans *trans; | ||
251 | const struct iwl_fw *fw; | ||
252 | const struct iwl_cfg *cfg; | ||
253 | struct iwl_phy_db *phy_db; | ||
254 | struct ieee80211_hw *hw; | ||
255 | |||
256 | /* for protecting access to iwl_mvm */ | ||
257 | struct mutex mutex; | ||
258 | struct list_head async_handlers_list; | ||
259 | spinlock_t async_handlers_lock; | ||
260 | struct work_struct async_handlers_wk; | ||
261 | |||
262 | struct work_struct roc_done_wk; | ||
263 | |||
264 | unsigned long status; | ||
265 | |||
266 | enum iwl_ucode_type cur_ucode; | ||
267 | bool ucode_loaded; | ||
268 | bool init_ucode_run; | ||
269 | u32 error_event_table; | ||
270 | u32 log_event_table; | ||
271 | |||
272 | u32 ampdu_ref; | ||
273 | |||
274 | struct iwl_notif_wait_data notif_wait; | ||
275 | |||
276 | unsigned long transport_queue_stop; | ||
277 | u8 queue_to_mac80211[IWL_MAX_HW_QUEUES]; | ||
278 | atomic_t queue_stop_count[IWL_MAX_HW_QUEUES]; | ||
279 | |||
280 | struct iwl_nvm_data *nvm_data; | ||
281 | /* eeprom blob for debugfs/testmode */ | ||
282 | u8 *eeprom_blob; | ||
283 | size_t eeprom_blob_size; | ||
284 | /* NVM sections for 7000 family */ | ||
285 | struct iwl_nvm_section nvm_sections[NVM_NUM_OF_SECTIONS]; | ||
286 | |||
287 | /* EEPROM MAC addresses */ | ||
288 | struct mac_address addresses[IWL_MVM_MAX_ADDRESSES]; | ||
289 | |||
290 | /* data related to data path */ | ||
291 | struct iwl_rx_phy_info last_phy_info; | ||
292 | struct ieee80211_sta __rcu *fw_id_to_mac_id[IWL_MVM_STATION_COUNT]; | ||
293 | struct work_struct sta_drained_wk; | ||
294 | unsigned long sta_drained[BITS_TO_LONGS(IWL_MVM_STATION_COUNT)]; | ||
295 | |||
296 | /* configured by mac80211 */ | ||
297 | u32 rts_threshold; | ||
298 | |||
299 | /* Scan status, cmd (pre-allocated) and auxiliary station */ | ||
300 | enum iwl_scan_status scan_status; | ||
301 | struct iwl_scan_cmd *scan_cmd; | ||
302 | |||
303 | /* Internal station */ | ||
304 | struct iwl_mvm_int_sta aux_sta; | ||
305 | |||
306 | u8 scan_last_antenna_idx; /* to toggle TX between antennas */ | ||
307 | u8 mgmt_last_antenna_idx; | ||
308 | |||
309 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
310 | struct dentry *debugfs_dir; | ||
311 | u32 dbgfs_sram_offset, dbgfs_sram_len; | ||
312 | bool prevent_power_down_d3; | ||
313 | #endif | ||
314 | |||
315 | struct iwl_mvm_phy_ctxt phy_ctxt_roc; | ||
316 | |||
317 | struct list_head time_event_list; | ||
318 | spinlock_t time_event_lock; | ||
319 | |||
320 | /* | ||
321 | * A bitmap indicating the index of the key in use. The firmware | ||
322 | * can hold 16 keys at most. Reflect this fact. | ||
323 | */ | ||
324 | unsigned long fw_key_table[BITS_TO_LONGS(STA_KEY_MAX_NUM)]; | ||
325 | u8 vif_count; | ||
326 | |||
327 | struct led_classdev led; | ||
328 | |||
329 | struct ieee80211_vif *p2p_device_vif; | ||
330 | }; | ||
331 | |||
332 | /* Extract MVM priv from op_mode and _hw */ | ||
333 | #define IWL_OP_MODE_GET_MVM(_iwl_op_mode) \ | ||
334 | ((struct iwl_mvm *)(_iwl_op_mode)->op_mode_specific) | ||
335 | |||
336 | #define IWL_MAC80211_GET_MVM(_hw) \ | ||
337 | IWL_OP_MODE_GET_MVM((struct iwl_op_mode *)((_hw)->priv)) | ||
338 | |||
339 | extern const u8 iwl_mvm_ac_to_tx_fifo[]; | ||
340 | |||
341 | struct iwl_rate_info { | ||
342 | u8 plcp; /* uCode API: IWL_RATE_6M_PLCP, etc. */ | ||
343 | u8 plcp_siso; /* uCode API: IWL_RATE_SISO_6M_PLCP, etc. */ | ||
344 | u8 plcp_mimo2; /* uCode API: IWL_RATE_MIMO2_6M_PLCP, etc. */ | ||
345 | u8 plcp_mimo3; /* uCode API: IWL_RATE_MIMO3_6M_PLCP, etc. */ | ||
346 | u8 ieee; /* MAC header: IWL_RATE_6M_IEEE, etc. */ | ||
347 | }; | ||
348 | |||
349 | /****************** | ||
350 | * MVM Methods | ||
351 | ******************/ | ||
352 | /* uCode */ | ||
353 | int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm); | ||
354 | |||
355 | /* Utils */ | ||
356 | int iwl_mvm_legacy_rate_to_mac80211_idx(u32 rate_n_flags, | ||
357 | enum ieee80211_band band); | ||
358 | u8 iwl_mvm_mac80211_idx_to_hwrate(int rate_idx); | ||
359 | void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm); | ||
360 | u8 first_antenna(u8 mask); | ||
361 | u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx); | ||
362 | |||
363 | /* Tx / Host Commands */ | ||
364 | int __must_check iwl_mvm_send_cmd(struct iwl_mvm *mvm, | ||
365 | struct iwl_host_cmd *cmd); | ||
366 | int __must_check iwl_mvm_send_cmd_pdu(struct iwl_mvm *mvm, u8 id, | ||
367 | u32 flags, u16 len, const void *data); | ||
368 | int __must_check iwl_mvm_send_cmd_status(struct iwl_mvm *mvm, | ||
369 | struct iwl_host_cmd *cmd, | ||
370 | u32 *status); | ||
371 | int __must_check iwl_mvm_send_cmd_pdu_status(struct iwl_mvm *mvm, u8 id, | ||
372 | u16 len, const void *data, | ||
373 | u32 *status); | ||
374 | int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb, | ||
375 | struct ieee80211_sta *sta); | ||
376 | int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb); | ||
377 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
378 | const char *iwl_mvm_get_tx_fail_reason(u32 status); | ||
379 | #else | ||
380 | static inline const char *iwl_mvm_get_tx_fail_reason(u32 status) { return ""; } | ||
381 | #endif | ||
382 | int iwl_mvm_flush_tx_path(struct iwl_mvm *mvm, u32 tfd_msk, bool sync); | ||
383 | void iwl_mvm_async_handlers_purge(struct iwl_mvm *mvm); | ||
384 | |||
385 | /* Statistics */ | ||
386 | int iwl_mvm_rx_reply_statistics(struct iwl_mvm *mvm, | ||
387 | struct iwl_rx_cmd_buffer *rxb, | ||
388 | struct iwl_device_cmd *cmd); | ||
389 | int iwl_mvm_rx_statistics(struct iwl_mvm *mvm, | ||
390 | struct iwl_rx_cmd_buffer *rxb, | ||
391 | struct iwl_device_cmd *cmd); | ||
392 | |||
393 | /* NVM */ | ||
394 | int iwl_nvm_init(struct iwl_mvm *mvm); | ||
395 | |||
396 | int iwl_mvm_up(struct iwl_mvm *mvm); | ||
397 | int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm); | ||
398 | |||
399 | int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm); | ||
400 | |||
401 | /* | ||
402 | * FW notifications / CMD responses handlers | ||
403 | * Convention: iwl_mvm_rx_<NAME OF THE CMD> | ||
404 | */ | ||
405 | int iwl_mvm_rx_rx_phy_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | ||
406 | struct iwl_device_cmd *cmd); | ||
407 | int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | ||
408 | struct iwl_device_cmd *cmd); | ||
409 | int iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | ||
410 | struct iwl_device_cmd *cmd); | ||
411 | int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | ||
412 | struct iwl_device_cmd *cmd); | ||
413 | int iwl_mvm_rx_radio_ver(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | ||
414 | struct iwl_device_cmd *cmd); | ||
415 | int iwl_mvm_rx_fw_error(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | ||
416 | struct iwl_device_cmd *cmd); | ||
417 | int iwl_mvm_rx_card_state_notif(struct iwl_mvm *mvm, | ||
418 | struct iwl_rx_cmd_buffer *rxb, | ||
419 | struct iwl_device_cmd *cmd); | ||
420 | int iwl_mvm_rx_radio_ver(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | ||
421 | struct iwl_device_cmd *cmd); | ||
422 | |||
423 | /* MVM PHY */ | ||
424 | int iwl_mvm_phy_ctxt_add(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, | ||
425 | struct cfg80211_chan_def *chandef, | ||
426 | u8 chains_static, u8 chains_dynamic); | ||
427 | int iwl_mvm_phy_ctxt_changed(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, | ||
428 | struct cfg80211_chan_def *chandef, | ||
429 | u8 chains_static, u8 chains_dynamic); | ||
430 | void iwl_mvm_phy_ctxt_remove(struct iwl_mvm *mvm, | ||
431 | struct iwl_mvm_phy_ctxt *ctxt); | ||
432 | |||
433 | /* MAC (virtual interface) programming */ | ||
434 | int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif); | ||
435 | void iwl_mvm_mac_ctxt_release(struct iwl_mvm *mvm, struct ieee80211_vif *vif); | ||
436 | int iwl_mvm_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif); | ||
437 | int iwl_mvm_mac_ctxt_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif); | ||
438 | int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif); | ||
439 | u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm, | ||
440 | struct ieee80211_vif *vif); | ||
441 | int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm, | ||
442 | struct ieee80211_vif *vif); | ||
443 | |||
444 | /* Bindings */ | ||
445 | int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif); | ||
446 | int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif); | ||
447 | |||
448 | /* Quota management */ | ||
449 | int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif); | ||
450 | |||
451 | /* Scanning */ | ||
452 | int iwl_mvm_scan_request(struct iwl_mvm *mvm, | ||
453 | struct ieee80211_vif *vif, | ||
454 | struct cfg80211_scan_request *req); | ||
455 | int iwl_mvm_rx_scan_response(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | ||
456 | struct iwl_device_cmd *cmd); | ||
457 | int iwl_mvm_rx_scan_complete(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | ||
458 | struct iwl_device_cmd *cmd); | ||
459 | void iwl_mvm_cancel_scan(struct iwl_mvm *mvm); | ||
460 | |||
461 | /* MVM debugfs */ | ||
462 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
463 | int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir); | ||
464 | int iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
465 | struct dentry *dbgfs_dir); | ||
466 | void iwl_power_get_params(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
467 | struct iwl_powertable_cmd *cmd); | ||
468 | #else | ||
469 | static inline int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, | ||
470 | struct dentry *dbgfs_dir) | ||
471 | { | ||
472 | return 0; | ||
473 | } | ||
474 | #endif /* CONFIG_IWLWIFI_DEBUGFS */ | ||
475 | |||
476 | /* rate scaling */ | ||
477 | int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, | ||
478 | u8 flags, bool init); | ||
479 | |||
480 | /* power managment */ | ||
481 | int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif); | ||
482 | int iwl_mvm_power_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif); | ||
483 | |||
484 | int iwl_mvm_leds_init(struct iwl_mvm *mvm); | ||
485 | void iwl_mvm_leds_exit(struct iwl_mvm *mvm); | ||
486 | |||
487 | /* D3 (WoWLAN, NetDetect) */ | ||
488 | int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan); | ||
489 | int iwl_mvm_resume(struct ieee80211_hw *hw); | ||
490 | void iwl_mvm_set_wakeup(struct ieee80211_hw *hw, bool enabled); | ||
491 | void iwl_mvm_set_rekey_data(struct ieee80211_hw *hw, | ||
492 | struct ieee80211_vif *vif, | ||
493 | struct cfg80211_gtk_rekey_data *data); | ||
494 | void iwl_mvm_ipv6_addr_change(struct ieee80211_hw *hw, | ||
495 | struct ieee80211_vif *vif, | ||
496 | struct inet6_dev *idev); | ||
497 | void iwl_mvm_set_default_unicast_key(struct ieee80211_hw *hw, | ||
498 | struct ieee80211_vif *vif, int idx); | ||
499 | |||
500 | #endif /* __IWL_MVM_H__ */ | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c new file mode 100644 index 000000000000..20016bcbdeab --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c | |||
@@ -0,0 +1,311 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called LICENSE.GPL. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | * | ||
62 | *****************************************************************************/ | ||
63 | #include "iwl-trans.h" | ||
64 | #include "mvm.h" | ||
65 | #include "iwl-eeprom-parse.h" | ||
66 | #include "iwl-eeprom-read.h" | ||
67 | #include "iwl-nvm-parse.h" | ||
68 | |||
69 | /* list of NVM sections we are allowed/need to read */ | ||
70 | static const int nvm_to_read[] = { | ||
71 | NVM_SECTION_TYPE_HW, | ||
72 | NVM_SECTION_TYPE_SW, | ||
73 | NVM_SECTION_TYPE_CALIBRATION, | ||
74 | NVM_SECTION_TYPE_PRODUCTION, | ||
75 | }; | ||
76 | |||
77 | /* used to simplify the shared operations on NCM_ACCESS_CMD versions */ | ||
78 | union iwl_nvm_access_cmd { | ||
79 | struct iwl_nvm_access_cmd_ver1 ver1; | ||
80 | struct iwl_nvm_access_cmd_ver2 ver2; | ||
81 | }; | ||
82 | union iwl_nvm_access_resp { | ||
83 | struct iwl_nvm_access_resp_ver1 ver1; | ||
84 | struct iwl_nvm_access_resp_ver2 ver2; | ||
85 | }; | ||
86 | |||
87 | static inline void iwl_nvm_fill_read_ver1(struct iwl_nvm_access_cmd_ver1 *cmd, | ||
88 | u16 offset, u16 length) | ||
89 | { | ||
90 | cmd->offset = cpu_to_le16(offset); | ||
91 | cmd->length = cpu_to_le16(length); | ||
92 | cmd->cache_refresh = 1; | ||
93 | } | ||
94 | |||
95 | static inline void iwl_nvm_fill_read_ver2(struct iwl_nvm_access_cmd_ver2 *cmd, | ||
96 | u16 offset, u16 length, u16 section) | ||
97 | { | ||
98 | cmd->offset = cpu_to_le16(offset); | ||
99 | cmd->length = cpu_to_le16(length); | ||
100 | cmd->type = cpu_to_le16(section); | ||
101 | } | ||
102 | |||
103 | static int iwl_nvm_read_chunk(struct iwl_mvm *mvm, u16 section, | ||
104 | u16 offset, u16 length, u8 *data) | ||
105 | { | ||
106 | union iwl_nvm_access_cmd nvm_access_cmd; | ||
107 | union iwl_nvm_access_resp *nvm_resp; | ||
108 | struct iwl_rx_packet *pkt; | ||
109 | struct iwl_host_cmd cmd = { | ||
110 | .id = NVM_ACCESS_CMD, | ||
111 | .flags = CMD_SYNC | CMD_WANT_SKB, | ||
112 | .data = { &nvm_access_cmd, }, | ||
113 | }; | ||
114 | int ret, bytes_read, offset_read; | ||
115 | u8 *resp_data; | ||
116 | |||
117 | memset(&nvm_access_cmd, 0, sizeof(nvm_access_cmd)); | ||
118 | |||
119 | /* TODO: not sure family should be the decider, maybe FW version? */ | ||
120 | if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) { | ||
121 | iwl_nvm_fill_read_ver2(&(nvm_access_cmd.ver2), | ||
122 | offset, length, section); | ||
123 | cmd.len[0] = sizeof(struct iwl_nvm_access_cmd_ver2); | ||
124 | } else { | ||
125 | iwl_nvm_fill_read_ver1(&(nvm_access_cmd.ver1), | ||
126 | offset, length); | ||
127 | cmd.len[0] = sizeof(struct iwl_nvm_access_cmd_ver1); | ||
128 | } | ||
129 | |||
130 | ret = iwl_mvm_send_cmd(mvm, &cmd); | ||
131 | if (ret) | ||
132 | return ret; | ||
133 | |||
134 | pkt = cmd.resp_pkt; | ||
135 | if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { | ||
136 | IWL_ERR(mvm, "Bad return from NVM_ACCES_COMMAND (0x%08X)\n", | ||
137 | pkt->hdr.flags); | ||
138 | ret = -EIO; | ||
139 | goto exit; | ||
140 | } | ||
141 | |||
142 | /* Extract NVM response */ | ||
143 | nvm_resp = (void *)pkt->data; | ||
144 | if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) { | ||
145 | ret = le16_to_cpu(nvm_resp->ver2.status); | ||
146 | bytes_read = le16_to_cpu(nvm_resp->ver2.length); | ||
147 | offset_read = le16_to_cpu(nvm_resp->ver2.offset); | ||
148 | resp_data = nvm_resp->ver2.data; | ||
149 | } else { | ||
150 | ret = le16_to_cpu(nvm_resp->ver1.length) <= 0; | ||
151 | bytes_read = le16_to_cpu(nvm_resp->ver1.length); | ||
152 | offset_read = le16_to_cpu(nvm_resp->ver1.offset); | ||
153 | resp_data = nvm_resp->ver1.data; | ||
154 | } | ||
155 | if (ret) { | ||
156 | IWL_ERR(mvm, | ||
157 | "NVM access command failed with status %d (device: %s)\n", | ||
158 | ret, mvm->cfg->name); | ||
159 | ret = -EINVAL; | ||
160 | goto exit; | ||
161 | } | ||
162 | |||
163 | if (offset_read != offset) { | ||
164 | IWL_ERR(mvm, "NVM ACCESS response with invalid offset %d\n", | ||
165 | offset_read); | ||
166 | ret = -EINVAL; | ||
167 | goto exit; | ||
168 | } | ||
169 | |||
170 | /* Write data to NVM */ | ||
171 | memcpy(data + offset, resp_data, bytes_read); | ||
172 | ret = bytes_read; | ||
173 | |||
174 | exit: | ||
175 | iwl_free_resp(&cmd); | ||
176 | return ret; | ||
177 | } | ||
178 | |||
179 | /* | ||
180 | * Reads an NVM section completely. | ||
181 | * NICs prior to 7000 family doesn't have a real NVM, but just read | ||
182 | * section 0 which is the EEPROM. Because the EEPROM reading is unlimited | ||
183 | * by uCode, we need to manually check in this case that we don't | ||
184 | * overflow and try to read more than the EEPROM size. | ||
185 | * For 7000 family NICs, we supply the maximal size we can read, and | ||
186 | * the uCode fills the response with as much data as we can, | ||
187 | * without overflowing, so no check is needed. | ||
188 | */ | ||
189 | static int iwl_nvm_read_section(struct iwl_mvm *mvm, u16 section, | ||
190 | u8 *data) | ||
191 | { | ||
192 | u16 length, offset = 0; | ||
193 | int ret; | ||
194 | bool old_eeprom = mvm->cfg->device_family != IWL_DEVICE_FAMILY_7000; | ||
195 | |||
196 | length = (iwlwifi_mod_params.amsdu_size_8K ? (8 * 1024) : (4 * 1024)) | ||
197 | - sizeof(union iwl_nvm_access_cmd) | ||
198 | - sizeof(struct iwl_rx_packet); | ||
199 | /* | ||
200 | * if length is greater than EEPROM size, truncate it because uCode | ||
201 | * doesn't check it by itself, and exit the loop when reached. | ||
202 | */ | ||
203 | if (old_eeprom && length > mvm->cfg->base_params->eeprom_size) | ||
204 | length = mvm->cfg->base_params->eeprom_size; | ||
205 | ret = length; | ||
206 | |||
207 | /* Read the NVM until exhausted (reading less than requested) */ | ||
208 | while (ret == length) { | ||
209 | ret = iwl_nvm_read_chunk(mvm, section, offset, length, data); | ||
210 | if (ret < 0) { | ||
211 | IWL_ERR(mvm, | ||
212 | "Cannot read NVM from section %d offset %d, length %d\n", | ||
213 | section, offset, length); | ||
214 | return ret; | ||
215 | } | ||
216 | offset += ret; | ||
217 | if (old_eeprom && offset == mvm->cfg->base_params->eeprom_size) | ||
218 | break; | ||
219 | } | ||
220 | |||
221 | IWL_INFO(mvm, "NVM section %d read completed\n", section); | ||
222 | return offset; | ||
223 | } | ||
224 | |||
225 | static struct iwl_nvm_data * | ||
226 | iwl_parse_nvm_sections(struct iwl_mvm *mvm) | ||
227 | { | ||
228 | struct iwl_nvm_section *sections = mvm->nvm_sections; | ||
229 | const __le16 *hw, *sw, *calib; | ||
230 | |||
231 | /* Checking for required sections */ | ||
232 | if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data || | ||
233 | !mvm->nvm_sections[NVM_SECTION_TYPE_HW].data) { | ||
234 | IWL_ERR(mvm, "Can't parse empty NVM sections\n"); | ||
235 | return NULL; | ||
236 | } | ||
237 | |||
238 | if (WARN_ON(!mvm->cfg)) | ||
239 | return NULL; | ||
240 | |||
241 | hw = (const __le16 *)sections[NVM_SECTION_TYPE_HW].data; | ||
242 | sw = (const __le16 *)sections[NVM_SECTION_TYPE_SW].data; | ||
243 | calib = (const __le16 *)sections[NVM_SECTION_TYPE_CALIBRATION].data; | ||
244 | return iwl_parse_nvm_data(mvm->trans->dev, mvm->cfg, hw, sw, calib); | ||
245 | } | ||
246 | |||
247 | int iwl_nvm_init(struct iwl_mvm *mvm) | ||
248 | { | ||
249 | int ret, i, section; | ||
250 | u8 *nvm_buffer, *temp; | ||
251 | |||
252 | if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) { | ||
253 | /* TODO: find correct NVM max size for a section */ | ||
254 | nvm_buffer = kmalloc(mvm->cfg->base_params->eeprom_size, | ||
255 | GFP_KERNEL); | ||
256 | if (!nvm_buffer) | ||
257 | return -ENOMEM; | ||
258 | for (i = 0; i < ARRAY_SIZE(nvm_to_read); i++) { | ||
259 | section = nvm_to_read[i]; | ||
260 | /* we override the constness for initial read */ | ||
261 | ret = iwl_nvm_read_section(mvm, section, nvm_buffer); | ||
262 | if (ret < 0) | ||
263 | break; | ||
264 | temp = kmemdup(nvm_buffer, ret, GFP_KERNEL); | ||
265 | if (!temp) { | ||
266 | ret = -ENOMEM; | ||
267 | break; | ||
268 | } | ||
269 | mvm->nvm_sections[section].data = temp; | ||
270 | mvm->nvm_sections[section].length = ret; | ||
271 | } | ||
272 | kfree(nvm_buffer); | ||
273 | if (ret < 0) | ||
274 | return ret; | ||
275 | } else { | ||
276 | /* allocate eeprom */ | ||
277 | mvm->eeprom_blob_size = mvm->cfg->base_params->eeprom_size; | ||
278 | IWL_DEBUG_EEPROM(mvm->trans->dev, "NVM size = %zd\n", | ||
279 | mvm->eeprom_blob_size); | ||
280 | mvm->eeprom_blob = kzalloc(mvm->eeprom_blob_size, GFP_KERNEL); | ||
281 | if (!mvm->eeprom_blob) | ||
282 | return -ENOMEM; | ||
283 | |||
284 | ret = iwl_nvm_read_section(mvm, 0, mvm->eeprom_blob); | ||
285 | if (ret != mvm->eeprom_blob_size) { | ||
286 | IWL_ERR(mvm, "Read partial NVM %d/%zd\n", | ||
287 | ret, mvm->eeprom_blob_size); | ||
288 | kfree(mvm->eeprom_blob); | ||
289 | mvm->eeprom_blob = NULL; | ||
290 | return -EINVAL; | ||
291 | } | ||
292 | } | ||
293 | |||
294 | ret = 0; | ||
295 | if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) | ||
296 | mvm->nvm_data = iwl_parse_nvm_sections(mvm); | ||
297 | else | ||
298 | mvm->nvm_data = | ||
299 | iwl_parse_eeprom_data(mvm->trans->dev, | ||
300 | mvm->cfg, | ||
301 | mvm->eeprom_blob, | ||
302 | mvm->eeprom_blob_size); | ||
303 | |||
304 | if (!mvm->nvm_data) { | ||
305 | kfree(mvm->eeprom_blob); | ||
306 | mvm->eeprom_blob = NULL; | ||
307 | ret = -ENOMEM; | ||
308 | } | ||
309 | |||
310 | return ret; | ||
311 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c new file mode 100644 index 000000000000..983dca3f888a --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c | |||
@@ -0,0 +1,679 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called LICENSE.GPL. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | * | ||
62 | *****************************************************************************/ | ||
63 | #include <linux/module.h> | ||
64 | #include <net/mac80211.h> | ||
65 | |||
66 | #include "iwl-notif-wait.h" | ||
67 | #include "iwl-trans.h" | ||
68 | #include "iwl-op-mode.h" | ||
69 | #include "iwl-fw.h" | ||
70 | #include "iwl-debug.h" | ||
71 | #include "iwl-drv.h" | ||
72 | #include "iwl-modparams.h" | ||
73 | #include "mvm.h" | ||
74 | #include "iwl-phy-db.h" | ||
75 | #include "iwl-eeprom-parse.h" | ||
76 | #include "iwl-csr.h" | ||
77 | #include "iwl-io.h" | ||
78 | #include "iwl-prph.h" | ||
79 | #include "rs.h" | ||
80 | #include "fw-api-scan.h" | ||
81 | #include "time-event.h" | ||
82 | |||
83 | /* | ||
84 | * module name, copyright, version, etc. | ||
85 | */ | ||
86 | #define DRV_DESCRIPTION "The new Intel(R) wireless AGN driver for Linux" | ||
87 | |||
88 | #define DRV_VERSION IWLWIFI_VERSION | ||
89 | |||
90 | MODULE_DESCRIPTION(DRV_DESCRIPTION); | ||
91 | MODULE_VERSION(DRV_VERSION); | ||
92 | MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); | ||
93 | MODULE_LICENSE("GPL"); | ||
94 | |||
95 | static const struct iwl_op_mode_ops iwl_mvm_ops; | ||
96 | |||
97 | struct iwl_mvm_mod_params iwlmvm_mod_params = { | ||
98 | .power_scheme = IWL_POWER_SCHEME_BPS, | ||
99 | /* rest of fields are 0 by default */ | ||
100 | }; | ||
101 | |||
102 | module_param_named(init_dbg, iwlmvm_mod_params.init_dbg, bool, S_IRUGO); | ||
103 | MODULE_PARM_DESC(init_dbg, | ||
104 | "set to true to debug an ASSERT in INIT fw (default: false"); | ||
105 | module_param_named(power_scheme, iwlmvm_mod_params.power_scheme, int, S_IRUGO); | ||
106 | MODULE_PARM_DESC(power_scheme, | ||
107 | "power management scheme: 1-active, 2-balanced, 3-low power, default: 2"); | ||
108 | |||
109 | /* | ||
110 | * module init and exit functions | ||
111 | */ | ||
112 | static int __init iwl_mvm_init(void) | ||
113 | { | ||
114 | int ret; | ||
115 | |||
116 | ret = iwl_mvm_rate_control_register(); | ||
117 | if (ret) { | ||
118 | pr_err("Unable to register rate control algorithm: %d\n", ret); | ||
119 | return ret; | ||
120 | } | ||
121 | |||
122 | ret = iwl_opmode_register("iwlmvm", &iwl_mvm_ops); | ||
123 | |||
124 | if (ret) { | ||
125 | pr_err("Unable to register MVM op_mode: %d\n", ret); | ||
126 | iwl_mvm_rate_control_unregister(); | ||
127 | } | ||
128 | |||
129 | return ret; | ||
130 | } | ||
131 | module_init(iwl_mvm_init); | ||
132 | |||
133 | static void __exit iwl_mvm_exit(void) | ||
134 | { | ||
135 | iwl_opmode_deregister("iwlmvm"); | ||
136 | iwl_mvm_rate_control_unregister(); | ||
137 | } | ||
138 | module_exit(iwl_mvm_exit); | ||
139 | |||
140 | static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode) | ||
141 | { | ||
142 | struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); | ||
143 | u8 radio_cfg_type, radio_cfg_step, radio_cfg_dash; | ||
144 | u32 reg_val = 0; | ||
145 | |||
146 | /* | ||
147 | * We can't upload the correct value to the INIT image | ||
148 | * as we don't have nvm_data by that time. | ||
149 | * | ||
150 | * TODO: Figure out what we should do here | ||
151 | */ | ||
152 | if (mvm->nvm_data) { | ||
153 | radio_cfg_type = mvm->nvm_data->radio_cfg_type; | ||
154 | radio_cfg_step = mvm->nvm_data->radio_cfg_step; | ||
155 | radio_cfg_dash = mvm->nvm_data->radio_cfg_dash; | ||
156 | } else { | ||
157 | radio_cfg_type = 0; | ||
158 | radio_cfg_step = 0; | ||
159 | radio_cfg_dash = 0; | ||
160 | } | ||
161 | |||
162 | /* SKU control */ | ||
163 | reg_val |= CSR_HW_REV_STEP(mvm->trans->hw_rev) << | ||
164 | CSR_HW_IF_CONFIG_REG_POS_MAC_STEP; | ||
165 | reg_val |= CSR_HW_REV_DASH(mvm->trans->hw_rev) << | ||
166 | CSR_HW_IF_CONFIG_REG_POS_MAC_DASH; | ||
167 | |||
168 | /* radio configuration */ | ||
169 | reg_val |= radio_cfg_type << CSR_HW_IF_CONFIG_REG_POS_PHY_TYPE; | ||
170 | reg_val |= radio_cfg_step << CSR_HW_IF_CONFIG_REG_POS_PHY_STEP; | ||
171 | reg_val |= radio_cfg_dash << CSR_HW_IF_CONFIG_REG_POS_PHY_DASH; | ||
172 | |||
173 | WARN_ON((radio_cfg_type << CSR_HW_IF_CONFIG_REG_POS_PHY_TYPE) & | ||
174 | ~CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE); | ||
175 | |||
176 | /* silicon bits */ | ||
177 | reg_val |= CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI; | ||
178 | reg_val |= CSR_HW_IF_CONFIG_REG_BIT_MAC_SI; | ||
179 | |||
180 | iwl_trans_set_bits_mask(mvm->trans, CSR_HW_IF_CONFIG_REG, | ||
181 | CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH | | ||
182 | CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP | | ||
183 | CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE | | ||
184 | CSR_HW_IF_CONFIG_REG_MSK_PHY_STEP | | ||
185 | CSR_HW_IF_CONFIG_REG_MSK_PHY_DASH | | ||
186 | CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI | | ||
187 | CSR_HW_IF_CONFIG_REG_BIT_MAC_SI, | ||
188 | reg_val); | ||
189 | |||
190 | IWL_DEBUG_INFO(mvm, "Radio type=0x%x-0x%x-0x%x\n", radio_cfg_type, | ||
191 | radio_cfg_step, radio_cfg_dash); | ||
192 | |||
193 | /* | ||
194 | * W/A : NIC is stuck in a reset state after Early PCIe power off | ||
195 | * (PCIe power is lost before PERST# is asserted), causing ME FW | ||
196 | * to lose ownership and not being able to obtain it back. | ||
197 | */ | ||
198 | iwl_set_bits_mask_prph(mvm->trans, APMG_PS_CTRL_REG, | ||
199 | APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS, | ||
200 | ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS); | ||
201 | } | ||
202 | |||
203 | struct iwl_rx_handlers { | ||
204 | u8 cmd_id; | ||
205 | bool async; | ||
206 | int (*fn)(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | ||
207 | struct iwl_device_cmd *cmd); | ||
208 | }; | ||
209 | |||
210 | #define RX_HANDLER(_cmd_id, _fn, _async) \ | ||
211 | { .cmd_id = _cmd_id , .fn = _fn , .async = _async } | ||
212 | |||
213 | /* | ||
214 | * Handlers for fw notifications | ||
215 | * Convention: RX_HANDLER(CMD_NAME, iwl_mvm_rx_CMD_NAME | ||
216 | * This list should be in order of frequency for performance purposes. | ||
217 | * | ||
218 | * The handler can be SYNC - this means that it will be called in the Rx path | ||
219 | * which can't acquire mvm->mutex. If the handler needs to hold mvm->mutex (and | ||
220 | * only in this case!), it should be set as ASYNC. In that case, it will be | ||
221 | * called from a worker with mvm->mutex held. | ||
222 | */ | ||
223 | static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { | ||
224 | RX_HANDLER(REPLY_RX_MPDU_CMD, iwl_mvm_rx_rx_mpdu, false), | ||
225 | RX_HANDLER(REPLY_RX_PHY_CMD, iwl_mvm_rx_rx_phy_cmd, false), | ||
226 | RX_HANDLER(TX_CMD, iwl_mvm_rx_tx_cmd, false), | ||
227 | RX_HANDLER(BA_NOTIF, iwl_mvm_rx_ba_notif, false), | ||
228 | RX_HANDLER(TIME_EVENT_NOTIFICATION, iwl_mvm_rx_time_event_notif, false), | ||
229 | |||
230 | RX_HANDLER(SCAN_REQUEST_CMD, iwl_mvm_rx_scan_response, false), | ||
231 | RX_HANDLER(SCAN_COMPLETE_NOTIFICATION, iwl_mvm_rx_scan_complete, false), | ||
232 | |||
233 | RX_HANDLER(RADIO_VERSION_NOTIFICATION, iwl_mvm_rx_radio_ver, false), | ||
234 | RX_HANDLER(CARD_STATE_NOTIFICATION, iwl_mvm_rx_card_state_notif, false), | ||
235 | |||
236 | RX_HANDLER(REPLY_ERROR, iwl_mvm_rx_fw_error, false), | ||
237 | }; | ||
238 | #undef RX_HANDLER | ||
239 | #define CMD(x) [x] = #x | ||
240 | |||
241 | static const char *iwl_mvm_cmd_strings[REPLY_MAX] = { | ||
242 | CMD(MVM_ALIVE), | ||
243 | CMD(REPLY_ERROR), | ||
244 | CMD(INIT_COMPLETE_NOTIF), | ||
245 | CMD(PHY_CONTEXT_CMD), | ||
246 | CMD(MGMT_MCAST_KEY), | ||
247 | CMD(TX_CMD), | ||
248 | CMD(TXPATH_FLUSH), | ||
249 | CMD(MAC_CONTEXT_CMD), | ||
250 | CMD(TIME_EVENT_CMD), | ||
251 | CMD(TIME_EVENT_NOTIFICATION), | ||
252 | CMD(BINDING_CONTEXT_CMD), | ||
253 | CMD(TIME_QUOTA_CMD), | ||
254 | CMD(RADIO_VERSION_NOTIFICATION), | ||
255 | CMD(SCAN_REQUEST_CMD), | ||
256 | CMD(SCAN_ABORT_CMD), | ||
257 | CMD(SCAN_START_NOTIFICATION), | ||
258 | CMD(SCAN_RESULTS_NOTIFICATION), | ||
259 | CMD(SCAN_COMPLETE_NOTIFICATION), | ||
260 | CMD(NVM_ACCESS_CMD), | ||
261 | CMD(PHY_CONFIGURATION_CMD), | ||
262 | CMD(CALIB_RES_NOTIF_PHY_DB), | ||
263 | CMD(SET_CALIB_DEFAULT_CMD), | ||
264 | CMD(CALIBRATION_COMPLETE_NOTIFICATION), | ||
265 | CMD(ADD_STA), | ||
266 | CMD(REMOVE_STA), | ||
267 | CMD(LQ_CMD), | ||
268 | CMD(SCAN_OFFLOAD_CONFIG_CMD), | ||
269 | CMD(SCAN_OFFLOAD_REQUEST_CMD), | ||
270 | CMD(SCAN_OFFLOAD_ABORT_CMD), | ||
271 | CMD(SCAN_OFFLOAD_COMPLETE), | ||
272 | CMD(SCAN_OFFLOAD_UPDATE_PROFILES_CMD), | ||
273 | CMD(POWER_TABLE_CMD), | ||
274 | CMD(WEP_KEY), | ||
275 | CMD(REPLY_RX_PHY_CMD), | ||
276 | CMD(REPLY_RX_MPDU_CMD), | ||
277 | CMD(BEACON_TEMPLATE_CMD), | ||
278 | CMD(STATISTICS_NOTIFICATION), | ||
279 | CMD(TX_ANT_CONFIGURATION_CMD), | ||
280 | CMD(D3_CONFIG_CMD), | ||
281 | CMD(PROT_OFFLOAD_CONFIG_CMD), | ||
282 | CMD(OFFLOADS_QUERY_CMD), | ||
283 | CMD(REMOTE_WAKE_CONFIG_CMD), | ||
284 | CMD(WOWLAN_PATTERNS), | ||
285 | CMD(WOWLAN_CONFIGURATION), | ||
286 | CMD(WOWLAN_TSC_RSC_PARAM), | ||
287 | CMD(WOWLAN_TKIP_PARAM), | ||
288 | CMD(WOWLAN_KEK_KCK_MATERIAL), | ||
289 | CMD(WOWLAN_GET_STATUSES), | ||
290 | CMD(WOWLAN_TX_POWER_PER_DB), | ||
291 | CMD(NET_DETECT_CONFIG_CMD), | ||
292 | CMD(NET_DETECT_PROFILES_QUERY_CMD), | ||
293 | CMD(NET_DETECT_PROFILES_CMD), | ||
294 | CMD(NET_DETECT_HOTSPOTS_CMD), | ||
295 | CMD(NET_DETECT_HOTSPOTS_QUERY_CMD), | ||
296 | }; | ||
297 | #undef CMD | ||
298 | |||
299 | /* this forward declaration can avoid to export the function */ | ||
300 | static void iwl_mvm_async_handlers_wk(struct work_struct *wk); | ||
301 | |||
302 | static struct iwl_op_mode * | ||
303 | iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, | ||
304 | const struct iwl_fw *fw, struct dentry *dbgfs_dir) | ||
305 | { | ||
306 | struct ieee80211_hw *hw; | ||
307 | struct iwl_op_mode *op_mode; | ||
308 | struct iwl_mvm *mvm; | ||
309 | struct iwl_trans_config trans_cfg = {}; | ||
310 | static const u8 no_reclaim_cmds[] = { | ||
311 | TX_CMD, | ||
312 | }; | ||
313 | int err, scan_size; | ||
314 | |||
315 | switch (cfg->device_family) { | ||
316 | case IWL_DEVICE_FAMILY_6030: | ||
317 | case IWL_DEVICE_FAMILY_6005: | ||
318 | case IWL_DEVICE_FAMILY_7000: | ||
319 | break; | ||
320 | default: | ||
321 | IWL_ERR(trans, "Trying to load mvm on an unsupported device\n"); | ||
322 | return NULL; | ||
323 | } | ||
324 | |||
325 | /******************************** | ||
326 | * 1. Allocating and configuring HW data | ||
327 | ********************************/ | ||
328 | hw = ieee80211_alloc_hw(sizeof(struct iwl_op_mode) + | ||
329 | sizeof(struct iwl_mvm), | ||
330 | &iwl_mvm_hw_ops); | ||
331 | if (!hw) | ||
332 | return NULL; | ||
333 | |||
334 | op_mode = hw->priv; | ||
335 | op_mode->ops = &iwl_mvm_ops; | ||
336 | op_mode->trans = trans; | ||
337 | |||
338 | mvm = IWL_OP_MODE_GET_MVM(op_mode); | ||
339 | mvm->dev = trans->dev; | ||
340 | mvm->trans = trans; | ||
341 | mvm->cfg = cfg; | ||
342 | mvm->fw = fw; | ||
343 | mvm->hw = hw; | ||
344 | |||
345 | mutex_init(&mvm->mutex); | ||
346 | spin_lock_init(&mvm->async_handlers_lock); | ||
347 | INIT_LIST_HEAD(&mvm->time_event_list); | ||
348 | INIT_LIST_HEAD(&mvm->async_handlers_list); | ||
349 | spin_lock_init(&mvm->time_event_lock); | ||
350 | |||
351 | INIT_WORK(&mvm->async_handlers_wk, iwl_mvm_async_handlers_wk); | ||
352 | INIT_WORK(&mvm->roc_done_wk, iwl_mvm_roc_done_wk); | ||
353 | INIT_WORK(&mvm->sta_drained_wk, iwl_mvm_sta_drained_wk); | ||
354 | |||
355 | SET_IEEE80211_DEV(mvm->hw, mvm->trans->dev); | ||
356 | |||
357 | /* | ||
358 | * Populate the state variables that the transport layer needs | ||
359 | * to know about. | ||
360 | */ | ||
361 | trans_cfg.op_mode = op_mode; | ||
362 | trans_cfg.no_reclaim_cmds = no_reclaim_cmds; | ||
363 | trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds); | ||
364 | trans_cfg.rx_buf_size_8k = iwlwifi_mod_params.amsdu_size_8K; | ||
365 | |||
366 | /* TODO: this should really be a TLV */ | ||
367 | if (cfg->device_family == IWL_DEVICE_FAMILY_7000) | ||
368 | trans_cfg.bc_table_dword = true; | ||
369 | |||
370 | if (!iwlwifi_mod_params.wd_disable) | ||
371 | trans_cfg.queue_watchdog_timeout = cfg->base_params->wd_timeout; | ||
372 | else | ||
373 | trans_cfg.queue_watchdog_timeout = IWL_WATCHDOG_DISABLED; | ||
374 | |||
375 | trans_cfg.command_names = iwl_mvm_cmd_strings; | ||
376 | |||
377 | trans_cfg.cmd_queue = IWL_MVM_CMD_QUEUE; | ||
378 | trans_cfg.cmd_fifo = IWL_MVM_CMD_FIFO; | ||
379 | |||
380 | snprintf(mvm->hw->wiphy->fw_version, | ||
381 | sizeof(mvm->hw->wiphy->fw_version), | ||
382 | "%s", fw->fw_version); | ||
383 | |||
384 | /* Configure transport layer */ | ||
385 | iwl_trans_configure(mvm->trans, &trans_cfg); | ||
386 | |||
387 | trans->rx_mpdu_cmd = REPLY_RX_MPDU_CMD; | ||
388 | trans->rx_mpdu_cmd_hdr_size = sizeof(struct iwl_rx_mpdu_res_start); | ||
389 | |||
390 | /* set up notification wait support */ | ||
391 | iwl_notification_wait_init(&mvm->notif_wait); | ||
392 | |||
393 | /* Init phy db */ | ||
394 | mvm->phy_db = iwl_phy_db_init(trans); | ||
395 | if (!mvm->phy_db) { | ||
396 | IWL_ERR(mvm, "Cannot init phy_db\n"); | ||
397 | goto out_free; | ||
398 | } | ||
399 | |||
400 | IWL_INFO(mvm, "Detected %s, REV=0x%X\n", | ||
401 | mvm->cfg->name, mvm->trans->hw_rev); | ||
402 | |||
403 | err = iwl_trans_start_hw(mvm->trans); | ||
404 | if (err) | ||
405 | goto out_free; | ||
406 | |||
407 | mutex_lock(&mvm->mutex); | ||
408 | err = iwl_run_init_mvm_ucode(mvm, true); | ||
409 | mutex_unlock(&mvm->mutex); | ||
410 | if (err && !iwlmvm_mod_params.init_dbg) { | ||
411 | IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", err); | ||
412 | goto out_free; | ||
413 | } | ||
414 | |||
415 | /* Stop the hw after the ALIVE and NVM has been read */ | ||
416 | if (!iwlmvm_mod_params.init_dbg) | ||
417 | iwl_trans_stop_hw(mvm->trans, false); | ||
418 | |||
419 | scan_size = sizeof(struct iwl_scan_cmd) + | ||
420 | mvm->fw->ucode_capa.max_probe_length + | ||
421 | (MAX_NUM_SCAN_CHANNELS * sizeof(struct iwl_scan_channel)); | ||
422 | mvm->scan_cmd = kmalloc(scan_size, GFP_KERNEL); | ||
423 | if (!mvm->scan_cmd) | ||
424 | goto out_free; | ||
425 | |||
426 | err = iwl_mvm_mac_setup_register(mvm); | ||
427 | if (err) | ||
428 | goto out_free; | ||
429 | |||
430 | err = iwl_mvm_dbgfs_register(mvm, dbgfs_dir); | ||
431 | if (err) | ||
432 | goto out_unregister; | ||
433 | |||
434 | return op_mode; | ||
435 | |||
436 | out_unregister: | ||
437 | ieee80211_unregister_hw(mvm->hw); | ||
438 | out_free: | ||
439 | iwl_phy_db_free(mvm->phy_db); | ||
440 | kfree(mvm->scan_cmd); | ||
441 | kfree(mvm->eeprom_blob); | ||
442 | iwl_trans_stop_hw(trans, true); | ||
443 | ieee80211_free_hw(mvm->hw); | ||
444 | return NULL; | ||
445 | } | ||
446 | |||
447 | static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) | ||
448 | { | ||
449 | struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); | ||
450 | int i; | ||
451 | |||
452 | iwl_mvm_leds_exit(mvm); | ||
453 | |||
454 | ieee80211_unregister_hw(mvm->hw); | ||
455 | |||
456 | kfree(mvm->scan_cmd); | ||
457 | |||
458 | iwl_trans_stop_hw(mvm->trans, true); | ||
459 | |||
460 | iwl_phy_db_free(mvm->phy_db); | ||
461 | mvm->phy_db = NULL; | ||
462 | |||
463 | kfree(mvm->eeprom_blob); | ||
464 | iwl_free_nvm_data(mvm->nvm_data); | ||
465 | for (i = 0; i < NVM_NUM_OF_SECTIONS; i++) | ||
466 | kfree(mvm->nvm_sections[i].data); | ||
467 | |||
468 | ieee80211_free_hw(mvm->hw); | ||
469 | } | ||
470 | |||
471 | struct iwl_async_handler_entry { | ||
472 | struct list_head list; | ||
473 | struct iwl_rx_cmd_buffer rxb; | ||
474 | int (*fn)(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | ||
475 | struct iwl_device_cmd *cmd); | ||
476 | }; | ||
477 | |||
478 | void iwl_mvm_async_handlers_purge(struct iwl_mvm *mvm) | ||
479 | { | ||
480 | struct iwl_async_handler_entry *entry, *tmp; | ||
481 | |||
482 | spin_lock_bh(&mvm->async_handlers_lock); | ||
483 | list_for_each_entry_safe(entry, tmp, &mvm->async_handlers_list, list) { | ||
484 | iwl_free_rxb(&entry->rxb); | ||
485 | list_del(&entry->list); | ||
486 | kfree(entry); | ||
487 | } | ||
488 | spin_unlock_bh(&mvm->async_handlers_lock); | ||
489 | } | ||
490 | |||
491 | static void iwl_mvm_async_handlers_wk(struct work_struct *wk) | ||
492 | { | ||
493 | struct iwl_mvm *mvm = | ||
494 | container_of(wk, struct iwl_mvm, async_handlers_wk); | ||
495 | struct iwl_async_handler_entry *entry, *tmp; | ||
496 | struct list_head local_list; | ||
497 | |||
498 | INIT_LIST_HEAD(&local_list); | ||
499 | |||
500 | /* Ensure that we are not in stop flow (check iwl_mvm_mac_stop) */ | ||
501 | mutex_lock(&mvm->mutex); | ||
502 | |||
503 | /* | ||
504 | * Sync with Rx path with a lock. Remove all the entries from this list, | ||
505 | * add them to a local one (lock free), and then handle them. | ||
506 | */ | ||
507 | spin_lock_bh(&mvm->async_handlers_lock); | ||
508 | list_splice_init(&mvm->async_handlers_list, &local_list); | ||
509 | spin_unlock_bh(&mvm->async_handlers_lock); | ||
510 | |||
511 | list_for_each_entry_safe(entry, tmp, &local_list, list) { | ||
512 | if (entry->fn(mvm, &entry->rxb, NULL)) | ||
513 | IWL_WARN(mvm, | ||
514 | "returned value from ASYNC handlers are ignored\n"); | ||
515 | iwl_free_rxb(&entry->rxb); | ||
516 | list_del(&entry->list); | ||
517 | kfree(entry); | ||
518 | } | ||
519 | mutex_unlock(&mvm->mutex); | ||
520 | } | ||
521 | |||
522 | static int iwl_mvm_rx_dispatch(struct iwl_op_mode *op_mode, | ||
523 | struct iwl_rx_cmd_buffer *rxb, | ||
524 | struct iwl_device_cmd *cmd) | ||
525 | { | ||
526 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
527 | struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); | ||
528 | u8 i; | ||
529 | |||
530 | /* | ||
531 | * Do the notification wait before RX handlers so | ||
532 | * even if the RX handler consumes the RXB we have | ||
533 | * access to it in the notification wait entry. | ||
534 | */ | ||
535 | iwl_notification_wait_notify(&mvm->notif_wait, pkt); | ||
536 | |||
537 | for (i = 0; i < ARRAY_SIZE(iwl_mvm_rx_handlers); i++) { | ||
538 | const struct iwl_rx_handlers *rx_h = &iwl_mvm_rx_handlers[i]; | ||
539 | if (rx_h->cmd_id == pkt->hdr.cmd) { | ||
540 | struct iwl_async_handler_entry *entry; | ||
541 | if (!rx_h->async) | ||
542 | return rx_h->fn(mvm, rxb, cmd); | ||
543 | |||
544 | entry = kzalloc(sizeof(*entry), GFP_ATOMIC); | ||
545 | /* we can't do much... */ | ||
546 | if (!entry) | ||
547 | return 0; | ||
548 | |||
549 | entry->rxb._page = rxb_steal_page(rxb); | ||
550 | entry->rxb._offset = rxb->_offset; | ||
551 | entry->rxb._rx_page_order = rxb->_rx_page_order; | ||
552 | entry->fn = rx_h->fn; | ||
553 | spin_lock(&mvm->async_handlers_lock); | ||
554 | list_add_tail(&entry->list, &mvm->async_handlers_list); | ||
555 | spin_unlock(&mvm->async_handlers_lock); | ||
556 | schedule_work(&mvm->async_handlers_wk); | ||
557 | } | ||
558 | } | ||
559 | |||
560 | return 0; | ||
561 | } | ||
562 | |||
563 | static void iwl_mvm_stop_sw_queue(struct iwl_op_mode *op_mode, int queue) | ||
564 | { | ||
565 | struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); | ||
566 | int mq = mvm->queue_to_mac80211[queue]; | ||
567 | |||
568 | if (WARN_ON_ONCE(mq == IWL_INVALID_MAC80211_QUEUE)) | ||
569 | return; | ||
570 | |||
571 | if (atomic_inc_return(&mvm->queue_stop_count[mq]) > 1) { | ||
572 | IWL_DEBUG_TX_QUEUES(mvm, | ||
573 | "queue %d (mac80211 %d) already stopped\n", | ||
574 | queue, mq); | ||
575 | return; | ||
576 | } | ||
577 | |||
578 | set_bit(mq, &mvm->transport_queue_stop); | ||
579 | ieee80211_stop_queue(mvm->hw, mq); | ||
580 | } | ||
581 | |||
582 | static void iwl_mvm_wake_sw_queue(struct iwl_op_mode *op_mode, int queue) | ||
583 | { | ||
584 | struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); | ||
585 | int mq = mvm->queue_to_mac80211[queue]; | ||
586 | |||
587 | if (WARN_ON_ONCE(mq == IWL_INVALID_MAC80211_QUEUE)) | ||
588 | return; | ||
589 | |||
590 | if (atomic_dec_return(&mvm->queue_stop_count[mq]) > 0) { | ||
591 | IWL_DEBUG_TX_QUEUES(mvm, | ||
592 | "queue %d (mac80211 %d) already awake\n", | ||
593 | queue, mq); | ||
594 | return; | ||
595 | } | ||
596 | |||
597 | clear_bit(mq, &mvm->transport_queue_stop); | ||
598 | |||
599 | ieee80211_wake_queue(mvm->hw, mq); | ||
600 | } | ||
601 | |||
602 | static void iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) | ||
603 | { | ||
604 | struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); | ||
605 | |||
606 | if (state) | ||
607 | set_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status); | ||
608 | else | ||
609 | clear_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status); | ||
610 | |||
611 | wiphy_rfkill_set_hw_state(mvm->hw->wiphy, state); | ||
612 | } | ||
613 | |||
614 | static void iwl_mvm_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb) | ||
615 | { | ||
616 | struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); | ||
617 | struct ieee80211_tx_info *info; | ||
618 | |||
619 | info = IEEE80211_SKB_CB(skb); | ||
620 | iwl_trans_free_tx_cmd(mvm->trans, info->driver_data[1]); | ||
621 | ieee80211_free_txskb(mvm->hw, skb); | ||
622 | } | ||
623 | |||
624 | static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode) | ||
625 | { | ||
626 | struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); | ||
627 | |||
628 | iwl_mvm_dump_nic_error_log(mvm); | ||
629 | |||
630 | iwl_abort_notification_waits(&mvm->notif_wait); | ||
631 | |||
632 | /* | ||
633 | * If we're restarting already, don't cycle restarts. | ||
634 | * If INIT fw asserted, it will likely fail again. | ||
635 | * If WoWLAN fw asserted, don't restart either, mac80211 | ||
636 | * can't recover this since we're already half suspended. | ||
637 | */ | ||
638 | if (test_and_set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { | ||
639 | IWL_ERR(mvm, "Firmware error during reconfiguration! Abort.\n"); | ||
640 | } else if (mvm->cur_ucode == IWL_UCODE_REGULAR && | ||
641 | iwlwifi_mod_params.restart_fw) { | ||
642 | /* | ||
643 | * This is a bit racy, but worst case we tell mac80211 about | ||
644 | * a stopped/aborted (sched) scan when that was already done | ||
645 | * which is not a problem. It is necessary to abort any scan | ||
646 | * here because mac80211 requires having the scan cleared | ||
647 | * before restarting. | ||
648 | * We'll reset the scan_status to NONE in restart cleanup in | ||
649 | * the next start() call from mac80211. | ||
650 | */ | ||
651 | switch (mvm->scan_status) { | ||
652 | case IWL_MVM_SCAN_NONE: | ||
653 | break; | ||
654 | case IWL_MVM_SCAN_OS: | ||
655 | ieee80211_scan_completed(mvm->hw, true); | ||
656 | break; | ||
657 | } | ||
658 | |||
659 | ieee80211_restart_hw(mvm->hw); | ||
660 | } | ||
661 | } | ||
662 | |||
663 | static void iwl_mvm_cmd_queue_full(struct iwl_op_mode *op_mode) | ||
664 | { | ||
665 | WARN_ON(1); | ||
666 | } | ||
667 | |||
668 | static const struct iwl_op_mode_ops iwl_mvm_ops = { | ||
669 | .start = iwl_op_mode_mvm_start, | ||
670 | .stop = iwl_op_mode_mvm_stop, | ||
671 | .rx = iwl_mvm_rx_dispatch, | ||
672 | .queue_full = iwl_mvm_stop_sw_queue, | ||
673 | .queue_not_full = iwl_mvm_wake_sw_queue, | ||
674 | .hw_rf_kill = iwl_mvm_set_hw_rfkill_state, | ||
675 | .free_skb = iwl_mvm_free_skb, | ||
676 | .nic_error = iwl_mvm_nic_error, | ||
677 | .cmd_queue_full = iwl_mvm_cmd_queue_full, | ||
678 | .nic_config = iwl_mvm_nic_config, | ||
679 | }; | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c new file mode 100644 index 000000000000..b428448f8ddf --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c | |||
@@ -0,0 +1,292 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called LICENSE.GPL. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | * | ||
62 | *****************************************************************************/ | ||
63 | |||
64 | #include <net/mac80211.h> | ||
65 | #include "fw-api.h" | ||
66 | #include "mvm.h" | ||
67 | |||
68 | /* Maps the driver specific channel width definition to the the fw values */ | ||
69 | static inline u8 iwl_mvm_get_channel_width(struct cfg80211_chan_def *chandef) | ||
70 | { | ||
71 | switch (chandef->width) { | ||
72 | case NL80211_CHAN_WIDTH_20_NOHT: | ||
73 | case NL80211_CHAN_WIDTH_20: | ||
74 | return PHY_VHT_CHANNEL_MODE20; | ||
75 | case NL80211_CHAN_WIDTH_40: | ||
76 | return PHY_VHT_CHANNEL_MODE40; | ||
77 | case NL80211_CHAN_WIDTH_80: | ||
78 | return PHY_VHT_CHANNEL_MODE80; | ||
79 | case NL80211_CHAN_WIDTH_160: | ||
80 | return PHY_VHT_CHANNEL_MODE160; | ||
81 | default: | ||
82 | WARN(1, "Invalid channel width=%u", chandef->width); | ||
83 | return PHY_VHT_CHANNEL_MODE20; | ||
84 | } | ||
85 | } | ||
86 | |||
87 | /* | ||
88 | * Maps the driver specific control channel position (relative to the center | ||
89 | * freq) definitions to the the fw values | ||
90 | */ | ||
91 | static inline u8 iwl_mvm_get_ctrl_pos(struct cfg80211_chan_def *chandef) | ||
92 | { | ||
93 | switch (chandef->chan->center_freq - chandef->center_freq1) { | ||
94 | case -70: | ||
95 | return PHY_VHT_CTRL_POS_4_BELOW; | ||
96 | case -50: | ||
97 | return PHY_VHT_CTRL_POS_3_BELOW; | ||
98 | case -30: | ||
99 | return PHY_VHT_CTRL_POS_2_BELOW; | ||
100 | case -10: | ||
101 | return PHY_VHT_CTRL_POS_1_BELOW; | ||
102 | case 10: | ||
103 | return PHY_VHT_CTRL_POS_1_ABOVE; | ||
104 | case 30: | ||
105 | return PHY_VHT_CTRL_POS_2_ABOVE; | ||
106 | case 50: | ||
107 | return PHY_VHT_CTRL_POS_3_ABOVE; | ||
108 | case 70: | ||
109 | return PHY_VHT_CTRL_POS_4_ABOVE; | ||
110 | default: | ||
111 | WARN(1, "Invalid channel definition"); | ||
112 | case 0: | ||
113 | /* | ||
114 | * The FW is expected to check the control channel position only | ||
115 | * when in HT/VHT and the channel width is not 20MHz. Return | ||
116 | * this value as the default one. | ||
117 | */ | ||
118 | return PHY_VHT_CTRL_POS_1_BELOW; | ||
119 | } | ||
120 | } | ||
121 | |||
122 | /* | ||
123 | * Construct the generic fields of the PHY context command | ||
124 | */ | ||
125 | static void iwl_mvm_phy_ctxt_cmd_hdr(struct iwl_mvm_phy_ctxt *ctxt, | ||
126 | struct iwl_phy_context_cmd *cmd, | ||
127 | u32 action, u32 apply_time) | ||
128 | { | ||
129 | memset(cmd, 0, sizeof(struct iwl_phy_context_cmd)); | ||
130 | |||
131 | cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(ctxt->id, | ||
132 | ctxt->color)); | ||
133 | cmd->action = cpu_to_le32(action); | ||
134 | cmd->apply_time = cpu_to_le32(apply_time); | ||
135 | } | ||
136 | |||
137 | /* | ||
138 | * Add the phy configuration to the PHY context command | ||
139 | */ | ||
140 | static void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm, | ||
141 | struct iwl_phy_context_cmd *cmd, | ||
142 | struct cfg80211_chan_def *chandef, | ||
143 | u8 chains_static, u8 chains_dynamic) | ||
144 | { | ||
145 | u8 valid_rx_chains, active_cnt, idle_cnt; | ||
146 | |||
147 | /* Set the channel info data */ | ||
148 | cmd->ci.band = (chandef->chan->band == IEEE80211_BAND_2GHZ ? | ||
149 | PHY_BAND_24 : PHY_BAND_5); | ||
150 | |||
151 | cmd->ci.channel = chandef->chan->hw_value; | ||
152 | cmd->ci.width = iwl_mvm_get_channel_width(chandef); | ||
153 | cmd->ci.ctrl_pos = iwl_mvm_get_ctrl_pos(chandef); | ||
154 | |||
155 | /* Set rx the chains */ | ||
156 | |||
157 | /* TODO: | ||
158 | * Need to add on chain noise calibration limitations, and | ||
159 | * BT coex considerations. | ||
160 | */ | ||
161 | valid_rx_chains = mvm->nvm_data->valid_rx_ant; | ||
162 | idle_cnt = chains_static; | ||
163 | active_cnt = chains_dynamic; | ||
164 | |||
165 | cmd->rxchain_info = cpu_to_le32(valid_rx_chains << | ||
166 | PHY_RX_CHAIN_VALID_POS); | ||
167 | cmd->rxchain_info |= cpu_to_le32(idle_cnt << PHY_RX_CHAIN_CNT_POS); | ||
168 | cmd->rxchain_info |= cpu_to_le32(active_cnt << | ||
169 | PHY_RX_CHAIN_MIMO_CNT_POS); | ||
170 | |||
171 | cmd->txchain_info = cpu_to_le32(mvm->nvm_data->valid_tx_ant); | ||
172 | } | ||
173 | |||
174 | /* | ||
175 | * Send a command to apply the current phy configuration. The command is send | ||
176 | * only if something in the configuration changed: in case that this is the | ||
177 | * first time that the phy configuration is applied or in case that the phy | ||
178 | * configuration changed from the previous apply. | ||
179 | */ | ||
180 | static int iwl_mvm_phy_ctxt_apply(struct iwl_mvm *mvm, | ||
181 | struct iwl_mvm_phy_ctxt *ctxt, | ||
182 | struct cfg80211_chan_def *chandef, | ||
183 | u8 chains_static, u8 chains_dynamic, | ||
184 | u32 action, u32 apply_time) | ||
185 | { | ||
186 | struct iwl_phy_context_cmd cmd; | ||
187 | int ret; | ||
188 | |||
189 | /* Set the command header fields */ | ||
190 | iwl_mvm_phy_ctxt_cmd_hdr(ctxt, &cmd, action, apply_time); | ||
191 | |||
192 | /* Set the command data */ | ||
193 | iwl_mvm_phy_ctxt_cmd_data(mvm, &cmd, chandef, | ||
194 | chains_static, chains_dynamic); | ||
195 | |||
196 | ret = iwl_mvm_send_cmd_pdu(mvm, PHY_CONTEXT_CMD, CMD_SYNC, | ||
197 | sizeof(struct iwl_phy_context_cmd), | ||
198 | &cmd); | ||
199 | if (ret) | ||
200 | IWL_ERR(mvm, "PHY ctxt cmd error. ret=%d\n", ret); | ||
201 | return ret; | ||
202 | } | ||
203 | |||
204 | |||
205 | struct phy_ctx_used_data { | ||
206 | unsigned long used[BITS_TO_LONGS(NUM_PHY_CTX)]; | ||
207 | }; | ||
208 | |||
209 | static void iwl_mvm_phy_ctx_used_iter(struct ieee80211_hw *hw, | ||
210 | struct ieee80211_chanctx_conf *ctx, | ||
211 | void *_data) | ||
212 | { | ||
213 | struct phy_ctx_used_data *data = _data; | ||
214 | struct iwl_mvm_phy_ctxt *phy_ctxt = (void *)ctx->drv_priv; | ||
215 | |||
216 | __set_bit(phy_ctxt->id, data->used); | ||
217 | } | ||
218 | |||
219 | /* | ||
220 | * Send a command to add a PHY context based on the current HW configuration. | ||
221 | */ | ||
222 | int iwl_mvm_phy_ctxt_add(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, | ||
223 | struct cfg80211_chan_def *chandef, | ||
224 | u8 chains_static, u8 chains_dynamic) | ||
225 | { | ||
226 | struct phy_ctx_used_data data = { | ||
227 | .used = { }, | ||
228 | }; | ||
229 | |||
230 | /* | ||
231 | * If this is a regular PHY context (not the ROC one) | ||
232 | * skip the ROC PHY context's ID. | ||
233 | */ | ||
234 | if (ctxt != &mvm->phy_ctxt_roc) | ||
235 | __set_bit(mvm->phy_ctxt_roc.id, data.used); | ||
236 | |||
237 | lockdep_assert_held(&mvm->mutex); | ||
238 | ctxt->color++; | ||
239 | |||
240 | if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { | ||
241 | ieee80211_iter_chan_contexts_atomic( | ||
242 | mvm->hw, iwl_mvm_phy_ctx_used_iter, &data); | ||
243 | |||
244 | ctxt->id = find_first_zero_bit(data.used, NUM_PHY_CTX); | ||
245 | if (WARN_ONCE(ctxt->id == NUM_PHY_CTX, | ||
246 | "Failed to init PHY context - no free ID!\n")) | ||
247 | return -EIO; | ||
248 | } | ||
249 | |||
250 | ctxt->channel = chandef->chan; | ||
251 | return iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef, | ||
252 | chains_static, chains_dynamic, | ||
253 | FW_CTXT_ACTION_ADD, 0); | ||
254 | } | ||
255 | |||
256 | /* | ||
257 | * Send a command to modify the PHY context based on the current HW | ||
258 | * configuration. Note that the function does not check that the configuration | ||
259 | * changed. | ||
260 | */ | ||
261 | int iwl_mvm_phy_ctxt_changed(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, | ||
262 | struct cfg80211_chan_def *chandef, | ||
263 | u8 chains_static, u8 chains_dynamic) | ||
264 | { | ||
265 | lockdep_assert_held(&mvm->mutex); | ||
266 | |||
267 | ctxt->channel = chandef->chan; | ||
268 | return iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef, | ||
269 | chains_static, chains_dynamic, | ||
270 | FW_CTXT_ACTION_MODIFY, 0); | ||
271 | } | ||
272 | |||
273 | /* | ||
274 | * Send a command to the FW to remove the given phy context. | ||
275 | * Once the command is sent, regardless of success or failure, the context is | ||
276 | * marked as invalid | ||
277 | */ | ||
278 | void iwl_mvm_phy_ctxt_remove(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt) | ||
279 | { | ||
280 | struct iwl_phy_context_cmd cmd; | ||
281 | int ret; | ||
282 | |||
283 | lockdep_assert_held(&mvm->mutex); | ||
284 | |||
285 | iwl_mvm_phy_ctxt_cmd_hdr(ctxt, &cmd, FW_CTXT_ACTION_REMOVE, 0); | ||
286 | ret = iwl_mvm_send_cmd_pdu(mvm, PHY_CONTEXT_CMD, CMD_SYNC, | ||
287 | sizeof(struct iwl_phy_context_cmd), | ||
288 | &cmd); | ||
289 | if (ret) | ||
290 | IWL_ERR(mvm, "Failed to send PHY remove: ctxt id=%d\n", | ||
291 | ctxt->id); | ||
292 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c new file mode 100644 index 000000000000..63628739cf4a --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/power.c | |||
@@ -0,0 +1,207 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called LICENSE.GPL. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | * | ||
62 | *****************************************************************************/ | ||
63 | |||
64 | #include <linux/kernel.h> | ||
65 | #include <linux/module.h> | ||
66 | #include <linux/slab.h> | ||
67 | #include <linux/init.h> | ||
68 | |||
69 | #include <net/mac80211.h> | ||
70 | |||
71 | #include "iwl-debug.h" | ||
72 | #include "mvm.h" | ||
73 | #include "iwl-modparams.h" | ||
74 | #include "fw-api-power.h" | ||
75 | |||
76 | #define POWER_KEEP_ALIVE_PERIOD_SEC 25 | ||
77 | |||
78 | static void iwl_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
79 | struct iwl_powertable_cmd *cmd) | ||
80 | { | ||
81 | struct ieee80211_hw *hw = mvm->hw; | ||
82 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
83 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
84 | struct ieee80211_channel *chan; | ||
85 | int dtimper, dtimper_msec; | ||
86 | int keep_alive; | ||
87 | bool radar_detect = false; | ||
88 | |||
89 | cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, | ||
90 | mvmvif->color)); | ||
91 | cmd->action = cpu_to_le32(FW_CTXT_ACTION_MODIFY); | ||
92 | |||
93 | if ((!vif->bss_conf.ps) || | ||
94 | (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM)) | ||
95 | return; | ||
96 | |||
97 | cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK); | ||
98 | |||
99 | dtimper = hw->conf.ps_dtim_period ?: 1; | ||
100 | |||
101 | /* Check if radar detection is required on current channel */ | ||
102 | rcu_read_lock(); | ||
103 | chanctx_conf = rcu_dereference(vif->chanctx_conf); | ||
104 | WARN_ON(!chanctx_conf); | ||
105 | if (chanctx_conf) { | ||
106 | chan = chanctx_conf->def.chan; | ||
107 | radar_detect = chan->flags & IEEE80211_CHAN_RADAR; | ||
108 | } | ||
109 | rcu_read_unlock(); | ||
110 | |||
111 | /* Check skip over DTIM conditions */ | ||
112 | if (!radar_detect && (dtimper <= 10) && | ||
113 | (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP)) { | ||
114 | cmd->flags |= cpu_to_le16(POWER_FLAGS_SLEEP_OVER_DTIM_MSK); | ||
115 | cmd->num_skip_dtim = 2; | ||
116 | } | ||
117 | |||
118 | /* Check that keep alive period is at least 3 * DTIM */ | ||
119 | dtimper_msec = dtimper * vif->bss_conf.beacon_int; | ||
120 | keep_alive = max_t(int, 3 * dtimper_msec, | ||
121 | MSEC_PER_SEC * POWER_KEEP_ALIVE_PERIOD_SEC); | ||
122 | keep_alive = DIV_ROUND_UP(keep_alive, MSEC_PER_SEC); | ||
123 | |||
124 | cmd->keep_alive_seconds = cpu_to_le16(keep_alive); | ||
125 | |||
126 | if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP) { | ||
127 | /* TODO: Also for D3 (device sleep / WoWLAN) */ | ||
128 | cmd->rx_data_timeout = cpu_to_le32(10); | ||
129 | cmd->tx_data_timeout = cpu_to_le32(10); | ||
130 | } else { | ||
131 | cmd->rx_data_timeout = cpu_to_le32(50); | ||
132 | cmd->tx_data_timeout = cpu_to_le32(50); | ||
133 | } | ||
134 | } | ||
135 | |||
136 | int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | ||
137 | { | ||
138 | struct iwl_powertable_cmd cmd = {}; | ||
139 | |||
140 | if (!iwlwifi_mod_params.power_save) { | ||
141 | IWL_DEBUG_POWER(mvm, "Power management is not allowed\n"); | ||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) | ||
146 | return 0; | ||
147 | |||
148 | iwl_power_build_cmd(mvm, vif, &cmd); | ||
149 | |||
150 | IWL_DEBUG_POWER(mvm, | ||
151 | "Sending power table command on mac id 0x%X for power level %d, flags = 0x%X\n", | ||
152 | cmd.id_and_color, iwlmvm_mod_params.power_scheme, | ||
153 | le16_to_cpu(cmd.flags)); | ||
154 | |||
155 | if (cmd.flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)) { | ||
156 | IWL_DEBUG_POWER(mvm, "Keep alive = %u sec\n", | ||
157 | le16_to_cpu(cmd.keep_alive_seconds)); | ||
158 | IWL_DEBUG_POWER(mvm, "Rx timeout = %u usec\n", | ||
159 | le32_to_cpu(cmd.rx_data_timeout)); | ||
160 | IWL_DEBUG_POWER(mvm, "Tx timeout = %u usec\n", | ||
161 | le32_to_cpu(cmd.tx_data_timeout)); | ||
162 | IWL_DEBUG_POWER(mvm, "Rx timeout (uAPSD) = %u usec\n", | ||
163 | le32_to_cpu(cmd.rx_data_timeout_uapsd)); | ||
164 | IWL_DEBUG_POWER(mvm, "Tx timeout = %u usec\n", | ||
165 | le32_to_cpu(cmd.tx_data_timeout_uapsd)); | ||
166 | IWL_DEBUG_POWER(mvm, "LP RX RSSI threshold = %u\n", | ||
167 | cmd.lprx_rssi_threshold); | ||
168 | IWL_DEBUG_POWER(mvm, "DTIMs to skip = %u\n", cmd.num_skip_dtim); | ||
169 | } | ||
170 | |||
171 | return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_SYNC, | ||
172 | sizeof(cmd), &cmd); | ||
173 | } | ||
174 | |||
175 | int iwl_mvm_power_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | ||
176 | { | ||
177 | struct iwl_powertable_cmd cmd = {}; | ||
178 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
179 | |||
180 | if (!iwlwifi_mod_params.power_save) { | ||
181 | IWL_DEBUG_POWER(mvm, "Power management is not allowed\n"); | ||
182 | return 0; | ||
183 | } | ||
184 | |||
185 | if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) | ||
186 | return 0; | ||
187 | |||
188 | cmd.id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, | ||
189 | mvmvif->color)); | ||
190 | cmd.action = cpu_to_le32(FW_CTXT_ACTION_MODIFY); | ||
191 | |||
192 | IWL_DEBUG_POWER(mvm, | ||
193 | "Sending power table command on mac id 0x%X for power level %d, flags = 0x%X\n", | ||
194 | cmd.id_and_color, iwlmvm_mod_params.power_scheme, | ||
195 | le16_to_cpu(cmd.flags)); | ||
196 | |||
197 | return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_SYNC, | ||
198 | sizeof(cmd), &cmd); | ||
199 | } | ||
200 | |||
201 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
202 | void iwl_power_get_params(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
203 | struct iwl_powertable_cmd *cmd) | ||
204 | { | ||
205 | iwl_power_build_cmd(mvm, vif, cmd); | ||
206 | } | ||
207 | #endif /* CONFIG_IWLWIFI_DEBUGFS */ | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/quota.c b/drivers/net/wireless/iwlwifi/mvm/quota.c new file mode 100644 index 000000000000..2d4611a563c5 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/quota.c | |||
@@ -0,0 +1,178 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called LICENSE.GPL. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | * | ||
62 | *****************************************************************************/ | ||
63 | |||
64 | #include <net/mac80211.h> | ||
65 | #include "fw-api.h" | ||
66 | #include "mvm.h" | ||
67 | |||
68 | struct iwl_mvm_quota_iterator_data { | ||
69 | int n_interfaces[MAX_BINDINGS]; | ||
70 | int colors[MAX_BINDINGS]; | ||
71 | struct ieee80211_vif *new_vif; | ||
72 | }; | ||
73 | |||
74 | static void iwl_mvm_quota_iterator(void *_data, u8 *mac, | ||
75 | struct ieee80211_vif *vif) | ||
76 | { | ||
77 | struct iwl_mvm_quota_iterator_data *data = _data; | ||
78 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
79 | u16 id; | ||
80 | |||
81 | /* | ||
82 | * We'll account for the new interface (if any) below, | ||
83 | * skip it here in case we're not called from within | ||
84 | * the add_interface callback (otherwise it won't show | ||
85 | * up in iteration) | ||
86 | */ | ||
87 | if (vif == data->new_vif) | ||
88 | return; | ||
89 | |||
90 | if (!mvmvif->phy_ctxt) | ||
91 | return; | ||
92 | |||
93 | /* currently, PHY ID == binding ID */ | ||
94 | id = mvmvif->phy_ctxt->id; | ||
95 | |||
96 | /* need at least one binding per PHY */ | ||
97 | BUILD_BUG_ON(NUM_PHY_CTX > MAX_BINDINGS); | ||
98 | |||
99 | if (WARN_ON_ONCE(id >= MAX_BINDINGS)) | ||
100 | return; | ||
101 | |||
102 | if (data->colors[id] < 0) | ||
103 | data->colors[id] = mvmvif->phy_ctxt->color; | ||
104 | else | ||
105 | WARN_ON_ONCE(data->colors[id] != mvmvif->phy_ctxt->color); | ||
106 | |||
107 | switch (vif->type) { | ||
108 | case NL80211_IFTYPE_STATION: | ||
109 | if (vif->bss_conf.assoc) | ||
110 | data->n_interfaces[id]++; | ||
111 | break; | ||
112 | case NL80211_IFTYPE_AP: | ||
113 | if (mvmvif->ap_active) | ||
114 | data->n_interfaces[id]++; | ||
115 | break; | ||
116 | case NL80211_IFTYPE_MONITOR: | ||
117 | data->n_interfaces[id]++; | ||
118 | break; | ||
119 | case NL80211_IFTYPE_P2P_DEVICE: | ||
120 | break; | ||
121 | case NL80211_IFTYPE_ADHOC: | ||
122 | if (vif->bss_conf.ibss_joined) | ||
123 | data->n_interfaces[id]++; | ||
124 | break; | ||
125 | default: | ||
126 | WARN_ON_ONCE(1); | ||
127 | break; | ||
128 | } | ||
129 | } | ||
130 | |||
131 | int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) | ||
132 | { | ||
133 | struct iwl_time_quota_cmd cmd; | ||
134 | int i, idx, ret; | ||
135 | struct iwl_mvm_quota_iterator_data data = { | ||
136 | .n_interfaces = {}, | ||
137 | .colors = { -1, -1, -1, -1 }, | ||
138 | .new_vif = newvif, | ||
139 | }; | ||
140 | |||
141 | /* update all upon completion */ | ||
142 | if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) | ||
143 | return 0; | ||
144 | |||
145 | BUILD_BUG_ON(data.colors[MAX_BINDINGS - 1] != -1); | ||
146 | |||
147 | lockdep_assert_held(&mvm->mutex); | ||
148 | |||
149 | memset(&cmd, 0, sizeof(cmd)); | ||
150 | |||
151 | ieee80211_iterate_active_interfaces_atomic( | ||
152 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, | ||
153 | iwl_mvm_quota_iterator, &data); | ||
154 | if (newvif) { | ||
155 | data.new_vif = NULL; | ||
156 | iwl_mvm_quota_iterator(&data, newvif->addr, newvif); | ||
157 | } | ||
158 | |||
159 | for (idx = 0, i = 0; i < MAX_BINDINGS; i++) { | ||
160 | if (data.n_interfaces[i] <= 0) | ||
161 | continue; | ||
162 | |||
163 | cmd.quotas[idx].id_and_color = | ||
164 | cpu_to_le32(FW_CMD_ID_AND_COLOR(i, data.colors[i])); | ||
165 | cmd.quotas[idx].quota = cpu_to_le32(100); | ||
166 | cmd.quotas[idx].max_duration = cpu_to_le32(1000); | ||
167 | idx++; | ||
168 | } | ||
169 | |||
170 | for (i = idx; i < MAX_BINDINGS; i++) | ||
171 | cmd.quotas[i].id_and_color = cpu_to_le32(FW_CTXT_INVALID); | ||
172 | |||
173 | ret = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, CMD_SYNC, | ||
174 | sizeof(cmd), &cmd); | ||
175 | if (ret) | ||
176 | IWL_ERR(mvm, "Failed to send quota: %d\n", ret); | ||
177 | return ret; | ||
178 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c new file mode 100644 index 000000000000..60a4291ca221 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c | |||
@@ -0,0 +1,3096 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of version 2 of the GNU General Public License as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program; if not, write to the Free Software Foundation, Inc., | ||
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA | ||
17 | * | ||
18 | * The full GNU General Public License is included in this distribution in the | ||
19 | * file called LICENSE. | ||
20 | * | ||
21 | * Contact Information: | ||
22 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
23 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
24 | * | ||
25 | *****************************************************************************/ | ||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/init.h> | ||
28 | #include <linux/skbuff.h> | ||
29 | #include <linux/slab.h> | ||
30 | #include <net/mac80211.h> | ||
31 | |||
32 | #include <linux/netdevice.h> | ||
33 | #include <linux/etherdevice.h> | ||
34 | #include <linux/delay.h> | ||
35 | |||
36 | #include <linux/workqueue.h> | ||
37 | #include "rs.h" | ||
38 | #include "fw-api.h" | ||
39 | #include "sta.h" | ||
40 | #include "iwl-op-mode.h" | ||
41 | #include "mvm.h" | ||
42 | |||
43 | #define RS_NAME "iwl-mvm-rs" | ||
44 | |||
45 | #define NUM_TRY_BEFORE_ANT_TOGGLE 1 | ||
46 | #define IWL_NUMBER_TRY 1 | ||
47 | #define IWL_HT_NUMBER_TRY 3 | ||
48 | |||
49 | #define IWL_RATE_MAX_WINDOW 62 /* # tx in history window */ | ||
50 | #define IWL_RATE_MIN_FAILURE_TH 6 /* min failures to calc tpt */ | ||
51 | #define IWL_RATE_MIN_SUCCESS_TH 8 /* min successes to calc tpt */ | ||
52 | |||
53 | /* max allowed rate miss before sync LQ cmd */ | ||
54 | #define IWL_MISSED_RATE_MAX 15 | ||
55 | /* max time to accum history 2 seconds */ | ||
56 | #define IWL_RATE_SCALE_FLUSH_INTVL (3*HZ) | ||
57 | |||
58 | static u8 rs_ht_to_legacy[] = { | ||
59 | IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX, | ||
60 | IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX, | ||
61 | IWL_RATE_6M_INDEX, | ||
62 | IWL_RATE_6M_INDEX, IWL_RATE_9M_INDEX, | ||
63 | IWL_RATE_12M_INDEX, IWL_RATE_18M_INDEX, | ||
64 | IWL_RATE_24M_INDEX, IWL_RATE_36M_INDEX, | ||
65 | IWL_RATE_48M_INDEX, IWL_RATE_54M_INDEX | ||
66 | }; | ||
67 | |||
68 | static const u8 ant_toggle_lookup[] = { | ||
69 | /*ANT_NONE -> */ ANT_NONE, | ||
70 | /*ANT_A -> */ ANT_B, | ||
71 | /*ANT_B -> */ ANT_C, | ||
72 | /*ANT_AB -> */ ANT_BC, | ||
73 | /*ANT_C -> */ ANT_A, | ||
74 | /*ANT_AC -> */ ANT_AB, | ||
75 | /*ANT_BC -> */ ANT_AC, | ||
76 | /*ANT_ABC -> */ ANT_ABC, | ||
77 | }; | ||
78 | |||
79 | #define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np) \ | ||
80 | [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \ | ||
81 | IWL_RATE_SISO_##s##M_PLCP, \ | ||
82 | IWL_RATE_MIMO2_##s##M_PLCP,\ | ||
83 | IWL_RATE_MIMO3_##s##M_PLCP,\ | ||
84 | IWL_RATE_##r##M_IEEE, \ | ||
85 | IWL_RATE_##ip##M_INDEX, \ | ||
86 | IWL_RATE_##in##M_INDEX, \ | ||
87 | IWL_RATE_##rp##M_INDEX, \ | ||
88 | IWL_RATE_##rn##M_INDEX, \ | ||
89 | IWL_RATE_##pp##M_INDEX, \ | ||
90 | IWL_RATE_##np##M_INDEX } | ||
91 | |||
92 | /* | ||
93 | * Parameter order: | ||
94 | * rate, ht rate, prev rate, next rate, prev tgg rate, next tgg rate | ||
95 | * | ||
96 | * If there isn't a valid next or previous rate then INV is used which | ||
97 | * maps to IWL_RATE_INVALID | ||
98 | * | ||
99 | */ | ||
100 | static const struct iwl_rs_rate_info iwl_rates[IWL_RATE_COUNT] = { | ||
101 | IWL_DECLARE_RATE_INFO(1, INV, INV, 2, INV, 2, INV, 2), /* 1mbps */ | ||
102 | IWL_DECLARE_RATE_INFO(2, INV, 1, 5, 1, 5, 1, 5), /* 2mbps */ | ||
103 | IWL_DECLARE_RATE_INFO(5, INV, 2, 6, 2, 11, 2, 11), /*5.5mbps */ | ||
104 | IWL_DECLARE_RATE_INFO(11, INV, 9, 12, 9, 12, 5, 18), /* 11mbps */ | ||
105 | IWL_DECLARE_RATE_INFO(6, 6, 5, 9, 5, 11, 5, 11), /* 6mbps */ | ||
106 | IWL_DECLARE_RATE_INFO(9, 6, 6, 11, 6, 11, 5, 11), /* 9mbps */ | ||
107 | IWL_DECLARE_RATE_INFO(12, 12, 11, 18, 11, 18, 11, 18), /* 12mbps */ | ||
108 | IWL_DECLARE_RATE_INFO(18, 18, 12, 24, 12, 24, 11, 24), /* 18mbps */ | ||
109 | IWL_DECLARE_RATE_INFO(24, 24, 18, 36, 18, 36, 18, 36), /* 24mbps */ | ||
110 | IWL_DECLARE_RATE_INFO(36, 36, 24, 48, 24, 48, 24, 48), /* 36mbps */ | ||
111 | IWL_DECLARE_RATE_INFO(48, 48, 36, 54, 36, 54, 36, 54), /* 48mbps */ | ||
112 | IWL_DECLARE_RATE_INFO(54, 54, 48, INV, 48, INV, 48, INV),/* 54mbps */ | ||
113 | IWL_DECLARE_RATE_INFO(60, 60, 48, INV, 48, INV, 48, INV),/* 60mbps */ | ||
114 | /* FIXME:RS: ^^ should be INV (legacy) */ | ||
115 | }; | ||
116 | |||
117 | static inline u8 rs_extract_rate(u32 rate_n_flags) | ||
118 | { | ||
119 | /* also works for HT because bits 7:6 are zero there */ | ||
120 | return (u8)(rate_n_flags & RATE_LEGACY_RATE_MSK); | ||
121 | } | ||
122 | |||
123 | static int iwl_hwrate_to_plcp_idx(u32 rate_n_flags) | ||
124 | { | ||
125 | int idx = 0; | ||
126 | |||
127 | /* HT rate format */ | ||
128 | if (rate_n_flags & RATE_MCS_HT_MSK) { | ||
129 | idx = rs_extract_rate(rate_n_flags); | ||
130 | |||
131 | if (idx >= IWL_RATE_MIMO3_6M_PLCP) | ||
132 | idx = idx - IWL_RATE_MIMO3_6M_PLCP; | ||
133 | else if (idx >= IWL_RATE_MIMO2_6M_PLCP) | ||
134 | idx = idx - IWL_RATE_MIMO2_6M_PLCP; | ||
135 | |||
136 | idx += IWL_FIRST_OFDM_RATE; | ||
137 | /* skip 9M not supported in ht*/ | ||
138 | if (idx >= IWL_RATE_9M_INDEX) | ||
139 | idx += 1; | ||
140 | if ((idx >= IWL_FIRST_OFDM_RATE) && (idx <= IWL_LAST_OFDM_RATE)) | ||
141 | return idx; | ||
142 | |||
143 | /* legacy rate format, search for match in table */ | ||
144 | } else { | ||
145 | for (idx = 0; idx < ARRAY_SIZE(iwl_rates); idx++) | ||
146 | if (iwl_rates[idx].plcp == | ||
147 | rs_extract_rate(rate_n_flags)) | ||
148 | return idx; | ||
149 | } | ||
150 | |||
151 | return -1; | ||
152 | } | ||
153 | |||
154 | static void rs_rate_scale_perform(struct iwl_mvm *mvm, | ||
155 | struct sk_buff *skb, | ||
156 | struct ieee80211_sta *sta, | ||
157 | struct iwl_lq_sta *lq_sta); | ||
158 | static void rs_fill_link_cmd(struct iwl_mvm *mvm, | ||
159 | struct iwl_lq_sta *lq_sta, u32 rate_n_flags); | ||
160 | static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search); | ||
161 | |||
162 | |||
163 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
164 | static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta, | ||
165 | u32 *rate_n_flags, int index); | ||
166 | #else | ||
167 | static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta, | ||
168 | u32 *rate_n_flags, int index) | ||
169 | {} | ||
170 | #endif | ||
171 | |||
172 | /** | ||
173 | * The following tables contain the expected throughput metrics for all rates | ||
174 | * | ||
175 | * 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 60 MBits | ||
176 | * | ||
177 | * where invalid entries are zeros. | ||
178 | * | ||
179 | * CCK rates are only valid in legacy table and will only be used in G | ||
180 | * (2.4 GHz) band. | ||
181 | */ | ||
182 | |||
183 | static s32 expected_tpt_legacy[IWL_RATE_COUNT] = { | ||
184 | 7, 13, 35, 58, 40, 57, 72, 98, 121, 154, 177, 186, 0 | ||
185 | }; | ||
186 | |||
187 | static s32 expected_tpt_siso20MHz[4][IWL_RATE_COUNT] = { | ||
188 | {0, 0, 0, 0, 42, 0, 76, 102, 124, 159, 183, 193, 202}, /* Norm */ | ||
189 | {0, 0, 0, 0, 46, 0, 82, 110, 132, 168, 192, 202, 210}, /* SGI */ | ||
190 | {0, 0, 0, 0, 47, 0, 91, 133, 171, 242, 305, 334, 362}, /* AGG */ | ||
191 | {0, 0, 0, 0, 52, 0, 101, 145, 187, 264, 330, 361, 390}, /* AGG+SGI */ | ||
192 | }; | ||
193 | |||
194 | static s32 expected_tpt_siso40MHz[4][IWL_RATE_COUNT] = { | ||
195 | {0, 0, 0, 0, 77, 0, 127, 160, 184, 220, 242, 250, 257}, /* Norm */ | ||
196 | {0, 0, 0, 0, 83, 0, 135, 169, 193, 229, 250, 257, 264}, /* SGI */ | ||
197 | {0, 0, 0, 0, 94, 0, 177, 249, 313, 423, 512, 550, 586}, /* AGG */ | ||
198 | {0, 0, 0, 0, 104, 0, 193, 270, 338, 454, 545, 584, 620}, /* AGG+SGI */ | ||
199 | }; | ||
200 | |||
201 | static s32 expected_tpt_mimo2_20MHz[4][IWL_RATE_COUNT] = { | ||
202 | {0, 0, 0, 0, 74, 0, 123, 155, 179, 214, 236, 244, 251}, /* Norm */ | ||
203 | {0, 0, 0, 0, 81, 0, 131, 164, 188, 223, 243, 251, 257}, /* SGI */ | ||
204 | {0, 0, 0, 0, 89, 0, 167, 235, 296, 402, 488, 526, 560}, /* AGG */ | ||
205 | {0, 0, 0, 0, 97, 0, 182, 255, 320, 431, 520, 558, 593}, /* AGG+SGI*/ | ||
206 | }; | ||
207 | |||
208 | static s32 expected_tpt_mimo2_40MHz[4][IWL_RATE_COUNT] = { | ||
209 | {0, 0, 0, 0, 123, 0, 182, 214, 235, 264, 279, 285, 289}, /* Norm */ | ||
210 | {0, 0, 0, 0, 131, 0, 191, 222, 242, 270, 284, 289, 293}, /* SGI */ | ||
211 | {0, 0, 0, 0, 171, 0, 305, 410, 496, 634, 731, 771, 805}, /* AGG */ | ||
212 | {0, 0, 0, 0, 186, 0, 329, 439, 527, 667, 764, 803, 838}, /* AGG+SGI */ | ||
213 | }; | ||
214 | |||
215 | static s32 expected_tpt_mimo3_20MHz[4][IWL_RATE_COUNT] = { | ||
216 | {0, 0, 0, 0, 99, 0, 153, 186, 208, 239, 256, 263, 268}, /* Norm */ | ||
217 | {0, 0, 0, 0, 106, 0, 162, 194, 215, 246, 262, 268, 273}, /* SGI */ | ||
218 | {0, 0, 0, 0, 134, 0, 249, 346, 431, 574, 685, 732, 775}, /* AGG */ | ||
219 | {0, 0, 0, 0, 148, 0, 272, 376, 465, 614, 727, 775, 818}, /* AGG+SGI */ | ||
220 | }; | ||
221 | |||
222 | static s32 expected_tpt_mimo3_40MHz[4][IWL_RATE_COUNT] = { | ||
223 | {0, 0, 0, 0, 152, 0, 211, 239, 255, 279, 290, 294, 297}, /* Norm */ | ||
224 | {0, 0, 0, 0, 160, 0, 219, 245, 261, 284, 294, 297, 300}, /* SGI */ | ||
225 | {0, 0, 0, 0, 254, 0, 443, 584, 695, 868, 984, 1030, 1070}, /* AGG */ | ||
226 | {0, 0, 0, 0, 277, 0, 478, 624, 737, 911, 1026, 1070, 1109}, /* AGG+SGI */ | ||
227 | }; | ||
228 | |||
229 | /* mbps, mcs */ | ||
230 | static const struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = { | ||
231 | { "1", "BPSK DSSS"}, | ||
232 | { "2", "QPSK DSSS"}, | ||
233 | {"5.5", "BPSK CCK"}, | ||
234 | { "11", "QPSK CCK"}, | ||
235 | { "6", "BPSK 1/2"}, | ||
236 | { "9", "BPSK 1/2"}, | ||
237 | { "12", "QPSK 1/2"}, | ||
238 | { "18", "QPSK 3/4"}, | ||
239 | { "24", "16QAM 1/2"}, | ||
240 | { "36", "16QAM 3/4"}, | ||
241 | { "48", "64QAM 2/3"}, | ||
242 | { "54", "64QAM 3/4"}, | ||
243 | { "60", "64QAM 5/6"}, | ||
244 | }; | ||
245 | |||
246 | #define MCS_INDEX_PER_STREAM (8) | ||
247 | |||
248 | static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window) | ||
249 | { | ||
250 | window->data = 0; | ||
251 | window->success_counter = 0; | ||
252 | window->success_ratio = IWL_INVALID_VALUE; | ||
253 | window->counter = 0; | ||
254 | window->average_tpt = IWL_INVALID_VALUE; | ||
255 | window->stamp = 0; | ||
256 | } | ||
257 | |||
258 | static inline u8 rs_is_valid_ant(u8 valid_antenna, u8 ant_type) | ||
259 | { | ||
260 | return (ant_type & valid_antenna) == ant_type; | ||
261 | } | ||
262 | |||
263 | /* | ||
264 | * removes the old data from the statistics. All data that is older than | ||
265 | * TID_MAX_TIME_DIFF, will be deleted. | ||
266 | */ | ||
267 | static void rs_tl_rm_old_stats(struct iwl_traffic_load *tl, u32 curr_time) | ||
268 | { | ||
269 | /* The oldest age we want to keep */ | ||
270 | u32 oldest_time = curr_time - TID_MAX_TIME_DIFF; | ||
271 | |||
272 | while (tl->queue_count && | ||
273 | (tl->time_stamp < oldest_time)) { | ||
274 | tl->total -= tl->packet_count[tl->head]; | ||
275 | tl->packet_count[tl->head] = 0; | ||
276 | tl->time_stamp += TID_QUEUE_CELL_SPACING; | ||
277 | tl->queue_count--; | ||
278 | tl->head++; | ||
279 | if (tl->head >= TID_QUEUE_MAX_SIZE) | ||
280 | tl->head = 0; | ||
281 | } | ||
282 | } | ||
283 | |||
284 | /* | ||
285 | * increment traffic load value for tid and also remove | ||
286 | * any old values if passed the certain time period | ||
287 | */ | ||
288 | static u8 rs_tl_add_packet(struct iwl_lq_sta *lq_data, | ||
289 | struct ieee80211_hdr *hdr) | ||
290 | { | ||
291 | u32 curr_time = jiffies_to_msecs(jiffies); | ||
292 | u32 time_diff; | ||
293 | s32 index; | ||
294 | struct iwl_traffic_load *tl = NULL; | ||
295 | u8 tid; | ||
296 | |||
297 | if (ieee80211_is_data_qos(hdr->frame_control)) { | ||
298 | u8 *qc = ieee80211_get_qos_ctl(hdr); | ||
299 | tid = qc[0] & 0xf; | ||
300 | } else { | ||
301 | return IWL_MAX_TID_COUNT; | ||
302 | } | ||
303 | |||
304 | if (unlikely(tid >= IWL_MAX_TID_COUNT)) | ||
305 | return IWL_MAX_TID_COUNT; | ||
306 | |||
307 | tl = &lq_data->load[tid]; | ||
308 | |||
309 | curr_time -= curr_time % TID_ROUND_VALUE; | ||
310 | |||
311 | /* Happens only for the first packet. Initialize the data */ | ||
312 | if (!(tl->queue_count)) { | ||
313 | tl->total = 1; | ||
314 | tl->time_stamp = curr_time; | ||
315 | tl->queue_count = 1; | ||
316 | tl->head = 0; | ||
317 | tl->packet_count[0] = 1; | ||
318 | return IWL_MAX_TID_COUNT; | ||
319 | } | ||
320 | |||
321 | time_diff = TIME_WRAP_AROUND(tl->time_stamp, curr_time); | ||
322 | index = time_diff / TID_QUEUE_CELL_SPACING; | ||
323 | |||
324 | /* The history is too long: remove data that is older than */ | ||
325 | /* TID_MAX_TIME_DIFF */ | ||
326 | if (index >= TID_QUEUE_MAX_SIZE) | ||
327 | rs_tl_rm_old_stats(tl, curr_time); | ||
328 | |||
329 | index = (tl->head + index) % TID_QUEUE_MAX_SIZE; | ||
330 | tl->packet_count[index] = tl->packet_count[index] + 1; | ||
331 | tl->total = tl->total + 1; | ||
332 | |||
333 | if ((index + 1) > tl->queue_count) | ||
334 | tl->queue_count = index + 1; | ||
335 | |||
336 | return tid; | ||
337 | } | ||
338 | |||
339 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
340 | /** | ||
341 | * Program the device to use fixed rate for frame transmit | ||
342 | * This is for debugging/testing only | ||
343 | * once the device start use fixed rate, we need to reload the module | ||
344 | * to being back the normal operation. | ||
345 | */ | ||
346 | static void rs_program_fix_rate(struct iwl_mvm *mvm, | ||
347 | struct iwl_lq_sta *lq_sta) | ||
348 | { | ||
349 | lq_sta->active_legacy_rate = 0x0FFF; /* 1 - 54 MBits, includes CCK */ | ||
350 | lq_sta->active_siso_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */ | ||
351 | lq_sta->active_mimo2_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */ | ||
352 | lq_sta->active_mimo3_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */ | ||
353 | |||
354 | IWL_DEBUG_RATE(mvm, "sta_id %d rate 0x%X\n", | ||
355 | lq_sta->lq.sta_id, lq_sta->dbg_fixed_rate); | ||
356 | |||
357 | if (lq_sta->dbg_fixed_rate) { | ||
358 | rs_fill_link_cmd(NULL, lq_sta, lq_sta->dbg_fixed_rate); | ||
359 | iwl_mvm_send_lq_cmd(lq_sta->drv, &lq_sta->lq, CMD_ASYNC, false); | ||
360 | } | ||
361 | } | ||
362 | #endif | ||
363 | |||
364 | /* | ||
365 | get the traffic load value for tid | ||
366 | */ | ||
367 | static u32 rs_tl_get_load(struct iwl_lq_sta *lq_data, u8 tid) | ||
368 | { | ||
369 | u32 curr_time = jiffies_to_msecs(jiffies); | ||
370 | u32 time_diff; | ||
371 | s32 index; | ||
372 | struct iwl_traffic_load *tl = NULL; | ||
373 | |||
374 | if (tid >= IWL_MAX_TID_COUNT) | ||
375 | return 0; | ||
376 | |||
377 | tl = &(lq_data->load[tid]); | ||
378 | |||
379 | curr_time -= curr_time % TID_ROUND_VALUE; | ||
380 | |||
381 | if (!(tl->queue_count)) | ||
382 | return 0; | ||
383 | |||
384 | time_diff = TIME_WRAP_AROUND(tl->time_stamp, curr_time); | ||
385 | index = time_diff / TID_QUEUE_CELL_SPACING; | ||
386 | |||
387 | /* The history is too long: remove data that is older than */ | ||
388 | /* TID_MAX_TIME_DIFF */ | ||
389 | if (index >= TID_QUEUE_MAX_SIZE) | ||
390 | rs_tl_rm_old_stats(tl, curr_time); | ||
391 | |||
392 | return tl->total; | ||
393 | } | ||
394 | |||
395 | static int rs_tl_turn_on_agg_for_tid(struct iwl_mvm *mvm, | ||
396 | struct iwl_lq_sta *lq_data, u8 tid, | ||
397 | struct ieee80211_sta *sta) | ||
398 | { | ||
399 | int ret = -EAGAIN; | ||
400 | u32 load; | ||
401 | |||
402 | load = rs_tl_get_load(lq_data, tid); | ||
403 | |||
404 | if ((iwlwifi_mod_params.auto_agg) || (load > IWL_AGG_LOAD_THRESHOLD)) { | ||
405 | IWL_DEBUG_HT(mvm, "Starting Tx agg: STA: %pM tid: %d\n", | ||
406 | sta->addr, tid); | ||
407 | ret = ieee80211_start_tx_ba_session(sta, tid, 5000); | ||
408 | if (ret == -EAGAIN) { | ||
409 | /* | ||
410 | * driver and mac80211 is out of sync | ||
411 | * this might be cause by reloading firmware | ||
412 | * stop the tx ba session here | ||
413 | */ | ||
414 | IWL_ERR(mvm, "Fail start Tx agg on tid: %d\n", | ||
415 | tid); | ||
416 | ieee80211_stop_tx_ba_session(sta, tid); | ||
417 | } | ||
418 | } else { | ||
419 | IWL_DEBUG_HT(mvm, | ||
420 | "Aggregation not enabled for tid %d because load = %u\n", | ||
421 | tid, load); | ||
422 | } | ||
423 | return ret; | ||
424 | } | ||
425 | |||
426 | static void rs_tl_turn_on_agg(struct iwl_mvm *mvm, u8 tid, | ||
427 | struct iwl_lq_sta *lq_data, | ||
428 | struct ieee80211_sta *sta) | ||
429 | { | ||
430 | if (tid < IWL_MAX_TID_COUNT) | ||
431 | rs_tl_turn_on_agg_for_tid(mvm, lq_data, tid, sta); | ||
432 | else | ||
433 | IWL_ERR(mvm, "tid exceeds max TID count: %d/%d\n", | ||
434 | tid, IWL_MAX_TID_COUNT); | ||
435 | } | ||
436 | |||
437 | static inline int get_num_of_ant_from_rate(u32 rate_n_flags) | ||
438 | { | ||
439 | return !!(rate_n_flags & RATE_MCS_ANT_A_MSK) + | ||
440 | !!(rate_n_flags & RATE_MCS_ANT_B_MSK) + | ||
441 | !!(rate_n_flags & RATE_MCS_ANT_C_MSK); | ||
442 | } | ||
443 | |||
444 | /* | ||
445 | * Static function to get the expected throughput from an iwl_scale_tbl_info | ||
446 | * that wraps a NULL pointer check | ||
447 | */ | ||
448 | static s32 get_expected_tpt(struct iwl_scale_tbl_info *tbl, int rs_index) | ||
449 | { | ||
450 | if (tbl->expected_tpt) | ||
451 | return tbl->expected_tpt[rs_index]; | ||
452 | return 0; | ||
453 | } | ||
454 | |||
455 | /** | ||
456 | * rs_collect_tx_data - Update the success/failure sliding window | ||
457 | * | ||
458 | * We keep a sliding window of the last 62 packets transmitted | ||
459 | * at this rate. window->data contains the bitmask of successful | ||
460 | * packets. | ||
461 | */ | ||
462 | static int rs_collect_tx_data(struct iwl_scale_tbl_info *tbl, | ||
463 | int scale_index, int attempts, int successes) | ||
464 | { | ||
465 | struct iwl_rate_scale_data *window = NULL; | ||
466 | static const u64 mask = (((u64)1) << (IWL_RATE_MAX_WINDOW - 1)); | ||
467 | s32 fail_count, tpt; | ||
468 | |||
469 | if (scale_index < 0 || scale_index >= IWL_RATE_COUNT) | ||
470 | return -EINVAL; | ||
471 | |||
472 | /* Select window for current tx bit rate */ | ||
473 | window = &(tbl->win[scale_index]); | ||
474 | |||
475 | /* Get expected throughput */ | ||
476 | tpt = get_expected_tpt(tbl, scale_index); | ||
477 | |||
478 | /* | ||
479 | * Keep track of only the latest 62 tx frame attempts in this rate's | ||
480 | * history window; anything older isn't really relevant any more. | ||
481 | * If we have filled up the sliding window, drop the oldest attempt; | ||
482 | * if the oldest attempt (highest bit in bitmap) shows "success", | ||
483 | * subtract "1" from the success counter (this is the main reason | ||
484 | * we keep these bitmaps!). | ||
485 | */ | ||
486 | while (attempts > 0) { | ||
487 | if (window->counter >= IWL_RATE_MAX_WINDOW) { | ||
488 | /* remove earliest */ | ||
489 | window->counter = IWL_RATE_MAX_WINDOW - 1; | ||
490 | |||
491 | if (window->data & mask) { | ||
492 | window->data &= ~mask; | ||
493 | window->success_counter--; | ||
494 | } | ||
495 | } | ||
496 | |||
497 | /* Increment frames-attempted counter */ | ||
498 | window->counter++; | ||
499 | |||
500 | /* Shift bitmap by one frame to throw away oldest history */ | ||
501 | window->data <<= 1; | ||
502 | |||
503 | /* Mark the most recent #successes attempts as successful */ | ||
504 | if (successes > 0) { | ||
505 | window->success_counter++; | ||
506 | window->data |= 0x1; | ||
507 | successes--; | ||
508 | } | ||
509 | |||
510 | attempts--; | ||
511 | } | ||
512 | |||
513 | /* Calculate current success ratio, avoid divide-by-0! */ | ||
514 | if (window->counter > 0) | ||
515 | window->success_ratio = 128 * (100 * window->success_counter) | ||
516 | / window->counter; | ||
517 | else | ||
518 | window->success_ratio = IWL_INVALID_VALUE; | ||
519 | |||
520 | fail_count = window->counter - window->success_counter; | ||
521 | |||
522 | /* Calculate average throughput, if we have enough history. */ | ||
523 | if ((fail_count >= IWL_RATE_MIN_FAILURE_TH) || | ||
524 | (window->success_counter >= IWL_RATE_MIN_SUCCESS_TH)) | ||
525 | window->average_tpt = (window->success_ratio * tpt + 64) / 128; | ||
526 | else | ||
527 | window->average_tpt = IWL_INVALID_VALUE; | ||
528 | |||
529 | /* Tag this window as having been updated */ | ||
530 | window->stamp = jiffies; | ||
531 | |||
532 | return 0; | ||
533 | } | ||
534 | |||
535 | /* | ||
536 | * Fill uCode API rate_n_flags field, based on "search" or "active" table. | ||
537 | */ | ||
538 | /* FIXME:RS:remove this function and put the flags statically in the table */ | ||
539 | static u32 rate_n_flags_from_tbl(struct iwl_mvm *mvm, | ||
540 | struct iwl_scale_tbl_info *tbl, | ||
541 | int index, u8 use_green) | ||
542 | { | ||
543 | u32 rate_n_flags = 0; | ||
544 | |||
545 | if (is_legacy(tbl->lq_type)) { | ||
546 | rate_n_flags = iwl_rates[index].plcp; | ||
547 | if (index >= IWL_FIRST_CCK_RATE && index <= IWL_LAST_CCK_RATE) | ||
548 | rate_n_flags |= RATE_MCS_CCK_MSK; | ||
549 | } else if (is_Ht(tbl->lq_type)) { | ||
550 | if (index > IWL_LAST_OFDM_RATE) { | ||
551 | IWL_ERR(mvm, "Invalid HT rate index %d\n", index); | ||
552 | index = IWL_LAST_OFDM_RATE; | ||
553 | } | ||
554 | rate_n_flags = RATE_MCS_HT_MSK; | ||
555 | |||
556 | if (is_siso(tbl->lq_type)) | ||
557 | rate_n_flags |= iwl_rates[index].plcp_siso; | ||
558 | else if (is_mimo2(tbl->lq_type)) | ||
559 | rate_n_flags |= iwl_rates[index].plcp_mimo2; | ||
560 | else | ||
561 | rate_n_flags |= iwl_rates[index].plcp_mimo3; | ||
562 | } else { | ||
563 | IWL_ERR(mvm, "Invalid tbl->lq_type %d\n", tbl->lq_type); | ||
564 | } | ||
565 | |||
566 | rate_n_flags |= ((tbl->ant_type << RATE_MCS_ANT_POS) & | ||
567 | RATE_MCS_ANT_ABC_MSK); | ||
568 | |||
569 | if (is_Ht(tbl->lq_type)) { | ||
570 | if (tbl->is_ht40) | ||
571 | rate_n_flags |= RATE_MCS_CHAN_WIDTH_40; | ||
572 | if (tbl->is_SGI) | ||
573 | rate_n_flags |= RATE_MCS_SGI_MSK; | ||
574 | |||
575 | if (use_green) { | ||
576 | rate_n_flags |= RATE_HT_MCS_GF_MSK; | ||
577 | if (is_siso(tbl->lq_type) && tbl->is_SGI) { | ||
578 | rate_n_flags &= ~RATE_MCS_SGI_MSK; | ||
579 | IWL_ERR(mvm, "GF was set with SGI:SISO\n"); | ||
580 | } | ||
581 | } | ||
582 | } | ||
583 | return rate_n_flags; | ||
584 | } | ||
585 | |||
586 | /* | ||
587 | * Interpret uCode API's rate_n_flags format, | ||
588 | * fill "search" or "active" tx mode table. | ||
589 | */ | ||
590 | static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags, | ||
591 | enum ieee80211_band band, | ||
592 | struct iwl_scale_tbl_info *tbl, | ||
593 | int *rate_idx) | ||
594 | { | ||
595 | u32 ant_msk = (rate_n_flags & RATE_MCS_ANT_ABC_MSK); | ||
596 | u8 num_of_ant = get_num_of_ant_from_rate(rate_n_flags); | ||
597 | u8 mcs; | ||
598 | |||
599 | memset(tbl, 0, sizeof(struct iwl_scale_tbl_info)); | ||
600 | *rate_idx = iwl_hwrate_to_plcp_idx(rate_n_flags); | ||
601 | |||
602 | if (*rate_idx == IWL_RATE_INVALID) { | ||
603 | *rate_idx = -1; | ||
604 | return -EINVAL; | ||
605 | } | ||
606 | tbl->is_SGI = 0; /* default legacy setup */ | ||
607 | tbl->is_ht40 = 0; | ||
608 | tbl->ant_type = (ant_msk >> RATE_MCS_ANT_POS); | ||
609 | tbl->lq_type = LQ_NONE; | ||
610 | tbl->max_search = IWL_MAX_SEARCH; | ||
611 | |||
612 | /* legacy rate format */ | ||
613 | if (!(rate_n_flags & RATE_MCS_HT_MSK)) { | ||
614 | if (num_of_ant == 1) { | ||
615 | if (band == IEEE80211_BAND_5GHZ) | ||
616 | tbl->lq_type = LQ_A; | ||
617 | else | ||
618 | tbl->lq_type = LQ_G; | ||
619 | } | ||
620 | /* HT rate format */ | ||
621 | } else { | ||
622 | if (rate_n_flags & RATE_MCS_SGI_MSK) | ||
623 | tbl->is_SGI = 1; | ||
624 | |||
625 | if (rate_n_flags & RATE_MCS_CHAN_WIDTH_40) /* TODO */ | ||
626 | tbl->is_ht40 = 1; | ||
627 | |||
628 | mcs = rs_extract_rate(rate_n_flags); | ||
629 | |||
630 | /* SISO */ | ||
631 | if (mcs <= IWL_RATE_SISO_60M_PLCP) { | ||
632 | if (num_of_ant == 1) | ||
633 | tbl->lq_type = LQ_SISO; /*else NONE*/ | ||
634 | /* MIMO2 */ | ||
635 | } else if (mcs <= IWL_RATE_MIMO2_60M_PLCP) { | ||
636 | if (num_of_ant == 2) | ||
637 | tbl->lq_type = LQ_MIMO2; | ||
638 | /* MIMO3 */ | ||
639 | } else { | ||
640 | if (num_of_ant == 3) { | ||
641 | tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH; | ||
642 | tbl->lq_type = LQ_MIMO3; | ||
643 | } | ||
644 | } | ||
645 | } | ||
646 | return 0; | ||
647 | } | ||
648 | |||
649 | /* switch to another antenna/antennas and return 1 */ | ||
650 | /* if no other valid antenna found, return 0 */ | ||
651 | static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags, | ||
652 | struct iwl_scale_tbl_info *tbl) | ||
653 | { | ||
654 | u8 new_ant_type; | ||
655 | |||
656 | if (!tbl->ant_type || tbl->ant_type > ANT_ABC) | ||
657 | return 0; | ||
658 | |||
659 | if (!rs_is_valid_ant(valid_ant, tbl->ant_type)) | ||
660 | return 0; | ||
661 | |||
662 | new_ant_type = ant_toggle_lookup[tbl->ant_type]; | ||
663 | |||
664 | while ((new_ant_type != tbl->ant_type) && | ||
665 | !rs_is_valid_ant(valid_ant, new_ant_type)) | ||
666 | new_ant_type = ant_toggle_lookup[new_ant_type]; | ||
667 | |||
668 | if (new_ant_type == tbl->ant_type) | ||
669 | return 0; | ||
670 | |||
671 | tbl->ant_type = new_ant_type; | ||
672 | *rate_n_flags &= ~RATE_MCS_ANT_ABC_MSK; | ||
673 | *rate_n_flags |= new_ant_type << RATE_MCS_ANT_POS; | ||
674 | return 1; | ||
675 | } | ||
676 | |||
677 | /** | ||
678 | * Green-field mode is valid if the station supports it and | ||
679 | * there are no non-GF stations present in the BSS. | ||
680 | */ | ||
681 | static bool rs_use_green(struct ieee80211_sta *sta) | ||
682 | { | ||
683 | struct iwl_mvm_sta *sta_priv = (void *)sta->drv_priv; | ||
684 | |||
685 | bool use_green = !(sta_priv->vif->bss_conf.ht_operation_mode & | ||
686 | IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); | ||
687 | |||
688 | return (sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD) && use_green; | ||
689 | } | ||
690 | |||
691 | /** | ||
692 | * rs_get_supported_rates - get the available rates | ||
693 | * | ||
694 | * if management frame or broadcast frame only return | ||
695 | * basic available rates. | ||
696 | * | ||
697 | */ | ||
698 | static u16 rs_get_supported_rates(struct iwl_lq_sta *lq_sta, | ||
699 | struct ieee80211_hdr *hdr, | ||
700 | enum iwl_table_type rate_type) | ||
701 | { | ||
702 | if (is_legacy(rate_type)) { | ||
703 | return lq_sta->active_legacy_rate; | ||
704 | } else { | ||
705 | if (is_siso(rate_type)) | ||
706 | return lq_sta->active_siso_rate; | ||
707 | else if (is_mimo2(rate_type)) | ||
708 | return lq_sta->active_mimo2_rate; | ||
709 | else | ||
710 | return lq_sta->active_mimo3_rate; | ||
711 | } | ||
712 | } | ||
713 | |||
714 | static u16 rs_get_adjacent_rate(struct iwl_mvm *mvm, u8 index, u16 rate_mask, | ||
715 | int rate_type) | ||
716 | { | ||
717 | u8 high = IWL_RATE_INVALID; | ||
718 | u8 low = IWL_RATE_INVALID; | ||
719 | |||
720 | /* 802.11A or ht walks to the next literal adjacent rate in | ||
721 | * the rate table */ | ||
722 | if (is_a_band(rate_type) || !is_legacy(rate_type)) { | ||
723 | int i; | ||
724 | u32 mask; | ||
725 | |||
726 | /* Find the previous rate that is in the rate mask */ | ||
727 | i = index - 1; | ||
728 | for (mask = (1 << i); i >= 0; i--, mask >>= 1) { | ||
729 | if (rate_mask & mask) { | ||
730 | low = i; | ||
731 | break; | ||
732 | } | ||
733 | } | ||
734 | |||
735 | /* Find the next rate that is in the rate mask */ | ||
736 | i = index + 1; | ||
737 | for (mask = (1 << i); i < IWL_RATE_COUNT; i++, mask <<= 1) { | ||
738 | if (rate_mask & mask) { | ||
739 | high = i; | ||
740 | break; | ||
741 | } | ||
742 | } | ||
743 | |||
744 | return (high << 8) | low; | ||
745 | } | ||
746 | |||
747 | low = index; | ||
748 | while (low != IWL_RATE_INVALID) { | ||
749 | low = iwl_rates[low].prev_rs; | ||
750 | if (low == IWL_RATE_INVALID) | ||
751 | break; | ||
752 | if (rate_mask & (1 << low)) | ||
753 | break; | ||
754 | IWL_DEBUG_RATE(mvm, "Skipping masked lower rate: %d\n", low); | ||
755 | } | ||
756 | |||
757 | high = index; | ||
758 | while (high != IWL_RATE_INVALID) { | ||
759 | high = iwl_rates[high].next_rs; | ||
760 | if (high == IWL_RATE_INVALID) | ||
761 | break; | ||
762 | if (rate_mask & (1 << high)) | ||
763 | break; | ||
764 | IWL_DEBUG_RATE(mvm, "Skipping masked higher rate: %d\n", high); | ||
765 | } | ||
766 | |||
767 | return (high << 8) | low; | ||
768 | } | ||
769 | |||
770 | static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta, | ||
771 | struct iwl_scale_tbl_info *tbl, | ||
772 | u8 scale_index, u8 ht_possible) | ||
773 | { | ||
774 | s32 low; | ||
775 | u16 rate_mask; | ||
776 | u16 high_low; | ||
777 | u8 switch_to_legacy = 0; | ||
778 | u8 is_green = lq_sta->is_green; | ||
779 | struct iwl_mvm *mvm = lq_sta->drv; | ||
780 | |||
781 | /* check if we need to switch from HT to legacy rates. | ||
782 | * assumption is that mandatory rates (1Mbps or 6Mbps) | ||
783 | * are always supported (spec demand) */ | ||
784 | if (!is_legacy(tbl->lq_type) && (!ht_possible || !scale_index)) { | ||
785 | switch_to_legacy = 1; | ||
786 | scale_index = rs_ht_to_legacy[scale_index]; | ||
787 | if (lq_sta->band == IEEE80211_BAND_5GHZ) | ||
788 | tbl->lq_type = LQ_A; | ||
789 | else | ||
790 | tbl->lq_type = LQ_G; | ||
791 | |||
792 | if (num_of_ant(tbl->ant_type) > 1) | ||
793 | tbl->ant_type = | ||
794 | first_antenna(mvm->nvm_data->valid_tx_ant); | ||
795 | |||
796 | tbl->is_ht40 = 0; | ||
797 | tbl->is_SGI = 0; | ||
798 | tbl->max_search = IWL_MAX_SEARCH; | ||
799 | } | ||
800 | |||
801 | rate_mask = rs_get_supported_rates(lq_sta, NULL, tbl->lq_type); | ||
802 | |||
803 | /* Mask with station rate restriction */ | ||
804 | if (is_legacy(tbl->lq_type)) { | ||
805 | /* supp_rates has no CCK bits in A mode */ | ||
806 | if (lq_sta->band == IEEE80211_BAND_5GHZ) | ||
807 | rate_mask = (u16)(rate_mask & | ||
808 | (lq_sta->supp_rates << IWL_FIRST_OFDM_RATE)); | ||
809 | else | ||
810 | rate_mask = (u16)(rate_mask & lq_sta->supp_rates); | ||
811 | } | ||
812 | |||
813 | /* If we switched from HT to legacy, check current rate */ | ||
814 | if (switch_to_legacy && (rate_mask & (1 << scale_index))) { | ||
815 | low = scale_index; | ||
816 | goto out; | ||
817 | } | ||
818 | |||
819 | high_low = rs_get_adjacent_rate(lq_sta->drv, scale_index, rate_mask, | ||
820 | tbl->lq_type); | ||
821 | low = high_low & 0xff; | ||
822 | |||
823 | if (low == IWL_RATE_INVALID) | ||
824 | low = scale_index; | ||
825 | |||
826 | out: | ||
827 | return rate_n_flags_from_tbl(lq_sta->drv, tbl, low, is_green); | ||
828 | } | ||
829 | |||
830 | /* | ||
831 | * Simple function to compare two rate scale table types | ||
832 | */ | ||
833 | static bool table_type_matches(struct iwl_scale_tbl_info *a, | ||
834 | struct iwl_scale_tbl_info *b) | ||
835 | { | ||
836 | return (a->lq_type == b->lq_type) && (a->ant_type == b->ant_type) && | ||
837 | (a->is_SGI == b->is_SGI); | ||
838 | } | ||
839 | |||
840 | /* | ||
841 | * mac80211 sends us Tx status | ||
842 | */ | ||
843 | static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband, | ||
844 | struct ieee80211_sta *sta, void *priv_sta, | ||
845 | struct sk_buff *skb) | ||
846 | { | ||
847 | int legacy_success; | ||
848 | int retries; | ||
849 | int rs_index, mac_index, i; | ||
850 | struct iwl_lq_sta *lq_sta = priv_sta; | ||
851 | struct iwl_lq_cmd *table; | ||
852 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||
853 | struct iwl_op_mode *op_mode = (struct iwl_op_mode *)mvm_r; | ||
854 | struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); | ||
855 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
856 | enum mac80211_rate_control_flags mac_flags; | ||
857 | u32 tx_rate; | ||
858 | struct iwl_scale_tbl_info tbl_type; | ||
859 | struct iwl_scale_tbl_info *curr_tbl, *other_tbl, *tmp_tbl; | ||
860 | |||
861 | IWL_DEBUG_RATE_LIMIT(mvm, | ||
862 | "get frame ack response, update rate scale window\n"); | ||
863 | |||
864 | /* Treat uninitialized rate scaling data same as non-existing. */ | ||
865 | if (!lq_sta) { | ||
866 | IWL_DEBUG_RATE(mvm, "Station rate scaling not created yet.\n"); | ||
867 | return; | ||
868 | } else if (!lq_sta->drv) { | ||
869 | IWL_DEBUG_RATE(mvm, "Rate scaling not initialized yet.\n"); | ||
870 | return; | ||
871 | } | ||
872 | |||
873 | if (!ieee80211_is_data(hdr->frame_control) || | ||
874 | info->flags & IEEE80211_TX_CTL_NO_ACK) | ||
875 | return; | ||
876 | |||
877 | /* This packet was aggregated but doesn't carry status info */ | ||
878 | if ((info->flags & IEEE80211_TX_CTL_AMPDU) && | ||
879 | !(info->flags & IEEE80211_TX_STAT_AMPDU)) | ||
880 | return; | ||
881 | |||
882 | /* | ||
883 | * Ignore this Tx frame response if its initial rate doesn't match | ||
884 | * that of latest Link Quality command. There may be stragglers | ||
885 | * from a previous Link Quality command, but we're no longer interested | ||
886 | * in those; they're either from the "active" mode while we're trying | ||
887 | * to check "search" mode, or a prior "search" mode after we've moved | ||
888 | * to a new "search" mode (which might become the new "active" mode). | ||
889 | */ | ||
890 | table = &lq_sta->lq; | ||
891 | tx_rate = le32_to_cpu(table->rs_table[0]); | ||
892 | rs_get_tbl_info_from_mcs(tx_rate, info->band, &tbl_type, &rs_index); | ||
893 | if (info->band == IEEE80211_BAND_5GHZ) | ||
894 | rs_index -= IWL_FIRST_OFDM_RATE; | ||
895 | mac_flags = info->status.rates[0].flags; | ||
896 | mac_index = info->status.rates[0].idx; | ||
897 | /* For HT packets, map MCS to PLCP */ | ||
898 | if (mac_flags & IEEE80211_TX_RC_MCS) { | ||
899 | /* Remove # of streams */ | ||
900 | mac_index &= RATE_HT_MCS_RATE_CODE_MSK; | ||
901 | if (mac_index >= (IWL_RATE_9M_INDEX - IWL_FIRST_OFDM_RATE)) | ||
902 | mac_index++; | ||
903 | /* | ||
904 | * mac80211 HT index is always zero-indexed; we need to move | ||
905 | * HT OFDM rates after CCK rates in 2.4 GHz band | ||
906 | */ | ||
907 | if (info->band == IEEE80211_BAND_2GHZ) | ||
908 | mac_index += IWL_FIRST_OFDM_RATE; | ||
909 | } | ||
910 | /* Here we actually compare this rate to the latest LQ command */ | ||
911 | if ((mac_index < 0) || | ||
912 | (tbl_type.is_SGI != !!(mac_flags & IEEE80211_TX_RC_SHORT_GI)) || | ||
913 | (tbl_type.is_ht40 != !!(mac_flags & IEEE80211_TX_RC_40_MHZ_WIDTH)) || | ||
914 | (tbl_type.ant_type != info->status.antenna) || | ||
915 | (!!(tx_rate & RATE_MCS_HT_MSK) != | ||
916 | !!(mac_flags & IEEE80211_TX_RC_MCS)) || | ||
917 | (!!(tx_rate & RATE_HT_MCS_GF_MSK) != | ||
918 | !!(mac_flags & IEEE80211_TX_RC_GREEN_FIELD)) || | ||
919 | (rs_index != mac_index)) { | ||
920 | IWL_DEBUG_RATE(mvm, | ||
921 | "initial rate %d does not match %d (0x%x)\n", | ||
922 | mac_index, rs_index, tx_rate); | ||
923 | /* | ||
924 | * Since rates mis-match, the last LQ command may have failed. | ||
925 | * After IWL_MISSED_RATE_MAX mis-matches, resync the uCode with | ||
926 | * ... driver. | ||
927 | */ | ||
928 | lq_sta->missed_rate_counter++; | ||
929 | if (lq_sta->missed_rate_counter > IWL_MISSED_RATE_MAX) { | ||
930 | lq_sta->missed_rate_counter = 0; | ||
931 | iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, CMD_ASYNC, false); | ||
932 | } | ||
933 | /* Regardless, ignore this status info for outdated rate */ | ||
934 | return; | ||
935 | } else | ||
936 | /* Rate did match, so reset the missed_rate_counter */ | ||
937 | lq_sta->missed_rate_counter = 0; | ||
938 | |||
939 | /* Figure out if rate scale algorithm is in active or search table */ | ||
940 | if (table_type_matches(&tbl_type, | ||
941 | &(lq_sta->lq_info[lq_sta->active_tbl]))) { | ||
942 | curr_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); | ||
943 | other_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]); | ||
944 | } else if (table_type_matches( | ||
945 | &tbl_type, &lq_sta->lq_info[1 - lq_sta->active_tbl])) { | ||
946 | curr_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]); | ||
947 | other_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); | ||
948 | } else { | ||
949 | IWL_DEBUG_RATE(mvm, | ||
950 | "Neither active nor search matches tx rate\n"); | ||
951 | tmp_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); | ||
952 | IWL_DEBUG_RATE(mvm, "active- lq:%x, ant:%x, SGI:%d\n", | ||
953 | tmp_tbl->lq_type, tmp_tbl->ant_type, | ||
954 | tmp_tbl->is_SGI); | ||
955 | tmp_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]); | ||
956 | IWL_DEBUG_RATE(mvm, "search- lq:%x, ant:%x, SGI:%d\n", | ||
957 | tmp_tbl->lq_type, tmp_tbl->ant_type, | ||
958 | tmp_tbl->is_SGI); | ||
959 | IWL_DEBUG_RATE(mvm, "actual- lq:%x, ant:%x, SGI:%d\n", | ||
960 | tbl_type.lq_type, tbl_type.ant_type, | ||
961 | tbl_type.is_SGI); | ||
962 | /* | ||
963 | * no matching table found, let's by-pass the data collection | ||
964 | * and continue to perform rate scale to find the rate table | ||
965 | */ | ||
966 | rs_stay_in_table(lq_sta, true); | ||
967 | goto done; | ||
968 | } | ||
969 | |||
970 | /* | ||
971 | * Updating the frame history depends on whether packets were | ||
972 | * aggregated. | ||
973 | * | ||
974 | * For aggregation, all packets were transmitted at the same rate, the | ||
975 | * first index into rate scale table. | ||
976 | */ | ||
977 | if (info->flags & IEEE80211_TX_STAT_AMPDU) { | ||
978 | tx_rate = le32_to_cpu(table->rs_table[0]); | ||
979 | rs_get_tbl_info_from_mcs(tx_rate, info->band, &tbl_type, | ||
980 | &rs_index); | ||
981 | rs_collect_tx_data(curr_tbl, rs_index, | ||
982 | info->status.ampdu_len, | ||
983 | info->status.ampdu_ack_len); | ||
984 | |||
985 | /* Update success/fail counts if not searching for new mode */ | ||
986 | if (lq_sta->stay_in_tbl) { | ||
987 | lq_sta->total_success += info->status.ampdu_ack_len; | ||
988 | lq_sta->total_failed += (info->status.ampdu_len - | ||
989 | info->status.ampdu_ack_len); | ||
990 | } | ||
991 | } else { | ||
992 | /* | ||
993 | * For legacy, update frame history with for each Tx retry. | ||
994 | */ | ||
995 | retries = info->status.rates[0].count - 1; | ||
996 | /* HW doesn't send more than 15 retries */ | ||
997 | retries = min(retries, 15); | ||
998 | |||
999 | /* The last transmission may have been successful */ | ||
1000 | legacy_success = !!(info->flags & IEEE80211_TX_STAT_ACK); | ||
1001 | /* Collect data for each rate used during failed TX attempts */ | ||
1002 | for (i = 0; i <= retries; ++i) { | ||
1003 | tx_rate = le32_to_cpu(table->rs_table[i]); | ||
1004 | rs_get_tbl_info_from_mcs(tx_rate, info->band, | ||
1005 | &tbl_type, &rs_index); | ||
1006 | /* | ||
1007 | * Only collect stats if retried rate is in the same RS | ||
1008 | * table as active/search. | ||
1009 | */ | ||
1010 | if (table_type_matches(&tbl_type, curr_tbl)) | ||
1011 | tmp_tbl = curr_tbl; | ||
1012 | else if (table_type_matches(&tbl_type, other_tbl)) | ||
1013 | tmp_tbl = other_tbl; | ||
1014 | else | ||
1015 | continue; | ||
1016 | rs_collect_tx_data(tmp_tbl, rs_index, 1, | ||
1017 | i < retries ? 0 : legacy_success); | ||
1018 | } | ||
1019 | |||
1020 | /* Update success/fail counts if not searching for new mode */ | ||
1021 | if (lq_sta->stay_in_tbl) { | ||
1022 | lq_sta->total_success += legacy_success; | ||
1023 | lq_sta->total_failed += retries + (1 - legacy_success); | ||
1024 | } | ||
1025 | } | ||
1026 | /* The last TX rate is cached in lq_sta; it's set in if/else above */ | ||
1027 | lq_sta->last_rate_n_flags = tx_rate; | ||
1028 | done: | ||
1029 | /* See if there's a better rate or modulation mode to try. */ | ||
1030 | if (sta && sta->supp_rates[sband->band]) | ||
1031 | rs_rate_scale_perform(mvm, skb, sta, lq_sta); | ||
1032 | } | ||
1033 | |||
1034 | /* | ||
1035 | * Begin a period of staying with a selected modulation mode. | ||
1036 | * Set "stay_in_tbl" flag to prevent any mode switches. | ||
1037 | * Set frame tx success limits according to legacy vs. high-throughput, | ||
1038 | * and reset overall (spanning all rates) tx success history statistics. | ||
1039 | * These control how long we stay using same modulation mode before | ||
1040 | * searching for a new mode. | ||
1041 | */ | ||
1042 | static void rs_set_stay_in_table(struct iwl_mvm *mvm, u8 is_legacy, | ||
1043 | struct iwl_lq_sta *lq_sta) | ||
1044 | { | ||
1045 | IWL_DEBUG_RATE(mvm, "we are staying in the same table\n"); | ||
1046 | lq_sta->stay_in_tbl = 1; /* only place this gets set */ | ||
1047 | if (is_legacy) { | ||
1048 | lq_sta->table_count_limit = IWL_LEGACY_TABLE_COUNT; | ||
1049 | lq_sta->max_failure_limit = IWL_LEGACY_FAILURE_LIMIT; | ||
1050 | lq_sta->max_success_limit = IWL_LEGACY_SUCCESS_LIMIT; | ||
1051 | } else { | ||
1052 | lq_sta->table_count_limit = IWL_NONE_LEGACY_TABLE_COUNT; | ||
1053 | lq_sta->max_failure_limit = IWL_NONE_LEGACY_FAILURE_LIMIT; | ||
1054 | lq_sta->max_success_limit = IWL_NONE_LEGACY_SUCCESS_LIMIT; | ||
1055 | } | ||
1056 | lq_sta->table_count = 0; | ||
1057 | lq_sta->total_failed = 0; | ||
1058 | lq_sta->total_success = 0; | ||
1059 | lq_sta->flush_timer = jiffies; | ||
1060 | lq_sta->action_counter = 0; | ||
1061 | } | ||
1062 | |||
1063 | /* | ||
1064 | * Find correct throughput table for given mode of modulation | ||
1065 | */ | ||
1066 | static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta, | ||
1067 | struct iwl_scale_tbl_info *tbl) | ||
1068 | { | ||
1069 | /* Used to choose among HT tables */ | ||
1070 | s32 (*ht_tbl_pointer)[IWL_RATE_COUNT]; | ||
1071 | |||
1072 | /* Check for invalid LQ type */ | ||
1073 | if (WARN_ON_ONCE(!is_legacy(tbl->lq_type) && !is_Ht(tbl->lq_type))) { | ||
1074 | tbl->expected_tpt = expected_tpt_legacy; | ||
1075 | return; | ||
1076 | } | ||
1077 | |||
1078 | /* Legacy rates have only one table */ | ||
1079 | if (is_legacy(tbl->lq_type)) { | ||
1080 | tbl->expected_tpt = expected_tpt_legacy; | ||
1081 | return; | ||
1082 | } | ||
1083 | |||
1084 | /* Choose among many HT tables depending on number of streams | ||
1085 | * (SISO/MIMO2/MIMO3), channel width (20/40), SGI, and aggregation | ||
1086 | * status */ | ||
1087 | if (is_siso(tbl->lq_type) && !tbl->is_ht40) | ||
1088 | ht_tbl_pointer = expected_tpt_siso20MHz; | ||
1089 | else if (is_siso(tbl->lq_type)) | ||
1090 | ht_tbl_pointer = expected_tpt_siso40MHz; | ||
1091 | else if (is_mimo2(tbl->lq_type) && !tbl->is_ht40) | ||
1092 | ht_tbl_pointer = expected_tpt_mimo2_20MHz; | ||
1093 | else if (is_mimo2(tbl->lq_type)) | ||
1094 | ht_tbl_pointer = expected_tpt_mimo2_40MHz; | ||
1095 | else if (is_mimo3(tbl->lq_type) && !tbl->is_ht40) | ||
1096 | ht_tbl_pointer = expected_tpt_mimo3_20MHz; | ||
1097 | else /* if (is_mimo3(tbl->lq_type)) <-- must be true */ | ||
1098 | ht_tbl_pointer = expected_tpt_mimo3_40MHz; | ||
1099 | |||
1100 | if (!tbl->is_SGI && !lq_sta->is_agg) /* Normal */ | ||
1101 | tbl->expected_tpt = ht_tbl_pointer[0]; | ||
1102 | else if (tbl->is_SGI && !lq_sta->is_agg) /* SGI */ | ||
1103 | tbl->expected_tpt = ht_tbl_pointer[1]; | ||
1104 | else if (!tbl->is_SGI && lq_sta->is_agg) /* AGG */ | ||
1105 | tbl->expected_tpt = ht_tbl_pointer[2]; | ||
1106 | else /* AGG+SGI */ | ||
1107 | tbl->expected_tpt = ht_tbl_pointer[3]; | ||
1108 | } | ||
1109 | |||
1110 | /* | ||
1111 | * Find starting rate for new "search" high-throughput mode of modulation. | ||
1112 | * Goal is to find lowest expected rate (under perfect conditions) that is | ||
1113 | * above the current measured throughput of "active" mode, to give new mode | ||
1114 | * a fair chance to prove itself without too many challenges. | ||
1115 | * | ||
1116 | * This gets called when transitioning to more aggressive modulation | ||
1117 | * (i.e. legacy to SISO or MIMO, or SISO to MIMO), as well as less aggressive | ||
1118 | * (i.e. MIMO to SISO). When moving to MIMO, bit rate will typically need | ||
1119 | * to decrease to match "active" throughput. When moving from MIMO to SISO, | ||
1120 | * bit rate will typically need to increase, but not if performance was bad. | ||
1121 | */ | ||
1122 | static s32 rs_get_best_rate(struct iwl_mvm *mvm, | ||
1123 | struct iwl_lq_sta *lq_sta, | ||
1124 | struct iwl_scale_tbl_info *tbl, /* "search" */ | ||
1125 | u16 rate_mask, s8 index) | ||
1126 | { | ||
1127 | /* "active" values */ | ||
1128 | struct iwl_scale_tbl_info *active_tbl = | ||
1129 | &(lq_sta->lq_info[lq_sta->active_tbl]); | ||
1130 | s32 active_sr = active_tbl->win[index].success_ratio; | ||
1131 | s32 active_tpt = active_tbl->expected_tpt[index]; | ||
1132 | |||
1133 | /* expected "search" throughput */ | ||
1134 | s32 *tpt_tbl = tbl->expected_tpt; | ||
1135 | |||
1136 | s32 new_rate, high, low, start_hi; | ||
1137 | u16 high_low; | ||
1138 | s8 rate = index; | ||
1139 | |||
1140 | new_rate = high = low = start_hi = IWL_RATE_INVALID; | ||
1141 | |||
1142 | while (1) { | ||
1143 | high_low = rs_get_adjacent_rate(mvm, rate, rate_mask, | ||
1144 | tbl->lq_type); | ||
1145 | |||
1146 | low = high_low & 0xff; | ||
1147 | high = (high_low >> 8) & 0xff; | ||
1148 | |||
1149 | /* | ||
1150 | * Lower the "search" bit rate, to give new "search" mode | ||
1151 | * approximately the same throughput as "active" if: | ||
1152 | * | ||
1153 | * 1) "Active" mode has been working modestly well (but not | ||
1154 | * great), and expected "search" throughput (under perfect | ||
1155 | * conditions) at candidate rate is above the actual | ||
1156 | * measured "active" throughput (but less than expected | ||
1157 | * "active" throughput under perfect conditions). | ||
1158 | * OR | ||
1159 | * 2) "Active" mode has been working perfectly or very well | ||
1160 | * and expected "search" throughput (under perfect | ||
1161 | * conditions) at candidate rate is above expected | ||
1162 | * "active" throughput (under perfect conditions). | ||
1163 | */ | ||
1164 | if ((((100 * tpt_tbl[rate]) > lq_sta->last_tpt) && | ||
1165 | ((active_sr > IWL_RATE_DECREASE_TH) && | ||
1166 | (active_sr <= IWL_RATE_HIGH_TH) && | ||
1167 | (tpt_tbl[rate] <= active_tpt))) || | ||
1168 | ((active_sr >= IWL_RATE_SCALE_SWITCH) && | ||
1169 | (tpt_tbl[rate] > active_tpt))) { | ||
1170 | /* (2nd or later pass) | ||
1171 | * If we've already tried to raise the rate, and are | ||
1172 | * now trying to lower it, use the higher rate. */ | ||
1173 | if (start_hi != IWL_RATE_INVALID) { | ||
1174 | new_rate = start_hi; | ||
1175 | break; | ||
1176 | } | ||
1177 | |||
1178 | new_rate = rate; | ||
1179 | |||
1180 | /* Loop again with lower rate */ | ||
1181 | if (low != IWL_RATE_INVALID) | ||
1182 | rate = low; | ||
1183 | |||
1184 | /* Lower rate not available, use the original */ | ||
1185 | else | ||
1186 | break; | ||
1187 | |||
1188 | /* Else try to raise the "search" rate to match "active" */ | ||
1189 | } else { | ||
1190 | /* (2nd or later pass) | ||
1191 | * If we've already tried to lower the rate, and are | ||
1192 | * now trying to raise it, use the lower rate. */ | ||
1193 | if (new_rate != IWL_RATE_INVALID) | ||
1194 | break; | ||
1195 | |||
1196 | /* Loop again with higher rate */ | ||
1197 | else if (high != IWL_RATE_INVALID) { | ||
1198 | start_hi = high; | ||
1199 | rate = high; | ||
1200 | |||
1201 | /* Higher rate not available, use the original */ | ||
1202 | } else { | ||
1203 | new_rate = rate; | ||
1204 | break; | ||
1205 | } | ||
1206 | } | ||
1207 | } | ||
1208 | |||
1209 | return new_rate; | ||
1210 | } | ||
1211 | |||
1212 | static bool iwl_is_ht40_tx_allowed(struct iwl_mvm *mvm, | ||
1213 | struct ieee80211_sta_ht_cap *ht_cap) | ||
1214 | { | ||
1215 | /* | ||
1216 | * Remainder of this function checks ht_cap, but if it's | ||
1217 | * NULL then we can do HT40 (special case for RXON) | ||
1218 | */ | ||
1219 | if (!ht_cap) | ||
1220 | return true; | ||
1221 | |||
1222 | if (!ht_cap->ht_supported) | ||
1223 | return false; | ||
1224 | |||
1225 | if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) | ||
1226 | return false; | ||
1227 | |||
1228 | return true; | ||
1229 | } | ||
1230 | |||
1231 | /* | ||
1232 | * Set up search table for MIMO2 | ||
1233 | */ | ||
1234 | static int rs_switch_to_mimo2(struct iwl_mvm *mvm, | ||
1235 | struct iwl_lq_sta *lq_sta, | ||
1236 | struct ieee80211_sta *sta, | ||
1237 | struct iwl_scale_tbl_info *tbl, int index) | ||
1238 | { | ||
1239 | u16 rate_mask; | ||
1240 | s32 rate; | ||
1241 | s8 is_green = lq_sta->is_green; | ||
1242 | |||
1243 | if (!sta->ht_cap.ht_supported) | ||
1244 | return -1; | ||
1245 | |||
1246 | if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2) | ||
1247 | == WLAN_HT_CAP_SM_PS_STATIC) | ||
1248 | return -1; | ||
1249 | |||
1250 | /* Need both Tx chains/antennas to support MIMO */ | ||
1251 | if (num_of_ant(mvm->nvm_data->valid_tx_ant) < 2) | ||
1252 | return -1; | ||
1253 | |||
1254 | IWL_DEBUG_RATE(mvm, "LQ: try to switch to MIMO2\n"); | ||
1255 | |||
1256 | tbl->lq_type = LQ_MIMO2; | ||
1257 | tbl->action = 0; | ||
1258 | tbl->max_search = IWL_MAX_SEARCH; | ||
1259 | rate_mask = lq_sta->active_mimo2_rate; | ||
1260 | |||
1261 | if (iwl_is_ht40_tx_allowed(mvm, &sta->ht_cap)) | ||
1262 | tbl->is_ht40 = 1; | ||
1263 | else | ||
1264 | tbl->is_ht40 = 0; | ||
1265 | |||
1266 | rs_set_expected_tpt_table(lq_sta, tbl); | ||
1267 | |||
1268 | rate = rs_get_best_rate(mvm, lq_sta, tbl, rate_mask, index); | ||
1269 | |||
1270 | IWL_DEBUG_RATE(mvm, "LQ: MIMO2 best rate %d mask %X\n", | ||
1271 | rate, rate_mask); | ||
1272 | if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) { | ||
1273 | IWL_DEBUG_RATE(mvm, "Can't switch with index %d rate mask %x\n", | ||
1274 | rate, rate_mask); | ||
1275 | return -1; | ||
1276 | } | ||
1277 | tbl->current_rate = rate_n_flags_from_tbl(mvm, tbl, rate, is_green); | ||
1278 | |||
1279 | IWL_DEBUG_RATE(mvm, "LQ: Switch to new mcs %X index is green %X\n", | ||
1280 | tbl->current_rate, is_green); | ||
1281 | return 0; | ||
1282 | } | ||
1283 | |||
1284 | /* | ||
1285 | * Set up search table for MIMO3 | ||
1286 | */ | ||
1287 | static int rs_switch_to_mimo3(struct iwl_mvm *mvm, | ||
1288 | struct iwl_lq_sta *lq_sta, | ||
1289 | struct ieee80211_sta *sta, | ||
1290 | struct iwl_scale_tbl_info *tbl, int index) | ||
1291 | { | ||
1292 | u16 rate_mask; | ||
1293 | s32 rate; | ||
1294 | s8 is_green = lq_sta->is_green; | ||
1295 | |||
1296 | if (!sta->ht_cap.ht_supported) | ||
1297 | return -1; | ||
1298 | |||
1299 | if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2) | ||
1300 | == WLAN_HT_CAP_SM_PS_STATIC) | ||
1301 | return -1; | ||
1302 | |||
1303 | /* Need both Tx chains/antennas to support MIMO */ | ||
1304 | if (num_of_ant(mvm->nvm_data->valid_tx_ant) < 3) | ||
1305 | return -1; | ||
1306 | |||
1307 | IWL_DEBUG_RATE(mvm, "LQ: try to switch to MIMO3\n"); | ||
1308 | |||
1309 | tbl->lq_type = LQ_MIMO3; | ||
1310 | tbl->action = 0; | ||
1311 | tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH; | ||
1312 | rate_mask = lq_sta->active_mimo3_rate; | ||
1313 | |||
1314 | if (iwl_is_ht40_tx_allowed(mvm, &sta->ht_cap)) | ||
1315 | tbl->is_ht40 = 1; | ||
1316 | else | ||
1317 | tbl->is_ht40 = 0; | ||
1318 | |||
1319 | rs_set_expected_tpt_table(lq_sta, tbl); | ||
1320 | |||
1321 | rate = rs_get_best_rate(mvm, lq_sta, tbl, rate_mask, index); | ||
1322 | |||
1323 | IWL_DEBUG_RATE(mvm, "LQ: MIMO3 best rate %d mask %X\n", | ||
1324 | rate, rate_mask); | ||
1325 | if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) { | ||
1326 | IWL_DEBUG_RATE(mvm, "Can't switch with index %d rate mask %x\n", | ||
1327 | rate, rate_mask); | ||
1328 | return -1; | ||
1329 | } | ||
1330 | tbl->current_rate = rate_n_flags_from_tbl(mvm, tbl, rate, is_green); | ||
1331 | |||
1332 | IWL_DEBUG_RATE(mvm, "LQ: Switch to new mcs %X index is green %X\n", | ||
1333 | tbl->current_rate, is_green); | ||
1334 | return 0; | ||
1335 | } | ||
1336 | |||
1337 | /* | ||
1338 | * Set up search table for SISO | ||
1339 | */ | ||
1340 | static int rs_switch_to_siso(struct iwl_mvm *mvm, | ||
1341 | struct iwl_lq_sta *lq_sta, | ||
1342 | struct ieee80211_sta *sta, | ||
1343 | struct iwl_scale_tbl_info *tbl, int index) | ||
1344 | { | ||
1345 | u16 rate_mask; | ||
1346 | u8 is_green = lq_sta->is_green; | ||
1347 | s32 rate; | ||
1348 | |||
1349 | if (!sta->ht_cap.ht_supported) | ||
1350 | return -1; | ||
1351 | |||
1352 | IWL_DEBUG_RATE(mvm, "LQ: try to switch to SISO\n"); | ||
1353 | |||
1354 | tbl->lq_type = LQ_SISO; | ||
1355 | tbl->action = 0; | ||
1356 | tbl->max_search = IWL_MAX_SEARCH; | ||
1357 | rate_mask = lq_sta->active_siso_rate; | ||
1358 | |||
1359 | if (iwl_is_ht40_tx_allowed(mvm, &sta->ht_cap)) | ||
1360 | tbl->is_ht40 = 1; | ||
1361 | else | ||
1362 | tbl->is_ht40 = 0; | ||
1363 | |||
1364 | if (is_green) | ||
1365 | tbl->is_SGI = 0; /*11n spec: no SGI in SISO+Greenfield*/ | ||
1366 | |||
1367 | rs_set_expected_tpt_table(lq_sta, tbl); | ||
1368 | rate = rs_get_best_rate(mvm, lq_sta, tbl, rate_mask, index); | ||
1369 | |||
1370 | IWL_DEBUG_RATE(mvm, "LQ: get best rate %d mask %X\n", rate, rate_mask); | ||
1371 | if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) { | ||
1372 | IWL_DEBUG_RATE(mvm, | ||
1373 | "can not switch with index %d rate mask %x\n", | ||
1374 | rate, rate_mask); | ||
1375 | return -1; | ||
1376 | } | ||
1377 | tbl->current_rate = rate_n_flags_from_tbl(mvm, tbl, rate, is_green); | ||
1378 | IWL_DEBUG_RATE(mvm, "LQ: Switch to new mcs %X index is green %X\n", | ||
1379 | tbl->current_rate, is_green); | ||
1380 | return 0; | ||
1381 | } | ||
1382 | |||
1383 | /* | ||
1384 | * Try to switch to new modulation mode from legacy | ||
1385 | */ | ||
1386 | static int rs_move_legacy_other(struct iwl_mvm *mvm, | ||
1387 | struct iwl_lq_sta *lq_sta, | ||
1388 | struct ieee80211_sta *sta, | ||
1389 | int index) | ||
1390 | { | ||
1391 | struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); | ||
1392 | struct iwl_scale_tbl_info *search_tbl = | ||
1393 | &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); | ||
1394 | struct iwl_rate_scale_data *window = &(tbl->win[index]); | ||
1395 | u32 sz = (sizeof(struct iwl_scale_tbl_info) - | ||
1396 | (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); | ||
1397 | u8 start_action; | ||
1398 | u8 valid_tx_ant = mvm->nvm_data->valid_tx_ant; | ||
1399 | u8 tx_chains_num = num_of_ant(valid_tx_ant); | ||
1400 | int ret; | ||
1401 | u8 update_search_tbl_counter = 0; | ||
1402 | |||
1403 | start_action = tbl->action; | ||
1404 | while (1) { | ||
1405 | lq_sta->action_counter++; | ||
1406 | switch (tbl->action) { | ||
1407 | case IWL_LEGACY_SWITCH_ANTENNA1: | ||
1408 | case IWL_LEGACY_SWITCH_ANTENNA2: | ||
1409 | IWL_DEBUG_RATE(mvm, "LQ: Legacy toggle Antenna\n"); | ||
1410 | |||
1411 | if ((tbl->action == IWL_LEGACY_SWITCH_ANTENNA1 && | ||
1412 | tx_chains_num <= 1) || | ||
1413 | (tbl->action == IWL_LEGACY_SWITCH_ANTENNA2 && | ||
1414 | tx_chains_num <= 2)) | ||
1415 | break; | ||
1416 | |||
1417 | /* Don't change antenna if success has been great */ | ||
1418 | if (window->success_ratio >= IWL_RS_GOOD_RATIO) | ||
1419 | break; | ||
1420 | |||
1421 | /* Set up search table to try other antenna */ | ||
1422 | memcpy(search_tbl, tbl, sz); | ||
1423 | |||
1424 | if (rs_toggle_antenna(valid_tx_ant, | ||
1425 | &search_tbl->current_rate, | ||
1426 | search_tbl)) { | ||
1427 | update_search_tbl_counter = 1; | ||
1428 | rs_set_expected_tpt_table(lq_sta, search_tbl); | ||
1429 | goto out; | ||
1430 | } | ||
1431 | break; | ||
1432 | case IWL_LEGACY_SWITCH_SISO: | ||
1433 | IWL_DEBUG_RATE(mvm, "LQ: Legacy switch to SISO\n"); | ||
1434 | |||
1435 | /* Set up search table to try SISO */ | ||
1436 | memcpy(search_tbl, tbl, sz); | ||
1437 | search_tbl->is_SGI = 0; | ||
1438 | ret = rs_switch_to_siso(mvm, lq_sta, sta, | ||
1439 | search_tbl, index); | ||
1440 | if (!ret) { | ||
1441 | lq_sta->action_counter = 0; | ||
1442 | goto out; | ||
1443 | } | ||
1444 | |||
1445 | break; | ||
1446 | case IWL_LEGACY_SWITCH_MIMO2_AB: | ||
1447 | case IWL_LEGACY_SWITCH_MIMO2_AC: | ||
1448 | case IWL_LEGACY_SWITCH_MIMO2_BC: | ||
1449 | IWL_DEBUG_RATE(mvm, "LQ: Legacy switch to MIMO2\n"); | ||
1450 | |||
1451 | /* Set up search table to try MIMO */ | ||
1452 | memcpy(search_tbl, tbl, sz); | ||
1453 | search_tbl->is_SGI = 0; | ||
1454 | |||
1455 | if (tbl->action == IWL_LEGACY_SWITCH_MIMO2_AB) | ||
1456 | search_tbl->ant_type = ANT_AB; | ||
1457 | else if (tbl->action == IWL_LEGACY_SWITCH_MIMO2_AC) | ||
1458 | search_tbl->ant_type = ANT_AC; | ||
1459 | else | ||
1460 | search_tbl->ant_type = ANT_BC; | ||
1461 | |||
1462 | if (!rs_is_valid_ant(valid_tx_ant, | ||
1463 | search_tbl->ant_type)) | ||
1464 | break; | ||
1465 | |||
1466 | ret = rs_switch_to_mimo2(mvm, lq_sta, sta, | ||
1467 | search_tbl, index); | ||
1468 | if (!ret) { | ||
1469 | lq_sta->action_counter = 0; | ||
1470 | goto out; | ||
1471 | } | ||
1472 | break; | ||
1473 | |||
1474 | case IWL_LEGACY_SWITCH_MIMO3_ABC: | ||
1475 | IWL_DEBUG_RATE(mvm, "LQ: Legacy switch to MIMO3\n"); | ||
1476 | |||
1477 | /* Set up search table to try MIMO3 */ | ||
1478 | memcpy(search_tbl, tbl, sz); | ||
1479 | search_tbl->is_SGI = 0; | ||
1480 | |||
1481 | search_tbl->ant_type = ANT_ABC; | ||
1482 | |||
1483 | if (!rs_is_valid_ant(valid_tx_ant, | ||
1484 | search_tbl->ant_type)) | ||
1485 | break; | ||
1486 | |||
1487 | ret = rs_switch_to_mimo3(mvm, lq_sta, sta, | ||
1488 | search_tbl, index); | ||
1489 | if (!ret) { | ||
1490 | lq_sta->action_counter = 0; | ||
1491 | goto out; | ||
1492 | } | ||
1493 | break; | ||
1494 | } | ||
1495 | tbl->action++; | ||
1496 | if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC) | ||
1497 | tbl->action = IWL_LEGACY_SWITCH_ANTENNA1; | ||
1498 | |||
1499 | if (tbl->action == start_action) | ||
1500 | break; | ||
1501 | } | ||
1502 | search_tbl->lq_type = LQ_NONE; | ||
1503 | return 0; | ||
1504 | |||
1505 | out: | ||
1506 | lq_sta->search_better_tbl = 1; | ||
1507 | tbl->action++; | ||
1508 | if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC) | ||
1509 | tbl->action = IWL_LEGACY_SWITCH_ANTENNA1; | ||
1510 | if (update_search_tbl_counter) | ||
1511 | search_tbl->action = tbl->action; | ||
1512 | return 0; | ||
1513 | } | ||
1514 | |||
1515 | /* | ||
1516 | * Try to switch to new modulation mode from SISO | ||
1517 | */ | ||
1518 | static int rs_move_siso_to_other(struct iwl_mvm *mvm, | ||
1519 | struct iwl_lq_sta *lq_sta, | ||
1520 | struct ieee80211_sta *sta, int index) | ||
1521 | { | ||
1522 | u8 is_green = lq_sta->is_green; | ||
1523 | struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); | ||
1524 | struct iwl_scale_tbl_info *search_tbl = | ||
1525 | &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); | ||
1526 | struct iwl_rate_scale_data *window = &(tbl->win[index]); | ||
1527 | struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; | ||
1528 | u32 sz = (sizeof(struct iwl_scale_tbl_info) - | ||
1529 | (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); | ||
1530 | u8 start_action; | ||
1531 | u8 valid_tx_ant = mvm->nvm_data->valid_tx_ant; | ||
1532 | u8 tx_chains_num = num_of_ant(valid_tx_ant); | ||
1533 | u8 update_search_tbl_counter = 0; | ||
1534 | int ret; | ||
1535 | |||
1536 | start_action = tbl->action; | ||
1537 | while (1) { | ||
1538 | lq_sta->action_counter++; | ||
1539 | switch (tbl->action) { | ||
1540 | case IWL_SISO_SWITCH_ANTENNA1: | ||
1541 | case IWL_SISO_SWITCH_ANTENNA2: | ||
1542 | IWL_DEBUG_RATE(mvm, "LQ: SISO toggle Antenna\n"); | ||
1543 | if ((tbl->action == IWL_SISO_SWITCH_ANTENNA1 && | ||
1544 | tx_chains_num <= 1) || | ||
1545 | (tbl->action == IWL_SISO_SWITCH_ANTENNA2 && | ||
1546 | tx_chains_num <= 2)) | ||
1547 | break; | ||
1548 | |||
1549 | if (window->success_ratio >= IWL_RS_GOOD_RATIO) | ||
1550 | break; | ||
1551 | |||
1552 | memcpy(search_tbl, tbl, sz); | ||
1553 | if (rs_toggle_antenna(valid_tx_ant, | ||
1554 | &search_tbl->current_rate, | ||
1555 | search_tbl)) { | ||
1556 | update_search_tbl_counter = 1; | ||
1557 | goto out; | ||
1558 | } | ||
1559 | break; | ||
1560 | case IWL_SISO_SWITCH_MIMO2_AB: | ||
1561 | case IWL_SISO_SWITCH_MIMO2_AC: | ||
1562 | case IWL_SISO_SWITCH_MIMO2_BC: | ||
1563 | IWL_DEBUG_RATE(mvm, "LQ: SISO switch to MIMO2\n"); | ||
1564 | memcpy(search_tbl, tbl, sz); | ||
1565 | search_tbl->is_SGI = 0; | ||
1566 | |||
1567 | if (tbl->action == IWL_SISO_SWITCH_MIMO2_AB) | ||
1568 | search_tbl->ant_type = ANT_AB; | ||
1569 | else if (tbl->action == IWL_SISO_SWITCH_MIMO2_AC) | ||
1570 | search_tbl->ant_type = ANT_AC; | ||
1571 | else | ||
1572 | search_tbl->ant_type = ANT_BC; | ||
1573 | |||
1574 | if (!rs_is_valid_ant(valid_tx_ant, | ||
1575 | search_tbl->ant_type)) | ||
1576 | break; | ||
1577 | |||
1578 | ret = rs_switch_to_mimo2(mvm, lq_sta, sta, | ||
1579 | search_tbl, index); | ||
1580 | if (!ret) | ||
1581 | goto out; | ||
1582 | break; | ||
1583 | case IWL_SISO_SWITCH_GI: | ||
1584 | if (!tbl->is_ht40 && !(ht_cap->cap & | ||
1585 | IEEE80211_HT_CAP_SGI_20)) | ||
1586 | break; | ||
1587 | if (tbl->is_ht40 && !(ht_cap->cap & | ||
1588 | IEEE80211_HT_CAP_SGI_40)) | ||
1589 | break; | ||
1590 | |||
1591 | IWL_DEBUG_RATE(mvm, "LQ: SISO toggle SGI/NGI\n"); | ||
1592 | |||
1593 | memcpy(search_tbl, tbl, sz); | ||
1594 | if (is_green) { | ||
1595 | if (!tbl->is_SGI) | ||
1596 | break; | ||
1597 | else | ||
1598 | IWL_ERR(mvm, | ||
1599 | "SGI was set in GF+SISO\n"); | ||
1600 | } | ||
1601 | search_tbl->is_SGI = !tbl->is_SGI; | ||
1602 | rs_set_expected_tpt_table(lq_sta, search_tbl); | ||
1603 | if (tbl->is_SGI) { | ||
1604 | s32 tpt = lq_sta->last_tpt / 100; | ||
1605 | if (tpt >= search_tbl->expected_tpt[index]) | ||
1606 | break; | ||
1607 | } | ||
1608 | search_tbl->current_rate = | ||
1609 | rate_n_flags_from_tbl(mvm, search_tbl, | ||
1610 | index, is_green); | ||
1611 | update_search_tbl_counter = 1; | ||
1612 | goto out; | ||
1613 | case IWL_SISO_SWITCH_MIMO3_ABC: | ||
1614 | IWL_DEBUG_RATE(mvm, "LQ: SISO switch to MIMO3\n"); | ||
1615 | memcpy(search_tbl, tbl, sz); | ||
1616 | search_tbl->is_SGI = 0; | ||
1617 | search_tbl->ant_type = ANT_ABC; | ||
1618 | |||
1619 | if (!rs_is_valid_ant(valid_tx_ant, | ||
1620 | search_tbl->ant_type)) | ||
1621 | break; | ||
1622 | |||
1623 | ret = rs_switch_to_mimo3(mvm, lq_sta, sta, | ||
1624 | search_tbl, index); | ||
1625 | if (!ret) | ||
1626 | goto out; | ||
1627 | break; | ||
1628 | } | ||
1629 | tbl->action++; | ||
1630 | if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC) | ||
1631 | tbl->action = IWL_SISO_SWITCH_ANTENNA1; | ||
1632 | |||
1633 | if (tbl->action == start_action) | ||
1634 | break; | ||
1635 | } | ||
1636 | search_tbl->lq_type = LQ_NONE; | ||
1637 | return 0; | ||
1638 | |||
1639 | out: | ||
1640 | lq_sta->search_better_tbl = 1; | ||
1641 | tbl->action++; | ||
1642 | if (tbl->action > IWL_SISO_SWITCH_MIMO3_ABC) | ||
1643 | tbl->action = IWL_SISO_SWITCH_ANTENNA1; | ||
1644 | if (update_search_tbl_counter) | ||
1645 | search_tbl->action = tbl->action; | ||
1646 | |||
1647 | return 0; | ||
1648 | } | ||
1649 | |||
1650 | /* | ||
1651 | * Try to switch to new modulation mode from MIMO2 | ||
1652 | */ | ||
1653 | static int rs_move_mimo2_to_other(struct iwl_mvm *mvm, | ||
1654 | struct iwl_lq_sta *lq_sta, | ||
1655 | struct ieee80211_sta *sta, int index) | ||
1656 | { | ||
1657 | s8 is_green = lq_sta->is_green; | ||
1658 | struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); | ||
1659 | struct iwl_scale_tbl_info *search_tbl = | ||
1660 | &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); | ||
1661 | struct iwl_rate_scale_data *window = &(tbl->win[index]); | ||
1662 | struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; | ||
1663 | u32 sz = (sizeof(struct iwl_scale_tbl_info) - | ||
1664 | (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); | ||
1665 | u8 start_action; | ||
1666 | u8 valid_tx_ant = mvm->nvm_data->valid_tx_ant; | ||
1667 | u8 tx_chains_num = num_of_ant(valid_tx_ant); | ||
1668 | u8 update_search_tbl_counter = 0; | ||
1669 | int ret; | ||
1670 | |||
1671 | start_action = tbl->action; | ||
1672 | while (1) { | ||
1673 | lq_sta->action_counter++; | ||
1674 | switch (tbl->action) { | ||
1675 | case IWL_MIMO2_SWITCH_ANTENNA1: | ||
1676 | case IWL_MIMO2_SWITCH_ANTENNA2: | ||
1677 | IWL_DEBUG_RATE(mvm, "LQ: MIMO2 toggle Antennas\n"); | ||
1678 | |||
1679 | if (tx_chains_num <= 2) | ||
1680 | break; | ||
1681 | |||
1682 | if (window->success_ratio >= IWL_RS_GOOD_RATIO) | ||
1683 | break; | ||
1684 | |||
1685 | memcpy(search_tbl, tbl, sz); | ||
1686 | if (rs_toggle_antenna(valid_tx_ant, | ||
1687 | &search_tbl->current_rate, | ||
1688 | search_tbl)) { | ||
1689 | update_search_tbl_counter = 1; | ||
1690 | goto out; | ||
1691 | } | ||
1692 | break; | ||
1693 | case IWL_MIMO2_SWITCH_SISO_A: | ||
1694 | case IWL_MIMO2_SWITCH_SISO_B: | ||
1695 | case IWL_MIMO2_SWITCH_SISO_C: | ||
1696 | IWL_DEBUG_RATE(mvm, "LQ: MIMO2 switch to SISO\n"); | ||
1697 | |||
1698 | /* Set up new search table for SISO */ | ||
1699 | memcpy(search_tbl, tbl, sz); | ||
1700 | |||
1701 | if (tbl->action == IWL_MIMO2_SWITCH_SISO_A) | ||
1702 | search_tbl->ant_type = ANT_A; | ||
1703 | else if (tbl->action == IWL_MIMO2_SWITCH_SISO_B) | ||
1704 | search_tbl->ant_type = ANT_B; | ||
1705 | else | ||
1706 | search_tbl->ant_type = ANT_C; | ||
1707 | |||
1708 | if (!rs_is_valid_ant(valid_tx_ant, | ||
1709 | search_tbl->ant_type)) | ||
1710 | break; | ||
1711 | |||
1712 | ret = rs_switch_to_siso(mvm, lq_sta, sta, | ||
1713 | search_tbl, index); | ||
1714 | if (!ret) | ||
1715 | goto out; | ||
1716 | |||
1717 | break; | ||
1718 | |||
1719 | case IWL_MIMO2_SWITCH_GI: | ||
1720 | if (!tbl->is_ht40 && !(ht_cap->cap & | ||
1721 | IEEE80211_HT_CAP_SGI_20)) | ||
1722 | break; | ||
1723 | if (tbl->is_ht40 && !(ht_cap->cap & | ||
1724 | IEEE80211_HT_CAP_SGI_40)) | ||
1725 | break; | ||
1726 | |||
1727 | IWL_DEBUG_RATE(mvm, "LQ: MIMO2 toggle SGI/NGI\n"); | ||
1728 | |||
1729 | /* Set up new search table for MIMO2 */ | ||
1730 | memcpy(search_tbl, tbl, sz); | ||
1731 | search_tbl->is_SGI = !tbl->is_SGI; | ||
1732 | rs_set_expected_tpt_table(lq_sta, search_tbl); | ||
1733 | /* | ||
1734 | * If active table already uses the fastest possible | ||
1735 | * modulation (dual stream with short guard interval), | ||
1736 | * and it's working well, there's no need to look | ||
1737 | * for a better type of modulation! | ||
1738 | */ | ||
1739 | if (tbl->is_SGI) { | ||
1740 | s32 tpt = lq_sta->last_tpt / 100; | ||
1741 | if (tpt >= search_tbl->expected_tpt[index]) | ||
1742 | break; | ||
1743 | } | ||
1744 | search_tbl->current_rate = | ||
1745 | rate_n_flags_from_tbl(mvm, search_tbl, | ||
1746 | index, is_green); | ||
1747 | update_search_tbl_counter = 1; | ||
1748 | goto out; | ||
1749 | |||
1750 | case IWL_MIMO2_SWITCH_MIMO3_ABC: | ||
1751 | IWL_DEBUG_RATE(mvm, "LQ: MIMO2 switch to MIMO3\n"); | ||
1752 | memcpy(search_tbl, tbl, sz); | ||
1753 | search_tbl->is_SGI = 0; | ||
1754 | search_tbl->ant_type = ANT_ABC; | ||
1755 | |||
1756 | if (!rs_is_valid_ant(valid_tx_ant, | ||
1757 | search_tbl->ant_type)) | ||
1758 | break; | ||
1759 | |||
1760 | ret = rs_switch_to_mimo3(mvm, lq_sta, sta, | ||
1761 | search_tbl, index); | ||
1762 | if (!ret) | ||
1763 | goto out; | ||
1764 | |||
1765 | break; | ||
1766 | } | ||
1767 | tbl->action++; | ||
1768 | if (tbl->action > IWL_MIMO2_SWITCH_MIMO3_ABC) | ||
1769 | tbl->action = IWL_MIMO2_SWITCH_ANTENNA1; | ||
1770 | |||
1771 | if (tbl->action == start_action) | ||
1772 | break; | ||
1773 | } | ||
1774 | search_tbl->lq_type = LQ_NONE; | ||
1775 | return 0; | ||
1776 | out: | ||
1777 | lq_sta->search_better_tbl = 1; | ||
1778 | tbl->action++; | ||
1779 | if (tbl->action > IWL_MIMO2_SWITCH_MIMO3_ABC) | ||
1780 | tbl->action = IWL_MIMO2_SWITCH_ANTENNA1; | ||
1781 | if (update_search_tbl_counter) | ||
1782 | search_tbl->action = tbl->action; | ||
1783 | |||
1784 | return 0; | ||
1785 | } | ||
1786 | |||
1787 | /* | ||
1788 | * Try to switch to new modulation mode from MIMO3 | ||
1789 | */ | ||
1790 | static int rs_move_mimo3_to_other(struct iwl_mvm *mvm, | ||
1791 | struct iwl_lq_sta *lq_sta, | ||
1792 | struct ieee80211_sta *sta, int index) | ||
1793 | { | ||
1794 | s8 is_green = lq_sta->is_green; | ||
1795 | struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); | ||
1796 | struct iwl_scale_tbl_info *search_tbl = | ||
1797 | &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); | ||
1798 | struct iwl_rate_scale_data *window = &(tbl->win[index]); | ||
1799 | struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; | ||
1800 | u32 sz = (sizeof(struct iwl_scale_tbl_info) - | ||
1801 | (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); | ||
1802 | u8 start_action; | ||
1803 | u8 valid_tx_ant = mvm->nvm_data->valid_tx_ant; | ||
1804 | u8 tx_chains_num = num_of_ant(valid_tx_ant); | ||
1805 | int ret; | ||
1806 | u8 update_search_tbl_counter = 0; | ||
1807 | |||
1808 | start_action = tbl->action; | ||
1809 | while (1) { | ||
1810 | lq_sta->action_counter++; | ||
1811 | switch (tbl->action) { | ||
1812 | case IWL_MIMO3_SWITCH_ANTENNA1: | ||
1813 | case IWL_MIMO3_SWITCH_ANTENNA2: | ||
1814 | IWL_DEBUG_RATE(mvm, "LQ: MIMO3 toggle Antennas\n"); | ||
1815 | |||
1816 | if (tx_chains_num <= 3) | ||
1817 | break; | ||
1818 | |||
1819 | if (window->success_ratio >= IWL_RS_GOOD_RATIO) | ||
1820 | break; | ||
1821 | |||
1822 | memcpy(search_tbl, tbl, sz); | ||
1823 | if (rs_toggle_antenna(valid_tx_ant, | ||
1824 | &search_tbl->current_rate, | ||
1825 | search_tbl)) | ||
1826 | goto out; | ||
1827 | break; | ||
1828 | case IWL_MIMO3_SWITCH_SISO_A: | ||
1829 | case IWL_MIMO3_SWITCH_SISO_B: | ||
1830 | case IWL_MIMO3_SWITCH_SISO_C: | ||
1831 | IWL_DEBUG_RATE(mvm, "LQ: MIMO3 switch to SISO\n"); | ||
1832 | |||
1833 | /* Set up new search table for SISO */ | ||
1834 | memcpy(search_tbl, tbl, sz); | ||
1835 | |||
1836 | if (tbl->action == IWL_MIMO3_SWITCH_SISO_A) | ||
1837 | search_tbl->ant_type = ANT_A; | ||
1838 | else if (tbl->action == IWL_MIMO3_SWITCH_SISO_B) | ||
1839 | search_tbl->ant_type = ANT_B; | ||
1840 | else | ||
1841 | search_tbl->ant_type = ANT_C; | ||
1842 | |||
1843 | if (!rs_is_valid_ant(valid_tx_ant, | ||
1844 | search_tbl->ant_type)) | ||
1845 | break; | ||
1846 | |||
1847 | ret = rs_switch_to_siso(mvm, lq_sta, sta, | ||
1848 | search_tbl, index); | ||
1849 | if (!ret) | ||
1850 | goto out; | ||
1851 | |||
1852 | break; | ||
1853 | |||
1854 | case IWL_MIMO3_SWITCH_MIMO2_AB: | ||
1855 | case IWL_MIMO3_SWITCH_MIMO2_AC: | ||
1856 | case IWL_MIMO3_SWITCH_MIMO2_BC: | ||
1857 | IWL_DEBUG_RATE(mvm, "LQ: MIMO3 switch to MIMO2\n"); | ||
1858 | |||
1859 | memcpy(search_tbl, tbl, sz); | ||
1860 | search_tbl->is_SGI = 0; | ||
1861 | if (tbl->action == IWL_MIMO3_SWITCH_MIMO2_AB) | ||
1862 | search_tbl->ant_type = ANT_AB; | ||
1863 | else if (tbl->action == IWL_MIMO3_SWITCH_MIMO2_AC) | ||
1864 | search_tbl->ant_type = ANT_AC; | ||
1865 | else | ||
1866 | search_tbl->ant_type = ANT_BC; | ||
1867 | |||
1868 | if (!rs_is_valid_ant(valid_tx_ant, | ||
1869 | search_tbl->ant_type)) | ||
1870 | break; | ||
1871 | |||
1872 | ret = rs_switch_to_mimo2(mvm, lq_sta, sta, | ||
1873 | search_tbl, index); | ||
1874 | if (!ret) | ||
1875 | goto out; | ||
1876 | |||
1877 | break; | ||
1878 | |||
1879 | case IWL_MIMO3_SWITCH_GI: | ||
1880 | if (!tbl->is_ht40 && !(ht_cap->cap & | ||
1881 | IEEE80211_HT_CAP_SGI_20)) | ||
1882 | break; | ||
1883 | if (tbl->is_ht40 && !(ht_cap->cap & | ||
1884 | IEEE80211_HT_CAP_SGI_40)) | ||
1885 | break; | ||
1886 | |||
1887 | IWL_DEBUG_RATE(mvm, "LQ: MIMO3 toggle SGI/NGI\n"); | ||
1888 | |||
1889 | /* Set up new search table for MIMO */ | ||
1890 | memcpy(search_tbl, tbl, sz); | ||
1891 | search_tbl->is_SGI = !tbl->is_SGI; | ||
1892 | rs_set_expected_tpt_table(lq_sta, search_tbl); | ||
1893 | /* | ||
1894 | * If active table already uses the fastest possible | ||
1895 | * modulation (dual stream with short guard interval), | ||
1896 | * and it's working well, there's no need to look | ||
1897 | * for a better type of modulation! | ||
1898 | */ | ||
1899 | if (tbl->is_SGI) { | ||
1900 | s32 tpt = lq_sta->last_tpt / 100; | ||
1901 | if (tpt >= search_tbl->expected_tpt[index]) | ||
1902 | break; | ||
1903 | } | ||
1904 | search_tbl->current_rate = | ||
1905 | rate_n_flags_from_tbl(mvm, search_tbl, | ||
1906 | index, is_green); | ||
1907 | update_search_tbl_counter = 1; | ||
1908 | goto out; | ||
1909 | } | ||
1910 | tbl->action++; | ||
1911 | if (tbl->action > IWL_MIMO3_SWITCH_GI) | ||
1912 | tbl->action = IWL_MIMO3_SWITCH_ANTENNA1; | ||
1913 | |||
1914 | if (tbl->action == start_action) | ||
1915 | break; | ||
1916 | } | ||
1917 | search_tbl->lq_type = LQ_NONE; | ||
1918 | return 0; | ||
1919 | out: | ||
1920 | lq_sta->search_better_tbl = 1; | ||
1921 | tbl->action++; | ||
1922 | if (tbl->action > IWL_MIMO3_SWITCH_GI) | ||
1923 | tbl->action = IWL_MIMO3_SWITCH_ANTENNA1; | ||
1924 | if (update_search_tbl_counter) | ||
1925 | search_tbl->action = tbl->action; | ||
1926 | |||
1927 | return 0; | ||
1928 | } | ||
1929 | |||
1930 | /* | ||
1931 | * Check whether we should continue using same modulation mode, or | ||
1932 | * begin search for a new mode, based on: | ||
1933 | * 1) # tx successes or failures while using this mode | ||
1934 | * 2) # times calling this function | ||
1935 | * 3) elapsed time in this mode (not used, for now) | ||
1936 | */ | ||
1937 | static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search) | ||
1938 | { | ||
1939 | struct iwl_scale_tbl_info *tbl; | ||
1940 | int i; | ||
1941 | int active_tbl; | ||
1942 | int flush_interval_passed = 0; | ||
1943 | struct iwl_mvm *mvm; | ||
1944 | |||
1945 | mvm = lq_sta->drv; | ||
1946 | active_tbl = lq_sta->active_tbl; | ||
1947 | |||
1948 | tbl = &(lq_sta->lq_info[active_tbl]); | ||
1949 | |||
1950 | /* If we've been disallowing search, see if we should now allow it */ | ||
1951 | if (lq_sta->stay_in_tbl) { | ||
1952 | /* Elapsed time using current modulation mode */ | ||
1953 | if (lq_sta->flush_timer) | ||
1954 | flush_interval_passed = | ||
1955 | time_after(jiffies, | ||
1956 | (unsigned long)(lq_sta->flush_timer + | ||
1957 | IWL_RATE_SCALE_FLUSH_INTVL)); | ||
1958 | |||
1959 | /* | ||
1960 | * Check if we should allow search for new modulation mode. | ||
1961 | * If many frames have failed or succeeded, or we've used | ||
1962 | * this same modulation for a long time, allow search, and | ||
1963 | * reset history stats that keep track of whether we should | ||
1964 | * allow a new search. Also (below) reset all bitmaps and | ||
1965 | * stats in active history. | ||
1966 | */ | ||
1967 | if (force_search || | ||
1968 | (lq_sta->total_failed > lq_sta->max_failure_limit) || | ||
1969 | (lq_sta->total_success > lq_sta->max_success_limit) || | ||
1970 | ((!lq_sta->search_better_tbl) && | ||
1971 | (lq_sta->flush_timer) && (flush_interval_passed))) { | ||
1972 | IWL_DEBUG_RATE(mvm, | ||
1973 | "LQ: stay is expired %d %d %d\n", | ||
1974 | lq_sta->total_failed, | ||
1975 | lq_sta->total_success, | ||
1976 | flush_interval_passed); | ||
1977 | |||
1978 | /* Allow search for new mode */ | ||
1979 | lq_sta->stay_in_tbl = 0; /* only place reset */ | ||
1980 | lq_sta->total_failed = 0; | ||
1981 | lq_sta->total_success = 0; | ||
1982 | lq_sta->flush_timer = 0; | ||
1983 | /* | ||
1984 | * Else if we've used this modulation mode enough repetitions | ||
1985 | * (regardless of elapsed time or success/failure), reset | ||
1986 | * history bitmaps and rate-specific stats for all rates in | ||
1987 | * active table. | ||
1988 | */ | ||
1989 | } else { | ||
1990 | lq_sta->table_count++; | ||
1991 | if (lq_sta->table_count >= | ||
1992 | lq_sta->table_count_limit) { | ||
1993 | lq_sta->table_count = 0; | ||
1994 | |||
1995 | IWL_DEBUG_RATE(mvm, | ||
1996 | "LQ: stay in table clear win\n"); | ||
1997 | for (i = 0; i < IWL_RATE_COUNT; i++) | ||
1998 | rs_rate_scale_clear_window( | ||
1999 | &(tbl->win[i])); | ||
2000 | } | ||
2001 | } | ||
2002 | |||
2003 | /* If transitioning to allow "search", reset all history | ||
2004 | * bitmaps and stats in active table (this will become the new | ||
2005 | * "search" table). */ | ||
2006 | if (!lq_sta->stay_in_tbl) { | ||
2007 | for (i = 0; i < IWL_RATE_COUNT; i++) | ||
2008 | rs_rate_scale_clear_window(&(tbl->win[i])); | ||
2009 | } | ||
2010 | } | ||
2011 | } | ||
2012 | |||
2013 | /* | ||
2014 | * setup rate table in uCode | ||
2015 | */ | ||
2016 | static void rs_update_rate_tbl(struct iwl_mvm *mvm, | ||
2017 | struct iwl_lq_sta *lq_sta, | ||
2018 | struct iwl_scale_tbl_info *tbl, | ||
2019 | int index, u8 is_green) | ||
2020 | { | ||
2021 | u32 rate; | ||
2022 | |||
2023 | /* Update uCode's rate table. */ | ||
2024 | rate = rate_n_flags_from_tbl(mvm, tbl, index, is_green); | ||
2025 | rs_fill_link_cmd(mvm, lq_sta, rate); | ||
2026 | iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, CMD_ASYNC, false); | ||
2027 | } | ||
2028 | |||
2029 | /* | ||
2030 | * Do rate scaling and search for new modulation mode. | ||
2031 | */ | ||
2032 | static void rs_rate_scale_perform(struct iwl_mvm *mvm, | ||
2033 | struct sk_buff *skb, | ||
2034 | struct ieee80211_sta *sta, | ||
2035 | struct iwl_lq_sta *lq_sta) | ||
2036 | { | ||
2037 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
2038 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||
2039 | int low = IWL_RATE_INVALID; | ||
2040 | int high = IWL_RATE_INVALID; | ||
2041 | int index; | ||
2042 | int i; | ||
2043 | struct iwl_rate_scale_data *window = NULL; | ||
2044 | int current_tpt = IWL_INVALID_VALUE; | ||
2045 | int low_tpt = IWL_INVALID_VALUE; | ||
2046 | int high_tpt = IWL_INVALID_VALUE; | ||
2047 | u32 fail_count; | ||
2048 | s8 scale_action = 0; | ||
2049 | u16 rate_mask; | ||
2050 | u8 update_lq = 0; | ||
2051 | struct iwl_scale_tbl_info *tbl, *tbl1; | ||
2052 | u16 rate_scale_index_msk = 0; | ||
2053 | u8 is_green = 0; | ||
2054 | u8 active_tbl = 0; | ||
2055 | u8 done_search = 0; | ||
2056 | u16 high_low; | ||
2057 | s32 sr; | ||
2058 | u8 tid = IWL_MAX_TID_COUNT; | ||
2059 | struct iwl_mvm_sta *sta_priv = (void *)sta->drv_priv; | ||
2060 | struct iwl_mvm_tid_data *tid_data; | ||
2061 | |||
2062 | IWL_DEBUG_RATE(mvm, "rate scale calculate new rate for skb\n"); | ||
2063 | |||
2064 | /* Send management frames and NO_ACK data using lowest rate. */ | ||
2065 | /* TODO: this could probably be improved.. */ | ||
2066 | if (!ieee80211_is_data(hdr->frame_control) || | ||
2067 | info->flags & IEEE80211_TX_CTL_NO_ACK) | ||
2068 | return; | ||
2069 | |||
2070 | lq_sta->supp_rates = sta->supp_rates[lq_sta->band]; | ||
2071 | |||
2072 | tid = rs_tl_add_packet(lq_sta, hdr); | ||
2073 | if ((tid != IWL_MAX_TID_COUNT) && | ||
2074 | (lq_sta->tx_agg_tid_en & (1 << tid))) { | ||
2075 | tid_data = &sta_priv->tid_data[tid]; | ||
2076 | if (tid_data->state == IWL_AGG_OFF) | ||
2077 | lq_sta->is_agg = 0; | ||
2078 | else | ||
2079 | lq_sta->is_agg = 1; | ||
2080 | } else { | ||
2081 | lq_sta->is_agg = 0; | ||
2082 | } | ||
2083 | |||
2084 | /* | ||
2085 | * Select rate-scale / modulation-mode table to work with in | ||
2086 | * the rest of this function: "search" if searching for better | ||
2087 | * modulation mode, or "active" if doing rate scaling within a mode. | ||
2088 | */ | ||
2089 | if (!lq_sta->search_better_tbl) | ||
2090 | active_tbl = lq_sta->active_tbl; | ||
2091 | else | ||
2092 | active_tbl = 1 - lq_sta->active_tbl; | ||
2093 | |||
2094 | tbl = &(lq_sta->lq_info[active_tbl]); | ||
2095 | if (is_legacy(tbl->lq_type)) | ||
2096 | lq_sta->is_green = 0; | ||
2097 | else | ||
2098 | lq_sta->is_green = rs_use_green(sta); | ||
2099 | is_green = lq_sta->is_green; | ||
2100 | |||
2101 | /* current tx rate */ | ||
2102 | index = lq_sta->last_txrate_idx; | ||
2103 | |||
2104 | IWL_DEBUG_RATE(mvm, "Rate scale index %d for type %d\n", index, | ||
2105 | tbl->lq_type); | ||
2106 | |||
2107 | /* rates available for this association, and for modulation mode */ | ||
2108 | rate_mask = rs_get_supported_rates(lq_sta, hdr, tbl->lq_type); | ||
2109 | |||
2110 | IWL_DEBUG_RATE(mvm, "mask 0x%04X\n", rate_mask); | ||
2111 | |||
2112 | /* mask with station rate restriction */ | ||
2113 | if (is_legacy(tbl->lq_type)) { | ||
2114 | if (lq_sta->band == IEEE80211_BAND_5GHZ) | ||
2115 | /* supp_rates has no CCK bits in A mode */ | ||
2116 | rate_scale_index_msk = (u16) (rate_mask & | ||
2117 | (lq_sta->supp_rates << IWL_FIRST_OFDM_RATE)); | ||
2118 | else | ||
2119 | rate_scale_index_msk = (u16) (rate_mask & | ||
2120 | lq_sta->supp_rates); | ||
2121 | |||
2122 | } else { | ||
2123 | rate_scale_index_msk = rate_mask; | ||
2124 | } | ||
2125 | |||
2126 | if (!rate_scale_index_msk) | ||
2127 | rate_scale_index_msk = rate_mask; | ||
2128 | |||
2129 | if (!((1 << index) & rate_scale_index_msk)) { | ||
2130 | IWL_ERR(mvm, "Current Rate is not valid\n"); | ||
2131 | if (lq_sta->search_better_tbl) { | ||
2132 | /* revert to active table if search table is not valid*/ | ||
2133 | tbl->lq_type = LQ_NONE; | ||
2134 | lq_sta->search_better_tbl = 0; | ||
2135 | tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); | ||
2136 | /* get "active" rate info */ | ||
2137 | index = iwl_hwrate_to_plcp_idx(tbl->current_rate); | ||
2138 | rs_update_rate_tbl(mvm, lq_sta, tbl, index, is_green); | ||
2139 | } | ||
2140 | return; | ||
2141 | } | ||
2142 | |||
2143 | /* Get expected throughput table and history window for current rate */ | ||
2144 | if (!tbl->expected_tpt) { | ||
2145 | IWL_ERR(mvm, "tbl->expected_tpt is NULL\n"); | ||
2146 | return; | ||
2147 | } | ||
2148 | |||
2149 | /* force user max rate if set by user */ | ||
2150 | if ((lq_sta->max_rate_idx != -1) && | ||
2151 | (lq_sta->max_rate_idx < index)) { | ||
2152 | index = lq_sta->max_rate_idx; | ||
2153 | update_lq = 1; | ||
2154 | window = &(tbl->win[index]); | ||
2155 | goto lq_update; | ||
2156 | } | ||
2157 | |||
2158 | window = &(tbl->win[index]); | ||
2159 | |||
2160 | /* | ||
2161 | * If there is not enough history to calculate actual average | ||
2162 | * throughput, keep analyzing results of more tx frames, without | ||
2163 | * changing rate or mode (bypass most of the rest of this function). | ||
2164 | * Set up new rate table in uCode only if old rate is not supported | ||
2165 | * in current association (use new rate found above). | ||
2166 | */ | ||
2167 | fail_count = window->counter - window->success_counter; | ||
2168 | if ((fail_count < IWL_RATE_MIN_FAILURE_TH) && | ||
2169 | (window->success_counter < IWL_RATE_MIN_SUCCESS_TH)) { | ||
2170 | IWL_DEBUG_RATE(mvm, | ||
2171 | "LQ: still below TH. succ=%d total=%d for index %d\n", | ||
2172 | window->success_counter, window->counter, index); | ||
2173 | |||
2174 | /* Can't calculate this yet; not enough history */ | ||
2175 | window->average_tpt = IWL_INVALID_VALUE; | ||
2176 | |||
2177 | /* Should we stay with this modulation mode, | ||
2178 | * or search for a new one? */ | ||
2179 | rs_stay_in_table(lq_sta, false); | ||
2180 | |||
2181 | goto out; | ||
2182 | } | ||
2183 | /* Else we have enough samples; calculate estimate of | ||
2184 | * actual average throughput */ | ||
2185 | if (window->average_tpt != ((window->success_ratio * | ||
2186 | tbl->expected_tpt[index] + 64) / 128)) { | ||
2187 | IWL_ERR(mvm, | ||
2188 | "expected_tpt should have been calculated by now\n"); | ||
2189 | window->average_tpt = ((window->success_ratio * | ||
2190 | tbl->expected_tpt[index] + 64) / 128); | ||
2191 | } | ||
2192 | |||
2193 | /* If we are searching for better modulation mode, check success. */ | ||
2194 | if (lq_sta->search_better_tbl) { | ||
2195 | /* If good success, continue using the "search" mode; | ||
2196 | * no need to send new link quality command, since we're | ||
2197 | * continuing to use the setup that we've been trying. */ | ||
2198 | if (window->average_tpt > lq_sta->last_tpt) { | ||
2199 | IWL_DEBUG_RATE(mvm, | ||
2200 | "LQ: SWITCHING TO NEW TABLE suc=%d cur-tpt=%d old-tpt=%d\n", | ||
2201 | window->success_ratio, | ||
2202 | window->average_tpt, | ||
2203 | lq_sta->last_tpt); | ||
2204 | |||
2205 | if (!is_legacy(tbl->lq_type)) | ||
2206 | lq_sta->enable_counter = 1; | ||
2207 | |||
2208 | /* Swap tables; "search" becomes "active" */ | ||
2209 | lq_sta->active_tbl = active_tbl; | ||
2210 | current_tpt = window->average_tpt; | ||
2211 | /* Else poor success; go back to mode in "active" table */ | ||
2212 | } else { | ||
2213 | IWL_DEBUG_RATE(mvm, | ||
2214 | "LQ: GOING BACK TO THE OLD TABLE suc=%d cur-tpt=%d old-tpt=%d\n", | ||
2215 | window->success_ratio, | ||
2216 | window->average_tpt, | ||
2217 | lq_sta->last_tpt); | ||
2218 | |||
2219 | /* Nullify "search" table */ | ||
2220 | tbl->lq_type = LQ_NONE; | ||
2221 | |||
2222 | /* Revert to "active" table */ | ||
2223 | active_tbl = lq_sta->active_tbl; | ||
2224 | tbl = &(lq_sta->lq_info[active_tbl]); | ||
2225 | |||
2226 | /* Revert to "active" rate and throughput info */ | ||
2227 | index = iwl_hwrate_to_plcp_idx(tbl->current_rate); | ||
2228 | current_tpt = lq_sta->last_tpt; | ||
2229 | |||
2230 | /* Need to set up a new rate table in uCode */ | ||
2231 | update_lq = 1; | ||
2232 | } | ||
2233 | |||
2234 | /* Either way, we've made a decision; modulation mode | ||
2235 | * search is done, allow rate adjustment next time. */ | ||
2236 | lq_sta->search_better_tbl = 0; | ||
2237 | done_search = 1; /* Don't switch modes below! */ | ||
2238 | goto lq_update; | ||
2239 | } | ||
2240 | |||
2241 | /* (Else) not in search of better modulation mode, try for better | ||
2242 | * starting rate, while staying in this mode. */ | ||
2243 | high_low = rs_get_adjacent_rate(mvm, index, rate_scale_index_msk, | ||
2244 | tbl->lq_type); | ||
2245 | low = high_low & 0xff; | ||
2246 | high = (high_low >> 8) & 0xff; | ||
2247 | |||
2248 | /* If user set max rate, dont allow higher than user constrain */ | ||
2249 | if ((lq_sta->max_rate_idx != -1) && | ||
2250 | (lq_sta->max_rate_idx < high)) | ||
2251 | high = IWL_RATE_INVALID; | ||
2252 | |||
2253 | sr = window->success_ratio; | ||
2254 | |||
2255 | /* Collect measured throughputs for current and adjacent rates */ | ||
2256 | current_tpt = window->average_tpt; | ||
2257 | if (low != IWL_RATE_INVALID) | ||
2258 | low_tpt = tbl->win[low].average_tpt; | ||
2259 | if (high != IWL_RATE_INVALID) | ||
2260 | high_tpt = tbl->win[high].average_tpt; | ||
2261 | |||
2262 | scale_action = 0; | ||
2263 | |||
2264 | /* Too many failures, decrease rate */ | ||
2265 | if ((sr <= IWL_RATE_DECREASE_TH) || (current_tpt == 0)) { | ||
2266 | IWL_DEBUG_RATE(mvm, | ||
2267 | "decrease rate because of low success_ratio\n"); | ||
2268 | scale_action = -1; | ||
2269 | /* No throughput measured yet for adjacent rates; try increase. */ | ||
2270 | } else if ((low_tpt == IWL_INVALID_VALUE) && | ||
2271 | (high_tpt == IWL_INVALID_VALUE)) { | ||
2272 | if (high != IWL_RATE_INVALID && sr >= IWL_RATE_INCREASE_TH) | ||
2273 | scale_action = 1; | ||
2274 | else if (low != IWL_RATE_INVALID) | ||
2275 | scale_action = 0; | ||
2276 | } | ||
2277 | |||
2278 | /* Both adjacent throughputs are measured, but neither one has better | ||
2279 | * throughput; we're using the best rate, don't change it! */ | ||
2280 | else if ((low_tpt != IWL_INVALID_VALUE) && | ||
2281 | (high_tpt != IWL_INVALID_VALUE) && | ||
2282 | (low_tpt < current_tpt) && | ||
2283 | (high_tpt < current_tpt)) | ||
2284 | scale_action = 0; | ||
2285 | |||
2286 | /* At least one adjacent rate's throughput is measured, | ||
2287 | * and may have better performance. */ | ||
2288 | else { | ||
2289 | /* Higher adjacent rate's throughput is measured */ | ||
2290 | if (high_tpt != IWL_INVALID_VALUE) { | ||
2291 | /* Higher rate has better throughput */ | ||
2292 | if (high_tpt > current_tpt && | ||
2293 | sr >= IWL_RATE_INCREASE_TH) { | ||
2294 | scale_action = 1; | ||
2295 | } else { | ||
2296 | scale_action = 0; | ||
2297 | } | ||
2298 | |||
2299 | /* Lower adjacent rate's throughput is measured */ | ||
2300 | } else if (low_tpt != IWL_INVALID_VALUE) { | ||
2301 | /* Lower rate has better throughput */ | ||
2302 | if (low_tpt > current_tpt) { | ||
2303 | IWL_DEBUG_RATE(mvm, | ||
2304 | "decrease rate because of low tpt\n"); | ||
2305 | scale_action = -1; | ||
2306 | } else if (sr >= IWL_RATE_INCREASE_TH) { | ||
2307 | scale_action = 1; | ||
2308 | } | ||
2309 | } | ||
2310 | } | ||
2311 | |||
2312 | /* Sanity check; asked for decrease, but success rate or throughput | ||
2313 | * has been good at old rate. Don't change it. */ | ||
2314 | if ((scale_action == -1) && (low != IWL_RATE_INVALID) && | ||
2315 | ((sr > IWL_RATE_HIGH_TH) || | ||
2316 | (current_tpt > (100 * tbl->expected_tpt[low])))) | ||
2317 | scale_action = 0; | ||
2318 | |||
2319 | switch (scale_action) { | ||
2320 | case -1: | ||
2321 | /* Decrease starting rate, update uCode's rate table */ | ||
2322 | if (low != IWL_RATE_INVALID) { | ||
2323 | update_lq = 1; | ||
2324 | index = low; | ||
2325 | } | ||
2326 | |||
2327 | break; | ||
2328 | case 1: | ||
2329 | /* Increase starting rate, update uCode's rate table */ | ||
2330 | if (high != IWL_RATE_INVALID) { | ||
2331 | update_lq = 1; | ||
2332 | index = high; | ||
2333 | } | ||
2334 | |||
2335 | break; | ||
2336 | case 0: | ||
2337 | /* No change */ | ||
2338 | default: | ||
2339 | break; | ||
2340 | } | ||
2341 | |||
2342 | IWL_DEBUG_RATE(mvm, | ||
2343 | "choose rate scale index %d action %d low %d high %d type %d\n", | ||
2344 | index, scale_action, low, high, tbl->lq_type); | ||
2345 | |||
2346 | lq_update: | ||
2347 | /* Replace uCode's rate table for the destination station. */ | ||
2348 | if (update_lq) | ||
2349 | rs_update_rate_tbl(mvm, lq_sta, tbl, index, is_green); | ||
2350 | |||
2351 | rs_stay_in_table(lq_sta, false); | ||
2352 | |||
2353 | /* | ||
2354 | * Search for new modulation mode if we're: | ||
2355 | * 1) Not changing rates right now | ||
2356 | * 2) Not just finishing up a search | ||
2357 | * 3) Allowing a new search | ||
2358 | */ | ||
2359 | if (!update_lq && !done_search && | ||
2360 | !lq_sta->stay_in_tbl && window->counter) { | ||
2361 | /* Save current throughput to compare with "search" throughput*/ | ||
2362 | lq_sta->last_tpt = current_tpt; | ||
2363 | |||
2364 | /* Select a new "search" modulation mode to try. | ||
2365 | * If one is found, set up the new "search" table. */ | ||
2366 | if (is_legacy(tbl->lq_type)) | ||
2367 | rs_move_legacy_other(mvm, lq_sta, sta, index); | ||
2368 | else if (is_siso(tbl->lq_type)) | ||
2369 | rs_move_siso_to_other(mvm, lq_sta, sta, index); | ||
2370 | else if (is_mimo2(tbl->lq_type)) | ||
2371 | rs_move_mimo2_to_other(mvm, lq_sta, sta, index); | ||
2372 | else | ||
2373 | rs_move_mimo3_to_other(mvm, lq_sta, sta, index); | ||
2374 | |||
2375 | /* If new "search" mode was selected, set up in uCode table */ | ||
2376 | if (lq_sta->search_better_tbl) { | ||
2377 | /* Access the "search" table, clear its history. */ | ||
2378 | tbl = &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); | ||
2379 | for (i = 0; i < IWL_RATE_COUNT; i++) | ||
2380 | rs_rate_scale_clear_window(&(tbl->win[i])); | ||
2381 | |||
2382 | /* Use new "search" start rate */ | ||
2383 | index = iwl_hwrate_to_plcp_idx(tbl->current_rate); | ||
2384 | |||
2385 | IWL_DEBUG_RATE(mvm, | ||
2386 | "Switch current mcs: %X index: %d\n", | ||
2387 | tbl->current_rate, index); | ||
2388 | rs_fill_link_cmd(mvm, lq_sta, tbl->current_rate); | ||
2389 | iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, CMD_ASYNC, false); | ||
2390 | } else { | ||
2391 | done_search = 1; | ||
2392 | } | ||
2393 | } | ||
2394 | |||
2395 | if (done_search && !lq_sta->stay_in_tbl) { | ||
2396 | /* If the "active" (non-search) mode was legacy, | ||
2397 | * and we've tried switching antennas, | ||
2398 | * but we haven't been able to try HT modes (not available), | ||
2399 | * stay with best antenna legacy modulation for a while | ||
2400 | * before next round of mode comparisons. */ | ||
2401 | tbl1 = &(lq_sta->lq_info[lq_sta->active_tbl]); | ||
2402 | if (is_legacy(tbl1->lq_type) && !sta->ht_cap.ht_supported && | ||
2403 | lq_sta->action_counter > tbl1->max_search) { | ||
2404 | IWL_DEBUG_RATE(mvm, "LQ: STAY in legacy table\n"); | ||
2405 | rs_set_stay_in_table(mvm, 1, lq_sta); | ||
2406 | } | ||
2407 | |||
2408 | /* If we're in an HT mode, and all 3 mode switch actions | ||
2409 | * have been tried and compared, stay in this best modulation | ||
2410 | * mode for a while before next round of mode comparisons. */ | ||
2411 | if (lq_sta->enable_counter && | ||
2412 | (lq_sta->action_counter >= tbl1->max_search)) { | ||
2413 | if ((lq_sta->last_tpt > IWL_AGG_TPT_THREHOLD) && | ||
2414 | (lq_sta->tx_agg_tid_en & (1 << tid)) && | ||
2415 | (tid != IWL_MAX_TID_COUNT)) { | ||
2416 | tid_data = &sta_priv->tid_data[tid]; | ||
2417 | if (tid_data->state == IWL_AGG_OFF) { | ||
2418 | IWL_DEBUG_RATE(mvm, | ||
2419 | "try to aggregate tid %d\n", | ||
2420 | tid); | ||
2421 | rs_tl_turn_on_agg(mvm, tid, | ||
2422 | lq_sta, sta); | ||
2423 | } | ||
2424 | } | ||
2425 | rs_set_stay_in_table(mvm, 0, lq_sta); | ||
2426 | } | ||
2427 | } | ||
2428 | |||
2429 | out: | ||
2430 | tbl->current_rate = rate_n_flags_from_tbl(mvm, tbl, index, is_green); | ||
2431 | lq_sta->last_txrate_idx = index; | ||
2432 | } | ||
2433 | |||
2434 | /** | ||
2435 | * rs_initialize_lq - Initialize a station's hardware rate table | ||
2436 | * | ||
2437 | * The uCode's station table contains a table of fallback rates | ||
2438 | * for automatic fallback during transmission. | ||
2439 | * | ||
2440 | * NOTE: This sets up a default set of values. These will be replaced later | ||
2441 | * if the driver's iwl-agn-rs rate scaling algorithm is used, instead of | ||
2442 | * rc80211_simple. | ||
2443 | * | ||
2444 | * NOTE: Run REPLY_ADD_STA command to set up station table entry, before | ||
2445 | * calling this function (which runs REPLY_TX_LINK_QUALITY_CMD, | ||
2446 | * which requires station table entry to exist). | ||
2447 | */ | ||
2448 | static void rs_initialize_lq(struct iwl_mvm *mvm, | ||
2449 | struct ieee80211_sta *sta, | ||
2450 | struct iwl_lq_sta *lq_sta, | ||
2451 | enum ieee80211_band band) | ||
2452 | { | ||
2453 | struct iwl_scale_tbl_info *tbl; | ||
2454 | int rate_idx; | ||
2455 | int i; | ||
2456 | u32 rate; | ||
2457 | u8 use_green = rs_use_green(sta); | ||
2458 | u8 active_tbl = 0; | ||
2459 | u8 valid_tx_ant; | ||
2460 | |||
2461 | if (!sta || !lq_sta) | ||
2462 | return; | ||
2463 | |||
2464 | i = lq_sta->last_txrate_idx; | ||
2465 | |||
2466 | valid_tx_ant = mvm->nvm_data->valid_tx_ant; | ||
2467 | |||
2468 | if (!lq_sta->search_better_tbl) | ||
2469 | active_tbl = lq_sta->active_tbl; | ||
2470 | else | ||
2471 | active_tbl = 1 - lq_sta->active_tbl; | ||
2472 | |||
2473 | tbl = &(lq_sta->lq_info[active_tbl]); | ||
2474 | |||
2475 | if ((i < 0) || (i >= IWL_RATE_COUNT)) | ||
2476 | i = 0; | ||
2477 | |||
2478 | rate = iwl_rates[i].plcp; | ||
2479 | tbl->ant_type = first_antenna(valid_tx_ant); | ||
2480 | rate |= tbl->ant_type << RATE_MCS_ANT_POS; | ||
2481 | |||
2482 | if (i >= IWL_FIRST_CCK_RATE && i <= IWL_LAST_CCK_RATE) | ||
2483 | rate |= RATE_MCS_CCK_MSK; | ||
2484 | |||
2485 | rs_get_tbl_info_from_mcs(rate, band, tbl, &rate_idx); | ||
2486 | if (!rs_is_valid_ant(valid_tx_ant, tbl->ant_type)) | ||
2487 | rs_toggle_antenna(valid_tx_ant, &rate, tbl); | ||
2488 | |||
2489 | rate = rate_n_flags_from_tbl(mvm, tbl, rate_idx, use_green); | ||
2490 | tbl->current_rate = rate; | ||
2491 | rs_set_expected_tpt_table(lq_sta, tbl); | ||
2492 | rs_fill_link_cmd(NULL, lq_sta, rate); | ||
2493 | /* TODO restore station should remember the lq cmd */ | ||
2494 | iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, CMD_SYNC, true); | ||
2495 | } | ||
2496 | |||
2497 | static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta, | ||
2498 | struct ieee80211_tx_rate_control *txrc) | ||
2499 | { | ||
2500 | struct sk_buff *skb = txrc->skb; | ||
2501 | struct ieee80211_supported_band *sband = txrc->sband; | ||
2502 | struct iwl_op_mode *op_mode __maybe_unused = | ||
2503 | (struct iwl_op_mode *)mvm_r; | ||
2504 | struct iwl_mvm *mvm __maybe_unused = IWL_OP_MODE_GET_MVM(op_mode); | ||
2505 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
2506 | struct iwl_lq_sta *lq_sta = mvm_sta; | ||
2507 | int rate_idx; | ||
2508 | |||
2509 | IWL_DEBUG_RATE_LIMIT(mvm, "rate scale calculate new rate for skb\n"); | ||
2510 | |||
2511 | /* Get max rate if user set max rate */ | ||
2512 | if (lq_sta) { | ||
2513 | lq_sta->max_rate_idx = txrc->max_rate_idx; | ||
2514 | if ((sband->band == IEEE80211_BAND_5GHZ) && | ||
2515 | (lq_sta->max_rate_idx != -1)) | ||
2516 | lq_sta->max_rate_idx += IWL_FIRST_OFDM_RATE; | ||
2517 | if ((lq_sta->max_rate_idx < 0) || | ||
2518 | (lq_sta->max_rate_idx >= IWL_RATE_COUNT)) | ||
2519 | lq_sta->max_rate_idx = -1; | ||
2520 | } | ||
2521 | |||
2522 | /* Treat uninitialized rate scaling data same as non-existing. */ | ||
2523 | if (lq_sta && !lq_sta->drv) { | ||
2524 | IWL_DEBUG_RATE(mvm, "Rate scaling not initialized yet.\n"); | ||
2525 | mvm_sta = NULL; | ||
2526 | } | ||
2527 | |||
2528 | /* Send management frames and NO_ACK data using lowest rate. */ | ||
2529 | if (rate_control_send_low(sta, mvm_sta, txrc)) | ||
2530 | return; | ||
2531 | |||
2532 | rate_idx = lq_sta->last_txrate_idx; | ||
2533 | |||
2534 | if (lq_sta->last_rate_n_flags & RATE_MCS_HT_MSK) { | ||
2535 | rate_idx -= IWL_FIRST_OFDM_RATE; | ||
2536 | /* 6M and 9M shared same MCS index */ | ||
2537 | rate_idx = (rate_idx > 0) ? (rate_idx - 1) : 0; | ||
2538 | if (rs_extract_rate(lq_sta->last_rate_n_flags) >= | ||
2539 | IWL_RATE_MIMO3_6M_PLCP) | ||
2540 | rate_idx = rate_idx + (2 * MCS_INDEX_PER_STREAM); | ||
2541 | else if (rs_extract_rate(lq_sta->last_rate_n_flags) >= | ||
2542 | IWL_RATE_MIMO2_6M_PLCP) | ||
2543 | rate_idx = rate_idx + MCS_INDEX_PER_STREAM; | ||
2544 | info->control.rates[0].flags = IEEE80211_TX_RC_MCS; | ||
2545 | if (lq_sta->last_rate_n_flags & RATE_MCS_SGI_MSK) | ||
2546 | info->control.rates[0].flags |= IEEE80211_TX_RC_SHORT_GI; | ||
2547 | if (lq_sta->last_rate_n_flags & RATE_MCS_CHAN_WIDTH_40) /* TODO */ | ||
2548 | info->control.rates[0].flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; | ||
2549 | if (lq_sta->last_rate_n_flags & RATE_HT_MCS_GF_MSK) | ||
2550 | info->control.rates[0].flags |= IEEE80211_TX_RC_GREEN_FIELD; | ||
2551 | } else { | ||
2552 | /* Check for invalid rates */ | ||
2553 | if ((rate_idx < 0) || (rate_idx >= IWL_RATE_COUNT_LEGACY) || | ||
2554 | ((sband->band == IEEE80211_BAND_5GHZ) && | ||
2555 | (rate_idx < IWL_FIRST_OFDM_RATE))) | ||
2556 | rate_idx = rate_lowest_index(sband, sta); | ||
2557 | /* On valid 5 GHz rate, adjust index */ | ||
2558 | else if (sband->band == IEEE80211_BAND_5GHZ) | ||
2559 | rate_idx -= IWL_FIRST_OFDM_RATE; | ||
2560 | info->control.rates[0].flags = 0; | ||
2561 | } | ||
2562 | info->control.rates[0].idx = rate_idx; | ||
2563 | } | ||
2564 | |||
2565 | static void *rs_alloc_sta(void *mvm_rate, struct ieee80211_sta *sta, | ||
2566 | gfp_t gfp) | ||
2567 | { | ||
2568 | struct iwl_mvm_sta *sta_priv = (struct iwl_mvm_sta *)sta->drv_priv; | ||
2569 | struct iwl_op_mode *op_mode __maybe_unused = | ||
2570 | (struct iwl_op_mode *)mvm_rate; | ||
2571 | struct iwl_mvm *mvm __maybe_unused = IWL_OP_MODE_GET_MVM(op_mode); | ||
2572 | |||
2573 | IWL_DEBUG_RATE(mvm, "create station rate scale window\n"); | ||
2574 | |||
2575 | return &sta_priv->lq_sta; | ||
2576 | } | ||
2577 | |||
2578 | /* | ||
2579 | * Called after adding a new station to initialize rate scaling | ||
2580 | */ | ||
2581 | void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | ||
2582 | enum ieee80211_band band) | ||
2583 | { | ||
2584 | int i, j; | ||
2585 | struct ieee80211_hw *hw = mvm->hw; | ||
2586 | struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; | ||
2587 | struct iwl_mvm_sta *sta_priv; | ||
2588 | struct iwl_lq_sta *lq_sta; | ||
2589 | struct ieee80211_supported_band *sband; | ||
2590 | unsigned long supp; /* must be unsigned long for for_each_set_bit */ | ||
2591 | |||
2592 | sta_priv = (struct iwl_mvm_sta *)sta->drv_priv; | ||
2593 | lq_sta = &sta_priv->lq_sta; | ||
2594 | sband = hw->wiphy->bands[band]; | ||
2595 | |||
2596 | lq_sta->lq.sta_id = sta_priv->sta_id; | ||
2597 | |||
2598 | for (j = 0; j < LQ_SIZE; j++) | ||
2599 | for (i = 0; i < IWL_RATE_COUNT; i++) | ||
2600 | rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]); | ||
2601 | |||
2602 | lq_sta->flush_timer = 0; | ||
2603 | lq_sta->supp_rates = sta->supp_rates[sband->band]; | ||
2604 | for (j = 0; j < LQ_SIZE; j++) | ||
2605 | for (i = 0; i < IWL_RATE_COUNT; i++) | ||
2606 | rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]); | ||
2607 | |||
2608 | IWL_DEBUG_RATE(mvm, | ||
2609 | "LQ: *** rate scale station global init for station %d ***\n", | ||
2610 | sta_priv->sta_id); | ||
2611 | /* TODO: what is a good starting rate for STA? About middle? Maybe not | ||
2612 | * the lowest or the highest rate.. Could consider using RSSI from | ||
2613 | * previous packets? Need to have IEEE 802.1X auth succeed immediately | ||
2614 | * after assoc.. */ | ||
2615 | |||
2616 | lq_sta->max_rate_idx = -1; | ||
2617 | lq_sta->missed_rate_counter = IWL_MISSED_RATE_MAX; | ||
2618 | lq_sta->is_green = rs_use_green(sta); | ||
2619 | lq_sta->band = sband->band; | ||
2620 | /* | ||
2621 | * active legacy rates as per supported rates bitmap | ||
2622 | */ | ||
2623 | supp = sta->supp_rates[sband->band]; | ||
2624 | lq_sta->active_legacy_rate = 0; | ||
2625 | for_each_set_bit(i, &supp, BITS_PER_LONG) | ||
2626 | lq_sta->active_legacy_rate |= BIT(sband->bitrates[i].hw_value); | ||
2627 | |||
2628 | /* | ||
2629 | * active_siso_rate mask includes 9 MBits (bit 5), and CCK (bits 0-3), | ||
2630 | * supp_rates[] does not; shift to convert format, force 9 MBits off. | ||
2631 | */ | ||
2632 | lq_sta->active_siso_rate = ht_cap->mcs.rx_mask[0] << 1; | ||
2633 | lq_sta->active_siso_rate |= ht_cap->mcs.rx_mask[0] & 0x1; | ||
2634 | lq_sta->active_siso_rate &= ~((u16)0x2); | ||
2635 | lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE; | ||
2636 | |||
2637 | /* Same here */ | ||
2638 | lq_sta->active_mimo2_rate = ht_cap->mcs.rx_mask[1] << 1; | ||
2639 | lq_sta->active_mimo2_rate |= ht_cap->mcs.rx_mask[1] & 0x1; | ||
2640 | lq_sta->active_mimo2_rate &= ~((u16)0x2); | ||
2641 | lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE; | ||
2642 | |||
2643 | lq_sta->active_mimo3_rate = ht_cap->mcs.rx_mask[2] << 1; | ||
2644 | lq_sta->active_mimo3_rate |= ht_cap->mcs.rx_mask[2] & 0x1; | ||
2645 | lq_sta->active_mimo3_rate &= ~((u16)0x2); | ||
2646 | lq_sta->active_mimo3_rate <<= IWL_FIRST_OFDM_RATE; | ||
2647 | |||
2648 | IWL_DEBUG_RATE(mvm, | ||
2649 | "SISO-RATE=%X MIMO2-RATE=%X MIMO3-RATE=%X\n", | ||
2650 | lq_sta->active_siso_rate, | ||
2651 | lq_sta->active_mimo2_rate, | ||
2652 | lq_sta->active_mimo3_rate); | ||
2653 | |||
2654 | /* These values will be overridden later */ | ||
2655 | lq_sta->lq.single_stream_ant_msk = | ||
2656 | first_antenna(mvm->nvm_data->valid_tx_ant); | ||
2657 | lq_sta->lq.dual_stream_ant_msk = | ||
2658 | mvm->nvm_data->valid_tx_ant & | ||
2659 | ~first_antenna(mvm->nvm_data->valid_tx_ant); | ||
2660 | if (!lq_sta->lq.dual_stream_ant_msk) { | ||
2661 | lq_sta->lq.dual_stream_ant_msk = ANT_AB; | ||
2662 | } else if (num_of_ant(mvm->nvm_data->valid_tx_ant) == 2) { | ||
2663 | lq_sta->lq.dual_stream_ant_msk = | ||
2664 | mvm->nvm_data->valid_tx_ant; | ||
2665 | } | ||
2666 | |||
2667 | /* as default allow aggregation for all tids */ | ||
2668 | lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID; | ||
2669 | lq_sta->drv = mvm; | ||
2670 | |||
2671 | /* Set last_txrate_idx to lowest rate */ | ||
2672 | lq_sta->last_txrate_idx = rate_lowest_index(sband, sta); | ||
2673 | if (sband->band == IEEE80211_BAND_5GHZ) | ||
2674 | lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE; | ||
2675 | lq_sta->is_agg = 0; | ||
2676 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
2677 | lq_sta->dbg_fixed_rate = 0; | ||
2678 | #endif | ||
2679 | |||
2680 | rs_initialize_lq(mvm, sta, lq_sta, band); | ||
2681 | } | ||
2682 | |||
2683 | static void rs_fill_link_cmd(struct iwl_mvm *mvm, | ||
2684 | struct iwl_lq_sta *lq_sta, u32 new_rate) | ||
2685 | { | ||
2686 | struct iwl_scale_tbl_info tbl_type; | ||
2687 | int index = 0; | ||
2688 | int rate_idx; | ||
2689 | int repeat_rate = 0; | ||
2690 | u8 ant_toggle_cnt = 0; | ||
2691 | u8 use_ht_possible = 1; | ||
2692 | u8 valid_tx_ant = 0; | ||
2693 | struct iwl_lq_cmd *lq_cmd = &lq_sta->lq; | ||
2694 | |||
2695 | /* Override starting rate (index 0) if needed for debug purposes */ | ||
2696 | rs_dbgfs_set_mcs(lq_sta, &new_rate, index); | ||
2697 | |||
2698 | /* Interpret new_rate (rate_n_flags) */ | ||
2699 | rs_get_tbl_info_from_mcs(new_rate, lq_sta->band, | ||
2700 | &tbl_type, &rate_idx); | ||
2701 | |||
2702 | /* How many times should we repeat the initial rate? */ | ||
2703 | if (is_legacy(tbl_type.lq_type)) { | ||
2704 | ant_toggle_cnt = 1; | ||
2705 | repeat_rate = IWL_NUMBER_TRY; | ||
2706 | } else { | ||
2707 | repeat_rate = min(IWL_HT_NUMBER_TRY, | ||
2708 | LINK_QUAL_AGG_DISABLE_START_DEF - 1); | ||
2709 | } | ||
2710 | |||
2711 | lq_cmd->mimo_delim = is_mimo(tbl_type.lq_type) ? 1 : 0; | ||
2712 | |||
2713 | /* Fill 1st table entry (index 0) */ | ||
2714 | lq_cmd->rs_table[index] = cpu_to_le32(new_rate); | ||
2715 | |||
2716 | if (num_of_ant(tbl_type.ant_type) == 1) | ||
2717 | lq_cmd->single_stream_ant_msk = tbl_type.ant_type; | ||
2718 | else if (num_of_ant(tbl_type.ant_type) == 2) | ||
2719 | lq_cmd->dual_stream_ant_msk = tbl_type.ant_type; | ||
2720 | /* otherwise we don't modify the existing value */ | ||
2721 | |||
2722 | index++; | ||
2723 | repeat_rate--; | ||
2724 | if (mvm) | ||
2725 | valid_tx_ant = mvm->nvm_data->valid_tx_ant; | ||
2726 | |||
2727 | /* Fill rest of rate table */ | ||
2728 | while (index < LINK_QUAL_MAX_RETRY_NUM) { | ||
2729 | /* Repeat initial/next rate. | ||
2730 | * For legacy IWL_NUMBER_TRY == 1, this loop will not execute. | ||
2731 | * For HT IWL_HT_NUMBER_TRY == 3, this executes twice. */ | ||
2732 | while (repeat_rate > 0 && (index < LINK_QUAL_MAX_RETRY_NUM)) { | ||
2733 | if (is_legacy(tbl_type.lq_type)) { | ||
2734 | if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE) | ||
2735 | ant_toggle_cnt++; | ||
2736 | else if (mvm && | ||
2737 | rs_toggle_antenna(valid_tx_ant, | ||
2738 | &new_rate, &tbl_type)) | ||
2739 | ant_toggle_cnt = 1; | ||
2740 | } | ||
2741 | |||
2742 | /* Override next rate if needed for debug purposes */ | ||
2743 | rs_dbgfs_set_mcs(lq_sta, &new_rate, index); | ||
2744 | |||
2745 | /* Fill next table entry */ | ||
2746 | lq_cmd->rs_table[index] = | ||
2747 | cpu_to_le32(new_rate); | ||
2748 | repeat_rate--; | ||
2749 | index++; | ||
2750 | } | ||
2751 | |||
2752 | rs_get_tbl_info_from_mcs(new_rate, lq_sta->band, &tbl_type, | ||
2753 | &rate_idx); | ||
2754 | |||
2755 | |||
2756 | /* Indicate to uCode which entries might be MIMO. | ||
2757 | * If initial rate was MIMO, this will finally end up | ||
2758 | * as (IWL_HT_NUMBER_TRY * 2), after 2nd pass, otherwise 0. */ | ||
2759 | if (is_mimo(tbl_type.lq_type)) | ||
2760 | lq_cmd->mimo_delim = index; | ||
2761 | |||
2762 | /* Get next rate */ | ||
2763 | new_rate = rs_get_lower_rate(lq_sta, &tbl_type, rate_idx, | ||
2764 | use_ht_possible); | ||
2765 | |||
2766 | /* How many times should we repeat the next rate? */ | ||
2767 | if (is_legacy(tbl_type.lq_type)) { | ||
2768 | if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE) | ||
2769 | ant_toggle_cnt++; | ||
2770 | else if (mvm && | ||
2771 | rs_toggle_antenna(valid_tx_ant, | ||
2772 | &new_rate, &tbl_type)) | ||
2773 | ant_toggle_cnt = 1; | ||
2774 | |||
2775 | repeat_rate = IWL_NUMBER_TRY; | ||
2776 | } else { | ||
2777 | repeat_rate = IWL_HT_NUMBER_TRY; | ||
2778 | } | ||
2779 | |||
2780 | /* Don't allow HT rates after next pass. | ||
2781 | * rs_get_lower_rate() will change type to LQ_A or LQ_G. */ | ||
2782 | use_ht_possible = 0; | ||
2783 | |||
2784 | /* Override next rate if needed for debug purposes */ | ||
2785 | rs_dbgfs_set_mcs(lq_sta, &new_rate, index); | ||
2786 | |||
2787 | /* Fill next table entry */ | ||
2788 | lq_cmd->rs_table[index] = cpu_to_le32(new_rate); | ||
2789 | |||
2790 | index++; | ||
2791 | repeat_rate--; | ||
2792 | } | ||
2793 | |||
2794 | lq_cmd->agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_DEF; | ||
2795 | lq_cmd->agg_disable_start_th = LINK_QUAL_AGG_DISABLE_START_DEF; | ||
2796 | |||
2797 | lq_cmd->agg_time_limit = | ||
2798 | cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF); | ||
2799 | } | ||
2800 | |||
2801 | static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) | ||
2802 | { | ||
2803 | return hw->priv; | ||
2804 | } | ||
2805 | /* rate scale requires free function to be implemented */ | ||
2806 | static void rs_free(void *mvm_rate) | ||
2807 | { | ||
2808 | return; | ||
2809 | } | ||
2810 | |||
2811 | static void rs_free_sta(void *mvm_r, struct ieee80211_sta *sta, | ||
2812 | void *mvm_sta) | ||
2813 | { | ||
2814 | struct iwl_op_mode *op_mode __maybe_unused = mvm_r; | ||
2815 | struct iwl_mvm *mvm __maybe_unused = IWL_OP_MODE_GET_MVM(op_mode); | ||
2816 | |||
2817 | IWL_DEBUG_RATE(mvm, "enter\n"); | ||
2818 | IWL_DEBUG_RATE(mvm, "leave\n"); | ||
2819 | } | ||
2820 | |||
2821 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
2822 | static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta, | ||
2823 | u32 *rate_n_flags, int index) | ||
2824 | { | ||
2825 | struct iwl_mvm *mvm; | ||
2826 | u8 valid_tx_ant; | ||
2827 | u8 ant_sel_tx; | ||
2828 | |||
2829 | mvm = lq_sta->drv; | ||
2830 | valid_tx_ant = mvm->nvm_data->valid_tx_ant; | ||
2831 | if (lq_sta->dbg_fixed_rate) { | ||
2832 | ant_sel_tx = | ||
2833 | ((lq_sta->dbg_fixed_rate & RATE_MCS_ANT_ABC_MSK) | ||
2834 | >> RATE_MCS_ANT_POS); | ||
2835 | if ((valid_tx_ant & ant_sel_tx) == ant_sel_tx) { | ||
2836 | *rate_n_flags = lq_sta->dbg_fixed_rate; | ||
2837 | IWL_DEBUG_RATE(mvm, "Fixed rate ON\n"); | ||
2838 | } else { | ||
2839 | lq_sta->dbg_fixed_rate = 0; | ||
2840 | IWL_ERR(mvm, | ||
2841 | "Invalid antenna selection 0x%X, Valid is 0x%X\n", | ||
2842 | ant_sel_tx, valid_tx_ant); | ||
2843 | IWL_DEBUG_RATE(mvm, "Fixed rate OFF\n"); | ||
2844 | } | ||
2845 | } else { | ||
2846 | IWL_DEBUG_RATE(mvm, "Fixed rate OFF\n"); | ||
2847 | } | ||
2848 | } | ||
2849 | |||
2850 | static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file, | ||
2851 | const char __user *user_buf, size_t count, loff_t *ppos) | ||
2852 | { | ||
2853 | struct iwl_lq_sta *lq_sta = file->private_data; | ||
2854 | struct iwl_mvm *mvm; | ||
2855 | char buf[64]; | ||
2856 | size_t buf_size; | ||
2857 | u32 parsed_rate; | ||
2858 | |||
2859 | |||
2860 | mvm = lq_sta->drv; | ||
2861 | memset(buf, 0, sizeof(buf)); | ||
2862 | buf_size = min(count, sizeof(buf) - 1); | ||
2863 | if (copy_from_user(buf, user_buf, buf_size)) | ||
2864 | return -EFAULT; | ||
2865 | |||
2866 | if (sscanf(buf, "%x", &parsed_rate) == 1) | ||
2867 | lq_sta->dbg_fixed_rate = parsed_rate; | ||
2868 | else | ||
2869 | lq_sta->dbg_fixed_rate = 0; | ||
2870 | |||
2871 | rs_program_fix_rate(mvm, lq_sta); | ||
2872 | |||
2873 | return count; | ||
2874 | } | ||
2875 | |||
2876 | static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, | ||
2877 | char __user *user_buf, size_t count, loff_t *ppos) | ||
2878 | { | ||
2879 | char *buff; | ||
2880 | int desc = 0; | ||
2881 | int i = 0; | ||
2882 | int index = 0; | ||
2883 | ssize_t ret; | ||
2884 | |||
2885 | struct iwl_lq_sta *lq_sta = file->private_data; | ||
2886 | struct iwl_mvm *mvm; | ||
2887 | struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); | ||
2888 | |||
2889 | mvm = lq_sta->drv; | ||
2890 | buff = kmalloc(1024, GFP_KERNEL); | ||
2891 | if (!buff) | ||
2892 | return -ENOMEM; | ||
2893 | |||
2894 | desc += sprintf(buff+desc, "sta_id %d\n", lq_sta->lq.sta_id); | ||
2895 | desc += sprintf(buff+desc, "failed=%d success=%d rate=0%X\n", | ||
2896 | lq_sta->total_failed, lq_sta->total_success, | ||
2897 | lq_sta->active_legacy_rate); | ||
2898 | desc += sprintf(buff+desc, "fixed rate 0x%X\n", | ||
2899 | lq_sta->dbg_fixed_rate); | ||
2900 | desc += sprintf(buff+desc, "valid_tx_ant %s%s%s\n", | ||
2901 | (mvm->nvm_data->valid_tx_ant & ANT_A) ? "ANT_A," : "", | ||
2902 | (mvm->nvm_data->valid_tx_ant & ANT_B) ? "ANT_B," : "", | ||
2903 | (mvm->nvm_data->valid_tx_ant & ANT_C) ? "ANT_C" : ""); | ||
2904 | desc += sprintf(buff+desc, "lq type %s\n", | ||
2905 | (is_legacy(tbl->lq_type)) ? "legacy" : "HT"); | ||
2906 | if (is_Ht(tbl->lq_type)) { | ||
2907 | desc += sprintf(buff+desc, " %s", | ||
2908 | (is_siso(tbl->lq_type)) ? "SISO" : | ||
2909 | ((is_mimo2(tbl->lq_type)) ? "MIMO2" : "MIMO3")); | ||
2910 | desc += sprintf(buff+desc, " %s", | ||
2911 | (tbl->is_ht40) ? "40MHz" : "20MHz"); | ||
2912 | desc += sprintf(buff+desc, " %s %s %s\n", | ||
2913 | (tbl->is_SGI) ? "SGI" : "", | ||
2914 | (lq_sta->is_green) ? "GF enabled" : "", | ||
2915 | (lq_sta->is_agg) ? "AGG on" : ""); | ||
2916 | } | ||
2917 | desc += sprintf(buff+desc, "last tx rate=0x%X\n", | ||
2918 | lq_sta->last_rate_n_flags); | ||
2919 | desc += sprintf(buff+desc, | ||
2920 | "general: flags=0x%X mimo-d=%d s-ant0x%x d-ant=0x%x\n", | ||
2921 | lq_sta->lq.flags, | ||
2922 | lq_sta->lq.mimo_delim, | ||
2923 | lq_sta->lq.single_stream_ant_msk, | ||
2924 | lq_sta->lq.dual_stream_ant_msk); | ||
2925 | |||
2926 | desc += sprintf(buff+desc, | ||
2927 | "agg: time_limit=%d dist_start_th=%d frame_cnt_limit=%d\n", | ||
2928 | le16_to_cpu(lq_sta->lq.agg_time_limit), | ||
2929 | lq_sta->lq.agg_disable_start_th, | ||
2930 | lq_sta->lq.agg_frame_cnt_limit); | ||
2931 | |||
2932 | desc += sprintf(buff+desc, | ||
2933 | "Start idx [0]=0x%x [1]=0x%x [2]=0x%x [3]=0x%x\n", | ||
2934 | lq_sta->lq.initial_rate_index[0], | ||
2935 | lq_sta->lq.initial_rate_index[1], | ||
2936 | lq_sta->lq.initial_rate_index[2], | ||
2937 | lq_sta->lq.initial_rate_index[3]); | ||
2938 | |||
2939 | for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) { | ||
2940 | index = iwl_hwrate_to_plcp_idx( | ||
2941 | le32_to_cpu(lq_sta->lq.rs_table[i])); | ||
2942 | if (is_legacy(tbl->lq_type)) { | ||
2943 | desc += sprintf(buff+desc, " rate[%d] 0x%X %smbps\n", | ||
2944 | i, le32_to_cpu(lq_sta->lq.rs_table[i]), | ||
2945 | iwl_rate_mcs[index].mbps); | ||
2946 | } else { | ||
2947 | desc += sprintf(buff+desc, | ||
2948 | " rate[%d] 0x%X %smbps (%s)\n", | ||
2949 | i, le32_to_cpu(lq_sta->lq.rs_table[i]), | ||
2950 | iwl_rate_mcs[index].mbps, | ||
2951 | iwl_rate_mcs[index].mcs); | ||
2952 | } | ||
2953 | } | ||
2954 | |||
2955 | ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc); | ||
2956 | kfree(buff); | ||
2957 | return ret; | ||
2958 | } | ||
2959 | |||
2960 | static const struct file_operations rs_sta_dbgfs_scale_table_ops = { | ||
2961 | .write = rs_sta_dbgfs_scale_table_write, | ||
2962 | .read = rs_sta_dbgfs_scale_table_read, | ||
2963 | .open = simple_open, | ||
2964 | .llseek = default_llseek, | ||
2965 | }; | ||
2966 | static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file, | ||
2967 | char __user *user_buf, size_t count, loff_t *ppos) | ||
2968 | { | ||
2969 | char *buff; | ||
2970 | int desc = 0; | ||
2971 | int i, j; | ||
2972 | ssize_t ret; | ||
2973 | |||
2974 | struct iwl_lq_sta *lq_sta = file->private_data; | ||
2975 | |||
2976 | buff = kmalloc(1024, GFP_KERNEL); | ||
2977 | if (!buff) | ||
2978 | return -ENOMEM; | ||
2979 | |||
2980 | for (i = 0; i < LQ_SIZE; i++) { | ||
2981 | desc += sprintf(buff+desc, | ||
2982 | "%s type=%d SGI=%d HT40=%d DUP=0 GF=%d\n" | ||
2983 | "rate=0x%X\n", | ||
2984 | lq_sta->active_tbl == i ? "*" : "x", | ||
2985 | lq_sta->lq_info[i].lq_type, | ||
2986 | lq_sta->lq_info[i].is_SGI, | ||
2987 | lq_sta->lq_info[i].is_ht40, | ||
2988 | lq_sta->is_green, | ||
2989 | lq_sta->lq_info[i].current_rate); | ||
2990 | for (j = 0; j < IWL_RATE_COUNT; j++) { | ||
2991 | desc += sprintf(buff+desc, | ||
2992 | "counter=%d success=%d %%=%d\n", | ||
2993 | lq_sta->lq_info[i].win[j].counter, | ||
2994 | lq_sta->lq_info[i].win[j].success_counter, | ||
2995 | lq_sta->lq_info[i].win[j].success_ratio); | ||
2996 | } | ||
2997 | } | ||
2998 | ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc); | ||
2999 | kfree(buff); | ||
3000 | return ret; | ||
3001 | } | ||
3002 | |||
3003 | static const struct file_operations rs_sta_dbgfs_stats_table_ops = { | ||
3004 | .read = rs_sta_dbgfs_stats_table_read, | ||
3005 | .open = simple_open, | ||
3006 | .llseek = default_llseek, | ||
3007 | }; | ||
3008 | |||
3009 | static ssize_t rs_sta_dbgfs_rate_scale_data_read(struct file *file, | ||
3010 | char __user *user_buf, size_t count, loff_t *ppos) | ||
3011 | { | ||
3012 | struct iwl_lq_sta *lq_sta = file->private_data; | ||
3013 | struct iwl_scale_tbl_info *tbl = &lq_sta->lq_info[lq_sta->active_tbl]; | ||
3014 | char buff[120]; | ||
3015 | int desc = 0; | ||
3016 | |||
3017 | if (is_Ht(tbl->lq_type)) | ||
3018 | desc += sprintf(buff+desc, | ||
3019 | "Bit Rate= %d Mb/s\n", | ||
3020 | tbl->expected_tpt[lq_sta->last_txrate_idx]); | ||
3021 | else | ||
3022 | desc += sprintf(buff+desc, | ||
3023 | "Bit Rate= %d Mb/s\n", | ||
3024 | iwl_rates[lq_sta->last_txrate_idx].ieee >> 1); | ||
3025 | |||
3026 | return simple_read_from_buffer(user_buf, count, ppos, buff, desc); | ||
3027 | } | ||
3028 | |||
3029 | static const struct file_operations rs_sta_dbgfs_rate_scale_data_ops = { | ||
3030 | .read = rs_sta_dbgfs_rate_scale_data_read, | ||
3031 | .open = simple_open, | ||
3032 | .llseek = default_llseek, | ||
3033 | }; | ||
3034 | |||
3035 | static void rs_add_debugfs(void *mvm, void *mvm_sta, struct dentry *dir) | ||
3036 | { | ||
3037 | struct iwl_lq_sta *lq_sta = mvm_sta; | ||
3038 | lq_sta->rs_sta_dbgfs_scale_table_file = | ||
3039 | debugfs_create_file("rate_scale_table", S_IRUSR | S_IWUSR, dir, | ||
3040 | lq_sta, &rs_sta_dbgfs_scale_table_ops); | ||
3041 | lq_sta->rs_sta_dbgfs_stats_table_file = | ||
3042 | debugfs_create_file("rate_stats_table", S_IRUSR, dir, | ||
3043 | lq_sta, &rs_sta_dbgfs_stats_table_ops); | ||
3044 | lq_sta->rs_sta_dbgfs_rate_scale_data_file = | ||
3045 | debugfs_create_file("rate_scale_data", S_IRUSR, dir, | ||
3046 | lq_sta, &rs_sta_dbgfs_rate_scale_data_ops); | ||
3047 | lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file = | ||
3048 | debugfs_create_u8("tx_agg_tid_enable", S_IRUSR | S_IWUSR, dir, | ||
3049 | &lq_sta->tx_agg_tid_en); | ||
3050 | } | ||
3051 | |||
3052 | static void rs_remove_debugfs(void *mvm, void *mvm_sta) | ||
3053 | { | ||
3054 | struct iwl_lq_sta *lq_sta = mvm_sta; | ||
3055 | debugfs_remove(lq_sta->rs_sta_dbgfs_scale_table_file); | ||
3056 | debugfs_remove(lq_sta->rs_sta_dbgfs_stats_table_file); | ||
3057 | debugfs_remove(lq_sta->rs_sta_dbgfs_rate_scale_data_file); | ||
3058 | debugfs_remove(lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file); | ||
3059 | } | ||
3060 | #endif | ||
3061 | |||
3062 | /* | ||
3063 | * Initialization of rate scaling information is done by driver after | ||
3064 | * the station is added. Since mac80211 calls this function before a | ||
3065 | * station is added we ignore it. | ||
3066 | */ | ||
3067 | static void rs_rate_init_stub(void *mvm_r, | ||
3068 | struct ieee80211_supported_band *sband, | ||
3069 | struct ieee80211_sta *sta, void *mvm_sta) | ||
3070 | { | ||
3071 | } | ||
3072 | static struct rate_control_ops rs_mvm_ops = { | ||
3073 | .module = NULL, | ||
3074 | .name = RS_NAME, | ||
3075 | .tx_status = rs_tx_status, | ||
3076 | .get_rate = rs_get_rate, | ||
3077 | .rate_init = rs_rate_init_stub, | ||
3078 | .alloc = rs_alloc, | ||
3079 | .free = rs_free, | ||
3080 | .alloc_sta = rs_alloc_sta, | ||
3081 | .free_sta = rs_free_sta, | ||
3082 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
3083 | .add_sta_debugfs = rs_add_debugfs, | ||
3084 | .remove_sta_debugfs = rs_remove_debugfs, | ||
3085 | #endif | ||
3086 | }; | ||
3087 | |||
3088 | int iwl_mvm_rate_control_register(void) | ||
3089 | { | ||
3090 | return ieee80211_rate_control_register(&rs_mvm_ops); | ||
3091 | } | ||
3092 | |||
3093 | void iwl_mvm_rate_control_unregister(void) | ||
3094 | { | ||
3095 | ieee80211_rate_control_unregister(&rs_mvm_ops); | ||
3096 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h new file mode 100644 index 000000000000..219c6857cc0f --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h | |||
@@ -0,0 +1,393 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of version 2 of the GNU General Public License as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program; if not, write to the Free Software Foundation, Inc., | ||
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA | ||
17 | * | ||
18 | * The full GNU General Public License is included in this distribution in the | ||
19 | * file called LICENSE. | ||
20 | * | ||
21 | * Contact Information: | ||
22 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
23 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
24 | * | ||
25 | *****************************************************************************/ | ||
26 | |||
27 | #ifndef __rs_h__ | ||
28 | #define __rs_h__ | ||
29 | |||
30 | #include <net/mac80211.h> | ||
31 | |||
32 | #include "iwl-config.h" | ||
33 | |||
34 | #include "fw-api.h" | ||
35 | #include "iwl-trans.h" | ||
36 | |||
37 | struct iwl_rs_rate_info { | ||
38 | u8 plcp; /* uCode API: IWL_RATE_6M_PLCP, etc. */ | ||
39 | u8 plcp_siso; /* uCode API: IWL_RATE_SISO_6M_PLCP, etc. */ | ||
40 | u8 plcp_mimo2; /* uCode API: IWL_RATE_MIMO2_6M_PLCP, etc. */ | ||
41 | u8 plcp_mimo3; /* uCode API: IWL_RATE_MIMO3_6M_PLCP, etc. */ | ||
42 | u8 ieee; /* MAC header: IWL_RATE_6M_IEEE, etc. */ | ||
43 | u8 prev_ieee; /* previous rate in IEEE speeds */ | ||
44 | u8 next_ieee; /* next rate in IEEE speeds */ | ||
45 | u8 prev_rs; /* previous rate used in rs algo */ | ||
46 | u8 next_rs; /* next rate used in rs algo */ | ||
47 | u8 prev_rs_tgg; /* previous rate used in TGG rs algo */ | ||
48 | u8 next_rs_tgg; /* next rate used in TGG rs algo */ | ||
49 | }; | ||
50 | |||
51 | #define IWL_RATE_60M_PLCP 3 | ||
52 | |||
53 | enum { | ||
54 | IWL_RATE_INVM_INDEX = IWL_RATE_COUNT, | ||
55 | IWL_RATE_INVALID = IWL_RATE_COUNT, | ||
56 | }; | ||
57 | |||
58 | #define LINK_QUAL_MAX_RETRY_NUM 16 | ||
59 | |||
60 | enum { | ||
61 | IWL_RATE_6M_INDEX_TABLE = 0, | ||
62 | IWL_RATE_9M_INDEX_TABLE, | ||
63 | IWL_RATE_12M_INDEX_TABLE, | ||
64 | IWL_RATE_18M_INDEX_TABLE, | ||
65 | IWL_RATE_24M_INDEX_TABLE, | ||
66 | IWL_RATE_36M_INDEX_TABLE, | ||
67 | IWL_RATE_48M_INDEX_TABLE, | ||
68 | IWL_RATE_54M_INDEX_TABLE, | ||
69 | IWL_RATE_1M_INDEX_TABLE, | ||
70 | IWL_RATE_2M_INDEX_TABLE, | ||
71 | IWL_RATE_5M_INDEX_TABLE, | ||
72 | IWL_RATE_11M_INDEX_TABLE, | ||
73 | IWL_RATE_INVM_INDEX_TABLE = IWL_RATE_INVM_INDEX - 1, | ||
74 | }; | ||
75 | |||
76 | /* #define vs. enum to keep from defaulting to 'large integer' */ | ||
77 | #define IWL_RATE_6M_MASK (1 << IWL_RATE_6M_INDEX) | ||
78 | #define IWL_RATE_9M_MASK (1 << IWL_RATE_9M_INDEX) | ||
79 | #define IWL_RATE_12M_MASK (1 << IWL_RATE_12M_INDEX) | ||
80 | #define IWL_RATE_18M_MASK (1 << IWL_RATE_18M_INDEX) | ||
81 | #define IWL_RATE_24M_MASK (1 << IWL_RATE_24M_INDEX) | ||
82 | #define IWL_RATE_36M_MASK (1 << IWL_RATE_36M_INDEX) | ||
83 | #define IWL_RATE_48M_MASK (1 << IWL_RATE_48M_INDEX) | ||
84 | #define IWL_RATE_54M_MASK (1 << IWL_RATE_54M_INDEX) | ||
85 | #define IWL_RATE_60M_MASK (1 << IWL_RATE_60M_INDEX) | ||
86 | #define IWL_RATE_1M_MASK (1 << IWL_RATE_1M_INDEX) | ||
87 | #define IWL_RATE_2M_MASK (1 << IWL_RATE_2M_INDEX) | ||
88 | #define IWL_RATE_5M_MASK (1 << IWL_RATE_5M_INDEX) | ||
89 | #define IWL_RATE_11M_MASK (1 << IWL_RATE_11M_INDEX) | ||
90 | |||
91 | |||
92 | /* uCode API values for OFDM high-throughput (HT) bit rates */ | ||
93 | enum { | ||
94 | IWL_RATE_SISO_6M_PLCP = 0, | ||
95 | IWL_RATE_SISO_12M_PLCP = 1, | ||
96 | IWL_RATE_SISO_18M_PLCP = 2, | ||
97 | IWL_RATE_SISO_24M_PLCP = 3, | ||
98 | IWL_RATE_SISO_36M_PLCP = 4, | ||
99 | IWL_RATE_SISO_48M_PLCP = 5, | ||
100 | IWL_RATE_SISO_54M_PLCP = 6, | ||
101 | IWL_RATE_SISO_60M_PLCP = 7, | ||
102 | IWL_RATE_MIMO2_6M_PLCP = 0x8, | ||
103 | IWL_RATE_MIMO2_12M_PLCP = 0x9, | ||
104 | IWL_RATE_MIMO2_18M_PLCP = 0xa, | ||
105 | IWL_RATE_MIMO2_24M_PLCP = 0xb, | ||
106 | IWL_RATE_MIMO2_36M_PLCP = 0xc, | ||
107 | IWL_RATE_MIMO2_48M_PLCP = 0xd, | ||
108 | IWL_RATE_MIMO2_54M_PLCP = 0xe, | ||
109 | IWL_RATE_MIMO2_60M_PLCP = 0xf, | ||
110 | IWL_RATE_MIMO3_6M_PLCP = 0x10, | ||
111 | IWL_RATE_MIMO3_12M_PLCP = 0x11, | ||
112 | IWL_RATE_MIMO3_18M_PLCP = 0x12, | ||
113 | IWL_RATE_MIMO3_24M_PLCP = 0x13, | ||
114 | IWL_RATE_MIMO3_36M_PLCP = 0x14, | ||
115 | IWL_RATE_MIMO3_48M_PLCP = 0x15, | ||
116 | IWL_RATE_MIMO3_54M_PLCP = 0x16, | ||
117 | IWL_RATE_MIMO3_60M_PLCP = 0x17, | ||
118 | IWL_RATE_SISO_INVM_PLCP, | ||
119 | IWL_RATE_MIMO2_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP, | ||
120 | IWL_RATE_MIMO3_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP, | ||
121 | }; | ||
122 | |||
123 | /* MAC header values for bit rates */ | ||
124 | enum { | ||
125 | IWL_RATE_6M_IEEE = 12, | ||
126 | IWL_RATE_9M_IEEE = 18, | ||
127 | IWL_RATE_12M_IEEE = 24, | ||
128 | IWL_RATE_18M_IEEE = 36, | ||
129 | IWL_RATE_24M_IEEE = 48, | ||
130 | IWL_RATE_36M_IEEE = 72, | ||
131 | IWL_RATE_48M_IEEE = 96, | ||
132 | IWL_RATE_54M_IEEE = 108, | ||
133 | IWL_RATE_60M_IEEE = 120, | ||
134 | IWL_RATE_1M_IEEE = 2, | ||
135 | IWL_RATE_2M_IEEE = 4, | ||
136 | IWL_RATE_5M_IEEE = 11, | ||
137 | IWL_RATE_11M_IEEE = 22, | ||
138 | }; | ||
139 | |||
140 | #define IWL_RATES_MASK ((1 << IWL_RATE_COUNT) - 1) | ||
141 | |||
142 | #define IWL_INVALID_VALUE -1 | ||
143 | |||
144 | #define IWL_MIN_RSSI_VAL -100 | ||
145 | #define IWL_MAX_RSSI_VAL 0 | ||
146 | |||
147 | /* These values specify how many Tx frame attempts before | ||
148 | * searching for a new modulation mode */ | ||
149 | #define IWL_LEGACY_FAILURE_LIMIT 160 | ||
150 | #define IWL_LEGACY_SUCCESS_LIMIT 480 | ||
151 | #define IWL_LEGACY_TABLE_COUNT 160 | ||
152 | |||
153 | #define IWL_NONE_LEGACY_FAILURE_LIMIT 400 | ||
154 | #define IWL_NONE_LEGACY_SUCCESS_LIMIT 4500 | ||
155 | #define IWL_NONE_LEGACY_TABLE_COUNT 1500 | ||
156 | |||
157 | /* Success ratio (ACKed / attempted tx frames) values (perfect is 128 * 100) */ | ||
158 | #define IWL_RS_GOOD_RATIO 12800 /* 100% */ | ||
159 | #define IWL_RATE_SCALE_SWITCH 10880 /* 85% */ | ||
160 | #define IWL_RATE_HIGH_TH 10880 /* 85% */ | ||
161 | #define IWL_RATE_INCREASE_TH 6400 /* 50% */ | ||
162 | #define IWL_RATE_DECREASE_TH 1920 /* 15% */ | ||
163 | |||
164 | /* possible actions when in legacy mode */ | ||
165 | #define IWL_LEGACY_SWITCH_ANTENNA1 0 | ||
166 | #define IWL_LEGACY_SWITCH_ANTENNA2 1 | ||
167 | #define IWL_LEGACY_SWITCH_SISO 2 | ||
168 | #define IWL_LEGACY_SWITCH_MIMO2_AB 3 | ||
169 | #define IWL_LEGACY_SWITCH_MIMO2_AC 4 | ||
170 | #define IWL_LEGACY_SWITCH_MIMO2_BC 5 | ||
171 | #define IWL_LEGACY_SWITCH_MIMO3_ABC 6 | ||
172 | |||
173 | /* possible actions when in siso mode */ | ||
174 | #define IWL_SISO_SWITCH_ANTENNA1 0 | ||
175 | #define IWL_SISO_SWITCH_ANTENNA2 1 | ||
176 | #define IWL_SISO_SWITCH_MIMO2_AB 2 | ||
177 | #define IWL_SISO_SWITCH_MIMO2_AC 3 | ||
178 | #define IWL_SISO_SWITCH_MIMO2_BC 4 | ||
179 | #define IWL_SISO_SWITCH_GI 5 | ||
180 | #define IWL_SISO_SWITCH_MIMO3_ABC 6 | ||
181 | |||
182 | |||
183 | /* possible actions when in mimo mode */ | ||
184 | #define IWL_MIMO2_SWITCH_ANTENNA1 0 | ||
185 | #define IWL_MIMO2_SWITCH_ANTENNA2 1 | ||
186 | #define IWL_MIMO2_SWITCH_SISO_A 2 | ||
187 | #define IWL_MIMO2_SWITCH_SISO_B 3 | ||
188 | #define IWL_MIMO2_SWITCH_SISO_C 4 | ||
189 | #define IWL_MIMO2_SWITCH_GI 5 | ||
190 | #define IWL_MIMO2_SWITCH_MIMO3_ABC 6 | ||
191 | |||
192 | |||
193 | /* possible actions when in mimo3 mode */ | ||
194 | #define IWL_MIMO3_SWITCH_ANTENNA1 0 | ||
195 | #define IWL_MIMO3_SWITCH_ANTENNA2 1 | ||
196 | #define IWL_MIMO3_SWITCH_SISO_A 2 | ||
197 | #define IWL_MIMO3_SWITCH_SISO_B 3 | ||
198 | #define IWL_MIMO3_SWITCH_SISO_C 4 | ||
199 | #define IWL_MIMO3_SWITCH_MIMO2_AB 5 | ||
200 | #define IWL_MIMO3_SWITCH_MIMO2_AC 6 | ||
201 | #define IWL_MIMO3_SWITCH_MIMO2_BC 7 | ||
202 | #define IWL_MIMO3_SWITCH_GI 8 | ||
203 | |||
204 | |||
205 | #define IWL_MAX_11N_MIMO3_SEARCH IWL_MIMO3_SWITCH_GI | ||
206 | #define IWL_MAX_SEARCH IWL_MIMO2_SWITCH_MIMO3_ABC | ||
207 | |||
208 | /*FIXME:RS:add possible actions for MIMO3*/ | ||
209 | |||
210 | #define IWL_ACTION_LIMIT 3 /* # possible actions */ | ||
211 | |||
212 | #define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000) /* 4 milliseconds */ | ||
213 | #define LINK_QUAL_AGG_TIME_LIMIT_MAX (8000) | ||
214 | #define LINK_QUAL_AGG_TIME_LIMIT_MIN (100) | ||
215 | |||
216 | #define LINK_QUAL_AGG_DISABLE_START_DEF (3) | ||
217 | #define LINK_QUAL_AGG_DISABLE_START_MAX (255) | ||
218 | #define LINK_QUAL_AGG_DISABLE_START_MIN (0) | ||
219 | |||
220 | #define LINK_QUAL_AGG_FRAME_LIMIT_DEF (63) | ||
221 | #define LINK_QUAL_AGG_FRAME_LIMIT_MAX (63) | ||
222 | #define LINK_QUAL_AGG_FRAME_LIMIT_MIN (0) | ||
223 | |||
224 | #define LQ_SIZE 2 /* 2 mode tables: "Active" and "Search" */ | ||
225 | |||
226 | /* load per tid defines for A-MPDU activation */ | ||
227 | #define IWL_AGG_TPT_THREHOLD 0 | ||
228 | #define IWL_AGG_LOAD_THRESHOLD 10 | ||
229 | #define IWL_AGG_ALL_TID 0xff | ||
230 | #define TID_QUEUE_CELL_SPACING 50 /*mS */ | ||
231 | #define TID_QUEUE_MAX_SIZE 20 | ||
232 | #define TID_ROUND_VALUE 5 /* mS */ | ||
233 | |||
234 | #define TID_MAX_TIME_DIFF ((TID_QUEUE_MAX_SIZE - 1) * TID_QUEUE_CELL_SPACING) | ||
235 | #define TIME_WRAP_AROUND(x, y) (((y) > (x)) ? (y) - (x) : (0-(x)) + (y)) | ||
236 | |||
237 | enum iwl_table_type { | ||
238 | LQ_NONE, | ||
239 | LQ_G, /* legacy types */ | ||
240 | LQ_A, | ||
241 | LQ_SISO, /* high-throughput types */ | ||
242 | LQ_MIMO2, | ||
243 | LQ_MIMO3, | ||
244 | LQ_MAX, | ||
245 | }; | ||
246 | |||
247 | #define is_legacy(tbl) (((tbl) == LQ_G) || ((tbl) == LQ_A)) | ||
248 | #define is_siso(tbl) ((tbl) == LQ_SISO) | ||
249 | #define is_mimo2(tbl) ((tbl) == LQ_MIMO2) | ||
250 | #define is_mimo3(tbl) ((tbl) == LQ_MIMO3) | ||
251 | #define is_mimo(tbl) (is_mimo2(tbl) || is_mimo3(tbl)) | ||
252 | #define is_Ht(tbl) (is_siso(tbl) || is_mimo(tbl)) | ||
253 | #define is_a_band(tbl) ((tbl) == LQ_A) | ||
254 | #define is_g_and(tbl) ((tbl) == LQ_G) | ||
255 | |||
256 | #define IWL_MAX_MCS_DISPLAY_SIZE 12 | ||
257 | |||
258 | struct iwl_rate_mcs_info { | ||
259 | char mbps[IWL_MAX_MCS_DISPLAY_SIZE]; | ||
260 | char mcs[IWL_MAX_MCS_DISPLAY_SIZE]; | ||
261 | }; | ||
262 | |||
263 | /** | ||
264 | * struct iwl_rate_scale_data -- tx success history for one rate | ||
265 | */ | ||
266 | struct iwl_rate_scale_data { | ||
267 | u64 data; /* bitmap of successful frames */ | ||
268 | s32 success_counter; /* number of frames successful */ | ||
269 | s32 success_ratio; /* per-cent * 128 */ | ||
270 | s32 counter; /* number of frames attempted */ | ||
271 | s32 average_tpt; /* success ratio * expected throughput */ | ||
272 | unsigned long stamp; | ||
273 | }; | ||
274 | |||
275 | /** | ||
276 | * struct iwl_scale_tbl_info -- tx params and success history for all rates | ||
277 | * | ||
278 | * There are two of these in struct iwl_lq_sta, | ||
279 | * one for "active", and one for "search". | ||
280 | */ | ||
281 | struct iwl_scale_tbl_info { | ||
282 | enum iwl_table_type lq_type; | ||
283 | u8 ant_type; | ||
284 | u8 is_SGI; /* 1 = short guard interval */ | ||
285 | u8 is_ht40; /* 1 = 40 MHz channel width */ | ||
286 | u8 action; /* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */ | ||
287 | u8 max_search; /* maximun number of tables we can search */ | ||
288 | s32 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */ | ||
289 | u32 current_rate; /* rate_n_flags, uCode API format */ | ||
290 | struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */ | ||
291 | }; | ||
292 | |||
293 | struct iwl_traffic_load { | ||
294 | unsigned long time_stamp; /* age of the oldest statistics */ | ||
295 | u32 packet_count[TID_QUEUE_MAX_SIZE]; /* packet count in this time | ||
296 | * slice */ | ||
297 | u32 total; /* total num of packets during the | ||
298 | * last TID_MAX_TIME_DIFF */ | ||
299 | u8 queue_count; /* number of queues that has | ||
300 | * been used since the last cleanup */ | ||
301 | u8 head; /* start of the circular buffer */ | ||
302 | }; | ||
303 | |||
304 | /** | ||
305 | * struct iwl_lq_sta -- driver's rate scaling private structure | ||
306 | * | ||
307 | * Pointer to this gets passed back and forth between driver and mac80211. | ||
308 | */ | ||
309 | struct iwl_lq_sta { | ||
310 | u8 active_tbl; /* index of active table, range 0-1 */ | ||
311 | u8 enable_counter; /* indicates HT mode */ | ||
312 | u8 stay_in_tbl; /* 1: disallow, 0: allow search for new mode */ | ||
313 | u8 search_better_tbl; /* 1: currently trying alternate mode */ | ||
314 | s32 last_tpt; | ||
315 | |||
316 | /* The following determine when to search for a new mode */ | ||
317 | u32 table_count_limit; | ||
318 | u32 max_failure_limit; /* # failed frames before new search */ | ||
319 | u32 max_success_limit; /* # successful frames before new search */ | ||
320 | u32 table_count; | ||
321 | u32 total_failed; /* total failed frames, any/all rates */ | ||
322 | u32 total_success; /* total successful frames, any/all rates */ | ||
323 | u64 flush_timer; /* time staying in mode before new search */ | ||
324 | |||
325 | u8 action_counter; /* # mode-switch actions tried */ | ||
326 | u8 is_green; | ||
327 | enum ieee80211_band band; | ||
328 | |||
329 | /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */ | ||
330 | u32 supp_rates; | ||
331 | u16 active_legacy_rate; | ||
332 | u16 active_siso_rate; | ||
333 | u16 active_mimo2_rate; | ||
334 | u16 active_mimo3_rate; | ||
335 | s8 max_rate_idx; /* Max rate set by user */ | ||
336 | u8 missed_rate_counter; | ||
337 | |||
338 | struct iwl_lq_cmd lq; | ||
339 | struct iwl_scale_tbl_info lq_info[LQ_SIZE]; /* "active", "search" */ | ||
340 | struct iwl_traffic_load load[IWL_MAX_TID_COUNT]; | ||
341 | u8 tx_agg_tid_en; | ||
342 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
343 | struct dentry *rs_sta_dbgfs_scale_table_file; | ||
344 | struct dentry *rs_sta_dbgfs_stats_table_file; | ||
345 | struct dentry *rs_sta_dbgfs_rate_scale_data_file; | ||
346 | struct dentry *rs_sta_dbgfs_tx_agg_tid_en_file; | ||
347 | u32 dbg_fixed_rate; | ||
348 | #endif | ||
349 | struct iwl_mvm *drv; | ||
350 | |||
351 | /* used to be in sta_info */ | ||
352 | int last_txrate_idx; | ||
353 | /* last tx rate_n_flags */ | ||
354 | u32 last_rate_n_flags; | ||
355 | /* packets destined for this STA are aggregated */ | ||
356 | u8 is_agg; | ||
357 | /* BT traffic this sta was last updated in */ | ||
358 | u8 last_bt_traffic; | ||
359 | }; | ||
360 | |||
361 | static inline u8 num_of_ant(u8 mask) | ||
362 | { | ||
363 | return !!((mask) & ANT_A) + | ||
364 | !!((mask) & ANT_B) + | ||
365 | !!((mask) & ANT_C); | ||
366 | } | ||
367 | |||
368 | /* Initialize station's rate scaling information after adding station */ | ||
369 | extern void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, | ||
370 | struct ieee80211_sta *sta, | ||
371 | enum ieee80211_band band); | ||
372 | |||
373 | /** | ||
374 | * iwl_rate_control_register - Register the rate control algorithm callbacks | ||
375 | * | ||
376 | * Since the rate control algorithm is hardware specific, there is no need | ||
377 | * or reason to place it as a stand alone module. The driver can call | ||
378 | * iwl_rate_control_register in order to register the rate control callbacks | ||
379 | * with the mac80211 subsystem. This should be performed prior to calling | ||
380 | * ieee80211_register_hw | ||
381 | * | ||
382 | */ | ||
383 | extern int iwl_mvm_rate_control_register(void); | ||
384 | |||
385 | /** | ||
386 | * iwl_rate_control_unregister - Unregister the rate control callbacks | ||
387 | * | ||
388 | * This should be called after calling ieee80211_unregister_hw, but before | ||
389 | * the driver is unloaded. | ||
390 | */ | ||
391 | extern void iwl_mvm_rate_control_unregister(void); | ||
392 | |||
393 | #endif /* __rs__ */ | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c new file mode 100644 index 000000000000..52da375e5740 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c | |||
@@ -0,0 +1,355 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called LICENSE.GPL. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | *****************************************************************************/ | ||
62 | #include "iwl-trans.h" | ||
63 | |||
64 | #include "mvm.h" | ||
65 | #include "fw-api.h" | ||
66 | |||
67 | /* | ||
68 | * iwl_mvm_rx_rx_phy_cmd - REPLY_RX_PHY_CMD handler | ||
69 | * | ||
70 | * Copies the phy information in mvm->last_phy_info, it will be used when the | ||
71 | * actual data will come from the fw in the next packet. | ||
72 | */ | ||
73 | int iwl_mvm_rx_rx_phy_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | ||
74 | struct iwl_device_cmd *cmd) | ||
75 | { | ||
76 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
77 | |||
78 | memcpy(&mvm->last_phy_info, pkt->data, sizeof(mvm->last_phy_info)); | ||
79 | mvm->ampdu_ref++; | ||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | /* | ||
84 | * iwl_mvm_pass_packet_to_mac80211 - builds the packet for mac80211 | ||
85 | * | ||
86 | * Adds the rxb to a new skb and give it to mac80211 | ||
87 | */ | ||
88 | static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm, | ||
89 | struct ieee80211_hdr *hdr, u16 len, | ||
90 | u32 ampdu_status, | ||
91 | struct iwl_rx_cmd_buffer *rxb, | ||
92 | struct ieee80211_rx_status *stats) | ||
93 | { | ||
94 | struct sk_buff *skb; | ||
95 | unsigned int hdrlen, fraglen; | ||
96 | |||
97 | /* Dont use dev_alloc_skb(), we'll have enough headroom once | ||
98 | * ieee80211_hdr pulled. | ||
99 | */ | ||
100 | skb = alloc_skb(128, GFP_ATOMIC); | ||
101 | if (!skb) { | ||
102 | IWL_ERR(mvm, "alloc_skb failed\n"); | ||
103 | return; | ||
104 | } | ||
105 | /* If frame is small enough to fit in skb->head, pull it completely. | ||
106 | * If not, only pull ieee80211_hdr so that splice() or TCP coalesce | ||
107 | * are more efficient. | ||
108 | */ | ||
109 | hdrlen = (len <= skb_tailroom(skb)) ? len : sizeof(*hdr); | ||
110 | |||
111 | memcpy(skb_put(skb, hdrlen), hdr, hdrlen); | ||
112 | fraglen = len - hdrlen; | ||
113 | |||
114 | if (fraglen) { | ||
115 | int offset = (void *)hdr + hdrlen - | ||
116 | rxb_addr(rxb) + rxb_offset(rxb); | ||
117 | |||
118 | skb_add_rx_frag(skb, 0, rxb_steal_page(rxb), offset, | ||
119 | fraglen, rxb->truesize); | ||
120 | } | ||
121 | |||
122 | memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); | ||
123 | |||
124 | ieee80211_rx(mvm->hw, skb); | ||
125 | } | ||
126 | |||
127 | /* | ||
128 | * iwl_mvm_calc_rssi - calculate the rssi in dBm | ||
129 | * @phy_info: the phy information for the coming packet | ||
130 | */ | ||
131 | static int iwl_mvm_calc_rssi(struct iwl_mvm *mvm, | ||
132 | struct iwl_rx_phy_info *phy_info) | ||
133 | { | ||
134 | u32 rssi_a, rssi_b, rssi_c, max_rssi, agc_db; | ||
135 | u32 val; | ||
136 | |||
137 | /* Find max rssi among 3 possible receivers. | ||
138 | * These values are measured by the Digital Signal Processor (DSP). | ||
139 | * They should stay fairly constant even as the signal strength varies, | ||
140 | * if the radio's Automatic Gain Control (AGC) is working right. | ||
141 | * AGC value (see below) will provide the "interesting" info. | ||
142 | */ | ||
143 | val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_RSSI_AB_IDX]); | ||
144 | rssi_a = (val & IWL_OFDM_RSSI_INBAND_A_MSK) >> IWL_OFDM_RSSI_A_POS; | ||
145 | rssi_b = (val & IWL_OFDM_RSSI_INBAND_B_MSK) >> IWL_OFDM_RSSI_B_POS; | ||
146 | val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_RSSI_C_IDX]); | ||
147 | rssi_c = (val & IWL_OFDM_RSSI_INBAND_C_MSK) >> IWL_OFDM_RSSI_C_POS; | ||
148 | |||
149 | val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_AGC_IDX]); | ||
150 | agc_db = (val & IWL_OFDM_AGC_DB_MSK) >> IWL_OFDM_AGC_DB_POS; | ||
151 | |||
152 | max_rssi = max_t(u32, rssi_a, rssi_b); | ||
153 | max_rssi = max_t(u32, max_rssi, rssi_c); | ||
154 | |||
155 | IWL_DEBUG_STATS(mvm, "Rssi In A %d B %d C %d Max %d AGC dB %d\n", | ||
156 | rssi_a, rssi_b, rssi_c, max_rssi, agc_db); | ||
157 | |||
158 | /* dBm = max_rssi dB - agc dB - constant. | ||
159 | * Higher AGC (higher radio gain) means lower signal. */ | ||
160 | return max_rssi - agc_db - IWL_RSSI_OFFSET; | ||
161 | } | ||
162 | |||
163 | /* | ||
164 | * iwl_mvm_set_mac80211_rx_flag - translate fw status to mac80211 format | ||
165 | * @mvm: the mvm object | ||
166 | * @hdr: 80211 header | ||
167 | * @stats: status in mac80211's format | ||
168 | * @rx_pkt_status: status coming from fw | ||
169 | * | ||
170 | * returns non 0 value if the packet should be dropped | ||
171 | */ | ||
172 | static u32 iwl_mvm_set_mac80211_rx_flag(struct iwl_mvm *mvm, | ||
173 | struct ieee80211_hdr *hdr, | ||
174 | struct ieee80211_rx_status *stats, | ||
175 | u32 rx_pkt_status) | ||
176 | { | ||
177 | if (!ieee80211_has_protected(hdr->frame_control) || | ||
178 | (rx_pkt_status & RX_MPDU_RES_STATUS_SEC_ENC_MSK) == | ||
179 | RX_MPDU_RES_STATUS_SEC_NO_ENC) | ||
180 | return 0; | ||
181 | |||
182 | /* packet was encrypted with unknown alg */ | ||
183 | if ((rx_pkt_status & RX_MPDU_RES_STATUS_SEC_ENC_MSK) == | ||
184 | RX_MPDU_RES_STATUS_SEC_ENC_ERR) | ||
185 | return 0; | ||
186 | |||
187 | switch (rx_pkt_status & RX_MPDU_RES_STATUS_SEC_ENC_MSK) { | ||
188 | case RX_MPDU_RES_STATUS_SEC_CCM_ENC: | ||
189 | /* alg is CCM: check MIC only */ | ||
190 | if (!(rx_pkt_status & RX_MPDU_RES_STATUS_MIC_OK)) | ||
191 | return -1; | ||
192 | |||
193 | stats->flag |= RX_FLAG_DECRYPTED; | ||
194 | IWL_DEBUG_WEP(mvm, "hw decrypted CCMP successfully\n"); | ||
195 | return 0; | ||
196 | |||
197 | case RX_MPDU_RES_STATUS_SEC_TKIP_ENC: | ||
198 | /* Don't drop the frame and decrypt it in SW */ | ||
199 | if (!(rx_pkt_status & RX_MPDU_RES_STATUS_TTAK_OK)) | ||
200 | return 0; | ||
201 | /* fall through if TTAK OK */ | ||
202 | |||
203 | case RX_MPDU_RES_STATUS_SEC_WEP_ENC: | ||
204 | if (!(rx_pkt_status & RX_MPDU_RES_STATUS_ICV_OK)) | ||
205 | return -1; | ||
206 | |||
207 | stats->flag |= RX_FLAG_DECRYPTED; | ||
208 | return 0; | ||
209 | |||
210 | default: | ||
211 | IWL_ERR(mvm, "Unhandled alg: 0x%x\n", rx_pkt_status); | ||
212 | } | ||
213 | |||
214 | return 0; | ||
215 | } | ||
216 | |||
217 | /* | ||
218 | * iwl_mvm_rx_rx_mpdu - REPLY_RX_MPDU_CMD handler | ||
219 | * | ||
220 | * Handles the actual data of the Rx packet from the fw | ||
221 | */ | ||
222 | int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | ||
223 | struct iwl_device_cmd *cmd) | ||
224 | { | ||
225 | struct ieee80211_hdr *hdr; | ||
226 | struct ieee80211_rx_status rx_status = {}; | ||
227 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
228 | struct iwl_rx_phy_info *phy_info; | ||
229 | struct iwl_rx_mpdu_res_start *rx_res; | ||
230 | u32 len; | ||
231 | u32 ampdu_status; | ||
232 | u32 rate_n_flags; | ||
233 | u32 rx_pkt_status; | ||
234 | |||
235 | phy_info = &mvm->last_phy_info; | ||
236 | rx_res = (struct iwl_rx_mpdu_res_start *)pkt->data; | ||
237 | hdr = (struct ieee80211_hdr *)(pkt->data + sizeof(*rx_res)); | ||
238 | len = le16_to_cpu(rx_res->byte_count); | ||
239 | rx_pkt_status = le32_to_cpup((__le32 *) | ||
240 | (pkt->data + sizeof(*rx_res) + len)); | ||
241 | |||
242 | memset(&rx_status, 0, sizeof(rx_status)); | ||
243 | |||
244 | /* | ||
245 | * drop the packet if it has failed being decrypted by HW | ||
246 | */ | ||
247 | if (iwl_mvm_set_mac80211_rx_flag(mvm, hdr, &rx_status, rx_pkt_status)) { | ||
248 | IWL_DEBUG_DROP(mvm, "Bad decryption results 0x%08x\n", | ||
249 | rx_pkt_status); | ||
250 | return 0; | ||
251 | } | ||
252 | |||
253 | if ((unlikely(phy_info->cfg_phy_cnt > 20))) { | ||
254 | IWL_DEBUG_DROP(mvm, "dsp size out of range [0,20]: %d\n", | ||
255 | phy_info->cfg_phy_cnt); | ||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | if (!(rx_pkt_status & RX_MPDU_RES_STATUS_CRC_OK) || | ||
260 | !(rx_pkt_status & RX_MPDU_RES_STATUS_OVERRUN_OK)) { | ||
261 | IWL_DEBUG_RX(mvm, "Bad CRC or FIFO: 0x%08X.\n", rx_pkt_status); | ||
262 | return 0; | ||
263 | } | ||
264 | |||
265 | /* This will be used in several places later */ | ||
266 | rate_n_flags = le32_to_cpu(phy_info->rate_n_flags); | ||
267 | |||
268 | /* rx_status carries information about the packet to mac80211 */ | ||
269 | rx_status.mactime = le64_to_cpu(phy_info->timestamp); | ||
270 | rx_status.band = | ||
271 | (phy_info->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_BAND_24)) ? | ||
272 | IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; | ||
273 | rx_status.freq = | ||
274 | ieee80211_channel_to_frequency(le16_to_cpu(phy_info->channel), | ||
275 | rx_status.band); | ||
276 | /* | ||
277 | * TSF as indicated by the fw is at INA time, but mac80211 expects the | ||
278 | * TSF at the beginning of the MPDU. | ||
279 | */ | ||
280 | /*rx_status.flag |= RX_FLAG_MACTIME_MPDU;*/ | ||
281 | |||
282 | /* Find max signal strength (dBm) among 3 antenna/receiver chains */ | ||
283 | rx_status.signal = iwl_mvm_calc_rssi(mvm, phy_info); | ||
284 | |||
285 | IWL_DEBUG_STATS_LIMIT(mvm, "Rssi %d, TSF %llu\n", rx_status.signal, | ||
286 | (unsigned long long)rx_status.mactime); | ||
287 | |||
288 | /* | ||
289 | * "antenna number" | ||
290 | * | ||
291 | * It seems that the antenna field in the phy flags value | ||
292 | * is actually a bit field. This is undefined by radiotap, | ||
293 | * it wants an actual antenna number but I always get "7" | ||
294 | * for most legacy frames I receive indicating that the | ||
295 | * same frame was received on all three RX chains. | ||
296 | * | ||
297 | * I think this field should be removed in favor of a | ||
298 | * new 802.11n radiotap field "RX chains" that is defined | ||
299 | * as a bitmask. | ||
300 | */ | ||
301 | rx_status.antenna = (le16_to_cpu(phy_info->phy_flags) & | ||
302 | RX_RES_PHY_FLAGS_ANTENNA) | ||
303 | >> RX_RES_PHY_FLAGS_ANTENNA_POS; | ||
304 | |||
305 | /* set the preamble flag if appropriate */ | ||
306 | if (phy_info->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_SHORT_PREAMBLE)) | ||
307 | rx_status.flag |= RX_FLAG_SHORTPRE; | ||
308 | |||
309 | if (phy_info->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_AGG)) { | ||
310 | /* | ||
311 | * We know which subframes of an A-MPDU belong | ||
312 | * together since we get a single PHY response | ||
313 | * from the firmware for all of them | ||
314 | */ | ||
315 | rx_status.flag |= RX_FLAG_AMPDU_DETAILS; | ||
316 | rx_status.ampdu_reference = mvm->ampdu_ref; | ||
317 | } | ||
318 | |||
319 | /* Set up the HT phy flags */ | ||
320 | switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) { | ||
321 | case RATE_MCS_CHAN_WIDTH_20: | ||
322 | break; | ||
323 | case RATE_MCS_CHAN_WIDTH_40: | ||
324 | rx_status.flag |= RX_FLAG_40MHZ; | ||
325 | break; | ||
326 | case RATE_MCS_CHAN_WIDTH_80: | ||
327 | rx_status.flag |= RX_FLAG_80MHZ; | ||
328 | break; | ||
329 | case RATE_MCS_CHAN_WIDTH_160: | ||
330 | rx_status.flag |= RX_FLAG_160MHZ; | ||
331 | break; | ||
332 | } | ||
333 | if (rate_n_flags & RATE_MCS_SGI_MSK) | ||
334 | rx_status.flag |= RX_FLAG_SHORT_GI; | ||
335 | if (rate_n_flags & RATE_HT_MCS_GF_MSK) | ||
336 | rx_status.flag |= RX_FLAG_HT_GF; | ||
337 | if (rate_n_flags & RATE_MCS_HT_MSK) { | ||
338 | rx_status.flag |= RX_FLAG_HT; | ||
339 | rx_status.rate_idx = rate_n_flags & RATE_HT_MCS_INDEX_MSK; | ||
340 | } else if (rate_n_flags & RATE_MCS_VHT_MSK) { | ||
341 | rx_status.vht_nss = | ||
342 | ((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >> | ||
343 | RATE_VHT_MCS_NSS_POS) + 1; | ||
344 | rx_status.rate_idx = rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK; | ||
345 | rx_status.flag |= RX_FLAG_VHT; | ||
346 | } else { | ||
347 | rx_status.rate_idx = | ||
348 | iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags, | ||
349 | rx_status.band); | ||
350 | } | ||
351 | |||
352 | iwl_mvm_pass_packet_to_mac80211(mvm, hdr, len, ampdu_status, | ||
353 | rxb, &rx_status); | ||
354 | return 0; | ||
355 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c new file mode 100644 index 000000000000..406c53ad0a49 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c | |||
@@ -0,0 +1,437 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called LICENSE.GPL. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | * | ||
62 | *****************************************************************************/ | ||
63 | |||
64 | #include <linux/etherdevice.h> | ||
65 | #include <net/mac80211.h> | ||
66 | |||
67 | #include "mvm.h" | ||
68 | #include "iwl-eeprom-parse.h" | ||
69 | #include "fw-api-scan.h" | ||
70 | |||
71 | #define IWL_PLCP_QUIET_THRESH 1 | ||
72 | #define IWL_ACTIVE_QUIET_TIME 10 | ||
73 | |||
74 | static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm) | ||
75 | { | ||
76 | u16 rx_chain; | ||
77 | u8 rx_ant = mvm->nvm_data->valid_rx_ant; | ||
78 | |||
79 | rx_chain = rx_ant << PHY_RX_CHAIN_VALID_POS; | ||
80 | rx_chain |= rx_ant << PHY_RX_CHAIN_FORCE_MIMO_SEL_POS; | ||
81 | rx_chain |= rx_ant << PHY_RX_CHAIN_FORCE_SEL_POS; | ||
82 | rx_chain |= 0x1 << PHY_RX_CHAIN_DRIVER_FORCE_POS; | ||
83 | return cpu_to_le16(rx_chain); | ||
84 | } | ||
85 | |||
86 | static inline __le32 iwl_mvm_scan_max_out_time(struct ieee80211_vif *vif) | ||
87 | { | ||
88 | if (vif->bss_conf.assoc) | ||
89 | return cpu_to_le32(200 * 1024); | ||
90 | else | ||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | static inline __le32 iwl_mvm_scan_suspend_time(struct ieee80211_vif *vif) | ||
95 | { | ||
96 | if (vif->bss_conf.assoc) | ||
97 | return cpu_to_le32(vif->bss_conf.beacon_int); | ||
98 | else | ||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | static inline __le32 | ||
103 | iwl_mvm_scan_rxon_flags(struct cfg80211_scan_request *req) | ||
104 | { | ||
105 | if (req->channels[0]->band == IEEE80211_BAND_2GHZ) | ||
106 | return cpu_to_le32(PHY_BAND_24); | ||
107 | else | ||
108 | return cpu_to_le32(PHY_BAND_5); | ||
109 | } | ||
110 | |||
111 | static inline __le32 | ||
112 | iwl_mvm_scan_rate_n_flags(struct iwl_mvm *mvm, enum ieee80211_band band, | ||
113 | bool no_cck) | ||
114 | { | ||
115 | u32 tx_ant; | ||
116 | |||
117 | mvm->scan_last_antenna_idx = | ||
118 | iwl_mvm_next_antenna(mvm, mvm->nvm_data->valid_tx_ant, | ||
119 | mvm->scan_last_antenna_idx); | ||
120 | tx_ant = BIT(mvm->scan_last_antenna_idx) << RATE_MCS_ANT_POS; | ||
121 | |||
122 | if (band == IEEE80211_BAND_2GHZ && !no_cck) | ||
123 | return cpu_to_le32(IWL_RATE_1M_PLCP | RATE_MCS_CCK_MSK | | ||
124 | tx_ant); | ||
125 | else | ||
126 | return cpu_to_le32(IWL_RATE_6M_PLCP | tx_ant); | ||
127 | } | ||
128 | |||
129 | /* | ||
130 | * We insert the SSIDs in an inverted order, because the FW will | ||
131 | * invert it back. The most prioritized SSID, which is first in the | ||
132 | * request list, is not copied here, but inserted directly to the probe | ||
133 | * request. | ||
134 | */ | ||
135 | static void iwl_mvm_scan_fill_ssids(struct iwl_scan_cmd *cmd, | ||
136 | struct cfg80211_scan_request *req) | ||
137 | { | ||
138 | int fw_idx, req_idx; | ||
139 | |||
140 | fw_idx = 0; | ||
141 | for (req_idx = req->n_ssids - 1; req_idx > 0; req_idx--) { | ||
142 | cmd->direct_scan[fw_idx].id = WLAN_EID_SSID; | ||
143 | cmd->direct_scan[fw_idx].len = req->ssids[req_idx].ssid_len; | ||
144 | memcpy(cmd->direct_scan[fw_idx].ssid, | ||
145 | req->ssids[req_idx].ssid, | ||
146 | req->ssids[req_idx].ssid_len); | ||
147 | } | ||
148 | } | ||
149 | |||
150 | /* | ||
151 | * If req->n_ssids > 0, it means we should do an active scan. | ||
152 | * In case of active scan w/o directed scan, we receive a zero-length SSID | ||
153 | * just to notify that this scan is active and not passive. | ||
154 | * In order to notify the FW of the number of SSIDs we wish to scan (including | ||
155 | * the zero-length one), we need to set the corresponding bits in chan->type, | ||
156 | * one for each SSID, and set the active bit (first). | ||
157 | */ | ||
158 | static u16 iwl_mvm_get_active_dwell(enum ieee80211_band band, int n_ssids) | ||
159 | { | ||
160 | if (band == IEEE80211_BAND_2GHZ) | ||
161 | return 30 + 3 * (n_ssids + 1); | ||
162 | return 20 + 2 * (n_ssids + 1); | ||
163 | } | ||
164 | |||
165 | static u16 iwl_mvm_get_passive_dwell(enum ieee80211_band band) | ||
166 | { | ||
167 | return band == IEEE80211_BAND_2GHZ ? 100 + 20 : 100 + 10; | ||
168 | } | ||
169 | |||
170 | static void iwl_mvm_scan_fill_channels(struct iwl_scan_cmd *cmd, | ||
171 | struct cfg80211_scan_request *req) | ||
172 | { | ||
173 | u16 passive_dwell = iwl_mvm_get_passive_dwell(req->channels[0]->band); | ||
174 | u16 active_dwell = iwl_mvm_get_active_dwell(req->channels[0]->band, | ||
175 | req->n_ssids); | ||
176 | struct iwl_scan_channel *chan = (struct iwl_scan_channel *) | ||
177 | (cmd->data + le16_to_cpu(cmd->tx_cmd.len)); | ||
178 | int i; | ||
179 | __le32 chan_type_value; | ||
180 | |||
181 | if (req->n_ssids > 0) | ||
182 | chan_type_value = cpu_to_le32(BIT(req->n_ssids + 1) - 1); | ||
183 | else | ||
184 | chan_type_value = SCAN_CHANNEL_TYPE_PASSIVE; | ||
185 | |||
186 | for (i = 0; i < cmd->channel_count; i++) { | ||
187 | chan->channel = cpu_to_le16(req->channels[i]->hw_value); | ||
188 | if (req->channels[i]->flags & IEEE80211_CHAN_PASSIVE_SCAN) | ||
189 | chan->type = SCAN_CHANNEL_TYPE_PASSIVE; | ||
190 | else | ||
191 | chan->type = chan_type_value; | ||
192 | chan->active_dwell = cpu_to_le16(active_dwell); | ||
193 | chan->passive_dwell = cpu_to_le16(passive_dwell); | ||
194 | chan->iteration_count = cpu_to_le16(1); | ||
195 | chan++; | ||
196 | } | ||
197 | } | ||
198 | |||
199 | /* | ||
200 | * Fill in probe request with the following parameters: | ||
201 | * TA is our vif HW address, which mac80211 ensures we have. | ||
202 | * Packet is broadcasted, so this is both SA and DA. | ||
203 | * The probe request IE is made out of two: first comes the most prioritized | ||
204 | * SSID if a directed scan is requested. Second comes whatever extra | ||
205 | * information was given to us as the scan request IE. | ||
206 | */ | ||
207 | static u16 iwl_mvm_fill_probe_req(struct ieee80211_mgmt *frame, const u8 *ta, | ||
208 | int n_ssids, const u8 *ssid, int ssid_len, | ||
209 | const u8 *ie, int ie_len, | ||
210 | int left) | ||
211 | { | ||
212 | int len = 0; | ||
213 | u8 *pos = NULL; | ||
214 | |||
215 | /* Make sure there is enough space for the probe request, | ||
216 | * two mandatory IEs and the data */ | ||
217 | left -= 24; | ||
218 | if (left < 0) | ||
219 | return 0; | ||
220 | |||
221 | frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); | ||
222 | eth_broadcast_addr(frame->da); | ||
223 | memcpy(frame->sa, ta, ETH_ALEN); | ||
224 | eth_broadcast_addr(frame->bssid); | ||
225 | frame->seq_ctrl = 0; | ||
226 | |||
227 | len += 24; | ||
228 | |||
229 | /* for passive scans, no need to fill anything */ | ||
230 | if (n_ssids == 0) | ||
231 | return (u16)len; | ||
232 | |||
233 | /* points to the payload of the request */ | ||
234 | pos = &frame->u.probe_req.variable[0]; | ||
235 | |||
236 | /* fill in our SSID IE */ | ||
237 | left -= ssid_len + 2; | ||
238 | if (left < 0) | ||
239 | return 0; | ||
240 | *pos++ = WLAN_EID_SSID; | ||
241 | *pos++ = ssid_len; | ||
242 | if (ssid && ssid_len) { /* ssid_len may be == 0 even if ssid is valid */ | ||
243 | memcpy(pos, ssid, ssid_len); | ||
244 | pos += ssid_len; | ||
245 | } | ||
246 | |||
247 | len += ssid_len + 2; | ||
248 | |||
249 | if (WARN_ON(left < ie_len)) | ||
250 | return len; | ||
251 | |||
252 | if (ie && ie_len) { | ||
253 | memcpy(pos, ie, ie_len); | ||
254 | len += ie_len; | ||
255 | } | ||
256 | |||
257 | return (u16)len; | ||
258 | } | ||
259 | |||
260 | int iwl_mvm_scan_request(struct iwl_mvm *mvm, | ||
261 | struct ieee80211_vif *vif, | ||
262 | struct cfg80211_scan_request *req) | ||
263 | { | ||
264 | struct iwl_host_cmd hcmd = { | ||
265 | .id = SCAN_REQUEST_CMD, | ||
266 | .len = { 0, }, | ||
267 | .data = { mvm->scan_cmd, }, | ||
268 | .flags = CMD_SYNC, | ||
269 | .dataflags = { IWL_HCMD_DFL_NOCOPY, }, | ||
270 | }; | ||
271 | struct iwl_scan_cmd *cmd = mvm->scan_cmd; | ||
272 | int ret; | ||
273 | u32 status; | ||
274 | int ssid_len = 0; | ||
275 | u8 *ssid = NULL; | ||
276 | |||
277 | lockdep_assert_held(&mvm->mutex); | ||
278 | BUG_ON(mvm->scan_cmd == NULL); | ||
279 | |||
280 | IWL_DEBUG_SCAN(mvm, "Handling mac80211 scan request\n"); | ||
281 | mvm->scan_status = IWL_MVM_SCAN_OS; | ||
282 | memset(cmd, 0, sizeof(struct iwl_scan_cmd) + | ||
283 | mvm->fw->ucode_capa.max_probe_length + | ||
284 | (MAX_NUM_SCAN_CHANNELS * sizeof(struct iwl_scan_channel))); | ||
285 | |||
286 | cmd->channel_count = (u8)req->n_channels; | ||
287 | cmd->quiet_time = cpu_to_le16(IWL_ACTIVE_QUIET_TIME); | ||
288 | cmd->quiet_plcp_th = cpu_to_le16(IWL_PLCP_QUIET_THRESH); | ||
289 | cmd->rxchain_sel_flags = iwl_mvm_scan_rx_chain(mvm); | ||
290 | cmd->max_out_time = iwl_mvm_scan_max_out_time(vif); | ||
291 | cmd->suspend_time = iwl_mvm_scan_suspend_time(vif); | ||
292 | cmd->rxon_flags = iwl_mvm_scan_rxon_flags(req); | ||
293 | cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP | | ||
294 | MAC_FILTER_IN_BEACON); | ||
295 | cmd->type = SCAN_TYPE_FORCED; | ||
296 | cmd->repeats = cpu_to_le32(1); | ||
297 | |||
298 | /* | ||
299 | * If the user asked for passive scan, don't change to active scan if | ||
300 | * you see any activity on the channel - remain passive. | ||
301 | */ | ||
302 | if (req->n_ssids > 0) { | ||
303 | cmd->passive2active = cpu_to_le16(1); | ||
304 | ssid = req->ssids[0].ssid; | ||
305 | ssid_len = req->ssids[0].ssid_len; | ||
306 | } else { | ||
307 | cmd->passive2active = 0; | ||
308 | } | ||
309 | |||
310 | iwl_mvm_scan_fill_ssids(cmd, req); | ||
311 | |||
312 | cmd->tx_cmd.tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL); | ||
313 | cmd->tx_cmd.sta_id = mvm->aux_sta.sta_id; | ||
314 | cmd->tx_cmd.life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE); | ||
315 | cmd->tx_cmd.rate_n_flags = | ||
316 | iwl_mvm_scan_rate_n_flags(mvm, req->channels[0]->band, | ||
317 | req->no_cck); | ||
318 | |||
319 | cmd->tx_cmd.len = | ||
320 | cpu_to_le16(iwl_mvm_fill_probe_req( | ||
321 | (struct ieee80211_mgmt *)cmd->data, | ||
322 | vif->addr, | ||
323 | req->n_ssids, ssid, ssid_len, | ||
324 | req->ie, req->ie_len, | ||
325 | mvm->fw->ucode_capa.max_probe_length)); | ||
326 | |||
327 | iwl_mvm_scan_fill_channels(cmd, req); | ||
328 | |||
329 | cmd->len = cpu_to_le16(sizeof(struct iwl_scan_cmd) + | ||
330 | le16_to_cpu(cmd->tx_cmd.len) + | ||
331 | (cmd->channel_count * sizeof(struct iwl_scan_channel))); | ||
332 | hcmd.len[0] = le16_to_cpu(cmd->len); | ||
333 | |||
334 | status = SCAN_RESPONSE_OK; | ||
335 | ret = iwl_mvm_send_cmd_status(mvm, &hcmd, &status); | ||
336 | if (!ret && status == SCAN_RESPONSE_OK) { | ||
337 | IWL_DEBUG_SCAN(mvm, "Scan request was sent successfully\n"); | ||
338 | } else { | ||
339 | /* | ||
340 | * If the scan failed, it usually means that the FW was unable | ||
341 | * to allocate the time events. Warn on it, but maybe we | ||
342 | * should try to send the command again with different params. | ||
343 | */ | ||
344 | IWL_ERR(mvm, "Scan failed! status 0x%x ret %d\n", | ||
345 | status, ret); | ||
346 | mvm->scan_status = IWL_MVM_SCAN_NONE; | ||
347 | ret = -EIO; | ||
348 | } | ||
349 | return ret; | ||
350 | } | ||
351 | |||
352 | int iwl_mvm_rx_scan_response(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | ||
353 | struct iwl_device_cmd *cmd) | ||
354 | { | ||
355 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
356 | struct iwl_cmd_response *resp = (void *)pkt->data; | ||
357 | |||
358 | IWL_DEBUG_SCAN(mvm, "Scan response received. status 0x%x\n", | ||
359 | le32_to_cpu(resp->status)); | ||
360 | return 0; | ||
361 | } | ||
362 | |||
363 | int iwl_mvm_rx_scan_complete(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | ||
364 | struct iwl_device_cmd *cmd) | ||
365 | { | ||
366 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
367 | struct iwl_scan_complete_notif *notif = (void *)pkt->data; | ||
368 | |||
369 | IWL_DEBUG_SCAN(mvm, "Scan complete: status=0x%x scanned channels=%d\n", | ||
370 | notif->status, notif->scanned_channels); | ||
371 | |||
372 | mvm->scan_status = IWL_MVM_SCAN_NONE; | ||
373 | ieee80211_scan_completed(mvm->hw, notif->status != SCAN_COMP_STATUS_OK); | ||
374 | |||
375 | return 0; | ||
376 | } | ||
377 | |||
378 | static bool iwl_mvm_scan_abort_notif(struct iwl_notif_wait_data *notif_wait, | ||
379 | struct iwl_rx_packet *pkt, void *data) | ||
380 | { | ||
381 | struct iwl_mvm *mvm = | ||
382 | container_of(notif_wait, struct iwl_mvm, notif_wait); | ||
383 | struct iwl_scan_complete_notif *notif; | ||
384 | u32 *resp; | ||
385 | |||
386 | switch (pkt->hdr.cmd) { | ||
387 | case SCAN_ABORT_CMD: | ||
388 | resp = (void *)pkt->data; | ||
389 | if (*resp == CAN_ABORT_STATUS) { | ||
390 | IWL_DEBUG_SCAN(mvm, | ||
391 | "Scan can be aborted, wait until completion\n"); | ||
392 | return false; | ||
393 | } | ||
394 | |||
395 | IWL_DEBUG_SCAN(mvm, "Scan cannot be aborted, exit now: %d\n", | ||
396 | *resp); | ||
397 | return true; | ||
398 | |||
399 | case SCAN_COMPLETE_NOTIFICATION: | ||
400 | notif = (void *)pkt->data; | ||
401 | IWL_DEBUG_SCAN(mvm, "Scan aborted: status 0x%x\n", | ||
402 | notif->status); | ||
403 | return true; | ||
404 | |||
405 | default: | ||
406 | WARN_ON(1); | ||
407 | return false; | ||
408 | }; | ||
409 | } | ||
410 | |||
411 | void iwl_mvm_cancel_scan(struct iwl_mvm *mvm) | ||
412 | { | ||
413 | struct iwl_notification_wait wait_scan_abort; | ||
414 | static const u8 scan_abort_notif[] = { SCAN_ABORT_CMD, | ||
415 | SCAN_COMPLETE_NOTIFICATION }; | ||
416 | int ret; | ||
417 | |||
418 | iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_abort, | ||
419 | scan_abort_notif, | ||
420 | ARRAY_SIZE(scan_abort_notif), | ||
421 | iwl_mvm_scan_abort_notif, NULL); | ||
422 | |||
423 | ret = iwl_mvm_send_cmd_pdu(mvm, SCAN_ABORT_CMD, CMD_SYNC, 0, NULL); | ||
424 | if (ret) { | ||
425 | IWL_ERR(mvm, "Couldn't send SCAN_ABORT_CMD: %d\n", ret); | ||
426 | goto out_remove_notif; | ||
427 | } | ||
428 | |||
429 | ret = iwl_wait_notification(&mvm->notif_wait, &wait_scan_abort, 1 * HZ); | ||
430 | if (ret) | ||
431 | IWL_ERR(mvm, "%s - failed on timeout\n", __func__); | ||
432 | |||
433 | return; | ||
434 | |||
435 | out_remove_notif: | ||
436 | iwl_remove_notification(&mvm->notif_wait, &wait_scan_abort); | ||
437 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c new file mode 100644 index 000000000000..69603c3b2b39 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c | |||
@@ -0,0 +1,1211 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called LICENSE.GPL. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | * | ||
62 | *****************************************************************************/ | ||
63 | #include <net/mac80211.h> | ||
64 | |||
65 | #include "mvm.h" | ||
66 | #include "sta.h" | ||
67 | |||
68 | static int iwl_mvm_find_free_sta_id(struct iwl_mvm *mvm) | ||
69 | { | ||
70 | int sta_id; | ||
71 | |||
72 | WARN_ON_ONCE(test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)); | ||
73 | |||
74 | lockdep_assert_held(&mvm->mutex); | ||
75 | |||
76 | /* Don't take rcu_read_lock() since we are protected by mvm->mutex */ | ||
77 | for (sta_id = 0; sta_id < IWL_MVM_STATION_COUNT; sta_id++) | ||
78 | if (!rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], | ||
79 | lockdep_is_held(&mvm->mutex))) | ||
80 | return sta_id; | ||
81 | return IWL_MVM_STATION_COUNT; | ||
82 | } | ||
83 | |||
84 | /* add a NEW station to fw */ | ||
85 | int iwl_mvm_sta_add_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta) | ||
86 | { | ||
87 | struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; | ||
88 | struct iwl_mvm_add_sta_cmd add_sta_cmd; | ||
89 | int ret; | ||
90 | u32 status; | ||
91 | u32 agg_size = 0, mpdu_dens = 0; | ||
92 | |||
93 | memset(&add_sta_cmd, 0, sizeof(add_sta_cmd)); | ||
94 | |||
95 | add_sta_cmd.sta_id = mvm_sta->sta_id; | ||
96 | add_sta_cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color); | ||
97 | add_sta_cmd.tfd_queue_msk = cpu_to_le32(mvm_sta->tfd_queue_msk); | ||
98 | memcpy(&add_sta_cmd.addr, sta->addr, ETH_ALEN); | ||
99 | |||
100 | /* STA_FLG_FAT_EN_MSK ? */ | ||
101 | /* STA_FLG_MIMO_EN_MSK ? */ | ||
102 | |||
103 | if (sta->ht_cap.ht_supported) { | ||
104 | add_sta_cmd.station_flags_msk |= | ||
105 | cpu_to_le32(STA_FLG_MAX_AGG_SIZE_MSK | | ||
106 | STA_FLG_AGG_MPDU_DENS_MSK); | ||
107 | |||
108 | mpdu_dens = sta->ht_cap.ampdu_density; | ||
109 | } | ||
110 | |||
111 | if (sta->vht_cap.vht_supported) { | ||
112 | agg_size = sta->vht_cap.cap & | ||
113 | IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; | ||
114 | agg_size >>= | ||
115 | IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT; | ||
116 | } else if (sta->ht_cap.ht_supported) { | ||
117 | agg_size = sta->ht_cap.ampdu_factor; | ||
118 | } | ||
119 | |||
120 | add_sta_cmd.station_flags |= | ||
121 | cpu_to_le32(agg_size << STA_FLG_MAX_AGG_SIZE_SHIFT); | ||
122 | add_sta_cmd.station_flags |= | ||
123 | cpu_to_le32(mpdu_dens << STA_FLG_AGG_MPDU_DENS_SHIFT); | ||
124 | |||
125 | status = ADD_STA_SUCCESS; | ||
126 | ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(add_sta_cmd), | ||
127 | &add_sta_cmd, &status); | ||
128 | if (ret) | ||
129 | return ret; | ||
130 | |||
131 | switch (status) { | ||
132 | case ADD_STA_SUCCESS: | ||
133 | IWL_DEBUG_ASSOC(mvm, "ADD_STA PASSED\n"); | ||
134 | break; | ||
135 | default: | ||
136 | ret = -EIO; | ||
137 | IWL_ERR(mvm, "ADD_STA failed\n"); | ||
138 | break; | ||
139 | } | ||
140 | |||
141 | return ret; | ||
142 | } | ||
143 | |||
144 | int iwl_mvm_add_sta(struct iwl_mvm *mvm, | ||
145 | struct ieee80211_vif *vif, | ||
146 | struct ieee80211_sta *sta) | ||
147 | { | ||
148 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
149 | struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; | ||
150 | int i, ret, sta_id; | ||
151 | |||
152 | lockdep_assert_held(&mvm->mutex); | ||
153 | |||
154 | if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) | ||
155 | sta_id = iwl_mvm_find_free_sta_id(mvm); | ||
156 | else | ||
157 | sta_id = mvm_sta->sta_id; | ||
158 | |||
159 | if (WARN_ON_ONCE(sta_id == IWL_MVM_STATION_COUNT)) | ||
160 | return -ENOSPC; | ||
161 | |||
162 | spin_lock_init(&mvm_sta->lock); | ||
163 | |||
164 | mvm_sta->sta_id = sta_id; | ||
165 | mvm_sta->mac_id_n_color = FW_CMD_ID_AND_COLOR(mvmvif->id, | ||
166 | mvmvif->color); | ||
167 | mvm_sta->vif = vif; | ||
168 | mvm_sta->max_agg_bufsize = LINK_QUAL_AGG_FRAME_LIMIT_DEF; | ||
169 | |||
170 | /* HW restart, don't assume the memory has been zeroed */ | ||
171 | atomic_set(&mvm_sta->pending_frames, 0); | ||
172 | mvm_sta->tid_disable_agg = 0; | ||
173 | mvm_sta->tfd_queue_msk = 0; | ||
174 | for (i = 0; i < IEEE80211_NUM_ACS; i++) | ||
175 | if (vif->hw_queue[i] != IEEE80211_INVAL_HW_QUEUE) | ||
176 | mvm_sta->tfd_queue_msk |= BIT(vif->hw_queue[i]); | ||
177 | |||
178 | if (vif->cab_queue != IEEE80211_INVAL_HW_QUEUE) | ||
179 | mvm_sta->tfd_queue_msk |= BIT(vif->cab_queue); | ||
180 | |||
181 | /* for HW restart - need to reset the seq_number etc... */ | ||
182 | memset(mvm_sta->tid_data, 0, sizeof(mvm_sta->tid_data)); | ||
183 | |||
184 | ret = iwl_mvm_sta_add_to_fw(mvm, sta); | ||
185 | if (ret) | ||
186 | return ret; | ||
187 | |||
188 | /* The first station added is the AP, the others are TDLS STAs */ | ||
189 | if (vif->type == NL80211_IFTYPE_STATION && | ||
190 | mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT) | ||
191 | mvmvif->ap_sta_id = sta_id; | ||
192 | |||
193 | rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id], sta); | ||
194 | |||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, | ||
199 | bool drain) | ||
200 | { | ||
201 | struct iwl_mvm_add_sta_cmd cmd = {}; | ||
202 | int ret; | ||
203 | u32 status; | ||
204 | |||
205 | lockdep_assert_held(&mvm->mutex); | ||
206 | |||
207 | cmd.mac_id_n_color = cpu_to_le32(mvmsta->mac_id_n_color); | ||
208 | cmd.sta_id = mvmsta->sta_id; | ||
209 | cmd.add_modify = STA_MODE_MODIFY; | ||
210 | cmd.station_flags = drain ? cpu_to_le32(STA_FLG_DRAIN_FLOW) : 0; | ||
211 | cmd.station_flags_msk = cpu_to_le32(STA_FLG_DRAIN_FLOW); | ||
212 | |||
213 | status = ADD_STA_SUCCESS; | ||
214 | ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd), | ||
215 | &cmd, &status); | ||
216 | if (ret) | ||
217 | return ret; | ||
218 | |||
219 | switch (status) { | ||
220 | case ADD_STA_SUCCESS: | ||
221 | IWL_DEBUG_INFO(mvm, "Frames for staid %d will drained in fw\n", | ||
222 | mvmsta->sta_id); | ||
223 | break; | ||
224 | default: | ||
225 | ret = -EIO; | ||
226 | IWL_ERR(mvm, "Couldn't drain frames for staid %d\n", | ||
227 | mvmsta->sta_id); | ||
228 | break; | ||
229 | } | ||
230 | |||
231 | return ret; | ||
232 | } | ||
233 | |||
234 | /* | ||
235 | * Remove a station from the FW table. Before sending the command to remove | ||
236 | * the station validate that the station is indeed known to the driver (sanity | ||
237 | * only). | ||
238 | */ | ||
239 | static int iwl_mvm_rm_sta_common(struct iwl_mvm *mvm, u8 sta_id) | ||
240 | { | ||
241 | struct ieee80211_sta *sta; | ||
242 | struct iwl_mvm_rm_sta_cmd rm_sta_cmd = { | ||
243 | .sta_id = sta_id, | ||
244 | }; | ||
245 | int ret; | ||
246 | |||
247 | sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], | ||
248 | lockdep_is_held(&mvm->mutex)); | ||
249 | |||
250 | /* Note: internal stations are marked as error values */ | ||
251 | if (!sta) { | ||
252 | IWL_ERR(mvm, "Invalid station id\n"); | ||
253 | return -EINVAL; | ||
254 | } | ||
255 | |||
256 | ret = iwl_mvm_send_cmd_pdu(mvm, REMOVE_STA, CMD_SYNC, | ||
257 | sizeof(rm_sta_cmd), &rm_sta_cmd); | ||
258 | if (ret) { | ||
259 | IWL_ERR(mvm, "Failed to remove station. Id=%d\n", sta_id); | ||
260 | return ret; | ||
261 | } | ||
262 | |||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | void iwl_mvm_sta_drained_wk(struct work_struct *wk) | ||
267 | { | ||
268 | struct iwl_mvm *mvm = container_of(wk, struct iwl_mvm, sta_drained_wk); | ||
269 | u8 sta_id; | ||
270 | |||
271 | /* | ||
272 | * The mutex is needed because of the SYNC cmd, but not only: if the | ||
273 | * work would run concurrently with iwl_mvm_rm_sta, it would run before | ||
274 | * iwl_mvm_rm_sta sets the station as busy, and exit. Then | ||
275 | * iwl_mvm_rm_sta would set the station as busy, and nobody will clean | ||
276 | * that later. | ||
277 | */ | ||
278 | mutex_lock(&mvm->mutex); | ||
279 | |||
280 | for_each_set_bit(sta_id, mvm->sta_drained, IWL_MVM_STATION_COUNT) { | ||
281 | int ret; | ||
282 | struct ieee80211_sta *sta = | ||
283 | rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], | ||
284 | lockdep_is_held(&mvm->mutex)); | ||
285 | |||
286 | /* This station is in use */ | ||
287 | if (!IS_ERR(sta)) | ||
288 | continue; | ||
289 | |||
290 | if (PTR_ERR(sta) == -EINVAL) { | ||
291 | IWL_ERR(mvm, "Drained sta %d, but it is internal?\n", | ||
292 | sta_id); | ||
293 | continue; | ||
294 | } | ||
295 | |||
296 | if (!sta) { | ||
297 | IWL_ERR(mvm, "Drained sta %d, but it was NULL?\n", | ||
298 | sta_id); | ||
299 | continue; | ||
300 | } | ||
301 | |||
302 | WARN_ON(PTR_ERR(sta) != -EBUSY); | ||
303 | /* This station was removed and we waited until it got drained, | ||
304 | * we can now proceed and remove it. | ||
305 | */ | ||
306 | ret = iwl_mvm_rm_sta_common(mvm, sta_id); | ||
307 | if (ret) { | ||
308 | IWL_ERR(mvm, | ||
309 | "Couldn't remove sta %d after it was drained\n", | ||
310 | sta_id); | ||
311 | continue; | ||
312 | } | ||
313 | rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id], NULL); | ||
314 | clear_bit(sta_id, mvm->sta_drained); | ||
315 | } | ||
316 | |||
317 | mutex_unlock(&mvm->mutex); | ||
318 | } | ||
319 | |||
320 | int iwl_mvm_rm_sta(struct iwl_mvm *mvm, | ||
321 | struct ieee80211_vif *vif, | ||
322 | struct ieee80211_sta *sta) | ||
323 | { | ||
324 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
325 | struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; | ||
326 | int ret; | ||
327 | |||
328 | lockdep_assert_held(&mvm->mutex); | ||
329 | |||
330 | if (vif->type == NL80211_IFTYPE_STATION && | ||
331 | mvmvif->ap_sta_id == mvm_sta->sta_id) { | ||
332 | /* | ||
333 | * Put a non-NULL since the fw station isn't removed. | ||
334 | * It will be removed after the MAC will be set as | ||
335 | * unassoc. | ||
336 | */ | ||
337 | rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id], | ||
338 | ERR_PTR(-EINVAL)); | ||
339 | |||
340 | /* flush its queues here since we are freeing mvm_sta */ | ||
341 | ret = iwl_mvm_flush_tx_path(mvm, mvm_sta->tfd_queue_msk, true); | ||
342 | |||
343 | /* if we are associated - we can't remove the AP STA now */ | ||
344 | if (vif->bss_conf.assoc) | ||
345 | return ret; | ||
346 | |||
347 | /* unassoc - go ahead - remove the AP STA now */ | ||
348 | mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; | ||
349 | } | ||
350 | |||
351 | /* | ||
352 | * There are frames pending on the AC queues for this station. | ||
353 | * We need to wait until all the frames are drained... | ||
354 | */ | ||
355 | if (atomic_read(&mvm_sta->pending_frames)) { | ||
356 | ret = iwl_mvm_drain_sta(mvm, mvm_sta, true); | ||
357 | rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id], | ||
358 | ERR_PTR(-EBUSY)); | ||
359 | } else { | ||
360 | ret = iwl_mvm_rm_sta_common(mvm, mvm_sta->sta_id); | ||
361 | rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id], NULL); | ||
362 | } | ||
363 | |||
364 | return ret; | ||
365 | } | ||
366 | |||
367 | int iwl_mvm_rm_sta_id(struct iwl_mvm *mvm, | ||
368 | struct ieee80211_vif *vif, | ||
369 | u8 sta_id) | ||
370 | { | ||
371 | int ret = iwl_mvm_rm_sta_common(mvm, sta_id); | ||
372 | |||
373 | lockdep_assert_held(&mvm->mutex); | ||
374 | |||
375 | rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id], NULL); | ||
376 | return ret; | ||
377 | } | ||
378 | |||
379 | int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta, | ||
380 | u32 qmask) | ||
381 | { | ||
382 | if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { | ||
383 | sta->sta_id = iwl_mvm_find_free_sta_id(mvm); | ||
384 | if (WARN_ON_ONCE(sta->sta_id == IWL_MVM_STATION_COUNT)) | ||
385 | return -ENOSPC; | ||
386 | } | ||
387 | |||
388 | sta->tfd_queue_msk = qmask; | ||
389 | |||
390 | /* put a non-NULL value so iterating over the stations won't stop */ | ||
391 | rcu_assign_pointer(mvm->fw_id_to_mac_id[sta->sta_id], ERR_PTR(-EINVAL)); | ||
392 | return 0; | ||
393 | } | ||
394 | |||
395 | void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta) | ||
396 | { | ||
397 | rcu_assign_pointer(mvm->fw_id_to_mac_id[sta->sta_id], NULL); | ||
398 | memset(sta, 0, sizeof(struct iwl_mvm_int_sta)); | ||
399 | sta->sta_id = IWL_MVM_STATION_COUNT; | ||
400 | } | ||
401 | |||
402 | static int iwl_mvm_add_int_sta_common(struct iwl_mvm *mvm, | ||
403 | struct iwl_mvm_int_sta *sta, | ||
404 | const u8 *addr, | ||
405 | u16 mac_id, u16 color) | ||
406 | { | ||
407 | struct iwl_mvm_add_sta_cmd cmd; | ||
408 | int ret; | ||
409 | u32 status; | ||
410 | |||
411 | lockdep_assert_held(&mvm->mutex); | ||
412 | |||
413 | memset(&cmd, 0, sizeof(struct iwl_mvm_add_sta_cmd)); | ||
414 | cmd.sta_id = sta->sta_id; | ||
415 | cmd.mac_id_n_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mac_id, | ||
416 | color)); | ||
417 | |||
418 | cmd.tfd_queue_msk = cpu_to_le32(sta->tfd_queue_msk); | ||
419 | |||
420 | if (addr) | ||
421 | memcpy(cmd.addr, addr, ETH_ALEN); | ||
422 | |||
423 | ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd), | ||
424 | &cmd, &status); | ||
425 | if (ret) | ||
426 | return ret; | ||
427 | |||
428 | switch (status) { | ||
429 | case ADD_STA_SUCCESS: | ||
430 | IWL_DEBUG_INFO(mvm, "Internal station added.\n"); | ||
431 | return 0; | ||
432 | default: | ||
433 | ret = -EIO; | ||
434 | IWL_ERR(mvm, "Add internal station failed, status=0x%x\n", | ||
435 | status); | ||
436 | break; | ||
437 | } | ||
438 | return ret; | ||
439 | } | ||
440 | |||
441 | int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm) | ||
442 | { | ||
443 | int ret; | ||
444 | |||
445 | lockdep_assert_held(&mvm->mutex); | ||
446 | |||
447 | /* Add the aux station, but without any queues */ | ||
448 | ret = iwl_mvm_allocate_int_sta(mvm, &mvm->aux_sta, 0); | ||
449 | if (ret) | ||
450 | return ret; | ||
451 | |||
452 | ret = iwl_mvm_add_int_sta_common(mvm, &mvm->aux_sta, NULL, | ||
453 | MAC_INDEX_AUX, 0); | ||
454 | |||
455 | if (ret) | ||
456 | iwl_mvm_dealloc_int_sta(mvm, &mvm->aux_sta); | ||
457 | return ret; | ||
458 | } | ||
459 | |||
460 | /* | ||
461 | * Send the add station command for the vif's broadcast station. | ||
462 | * Assumes that the station was already allocated. | ||
463 | * | ||
464 | * @mvm: the mvm component | ||
465 | * @vif: the interface to which the broadcast station is added | ||
466 | * @bsta: the broadcast station to add. | ||
467 | */ | ||
468 | int iwl_mvm_send_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
469 | struct iwl_mvm_int_sta *bsta) | ||
470 | { | ||
471 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
472 | static const u8 baddr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; | ||
473 | |||
474 | lockdep_assert_held(&mvm->mutex); | ||
475 | |||
476 | if (WARN_ON_ONCE(bsta->sta_id == IWL_MVM_STATION_COUNT)) | ||
477 | return -ENOSPC; | ||
478 | |||
479 | return iwl_mvm_add_int_sta_common(mvm, bsta, baddr, | ||
480 | mvmvif->id, mvmvif->color); | ||
481 | } | ||
482 | |||
483 | /* Send the FW a request to remove the station from it's internal data | ||
484 | * structures, but DO NOT remove the entry from the local data structures. */ | ||
485 | int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm, | ||
486 | struct iwl_mvm_int_sta *bsta) | ||
487 | { | ||
488 | int ret; | ||
489 | |||
490 | lockdep_assert_held(&mvm->mutex); | ||
491 | |||
492 | ret = iwl_mvm_rm_sta_common(mvm, bsta->sta_id); | ||
493 | if (ret) | ||
494 | IWL_WARN(mvm, "Failed sending remove station\n"); | ||
495 | return ret; | ||
496 | } | ||
497 | |||
498 | /* Allocate a new station entry for the broadcast station to the given vif, | ||
499 | * and send it to the FW. | ||
500 | * Note that each P2P mac should have its own broadcast station. | ||
501 | * | ||
502 | * @mvm: the mvm component | ||
503 | * @vif: the interface to which the broadcast station is added | ||
504 | * @bsta: the broadcast station to add. */ | ||
505 | int iwl_mvm_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
506 | struct iwl_mvm_int_sta *bsta) | ||
507 | { | ||
508 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
509 | static const u8 baddr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; | ||
510 | u32 qmask; | ||
511 | int ret; | ||
512 | |||
513 | lockdep_assert_held(&mvm->mutex); | ||
514 | |||
515 | qmask = iwl_mvm_mac_get_queues_mask(mvm, vif); | ||
516 | ret = iwl_mvm_allocate_int_sta(mvm, bsta, qmask); | ||
517 | if (ret) | ||
518 | return ret; | ||
519 | |||
520 | ret = iwl_mvm_add_int_sta_common(mvm, bsta, baddr, | ||
521 | mvmvif->id, mvmvif->color); | ||
522 | |||
523 | if (ret) | ||
524 | iwl_mvm_dealloc_int_sta(mvm, bsta); | ||
525 | return ret; | ||
526 | } | ||
527 | |||
528 | /* | ||
529 | * Send the FW a request to remove the station from it's internal data | ||
530 | * structures, and in addition remove it from the local data structure. | ||
531 | */ | ||
532 | int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *bsta) | ||
533 | { | ||
534 | int ret; | ||
535 | |||
536 | lockdep_assert_held(&mvm->mutex); | ||
537 | |||
538 | ret = iwl_mvm_rm_sta_common(mvm, bsta->sta_id); | ||
539 | if (ret) | ||
540 | return ret; | ||
541 | |||
542 | iwl_mvm_dealloc_int_sta(mvm, bsta); | ||
543 | return ret; | ||
544 | } | ||
545 | |||
546 | int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | ||
547 | int tid, u16 ssn, bool start) | ||
548 | { | ||
549 | struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; | ||
550 | struct iwl_mvm_add_sta_cmd cmd = {}; | ||
551 | int ret; | ||
552 | u32 status; | ||
553 | |||
554 | lockdep_assert_held(&mvm->mutex); | ||
555 | |||
556 | cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color); | ||
557 | cmd.sta_id = mvm_sta->sta_id; | ||
558 | cmd.add_modify = STA_MODE_MODIFY; | ||
559 | cmd.add_immediate_ba_tid = (u8) tid; | ||
560 | cmd.add_immediate_ba_ssn = cpu_to_le16(ssn); | ||
561 | cmd.modify_mask = start ? STA_MODIFY_ADD_BA_TID : | ||
562 | STA_MODIFY_REMOVE_BA_TID; | ||
563 | |||
564 | status = ADD_STA_SUCCESS; | ||
565 | ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd), | ||
566 | &cmd, &status); | ||
567 | if (ret) | ||
568 | return ret; | ||
569 | |||
570 | switch (status) { | ||
571 | case ADD_STA_SUCCESS: | ||
572 | IWL_DEBUG_INFO(mvm, "RX BA Session %sed in fw\n", | ||
573 | start ? "start" : "stopp"); | ||
574 | break; | ||
575 | case ADD_STA_IMMEDIATE_BA_FAILURE: | ||
576 | IWL_WARN(mvm, "RX BA Session refused by fw\n"); | ||
577 | ret = -ENOSPC; | ||
578 | break; | ||
579 | default: | ||
580 | ret = -EIO; | ||
581 | IWL_ERR(mvm, "RX BA Session failed %sing, status 0x%x\n", | ||
582 | start ? "start" : "stopp", status); | ||
583 | break; | ||
584 | } | ||
585 | |||
586 | return ret; | ||
587 | } | ||
588 | |||
589 | static int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | ||
590 | int tid, u8 queue, bool start) | ||
591 | { | ||
592 | struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; | ||
593 | struct iwl_mvm_add_sta_cmd cmd = {}; | ||
594 | int ret; | ||
595 | u32 status; | ||
596 | |||
597 | lockdep_assert_held(&mvm->mutex); | ||
598 | |||
599 | if (start) { | ||
600 | mvm_sta->tfd_queue_msk |= BIT(queue); | ||
601 | mvm_sta->tid_disable_agg &= ~BIT(tid); | ||
602 | } else { | ||
603 | mvm_sta->tfd_queue_msk &= ~BIT(queue); | ||
604 | mvm_sta->tid_disable_agg |= BIT(tid); | ||
605 | } | ||
606 | |||
607 | cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color); | ||
608 | cmd.sta_id = mvm_sta->sta_id; | ||
609 | cmd.add_modify = STA_MODE_MODIFY; | ||
610 | cmd.modify_mask = STA_MODIFY_QUEUES | STA_MODIFY_TID_DISABLE_TX; | ||
611 | cmd.tfd_queue_msk = cpu_to_le32(mvm_sta->tfd_queue_msk); | ||
612 | cmd.tid_disable_tx = cpu_to_le16(mvm_sta->tid_disable_agg); | ||
613 | |||
614 | status = ADD_STA_SUCCESS; | ||
615 | ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd), | ||
616 | &cmd, &status); | ||
617 | if (ret) | ||
618 | return ret; | ||
619 | |||
620 | switch (status) { | ||
621 | case ADD_STA_SUCCESS: | ||
622 | break; | ||
623 | default: | ||
624 | ret = -EIO; | ||
625 | IWL_ERR(mvm, "TX BA Session failed %sing, status 0x%x\n", | ||
626 | start ? "start" : "stopp", status); | ||
627 | break; | ||
628 | } | ||
629 | |||
630 | return ret; | ||
631 | } | ||
632 | |||
633 | static const u8 tid_to_ac[] = { | ||
634 | IEEE80211_AC_BE, | ||
635 | IEEE80211_AC_BK, | ||
636 | IEEE80211_AC_BK, | ||
637 | IEEE80211_AC_BE, | ||
638 | IEEE80211_AC_VI, | ||
639 | IEEE80211_AC_VI, | ||
640 | IEEE80211_AC_VO, | ||
641 | IEEE80211_AC_VO, | ||
642 | }; | ||
643 | |||
644 | int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
645 | struct ieee80211_sta *sta, u16 tid, u16 *ssn) | ||
646 | { | ||
647 | struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; | ||
648 | struct iwl_mvm_tid_data *tid_data; | ||
649 | int txq_id; | ||
650 | |||
651 | if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT)) | ||
652 | return -EINVAL; | ||
653 | |||
654 | if (mvmsta->tid_data[tid].state != IWL_AGG_OFF) { | ||
655 | IWL_ERR(mvm, "Start AGG when state is not IWL_AGG_OFF %d!\n", | ||
656 | mvmsta->tid_data[tid].state); | ||
657 | return -ENXIO; | ||
658 | } | ||
659 | |||
660 | lockdep_assert_held(&mvm->mutex); | ||
661 | |||
662 | for (txq_id = IWL_MVM_FIRST_AGG_QUEUE; | ||
663 | txq_id <= IWL_MVM_LAST_AGG_QUEUE; txq_id++) | ||
664 | if (mvm->queue_to_mac80211[txq_id] == | ||
665 | IWL_INVALID_MAC80211_QUEUE) | ||
666 | break; | ||
667 | |||
668 | if (txq_id > IWL_MVM_LAST_AGG_QUEUE) { | ||
669 | IWL_ERR(mvm, "Failed to allocate agg queue\n"); | ||
670 | return -EIO; | ||
671 | } | ||
672 | |||
673 | /* the new tx queue is still connected to the same mac80211 queue */ | ||
674 | mvm->queue_to_mac80211[txq_id] = vif->hw_queue[tid_to_ac[tid]]; | ||
675 | |||
676 | spin_lock_bh(&mvmsta->lock); | ||
677 | tid_data = &mvmsta->tid_data[tid]; | ||
678 | tid_data->ssn = SEQ_TO_SN(tid_data->seq_number); | ||
679 | tid_data->txq_id = txq_id; | ||
680 | *ssn = tid_data->ssn; | ||
681 | |||
682 | IWL_DEBUG_TX_QUEUES(mvm, | ||
683 | "Start AGG: sta %d tid %d queue %d - ssn = %d, next_recl = %d\n", | ||
684 | mvmsta->sta_id, tid, txq_id, tid_data->ssn, | ||
685 | tid_data->next_reclaimed); | ||
686 | |||
687 | if (tid_data->ssn == tid_data->next_reclaimed) { | ||
688 | tid_data->state = IWL_AGG_STARTING; | ||
689 | ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); | ||
690 | } else { | ||
691 | tid_data->state = IWL_EMPTYING_HW_QUEUE_ADDBA; | ||
692 | } | ||
693 | |||
694 | spin_unlock_bh(&mvmsta->lock); | ||
695 | |||
696 | return 0; | ||
697 | } | ||
698 | |||
699 | int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
700 | struct ieee80211_sta *sta, u16 tid, u8 buf_size) | ||
701 | { | ||
702 | struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; | ||
703 | struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; | ||
704 | int queue, fifo, ret; | ||
705 | u16 ssn; | ||
706 | |||
707 | buf_size = min_t(int, buf_size, LINK_QUAL_AGG_FRAME_LIMIT_DEF); | ||
708 | |||
709 | spin_lock_bh(&mvmsta->lock); | ||
710 | ssn = tid_data->ssn; | ||
711 | queue = tid_data->txq_id; | ||
712 | tid_data->state = IWL_AGG_ON; | ||
713 | tid_data->ssn = 0xffff; | ||
714 | spin_unlock_bh(&mvmsta->lock); | ||
715 | |||
716 | fifo = iwl_mvm_ac_to_tx_fifo[tid_to_ac[tid]]; | ||
717 | |||
718 | ret = iwl_mvm_sta_tx_agg(mvm, sta, tid, queue, true); | ||
719 | if (ret) | ||
720 | return -EIO; | ||
721 | |||
722 | iwl_trans_txq_enable(mvm->trans, queue, fifo, mvmsta->sta_id, tid, | ||
723 | buf_size, ssn); | ||
724 | |||
725 | /* | ||
726 | * Even though in theory the peer could have different | ||
727 | * aggregation reorder buffer sizes for different sessions, | ||
728 | * our ucode doesn't allow for that and has a global limit | ||
729 | * for each station. Therefore, use the minimum of all the | ||
730 | * aggregation sessions and our default value. | ||
731 | */ | ||
732 | mvmsta->max_agg_bufsize = | ||
733 | min(mvmsta->max_agg_bufsize, buf_size); | ||
734 | mvmsta->lq_sta.lq.agg_frame_cnt_limit = mvmsta->max_agg_bufsize; | ||
735 | |||
736 | if (mvm->cfg->ht_params->use_rts_for_aggregation) { | ||
737 | /* | ||
738 | * switch to RTS/CTS if it is the prefer protection | ||
739 | * method for HT traffic | ||
740 | */ | ||
741 | mvmsta->lq_sta.lq.flags |= LQ_FLAG_SET_STA_TLC_RTS_MSK; | ||
742 | /* | ||
743 | * TODO: remove the TLC_RTS flag when we tear down the last | ||
744 | * AGG session (agg_tids_count in DVM) | ||
745 | */ | ||
746 | } | ||
747 | |||
748 | IWL_DEBUG_HT(mvm, "Tx aggregation enabled on ra = %pM tid = %d\n", | ||
749 | sta->addr, tid); | ||
750 | |||
751 | return iwl_mvm_send_lq_cmd(mvm, &mvmsta->lq_sta.lq, CMD_ASYNC, false); | ||
752 | } | ||
753 | |||
754 | int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
755 | struct ieee80211_sta *sta, u16 tid) | ||
756 | { | ||
757 | struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; | ||
758 | struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; | ||
759 | u16 txq_id; | ||
760 | int err; | ||
761 | |||
762 | spin_lock_bh(&mvmsta->lock); | ||
763 | |||
764 | txq_id = tid_data->txq_id; | ||
765 | |||
766 | IWL_DEBUG_TX_QUEUES(mvm, "Stop AGG: sta %d tid %d q %d state %d\n", | ||
767 | mvmsta->sta_id, tid, txq_id, tid_data->state); | ||
768 | |||
769 | switch (tid_data->state) { | ||
770 | case IWL_AGG_ON: | ||
771 | tid_data->ssn = SEQ_TO_SN(tid_data->seq_number); | ||
772 | |||
773 | IWL_DEBUG_TX_QUEUES(mvm, | ||
774 | "ssn = %d, next_recl = %d\n", | ||
775 | tid_data->ssn, tid_data->next_reclaimed); | ||
776 | |||
777 | /* There are still packets for this RA / TID in the HW */ | ||
778 | if (tid_data->ssn != tid_data->next_reclaimed) { | ||
779 | tid_data->state = IWL_EMPTYING_HW_QUEUE_DELBA; | ||
780 | err = 0; | ||
781 | break; | ||
782 | } | ||
783 | |||
784 | tid_data->ssn = 0xffff; | ||
785 | iwl_trans_txq_disable(mvm->trans, txq_id); | ||
786 | /* fall through */ | ||
787 | case IWL_AGG_STARTING: | ||
788 | case IWL_EMPTYING_HW_QUEUE_ADDBA: | ||
789 | /* | ||
790 | * The agg session has been stopped before it was set up. This | ||
791 | * can happen when the AddBA timer times out for example. | ||
792 | */ | ||
793 | |||
794 | /* No barriers since we are under mutex */ | ||
795 | lockdep_assert_held(&mvm->mutex); | ||
796 | mvm->queue_to_mac80211[txq_id] = IWL_INVALID_MAC80211_QUEUE; | ||
797 | |||
798 | ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); | ||
799 | tid_data->state = IWL_AGG_OFF; | ||
800 | err = 0; | ||
801 | break; | ||
802 | default: | ||
803 | IWL_ERR(mvm, | ||
804 | "Stopping AGG while state not ON or starting for %d on %d (%d)\n", | ||
805 | mvmsta->sta_id, tid, tid_data->state); | ||
806 | IWL_ERR(mvm, | ||
807 | "\ttid_data->txq_id = %d\n", tid_data->txq_id); | ||
808 | err = -EINVAL; | ||
809 | } | ||
810 | |||
811 | spin_unlock_bh(&mvmsta->lock); | ||
812 | |||
813 | return err; | ||
814 | } | ||
815 | |||
816 | static int iwl_mvm_set_fw_key_idx(struct iwl_mvm *mvm) | ||
817 | { | ||
818 | int i; | ||
819 | |||
820 | lockdep_assert_held(&mvm->mutex); | ||
821 | |||
822 | i = find_first_zero_bit(mvm->fw_key_table, STA_KEY_MAX_NUM); | ||
823 | |||
824 | if (i == STA_KEY_MAX_NUM) | ||
825 | return STA_KEY_IDX_INVALID; | ||
826 | |||
827 | __set_bit(i, mvm->fw_key_table); | ||
828 | |||
829 | return i; | ||
830 | } | ||
831 | |||
832 | static u8 iwl_mvm_get_key_sta_id(struct ieee80211_vif *vif, | ||
833 | struct ieee80211_sta *sta) | ||
834 | { | ||
835 | struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv; | ||
836 | |||
837 | if (sta) { | ||
838 | struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; | ||
839 | |||
840 | return mvm_sta->sta_id; | ||
841 | } | ||
842 | |||
843 | /* | ||
844 | * The device expects GTKs for station interfaces to be | ||
845 | * installed as GTKs for the AP station. If we have no | ||
846 | * station ID, then use AP's station ID. | ||
847 | */ | ||
848 | if (vif->type == NL80211_IFTYPE_STATION && | ||
849 | mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) | ||
850 | return mvmvif->ap_sta_id; | ||
851 | |||
852 | return IWL_INVALID_STATION; | ||
853 | } | ||
854 | |||
855 | static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, | ||
856 | struct iwl_mvm_sta *mvm_sta, | ||
857 | struct ieee80211_key_conf *keyconf, | ||
858 | u8 sta_id, u32 tkip_iv32, u16 *tkip_p1k, | ||
859 | u32 cmd_flags) | ||
860 | { | ||
861 | __le16 key_flags; | ||
862 | struct iwl_mvm_add_sta_cmd cmd = {}; | ||
863 | int ret, status; | ||
864 | u16 keyidx; | ||
865 | int i; | ||
866 | |||
867 | keyidx = (keyconf->keyidx << STA_KEY_FLG_KEYID_POS) & | ||
868 | STA_KEY_FLG_KEYID_MSK; | ||
869 | key_flags = cpu_to_le16(keyidx); | ||
870 | key_flags |= cpu_to_le16(STA_KEY_FLG_WEP_KEY_MAP); | ||
871 | |||
872 | switch (keyconf->cipher) { | ||
873 | case WLAN_CIPHER_SUITE_TKIP: | ||
874 | key_flags |= cpu_to_le16(STA_KEY_FLG_TKIP); | ||
875 | cmd.key.tkip_rx_tsc_byte2 = tkip_iv32; | ||
876 | for (i = 0; i < 5; i++) | ||
877 | cmd.key.tkip_rx_ttak[i] = cpu_to_le16(tkip_p1k[i]); | ||
878 | memcpy(cmd.key.key, keyconf->key, keyconf->keylen); | ||
879 | break; | ||
880 | case WLAN_CIPHER_SUITE_CCMP: | ||
881 | key_flags |= cpu_to_le16(STA_KEY_FLG_CCM); | ||
882 | memcpy(cmd.key.key, keyconf->key, keyconf->keylen); | ||
883 | break; | ||
884 | default: | ||
885 | WARN_ON(1); | ||
886 | return -EINVAL; | ||
887 | } | ||
888 | |||
889 | if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE)) | ||
890 | key_flags |= cpu_to_le16(STA_KEY_MULTICAST); | ||
891 | |||
892 | cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color); | ||
893 | cmd.key.key_offset = keyconf->hw_key_idx; | ||
894 | cmd.key.key_flags = key_flags; | ||
895 | cmd.add_modify = STA_MODE_MODIFY; | ||
896 | cmd.modify_mask = STA_MODIFY_KEY; | ||
897 | cmd.sta_id = sta_id; | ||
898 | |||
899 | status = ADD_STA_SUCCESS; | ||
900 | if (cmd_flags == CMD_SYNC) | ||
901 | ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd), | ||
902 | &cmd, &status); | ||
903 | else | ||
904 | ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC, | ||
905 | sizeof(cmd), &cmd); | ||
906 | |||
907 | switch (status) { | ||
908 | case ADD_STA_SUCCESS: | ||
909 | IWL_DEBUG_WEP(mvm, "MODIFY_STA: set dynamic key passed\n"); | ||
910 | break; | ||
911 | default: | ||
912 | ret = -EIO; | ||
913 | IWL_ERR(mvm, "MODIFY_STA: set dynamic key failed\n"); | ||
914 | break; | ||
915 | } | ||
916 | |||
917 | return ret; | ||
918 | } | ||
919 | |||
920 | static int iwl_mvm_send_sta_igtk(struct iwl_mvm *mvm, | ||
921 | struct ieee80211_key_conf *keyconf, | ||
922 | u8 sta_id, bool remove_key) | ||
923 | { | ||
924 | struct iwl_mvm_mgmt_mcast_key_cmd igtk_cmd = {}; | ||
925 | |||
926 | /* verify the key details match the required command's expectations */ | ||
927 | if (WARN_ON((keyconf->cipher != WLAN_CIPHER_SUITE_AES_CMAC) || | ||
928 | (keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE) || | ||
929 | (keyconf->keyidx != 4 && keyconf->keyidx != 5))) | ||
930 | return -EINVAL; | ||
931 | |||
932 | igtk_cmd.key_id = cpu_to_le32(keyconf->keyidx); | ||
933 | igtk_cmd.sta_id = cpu_to_le32(sta_id); | ||
934 | |||
935 | if (remove_key) { | ||
936 | igtk_cmd.ctrl_flags |= cpu_to_le32(STA_KEY_NOT_VALID); | ||
937 | } else { | ||
938 | struct ieee80211_key_seq seq; | ||
939 | const u8 *pn; | ||
940 | |||
941 | memcpy(igtk_cmd.IGTK, keyconf->key, keyconf->keylen); | ||
942 | ieee80211_aes_cmac_calculate_k1_k2(keyconf, | ||
943 | igtk_cmd.K1, igtk_cmd.K2); | ||
944 | ieee80211_get_key_rx_seq(keyconf, 0, &seq); | ||
945 | pn = seq.aes_cmac.pn; | ||
946 | igtk_cmd.receive_seq_cnt = cpu_to_le64(((u64) pn[5] << 0) | | ||
947 | ((u64) pn[4] << 8) | | ||
948 | ((u64) pn[3] << 16) | | ||
949 | ((u64) pn[2] << 24) | | ||
950 | ((u64) pn[1] << 32) | | ||
951 | ((u64) pn[0] << 40)); | ||
952 | } | ||
953 | |||
954 | IWL_DEBUG_INFO(mvm, "%s igtk for sta %u\n", | ||
955 | remove_key ? "removing" : "installing", | ||
956 | igtk_cmd.sta_id); | ||
957 | |||
958 | return iwl_mvm_send_cmd_pdu(mvm, MGMT_MCAST_KEY, CMD_SYNC, | ||
959 | sizeof(igtk_cmd), &igtk_cmd); | ||
960 | } | ||
961 | |||
962 | |||
963 | static inline u8 *iwl_mvm_get_mac_addr(struct iwl_mvm *mvm, | ||
964 | struct ieee80211_vif *vif, | ||
965 | struct ieee80211_sta *sta) | ||
966 | { | ||
967 | struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv; | ||
968 | |||
969 | if (sta) | ||
970 | return sta->addr; | ||
971 | |||
972 | if (vif->type == NL80211_IFTYPE_STATION && | ||
973 | mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) { | ||
974 | u8 sta_id = mvmvif->ap_sta_id; | ||
975 | sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], | ||
976 | lockdep_is_held(&mvm->mutex)); | ||
977 | return sta->addr; | ||
978 | } | ||
979 | |||
980 | |||
981 | return NULL; | ||
982 | } | ||
983 | |||
984 | int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, | ||
985 | struct ieee80211_vif *vif, | ||
986 | struct ieee80211_sta *sta, | ||
987 | struct ieee80211_key_conf *keyconf, | ||
988 | bool have_key_offset) | ||
989 | { | ||
990 | struct iwl_mvm_sta *mvm_sta; | ||
991 | int ret; | ||
992 | u8 *addr, sta_id; | ||
993 | struct ieee80211_key_seq seq; | ||
994 | u16 p1k[5]; | ||
995 | |||
996 | lockdep_assert_held(&mvm->mutex); | ||
997 | |||
998 | /* Get the station id from the mvm local station table */ | ||
999 | sta_id = iwl_mvm_get_key_sta_id(vif, sta); | ||
1000 | if (sta_id == IWL_INVALID_STATION) { | ||
1001 | IWL_ERR(mvm, "Failed to find station id\n"); | ||
1002 | return -EINVAL; | ||
1003 | } | ||
1004 | |||
1005 | if (keyconf->cipher == WLAN_CIPHER_SUITE_AES_CMAC) { | ||
1006 | ret = iwl_mvm_send_sta_igtk(mvm, keyconf, sta_id, false); | ||
1007 | goto end; | ||
1008 | } | ||
1009 | |||
1010 | /* | ||
1011 | * It is possible that the 'sta' parameter is NULL, and thus | ||
1012 | * there is a need to retrieve the sta from the local station table. | ||
1013 | */ | ||
1014 | if (!sta) { | ||
1015 | sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], | ||
1016 | lockdep_is_held(&mvm->mutex)); | ||
1017 | if (IS_ERR_OR_NULL(sta)) { | ||
1018 | IWL_ERR(mvm, "Invalid station id\n"); | ||
1019 | return -EINVAL; | ||
1020 | } | ||
1021 | } | ||
1022 | |||
1023 | mvm_sta = (struct iwl_mvm_sta *)sta->drv_priv; | ||
1024 | if (WARN_ON_ONCE(mvm_sta->vif != vif)) | ||
1025 | return -EINVAL; | ||
1026 | |||
1027 | if (!have_key_offset) { | ||
1028 | /* | ||
1029 | * The D3 firmware hardcodes the PTK offset to 0, so we have to | ||
1030 | * configure it there. As a result, this workaround exists to | ||
1031 | * let the caller set the key offset (hw_key_idx), see d3.c. | ||
1032 | */ | ||
1033 | keyconf->hw_key_idx = iwl_mvm_set_fw_key_idx(mvm); | ||
1034 | if (keyconf->hw_key_idx == STA_KEY_IDX_INVALID) | ||
1035 | return -ENOSPC; | ||
1036 | } | ||
1037 | |||
1038 | switch (keyconf->cipher) { | ||
1039 | case WLAN_CIPHER_SUITE_TKIP: | ||
1040 | addr = iwl_mvm_get_mac_addr(mvm, vif, sta); | ||
1041 | /* get phase 1 key from mac80211 */ | ||
1042 | ieee80211_get_key_rx_seq(keyconf, 0, &seq); | ||
1043 | ieee80211_get_tkip_rx_p1k(keyconf, addr, seq.tkip.iv32, p1k); | ||
1044 | ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, sta_id, | ||
1045 | seq.tkip.iv32, p1k, CMD_SYNC); | ||
1046 | break; | ||
1047 | case WLAN_CIPHER_SUITE_CCMP: | ||
1048 | ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, sta_id, | ||
1049 | 0, NULL, CMD_SYNC); | ||
1050 | break; | ||
1051 | default: | ||
1052 | IWL_ERR(mvm, "Unknown cipher %x\n", keyconf->cipher); | ||
1053 | ret = -EINVAL; | ||
1054 | } | ||
1055 | |||
1056 | if (ret) | ||
1057 | __clear_bit(keyconf->hw_key_idx, mvm->fw_key_table); | ||
1058 | |||
1059 | end: | ||
1060 | IWL_DEBUG_WEP(mvm, "key: cipher=%x len=%d idx=%d sta=%pM ret=%d\n", | ||
1061 | keyconf->cipher, keyconf->keylen, keyconf->keyidx, | ||
1062 | sta->addr, ret); | ||
1063 | return ret; | ||
1064 | } | ||
1065 | |||
1066 | int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, | ||
1067 | struct ieee80211_vif *vif, | ||
1068 | struct ieee80211_sta *sta, | ||
1069 | struct ieee80211_key_conf *keyconf) | ||
1070 | { | ||
1071 | struct iwl_mvm_sta *mvm_sta; | ||
1072 | struct iwl_mvm_add_sta_cmd cmd = {}; | ||
1073 | __le16 key_flags; | ||
1074 | int ret, status; | ||
1075 | u8 sta_id; | ||
1076 | |||
1077 | lockdep_assert_held(&mvm->mutex); | ||
1078 | |||
1079 | /* Get the station id from the mvm local station table */ | ||
1080 | sta_id = iwl_mvm_get_key_sta_id(vif, sta); | ||
1081 | |||
1082 | IWL_DEBUG_WEP(mvm, "mvm remove dynamic key: idx=%d sta=%d\n", | ||
1083 | keyconf->keyidx, sta_id); | ||
1084 | |||
1085 | if (keyconf->cipher == WLAN_CIPHER_SUITE_AES_CMAC) | ||
1086 | return iwl_mvm_send_sta_igtk(mvm, keyconf, sta_id, true); | ||
1087 | |||
1088 | ret = __test_and_clear_bit(keyconf->hw_key_idx, mvm->fw_key_table); | ||
1089 | if (!ret) { | ||
1090 | IWL_ERR(mvm, "offset %d not used in fw key table.\n", | ||
1091 | keyconf->hw_key_idx); | ||
1092 | return -ENOENT; | ||
1093 | } | ||
1094 | |||
1095 | if (sta_id == IWL_INVALID_STATION) { | ||
1096 | IWL_DEBUG_WEP(mvm, "station non-existent, early return.\n"); | ||
1097 | return 0; | ||
1098 | } | ||
1099 | |||
1100 | /* | ||
1101 | * It is possible that the 'sta' parameter is NULL, and thus | ||
1102 | * there is a need to retrieve the sta from the local station table, | ||
1103 | * for example when a GTK is removed (where the sta_id will then be | ||
1104 | * the AP ID, and no station was passed by mac80211.) | ||
1105 | */ | ||
1106 | if (!sta) { | ||
1107 | sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], | ||
1108 | lockdep_is_held(&mvm->mutex)); | ||
1109 | if (!sta) { | ||
1110 | IWL_ERR(mvm, "Invalid station id\n"); | ||
1111 | return -EINVAL; | ||
1112 | } | ||
1113 | } | ||
1114 | |||
1115 | mvm_sta = (struct iwl_mvm_sta *)sta->drv_priv; | ||
1116 | if (WARN_ON_ONCE(mvm_sta->vif != vif)) | ||
1117 | return -EINVAL; | ||
1118 | |||
1119 | key_flags = cpu_to_le16(keyconf->keyidx & STA_KEY_FLG_KEYID_MSK); | ||
1120 | key_flags |= cpu_to_le16(STA_KEY_FLG_NO_ENC | STA_KEY_FLG_WEP_KEY_MAP); | ||
1121 | key_flags |= cpu_to_le16(STA_KEY_NOT_VALID); | ||
1122 | |||
1123 | if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE)) | ||
1124 | key_flags |= cpu_to_le16(STA_KEY_MULTICAST); | ||
1125 | |||
1126 | cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color); | ||
1127 | cmd.key.key_flags = key_flags; | ||
1128 | cmd.key.key_offset = keyconf->hw_key_idx; | ||
1129 | cmd.sta_id = sta_id; | ||
1130 | |||
1131 | cmd.modify_mask = STA_MODIFY_KEY; | ||
1132 | cmd.add_modify = STA_MODE_MODIFY; | ||
1133 | |||
1134 | status = ADD_STA_SUCCESS; | ||
1135 | ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd), | ||
1136 | &cmd, &status); | ||
1137 | |||
1138 | switch (status) { | ||
1139 | case ADD_STA_SUCCESS: | ||
1140 | IWL_DEBUG_WEP(mvm, "MODIFY_STA: remove sta key passed\n"); | ||
1141 | break; | ||
1142 | default: | ||
1143 | ret = -EIO; | ||
1144 | IWL_ERR(mvm, "MODIFY_STA: remove sta key failed\n"); | ||
1145 | break; | ||
1146 | } | ||
1147 | |||
1148 | return ret; | ||
1149 | } | ||
1150 | |||
1151 | void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm, | ||
1152 | struct ieee80211_vif *vif, | ||
1153 | struct ieee80211_key_conf *keyconf, | ||
1154 | struct ieee80211_sta *sta, u32 iv32, | ||
1155 | u16 *phase1key) | ||
1156 | { | ||
1157 | struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; | ||
1158 | u8 sta_id = iwl_mvm_get_key_sta_id(vif, sta); | ||
1159 | |||
1160 | if (sta_id == IWL_INVALID_STATION) | ||
1161 | return; | ||
1162 | |||
1163 | iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, sta_id, | ||
1164 | iv32, phase1key, CMD_ASYNC); | ||
1165 | } | ||
1166 | |||
1167 | void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm, int sta_id) | ||
1168 | { | ||
1169 | struct iwl_mvm_add_sta_cmd cmd = { | ||
1170 | .add_modify = STA_MODE_MODIFY, | ||
1171 | .sta_id = sta_id, | ||
1172 | .modify_mask = STA_MODIFY_SLEEPING_STA_TX_COUNT, | ||
1173 | .sleep_state_flags = cpu_to_le16(STA_SLEEP_STATE_AWAKE), | ||
1174 | }; | ||
1175 | int ret; | ||
1176 | |||
1177 | /* | ||
1178 | * Same modify mask for sleep_tx_count and sleep_state_flags but this | ||
1179 | * should be fine since if we set the STA as "awake", then | ||
1180 | * sleep_tx_count is not relevant. | ||
1181 | */ | ||
1182 | ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC, sizeof(cmd), &cmd); | ||
1183 | if (ret) | ||
1184 | IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret); | ||
1185 | } | ||
1186 | |||
1187 | void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm, int sta_id, | ||
1188 | enum ieee80211_frame_release_type reason, | ||
1189 | u16 cnt) | ||
1190 | { | ||
1191 | u16 sleep_state_flags = | ||
1192 | (reason == IEEE80211_FRAME_RELEASE_UAPSD) ? | ||
1193 | STA_SLEEP_STATE_UAPSD : STA_SLEEP_STATE_PS_POLL; | ||
1194 | struct iwl_mvm_add_sta_cmd cmd = { | ||
1195 | .add_modify = STA_MODE_MODIFY, | ||
1196 | .sta_id = sta_id, | ||
1197 | .modify_mask = STA_MODIFY_SLEEPING_STA_TX_COUNT, | ||
1198 | .sleep_tx_count = cpu_to_le16(cnt), | ||
1199 | /* | ||
1200 | * Same modify mask for sleep_tx_count and sleep_state_flags so | ||
1201 | * we must set the sleep_state_flags too. | ||
1202 | */ | ||
1203 | .sleep_state_flags = cpu_to_le16(sleep_state_flags), | ||
1204 | }; | ||
1205 | int ret; | ||
1206 | |||
1207 | /* TODO: somehow the fw doesn't seem to take PS_POLL into account */ | ||
1208 | ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC, sizeof(cmd), &cmd); | ||
1209 | if (ret) | ||
1210 | IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret); | ||
1211 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.h b/drivers/net/wireless/iwlwifi/mvm/sta.h new file mode 100644 index 000000000000..1bf301097984 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/sta.h | |||
@@ -0,0 +1,368 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called LICENSE.GPL. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | * | ||
62 | *****************************************************************************/ | ||
63 | |||
64 | #ifndef __sta_h__ | ||
65 | #define __sta_h__ | ||
66 | |||
67 | #include <linux/spinlock.h> | ||
68 | #include <net/mac80211.h> | ||
69 | #include <linux/wait.h> | ||
70 | |||
71 | #include "iwl-trans.h" /* for IWL_MAX_TID_COUNT */ | ||
72 | #include "fw-api.h" /* IWL_MVM_STATION_COUNT */ | ||
73 | #include "rs.h" | ||
74 | |||
75 | struct iwl_mvm; | ||
76 | |||
77 | /** | ||
78 | * DOC: station table - introduction | ||
79 | * | ||
80 | * The station table is a list of data structure that reprensent the stations. | ||
81 | * In STA/P2P client mode, the driver will hold one station for the AP/ GO. | ||
82 | * In GO/AP mode, the driver will have as many stations as associated clients. | ||
83 | * All these stations are reflected in the fw's station table. The driver | ||
84 | * keeps the fw's station table up to date with the ADD_STA command. Stations | ||
85 | * can be removed by the REMOVE_STA command. | ||
86 | * | ||
87 | * All the data related to a station is held in the structure %iwl_mvm_sta | ||
88 | * which is embed in the mac80211's %ieee80211_sta (in the drv_priv) area. | ||
89 | * This data includes the index of the station in the fw, per tid information | ||
90 | * (sequence numbers, Block-ack state machine, etc...). The stations are | ||
91 | * created and deleted by the %sta_state callback from %ieee80211_ops. | ||
92 | * | ||
93 | * The driver holds a map: %fw_id_to_mac_id that allows to fetch a | ||
94 | * %ieee80211_sta (and the %iwl_mvm_sta embedded into it) based on a fw | ||
95 | * station index. That way, the driver is able to get the tid related data in | ||
96 | * O(1) in time sensitive paths (Tx / Tx response / BA notification). These | ||
97 | * paths are triggered by the fw, and the driver needs to get a pointer to the | ||
98 | * %ieee80211 structure. This map helps to get that pointer quickly. | ||
99 | */ | ||
100 | |||
101 | /** | ||
102 | * DOC: station table - locking | ||
103 | * | ||
104 | * As stated before, the station is created / deleted by mac80211's %sta_state | ||
105 | * callback from %ieee80211_ops which can sleep. The next paragraph explains | ||
106 | * the locking of a single stations, the next ones relates to the station | ||
107 | * table. | ||
108 | * | ||
109 | * The station holds the sequence number per tid. So this data needs to be | ||
110 | * accessed in the Tx path (which is softIRQ). It also holds the Block-Ack | ||
111 | * information (the state machine / and the logic that checks if the queues | ||
112 | * were drained), so it also needs to be accessible from the Tx response flow. | ||
113 | * In short, the station needs to be access from sleepable context as well as | ||
114 | * from tasklets, so the station itself needs a spinlock. | ||
115 | * | ||
116 | * The writers of %fw_id_to_mac_id map are serialized by the global mutex of | ||
117 | * the mvm op_mode. This is possible since %sta_state can sleep. | ||
118 | * The pointers in this map are RCU protected, hence we won't replace the | ||
119 | * station while we have Tx / Tx response / BA notification running. | ||
120 | * | ||
121 | * If a station is deleted while it still has packets in its A-MPDU queues, | ||
122 | * then the reclaim flow will notice that there is no station in the map for | ||
123 | * sta_id and it will dump the responses. | ||
124 | */ | ||
125 | |||
126 | /** | ||
127 | * DOC: station table - internal stations | ||
128 | * | ||
129 | * The FW needs a few internal stations that are not reflected in | ||
130 | * mac80211, such as broadcast station in AP / GO mode, or AUX sta for | ||
131 | * scanning and P2P device (during the GO negotiation). | ||
132 | * For these kind of stations we have %iwl_mvm_int_sta struct which holds the | ||
133 | * data relevant for them from both %iwl_mvm_sta and %ieee80211_sta. | ||
134 | * Usually the data for these stations is static, so no locking is required, | ||
135 | * and no TID data as this is also not needed. | ||
136 | * One thing to note, is that these stations have an ID in the fw, but not | ||
137 | * in mac80211. In order to "reserve" them a sta_id in %fw_id_to_mac_id | ||
138 | * we fill ERR_PTR(EINVAL) in this mapping and all other dereferencing of | ||
139 | * pointers from this mapping need to check that the value is not error | ||
140 | * or NULL. | ||
141 | * | ||
142 | * Currently there is only one auxiliary station for scanning, initialized | ||
143 | * on init. | ||
144 | */ | ||
145 | |||
146 | /** | ||
147 | * DOC: station table - AP Station in STA mode | ||
148 | * | ||
149 | * %iwl_mvm_vif includes the index of the AP station in the fw's STA table: | ||
150 | * %ap_sta_id. To get the point to the coresponsding %ieee80211_sta, | ||
151 | * &fw_id_to_mac_id can be used. Due to the way the fw works, we must not remove | ||
152 | * the AP station from the fw before setting the MAC context as unassociated. | ||
153 | * Hence, %fw_id_to_mac_id[%ap_sta_id] will be NULLed when the AP station is | ||
154 | * removed by mac80211, but the station won't be removed in the fw until the | ||
155 | * VIF is set as unassociated. Then, %ap_sta_id will be invalidated. | ||
156 | */ | ||
157 | |||
158 | /** | ||
159 | * DOC: station table - Drain vs. Flush | ||
160 | * | ||
161 | * Flush means that all the frames in the SCD queue are dumped regardless the | ||
162 | * station to which they were sent. We do that when we disassociate and before | ||
163 | * we remove the STA of the AP. The flush can be done synchronously against the | ||
164 | * fw. | ||
165 | * Drain means that the fw will drop all the frames sent to a specific station. | ||
166 | * This is useful when a client (if we are IBSS / GO or AP) disassociates. In | ||
167 | * that case, we need to drain all the frames for that client from the AC queues | ||
168 | * that are shared with the other clients. Only then, we can remove the STA in | ||
169 | * the fw. In order to do so, we track the non-AMPDU packets for each station. | ||
170 | * If mac80211 removes a STA and if it still has non-AMPDU packets pending in | ||
171 | * the queues, we mark this station as %EBUSY in %fw_id_to_mac_id, and drop all | ||
172 | * the frames for this STA (%iwl_mvm_rm_sta). When the last frame is dropped | ||
173 | * (we know about it with its Tx response), we remove the station in fw and set | ||
174 | * it as %NULL in %fw_id_to_mac_id: this is the purpose of | ||
175 | * %iwl_mvm_sta_drained_wk. | ||
176 | */ | ||
177 | |||
178 | /** | ||
179 | * DOC: station table - fw restart | ||
180 | * | ||
181 | * When the fw asserts, or we have any other issue that requires to reset the | ||
182 | * driver, we require mac80211 to reconfigure the driver. Since the private | ||
183 | * data of the stations is embed in mac80211's %ieee80211_sta, that data will | ||
184 | * not be zeroed and needs to be reinitialized manually. | ||
185 | * %IWL_MVM_STATUS_IN_HW_RESTART is set during restart and that will hint us | ||
186 | * that we must not allocate a new sta_id but reuse the previous one. This | ||
187 | * means that the stations being re-added after the reset will have the same | ||
188 | * place in the fw as before the reset. We do need to zero the %fw_id_to_mac_id | ||
189 | * map, since the stations aren't in the fw any more. Internal stations that | ||
190 | * are not added by mac80211 will be re-added in the init flow that is called | ||
191 | * after the restart: mac80211 call's %iwl_mvm_mac_start which calls to | ||
192 | * %iwl_mvm_up. | ||
193 | */ | ||
194 | |||
195 | /** | ||
196 | * DOC: AP mode - PS | ||
197 | * | ||
198 | * When a station is asleep, the fw will set it as "asleep". All the | ||
199 | * non-aggregation frames to that station will be dropped by the fw | ||
200 | * (%TX_STATUS_FAIL_DEST_PS failure code). | ||
201 | * AMPDUs are in a separate queue that is stopped by the fw. We just need to | ||
202 | * let mac80211 know how many frames we have in these queues so that it can | ||
203 | * properly handle trigger frames. | ||
204 | * When the a trigger frame is received, mac80211 tells the driver to send | ||
205 | * frames from the AMPDU queues or AC queue depending on which queue are | ||
206 | * delivery-enabled and what TID has frames to transmit (Note that mac80211 has | ||
207 | * all the knowledege since all the non-agg frames are buffered / filtered, and | ||
208 | * the driver tells mac80211 about agg frames). The driver needs to tell the fw | ||
209 | * to let frames out even if the station is asleep. This is done by | ||
210 | * %iwl_mvm_sta_modify_sleep_tx_count. | ||
211 | * When we receive a frame from that station with PM bit unset, the | ||
212 | * driver needs to let the fw know that this station isn't alseep any more. | ||
213 | * This is done by %iwl_mvm_sta_modify_ps_wake. | ||
214 | * | ||
215 | * TODO - EOSP handling | ||
216 | */ | ||
217 | |||
218 | /** | ||
219 | * enum iwl_mvm_agg_state | ||
220 | * | ||
221 | * The state machine of the BA agreement establishment / tear down. | ||
222 | * These states relate to a specific RA / TID. | ||
223 | * | ||
224 | * @IWL_AGG_OFF: aggregation is not used | ||
225 | * @IWL_AGG_STARTING: aggregation are starting (between start and oper) | ||
226 | * @IWL_AGG_ON: aggregation session is up | ||
227 | * @IWL_EMPTYING_HW_QUEUE_ADDBA: establishing a BA session - waiting for the | ||
228 | * HW queue to be empty from packets for this RA /TID. | ||
229 | * @IWL_EMPTYING_HW_QUEUE_DELBA: tearing down a BA session - waiting for the | ||
230 | * HW queue to be empty from packets for this RA /TID. | ||
231 | */ | ||
232 | enum iwl_mvm_agg_state { | ||
233 | IWL_AGG_OFF = 0, | ||
234 | IWL_AGG_STARTING, | ||
235 | IWL_AGG_ON, | ||
236 | IWL_EMPTYING_HW_QUEUE_ADDBA, | ||
237 | IWL_EMPTYING_HW_QUEUE_DELBA, | ||
238 | }; | ||
239 | |||
240 | /** | ||
241 | * struct iwl_mvm_tid_data - holds the states for each RA / TID | ||
242 | * @seq_number: the next WiFi sequence number to use | ||
243 | * @next_reclaimed: the WiFi sequence number of the next packet to be acked. | ||
244 | * This is basically (last acked packet++). | ||
245 | * @rate_n_flags: Rate at which Tx was attempted. Holds the data between the | ||
246 | * Tx response (TX_CMD), and the block ack notification (COMPRESSED_BA). | ||
247 | * @state: state of the BA agreement establishment / tear down. | ||
248 | * @txq_id: Tx queue used by the BA session | ||
249 | * @ssn: the first packet to be sent in AGG HW queue in Tx AGG start flow, or | ||
250 | * the first packet to be sent in legacy HW queue in Tx AGG stop flow. | ||
251 | * Basically when next_reclaimed reaches ssn, we can tell mac80211 that | ||
252 | * we are ready to finish the Tx AGG stop / start flow. | ||
253 | * @wait_for_ba: Expect block-ack before next Tx reply | ||
254 | */ | ||
255 | struct iwl_mvm_tid_data { | ||
256 | u16 seq_number; | ||
257 | u16 next_reclaimed; | ||
258 | /* The rest is Tx AGG related */ | ||
259 | u32 rate_n_flags; | ||
260 | enum iwl_mvm_agg_state state; | ||
261 | u16 txq_id; | ||
262 | u16 ssn; | ||
263 | bool wait_for_ba; | ||
264 | }; | ||
265 | |||
266 | /** | ||
267 | * struct iwl_mvm_sta - representation of a station in the driver | ||
268 | * @sta_id: the index of the station in the fw (will be replaced by id_n_color) | ||
269 | * @tfd_queue_msk: the tfd queues used by the station | ||
270 | * @mac_id_n_color: the MAC context this station is linked to | ||
271 | * @tid_disable_agg: bitmap: if bit(tid) is set, the fw won't send ampdus for | ||
272 | * tid. | ||
273 | * @max_agg_bufsize: the maximal size of the AGG buffer for this station | ||
274 | * @lock: lock to protect the whole struct. Since %tid_data is access from Tx | ||
275 | * and from Tx response flow, it needs a spinlock. | ||
276 | * @pending_frames: number of frames for this STA on the shared Tx queues. | ||
277 | * @tid_data: per tid data. Look at %iwl_mvm_tid_data. | ||
278 | * | ||
279 | * When mac80211 creates a station it reserves some space (hw->sta_data_size) | ||
280 | * in the structure for use by driver. This structure is placed in that | ||
281 | * space. | ||
282 | * | ||
283 | */ | ||
284 | struct iwl_mvm_sta { | ||
285 | u32 sta_id; | ||
286 | u32 tfd_queue_msk; | ||
287 | u32 mac_id_n_color; | ||
288 | u16 tid_disable_agg; | ||
289 | u8 max_agg_bufsize; | ||
290 | spinlock_t lock; | ||
291 | atomic_t pending_frames; | ||
292 | struct iwl_mvm_tid_data tid_data[IWL_MAX_TID_COUNT]; | ||
293 | struct iwl_lq_sta lq_sta; | ||
294 | struct ieee80211_vif *vif; | ||
295 | |||
296 | #ifdef CONFIG_PM_SLEEP | ||
297 | u16 last_seq_ctl; | ||
298 | #endif | ||
299 | }; | ||
300 | |||
301 | /** | ||
302 | * struct iwl_mvm_int_sta - representation of an internal station (auxiliary or | ||
303 | * broadcast) | ||
304 | * @sta_id: the index of the station in the fw (will be replaced by id_n_color) | ||
305 | * @tfd_queue_msk: the tfd queues used by the station | ||
306 | */ | ||
307 | struct iwl_mvm_int_sta { | ||
308 | u32 sta_id; | ||
309 | u32 tfd_queue_msk; | ||
310 | }; | ||
311 | |||
312 | int iwl_mvm_sta_add_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta); | ||
313 | int iwl_mvm_add_sta(struct iwl_mvm *mvm, | ||
314 | struct ieee80211_vif *vif, | ||
315 | struct ieee80211_sta *sta); | ||
316 | int iwl_mvm_rm_sta(struct iwl_mvm *mvm, | ||
317 | struct ieee80211_vif *vif, | ||
318 | struct ieee80211_sta *sta); | ||
319 | int iwl_mvm_rm_sta_id(struct iwl_mvm *mvm, | ||
320 | struct ieee80211_vif *vif, | ||
321 | u8 sta_id); | ||
322 | int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, | ||
323 | struct ieee80211_vif *vif, | ||
324 | struct ieee80211_sta *sta, | ||
325 | struct ieee80211_key_conf *key, | ||
326 | bool have_key_offset); | ||
327 | int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, | ||
328 | struct ieee80211_vif *vif, | ||
329 | struct ieee80211_sta *sta, | ||
330 | struct ieee80211_key_conf *keyconf); | ||
331 | |||
332 | void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm, | ||
333 | struct ieee80211_vif *vif, | ||
334 | struct ieee80211_key_conf *keyconf, | ||
335 | struct ieee80211_sta *sta, u32 iv32, | ||
336 | u16 *phase1key); | ||
337 | |||
338 | /* AMPDU */ | ||
339 | int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | ||
340 | int tid, u16 ssn, bool start); | ||
341 | int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
342 | struct ieee80211_sta *sta, u16 tid, u16 *ssn); | ||
343 | int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
344 | struct ieee80211_sta *sta, u16 tid, u8 buf_size); | ||
345 | int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
346 | struct ieee80211_sta *sta, u16 tid); | ||
347 | |||
348 | int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm); | ||
349 | int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta, | ||
350 | u32 qmask); | ||
351 | void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm, | ||
352 | struct iwl_mvm_int_sta *sta); | ||
353 | int iwl_mvm_send_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
354 | struct iwl_mvm_int_sta *bsta); | ||
355 | int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm, | ||
356 | struct iwl_mvm_int_sta *bsta); | ||
357 | int iwl_mvm_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
358 | struct iwl_mvm_int_sta *bsta); | ||
359 | int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *bsta); | ||
360 | void iwl_mvm_sta_drained_wk(struct work_struct *wk); | ||
361 | void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm, int sta_id); | ||
362 | void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm, int sta_id, | ||
363 | enum ieee80211_frame_release_type reason, | ||
364 | u16 cnt); | ||
365 | int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, | ||
366 | bool drain); | ||
367 | |||
368 | #endif /* __sta_h__ */ | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c new file mode 100644 index 000000000000..b9f076f4f17c --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c | |||
@@ -0,0 +1,569 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called LICENSE.GPL. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | * | ||
62 | *****************************************************************************/ | ||
63 | |||
64 | #include <linux/jiffies.h> | ||
65 | #include <net/mac80211.h> | ||
66 | |||
67 | #include "iwl-notif-wait.h" | ||
68 | #include "iwl-trans.h" | ||
69 | #include "fw-api.h" | ||
70 | #include "time-event.h" | ||
71 | #include "mvm.h" | ||
72 | #include "iwl-io.h" | ||
73 | #include "iwl-prph.h" | ||
74 | |||
75 | /* A TimeUnit is 1024 microsecond */ | ||
76 | #define TU_TO_JIFFIES(_tu) (usecs_to_jiffies((_tu) * 1024)) | ||
77 | #define MSEC_TO_TU(_msec) (_msec*1000/1024) | ||
78 | |||
79 | void iwl_mvm_te_clear_data(struct iwl_mvm *mvm, | ||
80 | struct iwl_mvm_time_event_data *te_data) | ||
81 | { | ||
82 | lockdep_assert_held(&mvm->time_event_lock); | ||
83 | |||
84 | if (te_data->id == TE_MAX) | ||
85 | return; | ||
86 | |||
87 | list_del(&te_data->list); | ||
88 | te_data->running = false; | ||
89 | te_data->uid = 0; | ||
90 | te_data->id = TE_MAX; | ||
91 | te_data->vif = NULL; | ||
92 | } | ||
93 | |||
94 | void iwl_mvm_roc_done_wk(struct work_struct *wk) | ||
95 | { | ||
96 | struct iwl_mvm *mvm = container_of(wk, struct iwl_mvm, roc_done_wk); | ||
97 | |||
98 | synchronize_net(); | ||
99 | |||
100 | /* | ||
101 | * Flush the offchannel queue -- this is called when the time | ||
102 | * event finishes or is cancelled, so that frames queued for it | ||
103 | * won't get stuck on the queue and be transmitted in the next | ||
104 | * time event. | ||
105 | * We have to send the command asynchronously since this cannot | ||
106 | * be under the mutex for locking reasons, but that's not an | ||
107 | * issue as it will have to complete before the next command is | ||
108 | * executed, and a new time event means a new command. | ||
109 | */ | ||
110 | iwl_mvm_flush_tx_path(mvm, BIT(IWL_OFFCHANNEL_QUEUE), false); | ||
111 | } | ||
112 | |||
113 | static void iwl_mvm_roc_finished(struct iwl_mvm *mvm) | ||
114 | { | ||
115 | /* | ||
116 | * First, clear the ROC_RUNNING status bit. This will cause the TX | ||
117 | * path to drop offchannel transmissions. That would also be done | ||
118 | * by mac80211, but it is racy, in particular in the case that the | ||
119 | * time event actually completed in the firmware (which is handled | ||
120 | * in iwl_mvm_te_handle_notif). | ||
121 | */ | ||
122 | clear_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status); | ||
123 | |||
124 | /* | ||
125 | * Of course, our status bit is just as racy as mac80211, so in | ||
126 | * addition, fire off the work struct which will drop all frames | ||
127 | * from the hardware queues that made it through the race. First | ||
128 | * it will of course synchronize the TX path to make sure that | ||
129 | * any *new* TX will be rejected. | ||
130 | */ | ||
131 | schedule_work(&mvm->roc_done_wk); | ||
132 | } | ||
133 | |||
134 | /* | ||
135 | * Handles a FW notification for an event that is known to the driver. | ||
136 | * | ||
137 | * @mvm: the mvm component | ||
138 | * @te_data: the time event data | ||
139 | * @notif: the notification data corresponding the time event data. | ||
140 | */ | ||
141 | static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, | ||
142 | struct iwl_mvm_time_event_data *te_data, | ||
143 | struct iwl_time_event_notif *notif) | ||
144 | { | ||
145 | lockdep_assert_held(&mvm->time_event_lock); | ||
146 | |||
147 | IWL_DEBUG_TE(mvm, "Handle time event notif - UID = 0x%x action %d\n", | ||
148 | le32_to_cpu(notif->unique_id), | ||
149 | le32_to_cpu(notif->action)); | ||
150 | |||
151 | /* | ||
152 | * The FW sends the start/end time event notifications even for events | ||
153 | * that it fails to schedule. This is indicated in the status field of | ||
154 | * the notification. This happens in cases that the scheduler cannot | ||
155 | * find a schedule that can handle the event (for example requesting a | ||
156 | * P2P Device discoveribility, while there are other higher priority | ||
157 | * events in the system). | ||
158 | */ | ||
159 | WARN_ONCE(!le32_to_cpu(notif->status), | ||
160 | "Failed to schedule time event\n"); | ||
161 | |||
162 | if (le32_to_cpu(notif->action) == TE_NOTIF_HOST_END) { | ||
163 | IWL_DEBUG_TE(mvm, | ||
164 | "TE ended - current time %lu, estimated end %lu\n", | ||
165 | jiffies, te_data->end_jiffies); | ||
166 | |||
167 | if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) { | ||
168 | ieee80211_remain_on_channel_expired(mvm->hw); | ||
169 | iwl_mvm_roc_finished(mvm); | ||
170 | } | ||
171 | |||
172 | /* | ||
173 | * By now, we should have finished association | ||
174 | * and know the dtim period. | ||
175 | */ | ||
176 | if (te_data->vif->type == NL80211_IFTYPE_STATION && | ||
177 | (!te_data->vif->bss_conf.assoc || | ||
178 | !te_data->vif->bss_conf.dtim_period)) | ||
179 | IWL_ERR(mvm, | ||
180 | "No assocation and the time event is over already...\n"); | ||
181 | |||
182 | iwl_mvm_te_clear_data(mvm, te_data); | ||
183 | } else if (le32_to_cpu(notif->action) == TE_NOTIF_HOST_START) { | ||
184 | te_data->running = true; | ||
185 | te_data->end_jiffies = jiffies + | ||
186 | TU_TO_JIFFIES(te_data->duration); | ||
187 | |||
188 | if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) { | ||
189 | set_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status); | ||
190 | ieee80211_ready_on_channel(mvm->hw); | ||
191 | } | ||
192 | } else { | ||
193 | IWL_WARN(mvm, "Got TE with unknown action\n"); | ||
194 | } | ||
195 | } | ||
196 | |||
197 | /* | ||
198 | * The Rx handler for time event notifications | ||
199 | */ | ||
200 | int iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm, | ||
201 | struct iwl_rx_cmd_buffer *rxb, | ||
202 | struct iwl_device_cmd *cmd) | ||
203 | { | ||
204 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
205 | struct iwl_time_event_notif *notif = (void *)pkt->data; | ||
206 | struct iwl_mvm_time_event_data *te_data, *tmp; | ||
207 | |||
208 | IWL_DEBUG_TE(mvm, "Time event notification - UID = 0x%x action %d\n", | ||
209 | le32_to_cpu(notif->unique_id), | ||
210 | le32_to_cpu(notif->action)); | ||
211 | |||
212 | spin_lock_bh(&mvm->time_event_lock); | ||
213 | list_for_each_entry_safe(te_data, tmp, &mvm->time_event_list, list) { | ||
214 | if (le32_to_cpu(notif->unique_id) == te_data->uid) | ||
215 | iwl_mvm_te_handle_notif(mvm, te_data, notif); | ||
216 | } | ||
217 | spin_unlock_bh(&mvm->time_event_lock); | ||
218 | |||
219 | return 0; | ||
220 | } | ||
221 | |||
222 | static bool iwl_mvm_time_event_notif(struct iwl_notif_wait_data *notif_wait, | ||
223 | struct iwl_rx_packet *pkt, void *data) | ||
224 | { | ||
225 | struct iwl_mvm *mvm = | ||
226 | container_of(notif_wait, struct iwl_mvm, notif_wait); | ||
227 | struct iwl_mvm_time_event_data *te_data = data; | ||
228 | struct ieee80211_vif *vif = te_data->vif; | ||
229 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
230 | struct iwl_time_event_notif *notif; | ||
231 | struct iwl_time_event_resp *resp; | ||
232 | |||
233 | u32 mac_id_n_color = FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color); | ||
234 | |||
235 | /* until we do something else */ | ||
236 | WARN_ON(te_data->id != TE_BSS_STA_AGGRESSIVE_ASSOC); | ||
237 | |||
238 | switch (pkt->hdr.cmd) { | ||
239 | case TIME_EVENT_CMD: | ||
240 | resp = (void *)pkt->data; | ||
241 | /* TODO: I can't check that since the fw is buggy - it doesn't | ||
242 | * put the right values when we remove a TE. We can be here | ||
243 | * when we remove a TE because the remove TE command is sent in | ||
244 | * ASYNC... | ||
245 | * WARN_ON(mac_id_n_color != le32_to_cpu(resp->id_and_color)); | ||
246 | */ | ||
247 | te_data->uid = le32_to_cpu(resp->unique_id); | ||
248 | IWL_DEBUG_TE(mvm, "Got response - UID = 0x%x\n", te_data->uid); | ||
249 | return false; | ||
250 | |||
251 | case TIME_EVENT_NOTIFICATION: | ||
252 | notif = (void *)pkt->data; | ||
253 | WARN_ON(le32_to_cpu(notif->status) != 1); | ||
254 | WARN_ON(mac_id_n_color != le32_to_cpu(notif->id_and_color)); | ||
255 | /* check if this is our Time Event that is starting */ | ||
256 | if (le32_to_cpu(notif->unique_id) != te_data->uid) | ||
257 | return false; | ||
258 | IWL_DEBUG_TE(mvm, "Event %d is starting - time is %d\n", | ||
259 | te_data->uid, le32_to_cpu(notif->timestamp)); | ||
260 | |||
261 | WARN_ONCE(!le32_to_cpu(notif->status), | ||
262 | "Failed to schedule protected session TE\n"); | ||
263 | |||
264 | te_data->running = true; | ||
265 | te_data->end_jiffies = jiffies + | ||
266 | TU_TO_JIFFIES(te_data->duration); | ||
267 | return true; | ||
268 | |||
269 | default: | ||
270 | WARN_ON(1); | ||
271 | return false; | ||
272 | }; | ||
273 | } | ||
274 | |||
275 | void iwl_mvm_protect_session(struct iwl_mvm *mvm, | ||
276 | struct ieee80211_vif *vif, | ||
277 | u32 duration, u32 min_duration) | ||
278 | { | ||
279 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
280 | struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; | ||
281 | static const u8 time_event_notif[] = { TIME_EVENT_CMD, | ||
282 | TIME_EVENT_NOTIFICATION }; | ||
283 | struct iwl_notification_wait wait_time_event; | ||
284 | struct iwl_time_event_cmd time_cmd = {}; | ||
285 | int ret; | ||
286 | |||
287 | lockdep_assert_held(&mvm->mutex); | ||
288 | |||
289 | if (te_data->running && | ||
290 | time_after(te_data->end_jiffies, | ||
291 | jiffies + TU_TO_JIFFIES(min_duration))) { | ||
292 | IWL_DEBUG_TE(mvm, "We have enough time in the current TE: %u\n", | ||
293 | jiffies_to_msecs(te_data->end_jiffies - jiffies)); | ||
294 | return; | ||
295 | } | ||
296 | |||
297 | if (te_data->running) { | ||
298 | IWL_DEBUG_TE(mvm, "extend 0x%x: only %u ms left\n", | ||
299 | te_data->uid, | ||
300 | jiffies_to_msecs(te_data->end_jiffies - jiffies)); | ||
301 | /* | ||
302 | * we don't have enough time | ||
303 | * cancel the current TE and issue a new one | ||
304 | * Of course it would be better to remove the old one only | ||
305 | * when the new one is added, but we don't care if we are off | ||
306 | * channel for a bit. All we need to do, is not to return | ||
307 | * before we actually begin to be on the channel. | ||
308 | */ | ||
309 | iwl_mvm_stop_session_protection(mvm, vif); | ||
310 | } | ||
311 | |||
312 | iwl_init_notification_wait(&mvm->notif_wait, &wait_time_event, | ||
313 | time_event_notif, | ||
314 | ARRAY_SIZE(time_event_notif), | ||
315 | iwl_mvm_time_event_notif, | ||
316 | &mvmvif->time_event_data); | ||
317 | |||
318 | time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD); | ||
319 | time_cmd.id_and_color = | ||
320 | cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); | ||
321 | time_cmd.id = cpu_to_le32(TE_BSS_STA_AGGRESSIVE_ASSOC); | ||
322 | |||
323 | time_cmd.apply_time = | ||
324 | cpu_to_le32(iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG)); | ||
325 | time_cmd.dep_policy = TE_INDEPENDENT; | ||
326 | time_cmd.is_present = cpu_to_le32(1); | ||
327 | time_cmd.max_frags = cpu_to_le32(TE_FRAG_NONE); | ||
328 | time_cmd.max_delay = cpu_to_le32(500); | ||
329 | /* TODO: why do we need to interval = bi if it is not periodic? */ | ||
330 | time_cmd.interval = cpu_to_le32(1); | ||
331 | time_cmd.interval_reciprocal = cpu_to_le32(iwl_mvm_reciprocal(1)); | ||
332 | time_cmd.duration = cpu_to_le32(duration); | ||
333 | time_cmd.repeat = cpu_to_le32(1); | ||
334 | time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_START | TE_NOTIF_HOST_END); | ||
335 | |||
336 | te_data->vif = vif; | ||
337 | te_data->duration = duration; | ||
338 | |||
339 | spin_lock_bh(&mvm->time_event_lock); | ||
340 | te_data->id = le32_to_cpu(time_cmd.id); | ||
341 | list_add_tail(&te_data->list, &mvm->time_event_list); | ||
342 | spin_unlock_bh(&mvm->time_event_lock); | ||
343 | |||
344 | ret = iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC, | ||
345 | sizeof(time_cmd), &time_cmd); | ||
346 | if (ret) { | ||
347 | IWL_ERR(mvm, "Couldn't send TIME_EVENT_CMD: %d\n", ret); | ||
348 | goto out_remove_notif; | ||
349 | } | ||
350 | |||
351 | ret = iwl_wait_notification(&mvm->notif_wait, &wait_time_event, 1 * HZ); | ||
352 | if (ret) { | ||
353 | IWL_ERR(mvm, "%s - failed on timeout\n", __func__); | ||
354 | spin_lock_bh(&mvm->time_event_lock); | ||
355 | iwl_mvm_te_clear_data(mvm, te_data); | ||
356 | spin_unlock_bh(&mvm->time_event_lock); | ||
357 | } | ||
358 | |||
359 | return; | ||
360 | |||
361 | out_remove_notif: | ||
362 | iwl_remove_notification(&mvm->notif_wait, &wait_time_event); | ||
363 | } | ||
364 | |||
365 | /* | ||
366 | * Explicit request to remove a time event. The removal of a time event needs to | ||
367 | * be synchronized with the flow of a time event's end notification, which also | ||
368 | * removes the time event from the op mode data structures. | ||
369 | */ | ||
370 | void iwl_mvm_remove_time_event(struct iwl_mvm *mvm, | ||
371 | struct iwl_mvm_vif *mvmvif, | ||
372 | struct iwl_mvm_time_event_data *te_data) | ||
373 | { | ||
374 | struct iwl_time_event_cmd time_cmd = {}; | ||
375 | u32 id, uid; | ||
376 | int ret; | ||
377 | |||
378 | /* | ||
379 | * It is possible that by the time we got to this point the time | ||
380 | * event was already removed. | ||
381 | */ | ||
382 | spin_lock_bh(&mvm->time_event_lock); | ||
383 | |||
384 | /* Save time event uid before clearing its data */ | ||
385 | uid = te_data->uid; | ||
386 | id = te_data->id; | ||
387 | |||
388 | /* | ||
389 | * The clear_data function handles time events that were already removed | ||
390 | */ | ||
391 | iwl_mvm_te_clear_data(mvm, te_data); | ||
392 | spin_unlock_bh(&mvm->time_event_lock); | ||
393 | |||
394 | /* | ||
395 | * It is possible that by the time we try to remove it, the time event | ||
396 | * has already ended and removed. In such a case there is no need to | ||
397 | * send a removal command. | ||
398 | */ | ||
399 | if (id == TE_MAX) { | ||
400 | IWL_DEBUG_TE(mvm, "TE 0x%x has already ended\n", uid); | ||
401 | return; | ||
402 | } | ||
403 | |||
404 | /* When we remove a TE, the UID is to be set in the id field */ | ||
405 | time_cmd.id = cpu_to_le32(uid); | ||
406 | time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE); | ||
407 | time_cmd.id_and_color = | ||
408 | cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); | ||
409 | |||
410 | IWL_DEBUG_TE(mvm, "Removing TE 0x%x\n", le32_to_cpu(time_cmd.id)); | ||
411 | ret = iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_ASYNC, | ||
412 | sizeof(time_cmd), &time_cmd); | ||
413 | if (WARN_ON(ret)) | ||
414 | return; | ||
415 | } | ||
416 | |||
417 | void iwl_mvm_stop_session_protection(struct iwl_mvm *mvm, | ||
418 | struct ieee80211_vif *vif) | ||
419 | { | ||
420 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
421 | struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; | ||
422 | |||
423 | lockdep_assert_held(&mvm->mutex); | ||
424 | iwl_mvm_remove_time_event(mvm, mvmvif, te_data); | ||
425 | } | ||
426 | |||
427 | static bool iwl_mvm_roc_te_notif(struct iwl_notif_wait_data *notif_wait, | ||
428 | struct iwl_rx_packet *pkt, void *data) | ||
429 | { | ||
430 | struct iwl_mvm *mvm = | ||
431 | container_of(notif_wait, struct iwl_mvm, notif_wait); | ||
432 | struct iwl_mvm_time_event_data *te_data = data; | ||
433 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif); | ||
434 | struct iwl_time_event_resp *resp; | ||
435 | |||
436 | u32 mac_id_n_color = FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color); | ||
437 | |||
438 | /* until we do something else */ | ||
439 | WARN_ON(te_data->id != TE_P2P_DEVICE_DISCOVERABLE); | ||
440 | |||
441 | switch (pkt->hdr.cmd) { | ||
442 | case TIME_EVENT_CMD: | ||
443 | resp = (void *)pkt->data; | ||
444 | WARN_ON(mac_id_n_color != le32_to_cpu(resp->id_and_color)); | ||
445 | te_data->uid = le32_to_cpu(resp->unique_id); | ||
446 | IWL_DEBUG_TE(mvm, "Got response - UID = 0x%x\n", te_data->uid); | ||
447 | return true; | ||
448 | |||
449 | default: | ||
450 | WARN_ON(1); | ||
451 | return false; | ||
452 | }; | ||
453 | } | ||
454 | |||
455 | int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
456 | int duration) | ||
457 | { | ||
458 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
459 | struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; | ||
460 | static const u8 roc_te_notif[] = { TIME_EVENT_CMD }; | ||
461 | struct iwl_notification_wait wait_time_event; | ||
462 | struct iwl_time_event_cmd time_cmd = {}; | ||
463 | int ret; | ||
464 | |||
465 | lockdep_assert_held(&mvm->mutex); | ||
466 | if (te_data->running) { | ||
467 | IWL_WARN(mvm, "P2P_DEVICE remain on channel already running\n"); | ||
468 | return -EBUSY; | ||
469 | } | ||
470 | |||
471 | /* | ||
472 | * Flush the done work, just in case it's still pending, so that | ||
473 | * the work it does can complete and we can accept new frames. | ||
474 | */ | ||
475 | flush_work(&mvm->roc_done_wk); | ||
476 | |||
477 | iwl_init_notification_wait(&mvm->notif_wait, &wait_time_event, | ||
478 | roc_te_notif, | ||
479 | ARRAY_SIZE(roc_te_notif), | ||
480 | iwl_mvm_roc_te_notif, | ||
481 | &mvmvif->time_event_data); | ||
482 | |||
483 | time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD); | ||
484 | time_cmd.id_and_color = | ||
485 | cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); | ||
486 | time_cmd.id = cpu_to_le32(TE_P2P_DEVICE_DISCOVERABLE); | ||
487 | |||
488 | time_cmd.apply_time = cpu_to_le32(0); | ||
489 | time_cmd.dep_policy = cpu_to_le32(TE_INDEPENDENT); | ||
490 | time_cmd.is_present = cpu_to_le32(1); | ||
491 | |||
492 | time_cmd.interval = cpu_to_le32(1); | ||
493 | |||
494 | /* | ||
495 | * TE_P2P_DEVICE_DISCOVERABLE can have lower priority than other events | ||
496 | * that are being scheduled by the driver/fw, and thus it might not be | ||
497 | * scheduled. To improve the chances of it being scheduled, allow it to | ||
498 | * be fragmented. | ||
499 | * In addition, for the same reasons, allow to delay the scheduling of | ||
500 | * the time event. | ||
501 | */ | ||
502 | time_cmd.max_frags = cpu_to_le32(MSEC_TO_TU(duration)/20); | ||
503 | time_cmd.max_delay = cpu_to_le32(MSEC_TO_TU(duration/2)); | ||
504 | time_cmd.duration = cpu_to_le32(MSEC_TO_TU(duration)); | ||
505 | time_cmd.repeat = cpu_to_le32(1); | ||
506 | time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_START | TE_NOTIF_HOST_END); | ||
507 | |||
508 | /* Push the te data to the tracked te list */ | ||
509 | te_data->vif = vif; | ||
510 | te_data->duration = MSEC_TO_TU(duration); | ||
511 | |||
512 | spin_lock_bh(&mvm->time_event_lock); | ||
513 | te_data->id = le32_to_cpu(time_cmd.id); | ||
514 | list_add_tail(&te_data->list, &mvm->time_event_list); | ||
515 | spin_unlock_bh(&mvm->time_event_lock); | ||
516 | |||
517 | ret = iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC, | ||
518 | sizeof(time_cmd), &time_cmd); | ||
519 | if (ret) { | ||
520 | IWL_ERR(mvm, "Couldn't send TIME_EVENT_CMD: %d\n", ret); | ||
521 | goto out_remove_notif; | ||
522 | } | ||
523 | |||
524 | ret = iwl_wait_notification(&mvm->notif_wait, &wait_time_event, 1 * HZ); | ||
525 | if (ret) { | ||
526 | IWL_ERR(mvm, "%s - failed on timeout\n", __func__); | ||
527 | iwl_mvm_te_clear_data(mvm, te_data); | ||
528 | } | ||
529 | |||
530 | return ret; | ||
531 | |||
532 | out_remove_notif: | ||
533 | iwl_remove_notification(&mvm->notif_wait, &wait_time_event); | ||
534 | return ret; | ||
535 | } | ||
536 | |||
537 | void iwl_mvm_stop_p2p_roc(struct iwl_mvm *mvm) | ||
538 | { | ||
539 | struct iwl_mvm_vif *mvmvif; | ||
540 | struct iwl_mvm_time_event_data *te_data; | ||
541 | |||
542 | lockdep_assert_held(&mvm->mutex); | ||
543 | |||
544 | /* | ||
545 | * Iterate over the list of time events and find the time event that is | ||
546 | * associated with a P2P_DEVICE interface. | ||
547 | * This assumes that a P2P_DEVICE interface can have only a single time | ||
548 | * event at any given time and this time event coresponds to a ROC | ||
549 | * request | ||
550 | */ | ||
551 | mvmvif = NULL; | ||
552 | spin_lock_bh(&mvm->time_event_lock); | ||
553 | list_for_each_entry(te_data, &mvm->time_event_list, list) { | ||
554 | if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) { | ||
555 | mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif); | ||
556 | break; | ||
557 | } | ||
558 | } | ||
559 | spin_unlock_bh(&mvm->time_event_lock); | ||
560 | |||
561 | if (!mvmvif) { | ||
562 | IWL_WARN(mvm, "P2P_DEVICE no remain on channel event\n"); | ||
563 | return; | ||
564 | } | ||
565 | |||
566 | iwl_mvm_remove_time_event(mvm, mvmvif, te_data); | ||
567 | |||
568 | iwl_mvm_roc_finished(mvm); | ||
569 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.h b/drivers/net/wireless/iwlwifi/mvm/time-event.h new file mode 100644 index 000000000000..64fb57a5ab43 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.h | |||
@@ -0,0 +1,214 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called LICENSE.GPL. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | * | ||
62 | *****************************************************************************/ | ||
63 | |||
64 | #ifndef __time_event_h__ | ||
65 | #define __time_event_h__ | ||
66 | |||
67 | #include "fw-api.h" | ||
68 | |||
69 | #include "mvm.h" | ||
70 | |||
71 | /** | ||
72 | * DOC: Time Events - what is it? | ||
73 | * | ||
74 | * Time Events are a fw feature that allows the driver to control the presence | ||
75 | * of the device on the channel. Since the fw supports multiple channels | ||
76 | * concurrently, the fw may choose to jump to another channel at any time. | ||
77 | * In order to make sure that the fw is on a specific channel at a certain time | ||
78 | * and for a certain duration, the driver needs to issue a time event. | ||
79 | * | ||
80 | * The simplest example is for BSS association. The driver issues a time event, | ||
81 | * waits for it to start, and only then tells mac80211 that we can start the | ||
82 | * association. This way, we make sure that the association will be done | ||
83 | * smoothly and won't be interrupted by channel switch decided within the fw. | ||
84 | */ | ||
85 | |||
86 | /** | ||
87 | * DOC: The flow against the fw | ||
88 | * | ||
89 | * When the driver needs to make sure we are in a certain channel, at a certain | ||
90 | * time and for a certain duration, it sends a Time Event. The flow against the | ||
91 | * fw goes like this: | ||
92 | * 1) Driver sends a TIME_EVENT_CMD to the fw | ||
93 | * 2) Driver gets the response for that command. This response contains the | ||
94 | * Unique ID (UID) of the event. | ||
95 | * 3) The fw sends notification when the event starts. | ||
96 | * | ||
97 | * Of course the API provides various options that allow to cover parameters | ||
98 | * of the flow. | ||
99 | * What is the duration of the event? | ||
100 | * What is the start time of the event? | ||
101 | * Is there an end-time for the event? | ||
102 | * How much can the event be delayed? | ||
103 | * Can the event be split? | ||
104 | * If yes what is the maximal number of chunks? | ||
105 | * etc... | ||
106 | */ | ||
107 | |||
108 | /** | ||
109 | * DOC: Abstraction to the driver | ||
110 | * | ||
111 | * In order to simplify the use of time events to the rest of the driver, | ||
112 | * we abstract the use of time events. This component provides the functions | ||
113 | * needed by the driver. | ||
114 | */ | ||
115 | |||
116 | #define IWL_MVM_TE_SESSION_PROTECTION_MAX_TIME_MS 500 | ||
117 | #define IWL_MVM_TE_SESSION_PROTECTION_MIN_TIME_MS 400 | ||
118 | |||
119 | /** | ||
120 | * iwl_mvm_protect_session - start / extend the session protection. | ||
121 | * @mvm: the mvm component | ||
122 | * @vif: the virtual interface for which the session is issued | ||
123 | * @duration: the duration of the session in TU. | ||
124 | * @min_duration: will start a new session if the current session will end | ||
125 | * in less than min_duration. | ||
126 | * | ||
127 | * This function can be used to start a session protection which means that the | ||
128 | * fw will stay on the channel for %duration_ms milliseconds. This function | ||
129 | * will block (sleep) until the session starts. This function can also be used | ||
130 | * to extend a currently running session. | ||
131 | * This function is meant to be used for BSS association for example, where we | ||
132 | * want to make sure that the fw stays on the channel during the association. | ||
133 | */ | ||
134 | void iwl_mvm_protect_session(struct iwl_mvm *mvm, | ||
135 | struct ieee80211_vif *vif, | ||
136 | u32 duration, u32 min_duration); | ||
137 | |||
138 | /** | ||
139 | * iwl_mvm_stop_session_protection - cancel the session protection. | ||
140 | * @mvm: the mvm component | ||
141 | * @vif: the virtual interface for which the session is issued | ||
142 | * | ||
143 | * This functions cancels the session protection which is an act of good | ||
144 | * citizenship. If it is not needed any more it should be cancelled because | ||
145 | * the other bindings wait for the medium during that time. | ||
146 | * This funtions doesn't sleep. | ||
147 | */ | ||
148 | void iwl_mvm_stop_session_protection(struct iwl_mvm *mvm, | ||
149 | struct ieee80211_vif *vif); | ||
150 | |||
151 | /* | ||
152 | * iwl_mvm_rx_time_event_notif - handles %TIME_EVENT_NOTIFICATION. | ||
153 | */ | ||
154 | int iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm, | ||
155 | struct iwl_rx_cmd_buffer *rxb, | ||
156 | struct iwl_device_cmd *cmd); | ||
157 | |||
158 | /** | ||
159 | * iwl_mvm_start_p2p_roc - start remain on channel for p2p device functionlity | ||
160 | * @mvm: the mvm component | ||
161 | * @vif: the virtual interface for which the roc is requested. It is assumed | ||
162 | * that the vif type is NL80211_IFTYPE_P2P_DEVICE | ||
163 | * @duration: the requested duration in millisecond for the fw to be on the | ||
164 | * channel that is bound to the vif. | ||
165 | * | ||
166 | * This function can be used to issue a remain on channel session, | ||
167 | * which means that the fw will stay in the channel for the request %duration | ||
168 | * milliseconds. The function is async, meaning that it only issues the ROC | ||
169 | * request but does not wait for it to start. Once the FW is ready to serve the | ||
170 | * ROC request, it will issue a notification to the driver that it is on the | ||
171 | * requested channel. Once the FW completes the ROC request it will issue | ||
172 | * another notification to the driver. | ||
173 | */ | ||
174 | int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
175 | int duration); | ||
176 | |||
177 | /** | ||
178 | * iwl_mvm_stop_p2p_roc - stop remain on channel for p2p device functionlity | ||
179 | * @mvm: the mvm component | ||
180 | * | ||
181 | * This function can be used to cancel an ongoing ROC session. | ||
182 | * The function is async, it will instruct the FW to stop serving the ROC | ||
183 | * session, but will not wait for the actual stopping of the session. | ||
184 | */ | ||
185 | void iwl_mvm_stop_p2p_roc(struct iwl_mvm *mvm); | ||
186 | |||
187 | /** | ||
188 | * iwl_mvm_remove_time_event - general function to clean up of time event | ||
189 | * @mvm: the mvm component | ||
190 | * @vif: the vif to which the time event belongs | ||
191 | * @te_data: the time event data that corresponds to that time event | ||
192 | * | ||
193 | * This function can be used to cancel a time event regardless its type. | ||
194 | * It is useful for cleaning up time events running before removing an | ||
195 | * interface. | ||
196 | */ | ||
197 | void iwl_mvm_remove_time_event(struct iwl_mvm *mvm, | ||
198 | struct iwl_mvm_vif *mvmvif, | ||
199 | struct iwl_mvm_time_event_data *te_data); | ||
200 | |||
201 | /** | ||
202 | * iwl_mvm_te_clear_data - remove time event from list | ||
203 | * @mvm: the mvm component | ||
204 | * @te_data: the time event data to remove | ||
205 | * | ||
206 | * This function is mostly internal, it is made available here only | ||
207 | * for firmware restart purposes. | ||
208 | */ | ||
209 | void iwl_mvm_te_clear_data(struct iwl_mvm *mvm, | ||
210 | struct iwl_mvm_time_event_data *te_data); | ||
211 | |||
212 | void iwl_mvm_roc_done_wk(struct work_struct *wk); | ||
213 | |||
214 | #endif /* __time_event_h__ */ | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c new file mode 100644 index 000000000000..cada8efe0cca --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c | |||
@@ -0,0 +1,916 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called LICENSE.GPL. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | * | ||
62 | *****************************************************************************/ | ||
63 | #include <linux/ieee80211.h> | ||
64 | #include <linux/etherdevice.h> | ||
65 | |||
66 | #include "iwl-trans.h" | ||
67 | #include "iwl-eeprom-parse.h" | ||
68 | #include "mvm.h" | ||
69 | #include "sta.h" | ||
70 | |||
71 | /* | ||
72 | * Sets most of the Tx cmd's fields | ||
73 | */ | ||
74 | static void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, | ||
75 | struct iwl_tx_cmd *tx_cmd, | ||
76 | struct ieee80211_tx_info *info, u8 sta_id) | ||
77 | { | ||
78 | struct ieee80211_hdr *hdr = (void *)skb->data; | ||
79 | __le16 fc = hdr->frame_control; | ||
80 | u32 tx_flags = le32_to_cpu(tx_cmd->tx_flags); | ||
81 | u32 len = skb->len + FCS_LEN; | ||
82 | |||
83 | if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) | ||
84 | tx_flags |= TX_CMD_FLG_ACK; | ||
85 | else | ||
86 | tx_flags &= ~TX_CMD_FLG_ACK; | ||
87 | |||
88 | if (ieee80211_is_probe_resp(fc)) | ||
89 | tx_flags |= TX_CMD_FLG_TSF; | ||
90 | else if (ieee80211_is_back_req(fc)) | ||
91 | tx_flags |= TX_CMD_FLG_ACK | TX_CMD_FLG_BAR; | ||
92 | |||
93 | /* High prio packet (wrt. BT coex) if it is EAPOL, MCAST or MGMT */ | ||
94 | if (info->band == IEEE80211_BAND_2GHZ && | ||
95 | (skb->protocol == cpu_to_be16(ETH_P_PAE) || | ||
96 | is_multicast_ether_addr(hdr->addr1) || | ||
97 | ieee80211_is_back_req(fc) || | ||
98 | ieee80211_is_mgmt(fc))) | ||
99 | tx_flags |= TX_CMD_FLG_BT_DIS; | ||
100 | |||
101 | if (ieee80211_has_morefrags(fc)) | ||
102 | tx_flags |= TX_CMD_FLG_MORE_FRAG; | ||
103 | |||
104 | if (ieee80211_is_data_qos(fc)) { | ||
105 | u8 *qc = ieee80211_get_qos_ctl(hdr); | ||
106 | tx_cmd->tid_tspec = qc[0] & 0xf; | ||
107 | tx_flags &= ~TX_CMD_FLG_SEQ_CTL; | ||
108 | } else { | ||
109 | tx_cmd->tid_tspec = IWL_TID_NON_QOS; | ||
110 | if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) | ||
111 | tx_flags |= TX_CMD_FLG_SEQ_CTL; | ||
112 | else | ||
113 | tx_flags &= ~TX_CMD_FLG_SEQ_CTL; | ||
114 | } | ||
115 | |||
116 | if (ieee80211_is_mgmt(fc)) { | ||
117 | if (ieee80211_is_assoc_req(fc) || ieee80211_is_reassoc_req(fc)) | ||
118 | tx_cmd->pm_frame_timeout = cpu_to_le16(3); | ||
119 | else | ||
120 | tx_cmd->pm_frame_timeout = cpu_to_le16(2); | ||
121 | |||
122 | /* The spec allows Action frames in A-MPDU, we don't support | ||
123 | * it | ||
124 | */ | ||
125 | WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_AMPDU); | ||
126 | } else { | ||
127 | tx_cmd->pm_frame_timeout = 0; | ||
128 | } | ||
129 | |||
130 | if (info->flags & IEEE80211_TX_CTL_AMPDU) | ||
131 | tx_flags |= TX_CMD_FLG_PROT_REQUIRE; | ||
132 | |||
133 | if (ieee80211_is_data(fc) && len > mvm->rts_threshold && | ||
134 | !is_multicast_ether_addr(ieee80211_get_DA(hdr))) | ||
135 | tx_flags |= TX_CMD_FLG_PROT_REQUIRE; | ||
136 | |||
137 | tx_cmd->driver_txop = 0; | ||
138 | tx_cmd->tx_flags = cpu_to_le32(tx_flags); | ||
139 | /* Total # bytes to be transmitted */ | ||
140 | tx_cmd->len = cpu_to_le16((u16)skb->len); | ||
141 | tx_cmd->next_frame_len = 0; | ||
142 | tx_cmd->life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE); | ||
143 | tx_cmd->sta_id = sta_id; | ||
144 | } | ||
145 | |||
146 | /* | ||
147 | * Sets the fields in the Tx cmd that are rate related | ||
148 | */ | ||
149 | static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, | ||
150 | struct iwl_tx_cmd *tx_cmd, | ||
151 | struct ieee80211_tx_info *info, | ||
152 | struct ieee80211_sta *sta, | ||
153 | __le16 fc) | ||
154 | { | ||
155 | u32 rate_flags; | ||
156 | int rate_idx; | ||
157 | u8 rate_plcp; | ||
158 | |||
159 | /* Set retry limit on RTS packets */ | ||
160 | tx_cmd->rts_retry_limit = IWL_RTS_DFAULT_RETRY_LIMIT; | ||
161 | |||
162 | /* Set retry limit on DATA packets and Probe Responses*/ | ||
163 | if (ieee80211_is_probe_resp(fc)) { | ||
164 | tx_cmd->data_retry_limit = IWL_MGMT_DFAULT_RETRY_LIMIT; | ||
165 | tx_cmd->rts_retry_limit = | ||
166 | min(tx_cmd->data_retry_limit, tx_cmd->rts_retry_limit); | ||
167 | } else if (ieee80211_is_back_req(fc)) { | ||
168 | tx_cmd->data_retry_limit = IWL_BAR_DFAULT_RETRY_LIMIT; | ||
169 | } else { | ||
170 | tx_cmd->data_retry_limit = IWL_DEFAULT_TX_RETRY; | ||
171 | } | ||
172 | |||
173 | /* | ||
174 | * for data packets, rate info comes from the table inside he fw. This | ||
175 | * table is controlled by LINK_QUALITY commands | ||
176 | */ | ||
177 | |||
178 | if (ieee80211_is_data(fc)) { | ||
179 | tx_cmd->initial_rate_index = 0; | ||
180 | tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_STA_RATE); | ||
181 | return; | ||
182 | } else if (ieee80211_is_back_req(fc)) { | ||
183 | tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_STA_RATE); | ||
184 | } | ||
185 | |||
186 | /* HT rate doesn't make sense for a non data frame */ | ||
187 | WARN_ONCE(info->control.rates[0].flags & IEEE80211_TX_RC_MCS, | ||
188 | "Got an HT rate for a non data frame 0x%x\n", | ||
189 | info->control.rates[0].flags); | ||
190 | |||
191 | rate_idx = info->control.rates[0].idx; | ||
192 | /* if the rate isn't a well known legacy rate, take the lowest one */ | ||
193 | if (rate_idx < 0 || rate_idx > IWL_RATE_COUNT_LEGACY) | ||
194 | rate_idx = rate_lowest_index( | ||
195 | &mvm->nvm_data->bands[info->band], sta); | ||
196 | |||
197 | /* For 5 GHZ band, remap mac80211 rate indices into driver indices */ | ||
198 | if (info->band == IEEE80211_BAND_5GHZ) | ||
199 | rate_idx += IWL_FIRST_OFDM_RATE; | ||
200 | |||
201 | /* For 2.4 GHZ band, check that there is no need to remap */ | ||
202 | BUILD_BUG_ON(IWL_FIRST_CCK_RATE != 0); | ||
203 | |||
204 | /* Get PLCP rate for tx_cmd->rate_n_flags */ | ||
205 | rate_plcp = iwl_mvm_mac80211_idx_to_hwrate(rate_idx); | ||
206 | |||
207 | mvm->mgmt_last_antenna_idx = | ||
208 | iwl_mvm_next_antenna(mvm, mvm->nvm_data->valid_tx_ant, | ||
209 | mvm->mgmt_last_antenna_idx); | ||
210 | rate_flags = BIT(mvm->mgmt_last_antenna_idx) << RATE_MCS_ANT_POS; | ||
211 | |||
212 | /* Set CCK flag as needed */ | ||
213 | if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE)) | ||
214 | rate_flags |= RATE_MCS_CCK_MSK; | ||
215 | |||
216 | /* Set the rate in the TX cmd */ | ||
217 | tx_cmd->rate_n_flags = cpu_to_le32((u32)rate_plcp | rate_flags); | ||
218 | } | ||
219 | |||
220 | /* | ||
221 | * Sets the fields in the Tx cmd that are crypto related | ||
222 | */ | ||
223 | static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm, | ||
224 | struct ieee80211_tx_info *info, | ||
225 | struct iwl_tx_cmd *tx_cmd, | ||
226 | struct sk_buff *skb_frag) | ||
227 | { | ||
228 | struct ieee80211_key_conf *keyconf = info->control.hw_key; | ||
229 | |||
230 | switch (keyconf->cipher) { | ||
231 | case WLAN_CIPHER_SUITE_CCMP: | ||
232 | tx_cmd->sec_ctl = TX_CMD_SEC_CCM; | ||
233 | memcpy(tx_cmd->key, keyconf->key, keyconf->keylen); | ||
234 | if (info->flags & IEEE80211_TX_CTL_AMPDU) | ||
235 | tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_CCMP_AGG); | ||
236 | break; | ||
237 | |||
238 | case WLAN_CIPHER_SUITE_TKIP: | ||
239 | tx_cmd->sec_ctl = TX_CMD_SEC_TKIP; | ||
240 | ieee80211_get_tkip_p2k(keyconf, skb_frag, tx_cmd->key); | ||
241 | break; | ||
242 | |||
243 | case WLAN_CIPHER_SUITE_WEP104: | ||
244 | tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128; | ||
245 | /* fall through */ | ||
246 | case WLAN_CIPHER_SUITE_WEP40: | ||
247 | tx_cmd->sec_ctl |= TX_CMD_SEC_WEP | | ||
248 | ((keyconf->keyidx << TX_CMD_SEC_WEP_KEY_IDX_POS) & | ||
249 | TX_CMD_SEC_WEP_KEY_IDX_MSK); | ||
250 | |||
251 | memcpy(&tx_cmd->key[3], keyconf->key, keyconf->keylen); | ||
252 | break; | ||
253 | default: | ||
254 | IWL_ERR(mvm, "Unknown encode cipher %x\n", keyconf->cipher); | ||
255 | break; | ||
256 | } | ||
257 | } | ||
258 | |||
259 | /* | ||
260 | * Allocates and sets the Tx cmd the driver data pointers in the skb | ||
261 | */ | ||
262 | static struct iwl_device_cmd * | ||
263 | iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb, | ||
264 | struct ieee80211_sta *sta, u8 sta_id) | ||
265 | { | ||
266 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||
267 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
268 | struct iwl_device_cmd *dev_cmd; | ||
269 | struct iwl_tx_cmd *tx_cmd; | ||
270 | |||
271 | dev_cmd = iwl_trans_alloc_tx_cmd(mvm->trans); | ||
272 | |||
273 | if (unlikely(!dev_cmd)) | ||
274 | return NULL; | ||
275 | |||
276 | memset(dev_cmd, 0, sizeof(*dev_cmd)); | ||
277 | tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload; | ||
278 | |||
279 | if (info->control.hw_key) | ||
280 | iwl_mvm_set_tx_cmd_crypto(mvm, info, tx_cmd, skb); | ||
281 | |||
282 | iwl_mvm_set_tx_cmd(mvm, skb, tx_cmd, info, sta_id); | ||
283 | |||
284 | iwl_mvm_set_tx_cmd_rate(mvm, tx_cmd, info, sta, hdr->frame_control); | ||
285 | |||
286 | memset(&info->status, 0, sizeof(info->status)); | ||
287 | |||
288 | info->driver_data[0] = NULL; | ||
289 | info->driver_data[1] = dev_cmd; | ||
290 | |||
291 | return dev_cmd; | ||
292 | } | ||
293 | |||
294 | int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) | ||
295 | { | ||
296 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||
297 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
298 | struct iwl_device_cmd *dev_cmd; | ||
299 | struct iwl_tx_cmd *tx_cmd; | ||
300 | u8 sta_id; | ||
301 | |||
302 | if (WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_AMPDU)) | ||
303 | return -1; | ||
304 | |||
305 | if (WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM && | ||
306 | (!info->control.vif || | ||
307 | info->hw_queue != info->control.vif->cab_queue))) | ||
308 | return -1; | ||
309 | |||
310 | /* | ||
311 | * If the interface on which frame is sent is the P2P_DEVICE | ||
312 | * or an AP/GO interface use the broadcast station associated | ||
313 | * with it; otherwise use the AUX station. | ||
314 | */ | ||
315 | if (info->control.vif && | ||
316 | (info->control.vif->type == NL80211_IFTYPE_P2P_DEVICE || | ||
317 | info->control.vif->type == NL80211_IFTYPE_AP)) { | ||
318 | struct iwl_mvm_vif *mvmvif = | ||
319 | iwl_mvm_vif_from_mac80211(info->control.vif); | ||
320 | sta_id = mvmvif->bcast_sta.sta_id; | ||
321 | } else { | ||
322 | sta_id = mvm->aux_sta.sta_id; | ||
323 | } | ||
324 | |||
325 | IWL_DEBUG_TX(mvm, "station Id %d, queue=%d\n", sta_id, info->hw_queue); | ||
326 | |||
327 | dev_cmd = iwl_mvm_set_tx_params(mvm, skb, NULL, sta_id); | ||
328 | if (!dev_cmd) | ||
329 | return -1; | ||
330 | |||
331 | /* From now on, we cannot access info->control */ | ||
332 | tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload; | ||
333 | |||
334 | /* Copy MAC header from skb into command buffer */ | ||
335 | memcpy(tx_cmd->hdr, hdr, ieee80211_hdrlen(hdr->frame_control)); | ||
336 | |||
337 | if (iwl_trans_tx(mvm->trans, skb, dev_cmd, info->hw_queue)) { | ||
338 | iwl_trans_free_tx_cmd(mvm->trans, dev_cmd); | ||
339 | return -1; | ||
340 | } | ||
341 | |||
342 | return 0; | ||
343 | } | ||
344 | |||
345 | /* | ||
346 | * Sets the fields in the Tx cmd that are crypto related | ||
347 | */ | ||
348 | int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb, | ||
349 | struct ieee80211_sta *sta) | ||
350 | { | ||
351 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||
352 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
353 | struct iwl_mvm_sta *mvmsta; | ||
354 | struct iwl_device_cmd *dev_cmd; | ||
355 | struct iwl_tx_cmd *tx_cmd; | ||
356 | __le16 fc; | ||
357 | u16 seq_number = 0; | ||
358 | u8 tid = IWL_MAX_TID_COUNT; | ||
359 | u8 txq_id = info->hw_queue; | ||
360 | bool is_data_qos = false, is_ampdu = false; | ||
361 | |||
362 | mvmsta = (void *)sta->drv_priv; | ||
363 | fc = hdr->frame_control; | ||
364 | |||
365 | if (WARN_ON_ONCE(!mvmsta)) | ||
366 | return -1; | ||
367 | |||
368 | if (WARN_ON_ONCE(mvmsta->sta_id == IWL_INVALID_STATION)) | ||
369 | return -1; | ||
370 | |||
371 | dev_cmd = iwl_mvm_set_tx_params(mvm, skb, sta, mvmsta->sta_id); | ||
372 | if (!dev_cmd) | ||
373 | goto drop; | ||
374 | |||
375 | tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload; | ||
376 | /* From now on, we cannot access info->control */ | ||
377 | |||
378 | spin_lock(&mvmsta->lock); | ||
379 | |||
380 | if (ieee80211_is_data_qos(fc) && !ieee80211_is_qos_nullfunc(fc)) { | ||
381 | u8 *qc = NULL; | ||
382 | qc = ieee80211_get_qos_ctl(hdr); | ||
383 | tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; | ||
384 | if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT)) | ||
385 | goto drop_unlock_sta; | ||
386 | |||
387 | seq_number = mvmsta->tid_data[tid].seq_number; | ||
388 | seq_number &= IEEE80211_SCTL_SEQ; | ||
389 | hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); | ||
390 | hdr->seq_ctrl |= cpu_to_le16(seq_number); | ||
391 | seq_number += 0x10; | ||
392 | is_data_qos = true; | ||
393 | is_ampdu = info->flags & IEEE80211_TX_CTL_AMPDU; | ||
394 | } | ||
395 | |||
396 | /* Copy MAC header from skb into command buffer */ | ||
397 | memcpy(tx_cmd->hdr, hdr, ieee80211_hdrlen(fc)); | ||
398 | |||
399 | WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM); | ||
400 | |||
401 | if (is_ampdu) { | ||
402 | if (WARN_ON_ONCE(mvmsta->tid_data[tid].state != IWL_AGG_ON)) | ||
403 | goto drop_unlock_sta; | ||
404 | txq_id = mvmsta->tid_data[tid].txq_id; | ||
405 | } | ||
406 | |||
407 | IWL_DEBUG_TX(mvm, "TX to [%d|%d] Q:%d - seq: 0x%x\n", mvmsta->sta_id, | ||
408 | tid, txq_id, seq_number); | ||
409 | |||
410 | /* NOTE: aggregation will need changes here (for txq id) */ | ||
411 | if (iwl_trans_tx(mvm->trans, skb, dev_cmd, txq_id)) | ||
412 | goto drop_unlock_sta; | ||
413 | |||
414 | if (is_data_qos && !ieee80211_has_morefrags(fc)) | ||
415 | mvmsta->tid_data[tid].seq_number = seq_number; | ||
416 | |||
417 | spin_unlock(&mvmsta->lock); | ||
418 | |||
419 | if (mvmsta->vif->type == NL80211_IFTYPE_AP && | ||
420 | txq_id < IWL_FIRST_AMPDU_QUEUE) | ||
421 | atomic_inc(&mvmsta->pending_frames); | ||
422 | |||
423 | return 0; | ||
424 | |||
425 | drop_unlock_sta: | ||
426 | iwl_trans_free_tx_cmd(mvm->trans, dev_cmd); | ||
427 | spin_unlock(&mvmsta->lock); | ||
428 | drop: | ||
429 | return -1; | ||
430 | } | ||
431 | |||
432 | static void iwl_mvm_check_ratid_empty(struct iwl_mvm *mvm, | ||
433 | struct ieee80211_sta *sta, u8 tid) | ||
434 | { | ||
435 | struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; | ||
436 | struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; | ||
437 | struct ieee80211_vif *vif = mvmsta->vif; | ||
438 | |||
439 | lockdep_assert_held(&mvmsta->lock); | ||
440 | |||
441 | if (tid_data->ssn != tid_data->next_reclaimed) | ||
442 | return; | ||
443 | |||
444 | switch (tid_data->state) { | ||
445 | case IWL_EMPTYING_HW_QUEUE_ADDBA: | ||
446 | IWL_DEBUG_TX_QUEUES(mvm, | ||
447 | "Can continue addBA flow ssn = next_recl = %d\n", | ||
448 | tid_data->next_reclaimed); | ||
449 | tid_data->state = IWL_AGG_STARTING; | ||
450 | ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); | ||
451 | break; | ||
452 | |||
453 | case IWL_EMPTYING_HW_QUEUE_DELBA: | ||
454 | IWL_DEBUG_TX_QUEUES(mvm, | ||
455 | "Can continue DELBA flow ssn = next_recl = %d\n", | ||
456 | tid_data->next_reclaimed); | ||
457 | iwl_trans_txq_disable(mvm->trans, tid_data->txq_id); | ||
458 | tid_data->state = IWL_AGG_OFF; | ||
459 | /* | ||
460 | * we can't hold the mutex - but since we are after a sequence | ||
461 | * point (call to iwl_trans_txq_disable), so we don't even need | ||
462 | * a memory barrier. | ||
463 | */ | ||
464 | mvm->queue_to_mac80211[tid_data->txq_id] = | ||
465 | IWL_INVALID_MAC80211_QUEUE; | ||
466 | ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); | ||
467 | break; | ||
468 | |||
469 | default: | ||
470 | break; | ||
471 | } | ||
472 | } | ||
473 | |||
474 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
475 | const char *iwl_mvm_get_tx_fail_reason(u32 status) | ||
476 | { | ||
477 | #define TX_STATUS_FAIL(x) case TX_STATUS_FAIL_ ## x: return #x | ||
478 | #define TX_STATUS_POSTPONE(x) case TX_STATUS_POSTPONE_ ## x: return #x | ||
479 | |||
480 | switch (status & TX_STATUS_MSK) { | ||
481 | case TX_STATUS_SUCCESS: | ||
482 | return "SUCCESS"; | ||
483 | TX_STATUS_POSTPONE(DELAY); | ||
484 | TX_STATUS_POSTPONE(FEW_BYTES); | ||
485 | TX_STATUS_POSTPONE(BT_PRIO); | ||
486 | TX_STATUS_POSTPONE(QUIET_PERIOD); | ||
487 | TX_STATUS_POSTPONE(CALC_TTAK); | ||
488 | TX_STATUS_FAIL(INTERNAL_CROSSED_RETRY); | ||
489 | TX_STATUS_FAIL(SHORT_LIMIT); | ||
490 | TX_STATUS_FAIL(LONG_LIMIT); | ||
491 | TX_STATUS_FAIL(UNDERRUN); | ||
492 | TX_STATUS_FAIL(DRAIN_FLOW); | ||
493 | TX_STATUS_FAIL(RFKILL_FLUSH); | ||
494 | TX_STATUS_FAIL(LIFE_EXPIRE); | ||
495 | TX_STATUS_FAIL(DEST_PS); | ||
496 | TX_STATUS_FAIL(HOST_ABORTED); | ||
497 | TX_STATUS_FAIL(BT_RETRY); | ||
498 | TX_STATUS_FAIL(STA_INVALID); | ||
499 | TX_STATUS_FAIL(FRAG_DROPPED); | ||
500 | TX_STATUS_FAIL(TID_DISABLE); | ||
501 | TX_STATUS_FAIL(FIFO_FLUSHED); | ||
502 | TX_STATUS_FAIL(SMALL_CF_POLL); | ||
503 | TX_STATUS_FAIL(FW_DROP); | ||
504 | TX_STATUS_FAIL(STA_COLOR_MISMATCH); | ||
505 | } | ||
506 | |||
507 | return "UNKNOWN"; | ||
508 | |||
509 | #undef TX_STATUS_FAIL | ||
510 | #undef TX_STATUS_POSTPONE | ||
511 | } | ||
512 | #endif /* CONFIG_IWLWIFI_DEBUG */ | ||
513 | |||
514 | /** | ||
515 | * translate ucode response to mac80211 tx status control values | ||
516 | */ | ||
517 | static void iwl_mvm_hwrate_to_tx_control(u32 rate_n_flags, | ||
518 | struct ieee80211_tx_info *info) | ||
519 | { | ||
520 | struct ieee80211_tx_rate *r = &info->status.rates[0]; | ||
521 | |||
522 | info->status.antenna = | ||
523 | ((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS); | ||
524 | if (rate_n_flags & RATE_HT_MCS_GF_MSK) | ||
525 | r->flags |= IEEE80211_TX_RC_GREEN_FIELD; | ||
526 | switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) { | ||
527 | case RATE_MCS_CHAN_WIDTH_20: | ||
528 | break; | ||
529 | case RATE_MCS_CHAN_WIDTH_40: | ||
530 | r->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; | ||
531 | break; | ||
532 | case RATE_MCS_CHAN_WIDTH_80: | ||
533 | r->flags |= IEEE80211_TX_RC_80_MHZ_WIDTH; | ||
534 | break; | ||
535 | case RATE_MCS_CHAN_WIDTH_160: | ||
536 | r->flags |= IEEE80211_TX_RC_160_MHZ_WIDTH; | ||
537 | break; | ||
538 | } | ||
539 | if (rate_n_flags & RATE_MCS_SGI_MSK) | ||
540 | r->flags |= IEEE80211_TX_RC_SHORT_GI; | ||
541 | if (rate_n_flags & RATE_MCS_HT_MSK) { | ||
542 | r->flags |= IEEE80211_TX_RC_MCS; | ||
543 | r->idx = rate_n_flags & RATE_HT_MCS_INDEX_MSK; | ||
544 | } else if (rate_n_flags & RATE_MCS_VHT_MSK) { | ||
545 | ieee80211_rate_set_vht( | ||
546 | r, rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK, | ||
547 | ((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >> | ||
548 | RATE_VHT_MCS_NSS_POS) + 1); | ||
549 | r->flags |= IEEE80211_TX_RC_VHT_MCS; | ||
550 | } else { | ||
551 | r->idx = iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags, | ||
552 | info->band); | ||
553 | } | ||
554 | } | ||
555 | |||
556 | static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, | ||
557 | struct iwl_rx_packet *pkt) | ||
558 | { | ||
559 | struct ieee80211_sta *sta; | ||
560 | u16 sequence = le16_to_cpu(pkt->hdr.sequence); | ||
561 | int txq_id = SEQ_TO_QUEUE(sequence); | ||
562 | struct iwl_mvm_tx_resp *tx_resp = (void *)pkt->data; | ||
563 | int sta_id = IWL_MVM_TX_RES_GET_RA(tx_resp->ra_tid); | ||
564 | int tid = IWL_MVM_TX_RES_GET_TID(tx_resp->ra_tid); | ||
565 | u32 status = le16_to_cpu(tx_resp->status.status); | ||
566 | u16 ssn = iwl_mvm_get_scd_ssn(tx_resp); | ||
567 | struct iwl_mvm_sta *mvmsta; | ||
568 | struct sk_buff_head skbs; | ||
569 | u8 skb_freed = 0; | ||
570 | u16 next_reclaimed, seq_ctl; | ||
571 | |||
572 | __skb_queue_head_init(&skbs); | ||
573 | |||
574 | seq_ctl = le16_to_cpu(tx_resp->seq_ctl); | ||
575 | |||
576 | /* we can free until ssn % q.n_bd not inclusive */ | ||
577 | iwl_trans_reclaim(mvm->trans, txq_id, ssn, &skbs); | ||
578 | |||
579 | while (!skb_queue_empty(&skbs)) { | ||
580 | struct sk_buff *skb = __skb_dequeue(&skbs); | ||
581 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
582 | |||
583 | skb_freed++; | ||
584 | |||
585 | iwl_trans_free_tx_cmd(mvm->trans, info->driver_data[1]); | ||
586 | |||
587 | memset(&info->status, 0, sizeof(info->status)); | ||
588 | |||
589 | info->flags &= ~IEEE80211_TX_CTL_AMPDU; | ||
590 | |||
591 | /* inform mac80211 about what happened with the frame */ | ||
592 | switch (status & TX_STATUS_MSK) { | ||
593 | case TX_STATUS_SUCCESS: | ||
594 | case TX_STATUS_DIRECT_DONE: | ||
595 | info->flags |= IEEE80211_TX_STAT_ACK; | ||
596 | break; | ||
597 | case TX_STATUS_FAIL_DEST_PS: | ||
598 | info->flags |= IEEE80211_TX_STAT_TX_FILTERED; | ||
599 | break; | ||
600 | default: | ||
601 | break; | ||
602 | } | ||
603 | |||
604 | info->status.rates[0].count = tx_resp->failure_frame + 1; | ||
605 | iwl_mvm_hwrate_to_tx_control(le32_to_cpu(tx_resp->initial_rate), | ||
606 | info); | ||
607 | |||
608 | /* Single frame failure in an AMPDU queue => send BAR */ | ||
609 | if (txq_id >= IWL_FIRST_AMPDU_QUEUE && | ||
610 | !(info->flags & IEEE80211_TX_STAT_ACK)) { | ||
611 | /* there must be only one skb in the skb_list */ | ||
612 | WARN_ON_ONCE(skb_freed > 1 || | ||
613 | !skb_queue_empty(&skbs)); | ||
614 | info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; | ||
615 | } | ||
616 | |||
617 | /* W/A FW bug: seq_ctl is wrong when the queue is flushed */ | ||
618 | if (status == TX_STATUS_FAIL_FIFO_FLUSHED) { | ||
619 | struct ieee80211_hdr *hdr = (void *)skb->data; | ||
620 | seq_ctl = le16_to_cpu(hdr->seq_ctrl); | ||
621 | } | ||
622 | |||
623 | ieee80211_tx_status(mvm->hw, skb); | ||
624 | } | ||
625 | |||
626 | if (txq_id >= IWL_FIRST_AMPDU_QUEUE) { | ||
627 | /* If this is an aggregation queue, we use the ssn since: | ||
628 | * ssn = wifi seq_num % 256. | ||
629 | * The seq_ctl is the sequence control of the packet to which | ||
630 | * this Tx response relates. But if there is a hole in the | ||
631 | * bitmap of the BA we received, this Tx response may allow to | ||
632 | * reclaim the hole and all the subsequent packets that were | ||
633 | * already acked. In that case, seq_ctl != ssn, and the next | ||
634 | * packet to be reclaimed will be ssn and not seq_ctl. In that | ||
635 | * case, several packets will be reclaimed even if | ||
636 | * frame_count = 1. | ||
637 | * | ||
638 | * The ssn is the index (% 256) of the latest packet that has | ||
639 | * treated (acked / dropped) + 1. | ||
640 | */ | ||
641 | next_reclaimed = ssn; | ||
642 | } else { | ||
643 | /* The next packet to be reclaimed is the one after this one */ | ||
644 | next_reclaimed = SEQ_TO_SN(seq_ctl + 0x10); | ||
645 | } | ||
646 | |||
647 | IWL_DEBUG_TX_REPLY(mvm, | ||
648 | "TXQ %d status %s (0x%08x)\n\t\t\t\tinitial_rate 0x%x " | ||
649 | "retries %d, idx=%d ssn=%d next_reclaimed=0x%x seq_ctl=0x%x\n", | ||
650 | txq_id, iwl_mvm_get_tx_fail_reason(status), | ||
651 | status, le32_to_cpu(tx_resp->initial_rate), | ||
652 | tx_resp->failure_frame, SEQ_TO_INDEX(sequence), | ||
653 | ssn, next_reclaimed, seq_ctl); | ||
654 | |||
655 | rcu_read_lock(); | ||
656 | |||
657 | sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); | ||
658 | |||
659 | if (!IS_ERR_OR_NULL(sta)) { | ||
660 | mvmsta = (void *)sta->drv_priv; | ||
661 | |||
662 | if (tid != IWL_TID_NON_QOS) { | ||
663 | struct iwl_mvm_tid_data *tid_data = | ||
664 | &mvmsta->tid_data[tid]; | ||
665 | |||
666 | spin_lock(&mvmsta->lock); | ||
667 | tid_data->next_reclaimed = next_reclaimed; | ||
668 | IWL_DEBUG_TX_REPLY(mvm, "Next reclaimed packet:%d\n", | ||
669 | next_reclaimed); | ||
670 | iwl_mvm_check_ratid_empty(mvm, sta, tid); | ||
671 | spin_unlock(&mvmsta->lock); | ||
672 | } | ||
673 | |||
674 | #ifdef CONFIG_PM_SLEEP | ||
675 | mvmsta->last_seq_ctl = seq_ctl; | ||
676 | #endif | ||
677 | } else { | ||
678 | sta = NULL; | ||
679 | mvmsta = NULL; | ||
680 | } | ||
681 | |||
682 | /* | ||
683 | * If the txq is not an AMPDU queue, there is no chance we freed | ||
684 | * several skbs. Check that out... | ||
685 | * If there are no pending frames for this STA, notify mac80211 that | ||
686 | * this station can go to sleep in its STA table. | ||
687 | */ | ||
688 | if (txq_id < IWL_FIRST_AMPDU_QUEUE && mvmsta && | ||
689 | !WARN_ON(skb_freed > 1) && | ||
690 | mvmsta->vif->type == NL80211_IFTYPE_AP && | ||
691 | atomic_sub_and_test(skb_freed, &mvmsta->pending_frames)) { | ||
692 | ieee80211_sta_block_awake(mvm->hw, sta, false); | ||
693 | set_bit(sta_id, mvm->sta_drained); | ||
694 | schedule_work(&mvm->sta_drained_wk); | ||
695 | } | ||
696 | |||
697 | rcu_read_unlock(); | ||
698 | } | ||
699 | |||
700 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
701 | #define AGG_TX_STATE_(x) case AGG_TX_STATE_ ## x: return #x | ||
702 | static const char *iwl_get_agg_tx_status(u16 status) | ||
703 | { | ||
704 | switch (status & AGG_TX_STATE_STATUS_MSK) { | ||
705 | AGG_TX_STATE_(TRANSMITTED); | ||
706 | AGG_TX_STATE_(UNDERRUN); | ||
707 | AGG_TX_STATE_(BT_PRIO); | ||
708 | AGG_TX_STATE_(FEW_BYTES); | ||
709 | AGG_TX_STATE_(ABORT); | ||
710 | AGG_TX_STATE_(LAST_SENT_TTL); | ||
711 | AGG_TX_STATE_(LAST_SENT_TRY_CNT); | ||
712 | AGG_TX_STATE_(LAST_SENT_BT_KILL); | ||
713 | AGG_TX_STATE_(SCD_QUERY); | ||
714 | AGG_TX_STATE_(TEST_BAD_CRC32); | ||
715 | AGG_TX_STATE_(RESPONSE); | ||
716 | AGG_TX_STATE_(DUMP_TX); | ||
717 | AGG_TX_STATE_(DELAY_TX); | ||
718 | } | ||
719 | |||
720 | return "UNKNOWN"; | ||
721 | } | ||
722 | |||
723 | static void iwl_mvm_rx_tx_cmd_agg_dbg(struct iwl_mvm *mvm, | ||
724 | struct iwl_rx_packet *pkt) | ||
725 | { | ||
726 | struct iwl_mvm_tx_resp *tx_resp = (void *)pkt->data; | ||
727 | struct agg_tx_status *frame_status = &tx_resp->status; | ||
728 | int i; | ||
729 | |||
730 | for (i = 0; i < tx_resp->frame_count; i++) { | ||
731 | u16 fstatus = le16_to_cpu(frame_status[i].status); | ||
732 | |||
733 | IWL_DEBUG_TX_REPLY(mvm, | ||
734 | "status %s (0x%04x), try-count (%d) seq (0x%x)\n", | ||
735 | iwl_get_agg_tx_status(fstatus), | ||
736 | fstatus & AGG_TX_STATE_STATUS_MSK, | ||
737 | (fstatus & AGG_TX_STATE_TRY_CNT_MSK) >> | ||
738 | AGG_TX_STATE_TRY_CNT_POS, | ||
739 | le16_to_cpu(frame_status[i].sequence)); | ||
740 | } | ||
741 | } | ||
742 | #else | ||
743 | static void iwl_mvm_rx_tx_cmd_agg_dbg(struct iwl_mvm *mvm, | ||
744 | struct iwl_rx_packet *pkt) | ||
745 | {} | ||
746 | #endif /* CONFIG_IWLWIFI_DEBUG */ | ||
747 | |||
748 | static void iwl_mvm_rx_tx_cmd_agg(struct iwl_mvm *mvm, | ||
749 | struct iwl_rx_packet *pkt) | ||
750 | { | ||
751 | struct iwl_mvm_tx_resp *tx_resp = (void *)pkt->data; | ||
752 | int sta_id = IWL_MVM_TX_RES_GET_RA(tx_resp->ra_tid); | ||
753 | int tid = IWL_MVM_TX_RES_GET_TID(tx_resp->ra_tid); | ||
754 | u16 sequence = le16_to_cpu(pkt->hdr.sequence); | ||
755 | struct ieee80211_sta *sta; | ||
756 | |||
757 | if (WARN_ON_ONCE(SEQ_TO_QUEUE(sequence) < IWL_FIRST_AMPDU_QUEUE)) | ||
758 | return; | ||
759 | |||
760 | if (WARN_ON_ONCE(tid == IWL_TID_NON_QOS)) | ||
761 | return; | ||
762 | |||
763 | iwl_mvm_rx_tx_cmd_agg_dbg(mvm, pkt); | ||
764 | |||
765 | rcu_read_lock(); | ||
766 | |||
767 | sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); | ||
768 | |||
769 | if (!WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) { | ||
770 | struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; | ||
771 | mvmsta->tid_data[tid].rate_n_flags = | ||
772 | le32_to_cpu(tx_resp->initial_rate); | ||
773 | } | ||
774 | |||
775 | rcu_read_unlock(); | ||
776 | } | ||
777 | |||
778 | int iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | ||
779 | struct iwl_device_cmd *cmd) | ||
780 | { | ||
781 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
782 | struct iwl_mvm_tx_resp *tx_resp = (void *)pkt->data; | ||
783 | |||
784 | if (tx_resp->frame_count == 1) | ||
785 | iwl_mvm_rx_tx_cmd_single(mvm, pkt); | ||
786 | else | ||
787 | iwl_mvm_rx_tx_cmd_agg(mvm, pkt); | ||
788 | |||
789 | return 0; | ||
790 | } | ||
791 | |||
792 | int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | ||
793 | struct iwl_device_cmd *cmd) | ||
794 | { | ||
795 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
796 | struct iwl_mvm_ba_notif *ba_notif = (void *)pkt->data; | ||
797 | struct sk_buff_head reclaimed_skbs; | ||
798 | struct iwl_mvm_tid_data *tid_data; | ||
799 | struct ieee80211_tx_info *info; | ||
800 | struct ieee80211_sta *sta; | ||
801 | struct iwl_mvm_sta *mvmsta; | ||
802 | struct ieee80211_hdr *hdr; | ||
803 | struct sk_buff *skb; | ||
804 | int sta_id, tid, freed; | ||
805 | |||
806 | /* "flow" corresponds to Tx queue */ | ||
807 | u16 scd_flow = le16_to_cpu(ba_notif->scd_flow); | ||
808 | |||
809 | /* "ssn" is start of block-ack Tx window, corresponds to index | ||
810 | * (in Tx queue's circular buffer) of first TFD/frame in window */ | ||
811 | u16 ba_resp_scd_ssn = le16_to_cpu(ba_notif->scd_ssn); | ||
812 | |||
813 | sta_id = ba_notif->sta_id; | ||
814 | tid = ba_notif->tid; | ||
815 | |||
816 | rcu_read_lock(); | ||
817 | |||
818 | sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); | ||
819 | |||
820 | /* Reclaiming frames for a station that has been deleted ? */ | ||
821 | if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) { | ||
822 | rcu_read_unlock(); | ||
823 | return 0; | ||
824 | } | ||
825 | |||
826 | mvmsta = (void *)sta->drv_priv; | ||
827 | tid_data = &mvmsta->tid_data[tid]; | ||
828 | |||
829 | if (WARN_ONCE(tid_data->txq_id != scd_flow, "Q %d, tid %d, flow %d", | ||
830 | tid_data->txq_id, tid, scd_flow)) { | ||
831 | rcu_read_unlock(); | ||
832 | return 0; | ||
833 | } | ||
834 | |||
835 | spin_lock(&mvmsta->lock); | ||
836 | |||
837 | __skb_queue_head_init(&reclaimed_skbs); | ||
838 | |||
839 | /* | ||
840 | * Release all TFDs before the SSN, i.e. all TFDs in front of | ||
841 | * block-ack window (we assume that they've been successfully | ||
842 | * transmitted ... if not, it's too late anyway). | ||
843 | */ | ||
844 | iwl_trans_reclaim(mvm->trans, scd_flow, ba_resp_scd_ssn, | ||
845 | &reclaimed_skbs); | ||
846 | |||
847 | IWL_DEBUG_TX_REPLY(mvm, | ||
848 | "BA_NOTIFICATION Received from %pM, sta_id = %d\n", | ||
849 | (u8 *)&ba_notif->sta_addr_lo32, | ||
850 | ba_notif->sta_id); | ||
851 | IWL_DEBUG_TX_REPLY(mvm, | ||
852 | "TID = %d, SeqCtl = %d, bitmap = 0x%llx, scd_flow = %d, scd_ssn = %d sent:%d, acked:%d\n", | ||
853 | ba_notif->tid, le16_to_cpu(ba_notif->seq_ctl), | ||
854 | (unsigned long long)le64_to_cpu(ba_notif->bitmap), | ||
855 | scd_flow, ba_resp_scd_ssn, ba_notif->txed, | ||
856 | ba_notif->txed_2_done); | ||
857 | |||
858 | tid_data->next_reclaimed = ba_resp_scd_ssn; | ||
859 | |||
860 | iwl_mvm_check_ratid_empty(mvm, sta, tid); | ||
861 | |||
862 | freed = 0; | ||
863 | |||
864 | skb_queue_walk(&reclaimed_skbs, skb) { | ||
865 | hdr = (struct ieee80211_hdr *)skb->data; | ||
866 | |||
867 | if (ieee80211_is_data_qos(hdr->frame_control)) | ||
868 | freed++; | ||
869 | else | ||
870 | WARN_ON_ONCE(1); | ||
871 | |||
872 | info = IEEE80211_SKB_CB(skb); | ||
873 | iwl_trans_free_tx_cmd(mvm->trans, info->driver_data[1]); | ||
874 | |||
875 | if (freed == 1) { | ||
876 | /* this is the first skb we deliver in this batch */ | ||
877 | /* put the rate scaling data there */ | ||
878 | info = IEEE80211_SKB_CB(skb); | ||
879 | memset(&info->status, 0, sizeof(info->status)); | ||
880 | info->flags |= IEEE80211_TX_STAT_ACK; | ||
881 | info->flags |= IEEE80211_TX_STAT_AMPDU; | ||
882 | info->status.ampdu_ack_len = ba_notif->txed_2_done; | ||
883 | info->status.ampdu_len = ba_notif->txed; | ||
884 | iwl_mvm_hwrate_to_tx_control(tid_data->rate_n_flags, | ||
885 | info); | ||
886 | } | ||
887 | } | ||
888 | |||
889 | spin_unlock(&mvmsta->lock); | ||
890 | |||
891 | rcu_read_unlock(); | ||
892 | |||
893 | while (!skb_queue_empty(&reclaimed_skbs)) { | ||
894 | skb = __skb_dequeue(&reclaimed_skbs); | ||
895 | ieee80211_tx_status(mvm->hw, skb); | ||
896 | } | ||
897 | |||
898 | return 0; | ||
899 | } | ||
900 | |||
901 | int iwl_mvm_flush_tx_path(struct iwl_mvm *mvm, u32 tfd_msk, bool sync) | ||
902 | { | ||
903 | int ret; | ||
904 | struct iwl_tx_path_flush_cmd flush_cmd = { | ||
905 | .queues_ctl = cpu_to_le32(tfd_msk), | ||
906 | .flush_ctl = cpu_to_le16(DUMP_TX_FIFO_FLUSH), | ||
907 | }; | ||
908 | |||
909 | u32 flags = sync ? CMD_SYNC : CMD_ASYNC; | ||
910 | |||
911 | ret = iwl_mvm_send_cmd_pdu(mvm, TXPATH_FLUSH, flags, | ||
912 | sizeof(flush_cmd), &flush_cmd); | ||
913 | if (ret) | ||
914 | IWL_ERR(mvm, "Failed to send flush command (%d)\n", ret); | ||
915 | return ret; | ||
916 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c new file mode 100644 index 000000000000..000e842c2edd --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c | |||
@@ -0,0 +1,472 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called LICENSE.GPL. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | * | ||
62 | *****************************************************************************/ | ||
63 | #include <net/mac80211.h> | ||
64 | |||
65 | #include "iwl-debug.h" | ||
66 | #include "iwl-io.h" | ||
67 | |||
68 | #include "mvm.h" | ||
69 | #include "fw-api-rs.h" | ||
70 | |||
71 | /* | ||
72 | * Will return 0 even if the cmd failed when RFKILL is asserted unless | ||
73 | * CMD_WANT_SKB is set in cmd->flags. | ||
74 | */ | ||
75 | int iwl_mvm_send_cmd(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd) | ||
76 | { | ||
77 | int ret; | ||
78 | |||
79 | /* | ||
80 | * Synchronous commands from this op-mode must hold | ||
81 | * the mutex, this ensures we don't try to send two | ||
82 | * (or more) synchronous commands at a time. | ||
83 | */ | ||
84 | if (!(cmd->flags & CMD_ASYNC)) | ||
85 | lockdep_assert_held(&mvm->mutex); | ||
86 | |||
87 | ret = iwl_trans_send_cmd(mvm->trans, cmd); | ||
88 | |||
89 | /* | ||
90 | * If the caller wants the SKB, then don't hide any problems, the | ||
91 | * caller might access the response buffer which will be NULL if | ||
92 | * the command failed. | ||
93 | */ | ||
94 | if (cmd->flags & CMD_WANT_SKB) | ||
95 | return ret; | ||
96 | |||
97 | /* Silently ignore failures if RFKILL is asserted */ | ||
98 | if (!ret || ret == -ERFKILL) | ||
99 | return 0; | ||
100 | return ret; | ||
101 | } | ||
102 | |||
103 | int iwl_mvm_send_cmd_pdu(struct iwl_mvm *mvm, u8 id, | ||
104 | u32 flags, u16 len, const void *data) | ||
105 | { | ||
106 | struct iwl_host_cmd cmd = { | ||
107 | .id = id, | ||
108 | .len = { len, }, | ||
109 | .data = { data, }, | ||
110 | .flags = flags, | ||
111 | }; | ||
112 | |||
113 | return iwl_mvm_send_cmd(mvm, &cmd); | ||
114 | } | ||
115 | |||
116 | /* | ||
117 | * We assume that the caller set the status to the sucess value | ||
118 | */ | ||
119 | int iwl_mvm_send_cmd_status(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd, | ||
120 | u32 *status) | ||
121 | { | ||
122 | struct iwl_rx_packet *pkt; | ||
123 | struct iwl_cmd_response *resp; | ||
124 | int ret, resp_len; | ||
125 | |||
126 | lockdep_assert_held(&mvm->mutex); | ||
127 | |||
128 | /* | ||
129 | * Only synchronous commands can wait for status, | ||
130 | * we use WANT_SKB so the caller can't. | ||
131 | */ | ||
132 | if (WARN_ONCE(cmd->flags & (CMD_ASYNC | CMD_WANT_SKB), | ||
133 | "cmd flags %x", cmd->flags)) | ||
134 | return -EINVAL; | ||
135 | |||
136 | cmd->flags |= CMD_SYNC | CMD_WANT_SKB; | ||
137 | |||
138 | ret = iwl_trans_send_cmd(mvm->trans, cmd); | ||
139 | if (ret == -ERFKILL) { | ||
140 | /* | ||
141 | * The command failed because of RFKILL, don't update | ||
142 | * the status, leave it as success and return 0. | ||
143 | */ | ||
144 | return 0; | ||
145 | } else if (ret) { | ||
146 | return ret; | ||
147 | } | ||
148 | |||
149 | pkt = cmd->resp_pkt; | ||
150 | /* Can happen if RFKILL is asserted */ | ||
151 | if (!pkt) { | ||
152 | ret = 0; | ||
153 | goto out_free_resp; | ||
154 | } | ||
155 | |||
156 | if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { | ||
157 | ret = -EIO; | ||
158 | goto out_free_resp; | ||
159 | } | ||
160 | |||
161 | resp_len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; | ||
162 | if (WARN_ON_ONCE(resp_len != sizeof(pkt->hdr) + sizeof(*resp))) { | ||
163 | ret = -EIO; | ||
164 | goto out_free_resp; | ||
165 | } | ||
166 | |||
167 | resp = (void *)pkt->data; | ||
168 | *status = le32_to_cpu(resp->status); | ||
169 | out_free_resp: | ||
170 | iwl_free_resp(cmd); | ||
171 | return ret; | ||
172 | } | ||
173 | |||
174 | /* | ||
175 | * We assume that the caller set the status to the sucess value | ||
176 | */ | ||
177 | int iwl_mvm_send_cmd_pdu_status(struct iwl_mvm *mvm, u8 id, u16 len, | ||
178 | const void *data, u32 *status) | ||
179 | { | ||
180 | struct iwl_host_cmd cmd = { | ||
181 | .id = id, | ||
182 | .len = { len, }, | ||
183 | .data = { data, }, | ||
184 | }; | ||
185 | |||
186 | return iwl_mvm_send_cmd_status(mvm, &cmd, status); | ||
187 | } | ||
188 | |||
189 | #define IWL_DECLARE_RATE_INFO(r) \ | ||
190 | [IWL_RATE_##r##M_INDEX] = IWL_RATE_##r##M_PLCP | ||
191 | |||
192 | /* | ||
193 | * Translate from fw_rate_index (IWL_RATE_XXM_INDEX) to PLCP | ||
194 | */ | ||
195 | static const u8 fw_rate_idx_to_plcp[IWL_RATE_COUNT] = { | ||
196 | IWL_DECLARE_RATE_INFO(1), | ||
197 | IWL_DECLARE_RATE_INFO(2), | ||
198 | IWL_DECLARE_RATE_INFO(5), | ||
199 | IWL_DECLARE_RATE_INFO(11), | ||
200 | IWL_DECLARE_RATE_INFO(6), | ||
201 | IWL_DECLARE_RATE_INFO(9), | ||
202 | IWL_DECLARE_RATE_INFO(12), | ||
203 | IWL_DECLARE_RATE_INFO(18), | ||
204 | IWL_DECLARE_RATE_INFO(24), | ||
205 | IWL_DECLARE_RATE_INFO(36), | ||
206 | IWL_DECLARE_RATE_INFO(48), | ||
207 | IWL_DECLARE_RATE_INFO(54), | ||
208 | }; | ||
209 | |||
210 | int iwl_mvm_legacy_rate_to_mac80211_idx(u32 rate_n_flags, | ||
211 | enum ieee80211_band band) | ||
212 | { | ||
213 | int rate = rate_n_flags & RATE_LEGACY_RATE_MSK; | ||
214 | int idx; | ||
215 | int band_offset = 0; | ||
216 | |||
217 | /* Legacy rate format, search for match in table */ | ||
218 | if (band == IEEE80211_BAND_5GHZ) | ||
219 | band_offset = IWL_FIRST_OFDM_RATE; | ||
220 | for (idx = band_offset; idx < IWL_RATE_COUNT_LEGACY; idx++) | ||
221 | if (fw_rate_idx_to_plcp[idx] == rate) | ||
222 | return idx - band_offset; | ||
223 | |||
224 | return -1; | ||
225 | } | ||
226 | |||
227 | u8 iwl_mvm_mac80211_idx_to_hwrate(int rate_idx) | ||
228 | { | ||
229 | /* Get PLCP rate for tx_cmd->rate_n_flags */ | ||
230 | return fw_rate_idx_to_plcp[rate_idx]; | ||
231 | } | ||
232 | |||
233 | int iwl_mvm_rx_fw_error(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | ||
234 | struct iwl_device_cmd *cmd) | ||
235 | { | ||
236 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
237 | struct iwl_error_resp *err_resp = (void *)pkt->data; | ||
238 | |||
239 | IWL_ERR(mvm, "FW Error notification: type 0x%08X cmd_id 0x%02X\n", | ||
240 | le32_to_cpu(err_resp->error_type), err_resp->cmd_id); | ||
241 | IWL_ERR(mvm, "FW Error notification: seq 0x%04X service 0x%08X\n", | ||
242 | le16_to_cpu(err_resp->bad_cmd_seq_num), | ||
243 | le32_to_cpu(err_resp->error_service)); | ||
244 | IWL_ERR(mvm, "FW Error notification: timestamp 0x%16llX\n", | ||
245 | le64_to_cpu(err_resp->timestamp)); | ||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | /* | ||
250 | * Returns the first antenna as ANT_[ABC], as defined in iwl-config.h. | ||
251 | * The parameter should also be a combination of ANT_[ABC]. | ||
252 | */ | ||
253 | u8 first_antenna(u8 mask) | ||
254 | { | ||
255 | BUILD_BUG_ON(ANT_A != BIT(0)); /* using ffs is wrong if not */ | ||
256 | WARN_ON_ONCE(!mask); /* ffs will return 0 if mask is zeroed */ | ||
257 | return (u8)(BIT(ffs(mask))); | ||
258 | } | ||
259 | |||
260 | /* | ||
261 | * Toggles between TX antennas to send the probe request on. | ||
262 | * Receives the bitmask of valid TX antennas and the *index* used | ||
263 | * for the last TX, and returns the next valid *index* to use. | ||
264 | * In order to set it in the tx_cmd, must do BIT(idx). | ||
265 | */ | ||
266 | u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx) | ||
267 | { | ||
268 | u8 ind = last_idx; | ||
269 | int i; | ||
270 | |||
271 | for (i = 0; i < RATE_MCS_ANT_NUM; i++) { | ||
272 | ind = (ind + 1) % RATE_MCS_ANT_NUM; | ||
273 | if (valid & BIT(ind)) | ||
274 | return ind; | ||
275 | } | ||
276 | |||
277 | WARN_ONCE(1, "Failed to toggle between antennas 0x%x", valid); | ||
278 | return last_idx; | ||
279 | } | ||
280 | |||
281 | static struct { | ||
282 | char *name; | ||
283 | u8 num; | ||
284 | } advanced_lookup[] = { | ||
285 | { "NMI_INTERRUPT_WDG", 0x34 }, | ||
286 | { "SYSASSERT", 0x35 }, | ||
287 | { "UCODE_VERSION_MISMATCH", 0x37 }, | ||
288 | { "BAD_COMMAND", 0x38 }, | ||
289 | { "NMI_INTERRUPT_DATA_ACTION_PT", 0x3C }, | ||
290 | { "FATAL_ERROR", 0x3D }, | ||
291 | { "NMI_TRM_HW_ERR", 0x46 }, | ||
292 | { "NMI_INTERRUPT_TRM", 0x4C }, | ||
293 | { "NMI_INTERRUPT_BREAK_POINT", 0x54 }, | ||
294 | { "NMI_INTERRUPT_WDG_RXF_FULL", 0x5C }, | ||
295 | { "NMI_INTERRUPT_WDG_NO_RBD_RXF_FULL", 0x64 }, | ||
296 | { "NMI_INTERRUPT_HOST", 0x66 }, | ||
297 | { "NMI_INTERRUPT_ACTION_PT", 0x7C }, | ||
298 | { "NMI_INTERRUPT_UNKNOWN", 0x84 }, | ||
299 | { "NMI_INTERRUPT_INST_ACTION_PT", 0x86 }, | ||
300 | { "ADVANCED_SYSASSERT", 0 }, | ||
301 | }; | ||
302 | |||
303 | static const char *desc_lookup(u32 num) | ||
304 | { | ||
305 | int i; | ||
306 | |||
307 | for (i = 0; i < ARRAY_SIZE(advanced_lookup) - 1; i++) | ||
308 | if (advanced_lookup[i].num == num) | ||
309 | return advanced_lookup[i].name; | ||
310 | |||
311 | /* No entry matches 'num', so it is the last: ADVANCED_SYSASSERT */ | ||
312 | return advanced_lookup[i].name; | ||
313 | } | ||
314 | |||
315 | /* | ||
316 | * Note: This structure is read from the device with IO accesses, | ||
317 | * and the reading already does the endian conversion. As it is | ||
318 | * read with u32-sized accesses, any members with a different size | ||
319 | * need to be ordered correctly though! | ||
320 | */ | ||
321 | struct iwl_error_event_table { | ||
322 | u32 valid; /* (nonzero) valid, (0) log is empty */ | ||
323 | u32 error_id; /* type of error */ | ||
324 | u32 pc; /* program counter */ | ||
325 | u32 blink1; /* branch link */ | ||
326 | u32 blink2; /* branch link */ | ||
327 | u32 ilink1; /* interrupt link */ | ||
328 | u32 ilink2; /* interrupt link */ | ||
329 | u32 data1; /* error-specific data */ | ||
330 | u32 data2; /* error-specific data */ | ||
331 | u32 data3; /* error-specific data */ | ||
332 | u32 bcon_time; /* beacon timer */ | ||
333 | u32 tsf_low; /* network timestamp function timer */ | ||
334 | u32 tsf_hi; /* network timestamp function timer */ | ||
335 | u32 gp1; /* GP1 timer register */ | ||
336 | u32 gp2; /* GP2 timer register */ | ||
337 | u32 gp3; /* GP3 timer register */ | ||
338 | u32 ucode_ver; /* uCode version */ | ||
339 | u32 hw_ver; /* HW Silicon version */ | ||
340 | u32 brd_ver; /* HW board version */ | ||
341 | u32 log_pc; /* log program counter */ | ||
342 | u32 frame_ptr; /* frame pointer */ | ||
343 | u32 stack_ptr; /* stack pointer */ | ||
344 | u32 hcmd; /* last host command header */ | ||
345 | u32 isr0; /* isr status register LMPM_NIC_ISR0: | ||
346 | * rxtx_flag */ | ||
347 | u32 isr1; /* isr status register LMPM_NIC_ISR1: | ||
348 | * host_flag */ | ||
349 | u32 isr2; /* isr status register LMPM_NIC_ISR2: | ||
350 | * enc_flag */ | ||
351 | u32 isr3; /* isr status register LMPM_NIC_ISR3: | ||
352 | * time_flag */ | ||
353 | u32 isr4; /* isr status register LMPM_NIC_ISR4: | ||
354 | * wico interrupt */ | ||
355 | u32 isr_pref; /* isr status register LMPM_NIC_PREF_STAT */ | ||
356 | u32 wait_event; /* wait event() caller address */ | ||
357 | u32 l2p_control; /* L2pControlField */ | ||
358 | u32 l2p_duration; /* L2pDurationField */ | ||
359 | u32 l2p_mhvalid; /* L2pMhValidBits */ | ||
360 | u32 l2p_addr_match; /* L2pAddrMatchStat */ | ||
361 | u32 lmpm_pmg_sel; /* indicate which clocks are turned on | ||
362 | * (LMPM_PMG_SEL) */ | ||
363 | u32 u_timestamp; /* indicate when the date and time of the | ||
364 | * compilation */ | ||
365 | u32 flow_handler; /* FH read/write pointers, RX credit */ | ||
366 | } __packed; | ||
367 | |||
368 | #define ERROR_START_OFFSET (1 * sizeof(u32)) | ||
369 | #define ERROR_ELEM_SIZE (7 * sizeof(u32)) | ||
370 | |||
371 | void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) | ||
372 | { | ||
373 | struct iwl_trans *trans = mvm->trans; | ||
374 | struct iwl_error_event_table table; | ||
375 | u32 base; | ||
376 | |||
377 | base = mvm->error_event_table; | ||
378 | if (mvm->cur_ucode == IWL_UCODE_INIT) { | ||
379 | if (!base) | ||
380 | base = mvm->fw->init_errlog_ptr; | ||
381 | } else { | ||
382 | if (!base) | ||
383 | base = mvm->fw->inst_errlog_ptr; | ||
384 | } | ||
385 | |||
386 | if (base < 0x800000 || base >= 0x80C000) { | ||
387 | IWL_ERR(mvm, | ||
388 | "Not valid error log pointer 0x%08X for %s uCode\n", | ||
389 | base, | ||
390 | (mvm->cur_ucode == IWL_UCODE_INIT) | ||
391 | ? "Init" : "RT"); | ||
392 | return; | ||
393 | } | ||
394 | |||
395 | iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table)); | ||
396 | |||
397 | if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { | ||
398 | IWL_ERR(trans, "Start IWL Error Log Dump:\n"); | ||
399 | IWL_ERR(trans, "Status: 0x%08lX, count: %d\n", | ||
400 | mvm->status, table.valid); | ||
401 | } | ||
402 | |||
403 | trace_iwlwifi_dev_ucode_error(trans->dev, table.error_id, table.tsf_low, | ||
404 | table.data1, table.data2, table.data3, | ||
405 | table.blink1, table.blink2, table.ilink1, | ||
406 | table.ilink2, table.bcon_time, table.gp1, | ||
407 | table.gp2, table.gp3, table.ucode_ver, | ||
408 | table.hw_ver, table.brd_ver); | ||
409 | IWL_ERR(mvm, "0x%08X | %-28s\n", table.error_id, | ||
410 | desc_lookup(table.error_id)); | ||
411 | IWL_ERR(mvm, "0x%08X | uPc\n", table.pc); | ||
412 | IWL_ERR(mvm, "0x%08X | branchlink1\n", table.blink1); | ||
413 | IWL_ERR(mvm, "0x%08X | branchlink2\n", table.blink2); | ||
414 | IWL_ERR(mvm, "0x%08X | interruptlink1\n", table.ilink1); | ||
415 | IWL_ERR(mvm, "0x%08X | interruptlink2\n", table.ilink2); | ||
416 | IWL_ERR(mvm, "0x%08X | data1\n", table.data1); | ||
417 | IWL_ERR(mvm, "0x%08X | data2\n", table.data2); | ||
418 | IWL_ERR(mvm, "0x%08X | data3\n", table.data3); | ||
419 | IWL_ERR(mvm, "0x%08X | beacon time\n", table.bcon_time); | ||
420 | IWL_ERR(mvm, "0x%08X | tsf low\n", table.tsf_low); | ||
421 | IWL_ERR(mvm, "0x%08X | tsf hi\n", table.tsf_hi); | ||
422 | IWL_ERR(mvm, "0x%08X | time gp1\n", table.gp1); | ||
423 | IWL_ERR(mvm, "0x%08X | time gp2\n", table.gp2); | ||
424 | IWL_ERR(mvm, "0x%08X | time gp3\n", table.gp3); | ||
425 | IWL_ERR(mvm, "0x%08X | uCode version\n", table.ucode_ver); | ||
426 | IWL_ERR(mvm, "0x%08X | hw version\n", table.hw_ver); | ||
427 | IWL_ERR(mvm, "0x%08X | board version\n", table.brd_ver); | ||
428 | IWL_ERR(mvm, "0x%08X | hcmd\n", table.hcmd); | ||
429 | IWL_ERR(mvm, "0x%08X | isr0\n", table.isr0); | ||
430 | IWL_ERR(mvm, "0x%08X | isr1\n", table.isr1); | ||
431 | IWL_ERR(mvm, "0x%08X | isr2\n", table.isr2); | ||
432 | IWL_ERR(mvm, "0x%08X | isr3\n", table.isr3); | ||
433 | IWL_ERR(mvm, "0x%08X | isr4\n", table.isr4); | ||
434 | IWL_ERR(mvm, "0x%08X | isr_pref\n", table.isr_pref); | ||
435 | IWL_ERR(mvm, "0x%08X | wait_event\n", table.wait_event); | ||
436 | IWL_ERR(mvm, "0x%08X | l2p_control\n", table.l2p_control); | ||
437 | IWL_ERR(mvm, "0x%08X | l2p_duration\n", table.l2p_duration); | ||
438 | IWL_ERR(mvm, "0x%08X | l2p_mhvalid\n", table.l2p_mhvalid); | ||
439 | IWL_ERR(mvm, "0x%08X | l2p_addr_match\n", table.l2p_addr_match); | ||
440 | IWL_ERR(mvm, "0x%08X | lmpm_pmg_sel\n", table.lmpm_pmg_sel); | ||
441 | IWL_ERR(mvm, "0x%08X | timestamp\n", table.u_timestamp); | ||
442 | IWL_ERR(mvm, "0x%08X | flow_handler\n", table.flow_handler); | ||
443 | } | ||
444 | |||
445 | /** | ||
446 | * iwl_mvm_send_lq_cmd() - Send link quality command | ||
447 | * @init: This command is sent as part of station initialization right | ||
448 | * after station has been added. | ||
449 | * | ||
450 | * The link quality command is sent as the last step of station creation. | ||
451 | * This is the special case in which init is set and we call a callback in | ||
452 | * this case to clear the state indicating that station creation is in | ||
453 | * progress. | ||
454 | */ | ||
455 | int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, | ||
456 | u8 flags, bool init) | ||
457 | { | ||
458 | struct iwl_host_cmd cmd = { | ||
459 | .id = LQ_CMD, | ||
460 | .len = { sizeof(struct iwl_lq_cmd), }, | ||
461 | .flags = flags, | ||
462 | .data = { lq, }, | ||
463 | }; | ||
464 | |||
465 | if (WARN_ON(lq->sta_id == IWL_INVALID_STATION)) | ||
466 | return -EINVAL; | ||
467 | |||
468 | if (WARN_ON(init && (cmd.flags & CMD_ASYNC))) | ||
469 | return -EINVAL; | ||
470 | |||
471 | return iwl_mvm_send_cmd(mvm, &cmd); | ||
472 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/pcie/1000.c b/drivers/net/wireless/iwlwifi/pcie/1000.c index f8620ecae6b4..ff3389757281 100644 --- a/drivers/net/wireless/iwlwifi/pcie/1000.c +++ b/drivers/net/wireless/iwlwifi/pcie/1000.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify it | 5 | * This program is free software; you can redistribute it and/or modify it |
6 | * under the terms of version 2 of the GNU General Public License as | 6 | * under the terms of version 2 of the GNU General Public License as |
diff --git a/drivers/net/wireless/iwlwifi/pcie/2000.c b/drivers/net/wireless/iwlwifi/pcie/2000.c index 244019cec3e1..e7de33128b16 100644 --- a/drivers/net/wireless/iwlwifi/pcie/2000.c +++ b/drivers/net/wireless/iwlwifi/pcie/2000.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify it | 5 | * This program is free software; you can redistribute it and/or modify it |
6 | * under the terms of version 2 of the GNU General Public License as | 6 | * under the terms of version 2 of the GNU General Public License as |
diff --git a/drivers/net/wireless/iwlwifi/pcie/5000.c b/drivers/net/wireless/iwlwifi/pcie/5000.c index 83ca40321ff1..5096f7c96ab6 100644 --- a/drivers/net/wireless/iwlwifi/pcie/5000.c +++ b/drivers/net/wireless/iwlwifi/pcie/5000.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify it | 5 | * This program is free software; you can redistribute it and/or modify it |
6 | * under the terms of version 2 of the GNU General Public License as | 6 | * under the terms of version 2 of the GNU General Public License as |
diff --git a/drivers/net/wireless/iwlwifi/pcie/6000.c b/drivers/net/wireless/iwlwifi/pcie/6000.c index d4df976d4709..801ff49796dd 100644 --- a/drivers/net/wireless/iwlwifi/pcie/6000.c +++ b/drivers/net/wireless/iwlwifi/pcie/6000.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify it | 5 | * This program is free software; you can redistribute it and/or modify it |
6 | * under the terms of version 2 of the GNU General Public License as | 6 | * under the terms of version 2 of the GNU General Public License as |
diff --git a/drivers/net/wireless/iwlwifi/pcie/7000.c b/drivers/net/wireless/iwlwifi/pcie/7000.c new file mode 100644 index 000000000000..6e35b2b72332 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/pcie/7000.c | |||
@@ -0,0 +1,111 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of version 2 of the GNU General Public License as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program; if not, write to the Free Software Foundation, Inc., | ||
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA | ||
17 | * | ||
18 | * The full GNU General Public License is included in this distribution in the | ||
19 | * file called LICENSE. | ||
20 | * | ||
21 | * Contact Information: | ||
22 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
23 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
24 | * | ||
25 | *****************************************************************************/ | ||
26 | |||
27 | #include <linux/module.h> | ||
28 | #include <linux/stringify.h> | ||
29 | #include "iwl-config.h" | ||
30 | #include "iwl-agn-hw.h" | ||
31 | #include "cfg.h" | ||
32 | |||
33 | /* Highest firmware API version supported */ | ||
34 | #define IWL7260_UCODE_API_MAX 6 | ||
35 | #define IWL3160_UCODE_API_MAX 6 | ||
36 | |||
37 | /* Oldest version we won't warn about */ | ||
38 | #define IWL7260_UCODE_API_OK 6 | ||
39 | #define IWL3160_UCODE_API_OK 6 | ||
40 | |||
41 | /* Lowest firmware API version supported */ | ||
42 | #define IWL7260_UCODE_API_MIN 6 | ||
43 | #define IWL3160_UCODE_API_MIN 6 | ||
44 | |||
45 | /* NVM versions */ | ||
46 | #define IWL7260_NVM_VERSION 0x0a1d | ||
47 | #define IWL7260_TX_POWER_VERSION 0xffff /* meaningless */ | ||
48 | #define IWL3160_NVM_VERSION 0x709 | ||
49 | #define IWL3160_TX_POWER_VERSION 0xffff /* meaningless */ | ||
50 | |||
51 | #define IWL7260_FW_PRE "iwlwifi-7260-" | ||
52 | #define IWL7260_MODULE_FIRMWARE(api) IWL7260_FW_PRE __stringify(api) ".ucode" | ||
53 | |||
54 | #define IWL3160_FW_PRE "iwlwifi-3160-" | ||
55 | #define IWL3160_MODULE_FIRMWARE(api) IWL3160_FW_PRE __stringify(api) ".ucode" | ||
56 | |||
57 | static const struct iwl_base_params iwl7000_base_params = { | ||
58 | .eeprom_size = OTP_LOW_IMAGE_SIZE, | ||
59 | .num_of_queues = IWLAGN_NUM_QUEUES, | ||
60 | .pll_cfg_val = 0, | ||
61 | .shadow_ram_support = true, | ||
62 | .led_compensation = 57, | ||
63 | .adv_thermal_throttle = true, | ||
64 | .support_ct_kill_exit = true, | ||
65 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, | ||
66 | .chain_noise_scale = 1000, | ||
67 | .wd_timeout = IWL_LONG_WD_TIMEOUT, | ||
68 | .max_event_log_size = 512, | ||
69 | .shadow_reg_enable = false, /* TODO: fix bugs using this feature */ | ||
70 | }; | ||
71 | |||
72 | static const struct iwl_ht_params iwl7000_ht_params = { | ||
73 | .ht_greenfield_support = true, | ||
74 | .use_rts_for_aggregation = true, /* use rts/cts protection */ | ||
75 | .ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ), | ||
76 | }; | ||
77 | |||
78 | #define IWL_DEVICE_7000 \ | ||
79 | .ucode_api_max = IWL7260_UCODE_API_MAX, \ | ||
80 | .ucode_api_ok = IWL7260_UCODE_API_OK, \ | ||
81 | .ucode_api_min = IWL7260_UCODE_API_MIN, \ | ||
82 | .device_family = IWL_DEVICE_FAMILY_7000, \ | ||
83 | .max_inst_size = IWL60_RTC_INST_SIZE, \ | ||
84 | .max_data_size = IWL60_RTC_DATA_SIZE, \ | ||
85 | .base_params = &iwl7000_base_params, \ | ||
86 | /* TODO: .bt_params? */ \ | ||
87 | .need_temp_offset_calib = true, \ | ||
88 | .led_mode = IWL_LED_RF_STATE, \ | ||
89 | .adv_pm = true \ | ||
90 | |||
91 | |||
92 | const struct iwl_cfg iwl7260_2ac_cfg = { | ||
93 | .name = "Intel(R) Dual Band Wireless AC7260", | ||
94 | .fw_name_pre = IWL7260_FW_PRE, | ||
95 | IWL_DEVICE_7000, | ||
96 | .ht_params = &iwl7000_ht_params, | ||
97 | .nvm_ver = IWL7260_NVM_VERSION, | ||
98 | .nvm_calib_ver = IWL7260_TX_POWER_VERSION, | ||
99 | }; | ||
100 | |||
101 | const struct iwl_cfg iwl3160_ac_cfg = { | ||
102 | .name = "Intel(R) Dual Band Wireless AC3160", | ||
103 | .fw_name_pre = IWL3160_FW_PRE, | ||
104 | IWL_DEVICE_7000, | ||
105 | .ht_params = &iwl7000_ht_params, | ||
106 | .nvm_ver = IWL3160_NVM_VERSION, | ||
107 | .nvm_calib_ver = IWL3160_TX_POWER_VERSION, | ||
108 | }; | ||
109 | |||
110 | MODULE_FIRMWARE(IWL7260_MODULE_FIRMWARE(IWL7260_UCODE_API_OK)); | ||
111 | MODULE_FIRMWARE(IWL3160_MODULE_FIRMWARE(IWL3160_UCODE_API_OK)); | ||
diff --git a/drivers/net/wireless/iwlwifi/pcie/cfg.h b/drivers/net/wireless/iwlwifi/pcie/cfg.h index 82152311d73b..c6f8e83c3551 100644 --- a/drivers/net/wireless/iwlwifi/pcie/cfg.h +++ b/drivers/net/wireless/iwlwifi/pcie/cfg.h | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
@@ -109,5 +109,7 @@ extern const struct iwl_cfg iwl6035_2agn_cfg; | |||
109 | extern const struct iwl_cfg iwl105_bgn_cfg; | 109 | extern const struct iwl_cfg iwl105_bgn_cfg; |
110 | extern const struct iwl_cfg iwl105_bgn_d_cfg; | 110 | extern const struct iwl_cfg iwl105_bgn_d_cfg; |
111 | extern const struct iwl_cfg iwl135_bgn_cfg; | 111 | extern const struct iwl_cfg iwl135_bgn_cfg; |
112 | extern const struct iwl_cfg iwl7260_2ac_cfg; | ||
113 | extern const struct iwl_cfg iwl3160_ac_cfg; | ||
112 | 114 | ||
113 | #endif /* __iwl_pci_h__ */ | 115 | #endif /* __iwl_pci_h__ */ |
diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index c2e141af353c..7bc0fb9128dd 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
@@ -255,6 +255,12 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { | |||
255 | {IWL_PCI_DEVICE(0x0893, 0x0262, iwl135_bgn_cfg)}, | 255 | {IWL_PCI_DEVICE(0x0893, 0x0262, iwl135_bgn_cfg)}, |
256 | {IWL_PCI_DEVICE(0x0892, 0x0462, iwl135_bgn_cfg)}, | 256 | {IWL_PCI_DEVICE(0x0892, 0x0462, iwl135_bgn_cfg)}, |
257 | 257 | ||
258 | /* 7000 Series */ | ||
259 | {IWL_PCI_DEVICE(0x08B1, 0x4070, iwl7260_2ac_cfg)}, | ||
260 | {IWL_PCI_DEVICE(0x08B1, 0xC070, iwl7260_2ac_cfg)}, | ||
261 | {IWL_PCI_DEVICE(0x08B3, 0x0070, iwl3160_ac_cfg)}, | ||
262 | {IWL_PCI_DEVICE(0x08B3, 0x8070, iwl3160_ac_cfg)}, | ||
263 | |||
258 | {0} | 264 | {0} |
259 | }; | 265 | }; |
260 | MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids); | 266 | MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids); |
diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index 20735a008cab..5f6bb4e09d42 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * Portions of this file are derived from the ipw3945 project, as well | 5 | * Portions of this file are derived from the ipw3945 project, as well |
6 | * as portions of the ieee80211 subsystem header files. | 6 | * as portions of the ieee80211 subsystem header files. |
@@ -235,6 +235,7 @@ struct iwl_txq { | |||
235 | * @bc_table_dword: true if the BC table expects DWORD (as opposed to bytes) | 235 | * @bc_table_dword: true if the BC table expects DWORD (as opposed to bytes) |
236 | * @rx_page_order: page order for receive buffer size | 236 | * @rx_page_order: page order for receive buffer size |
237 | * @wd_timeout: queue watchdog timeout (jiffies) | 237 | * @wd_timeout: queue watchdog timeout (jiffies) |
238 | * @reg_lock: protect hw register access | ||
238 | */ | 239 | */ |
239 | struct iwl_trans_pcie { | 240 | struct iwl_trans_pcie { |
240 | struct iwl_rxq rxq; | 241 | struct iwl_rxq rxq; |
@@ -283,6 +284,9 @@ struct iwl_trans_pcie { | |||
283 | 284 | ||
284 | /* queue watchdog */ | 285 | /* queue watchdog */ |
285 | unsigned long wd_timeout; | 286 | unsigned long wd_timeout; |
287 | |||
288 | /*protect hw register */ | ||
289 | spinlock_t reg_lock; | ||
286 | }; | 290 | }; |
287 | 291 | ||
288 | /** | 292 | /** |
diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index 4e6591d24e61..a9ca1d35fa93 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * Portions of this file are derived from the ipw3945 project, as well | 5 | * Portions of this file are derived from the ipw3945 project, as well |
6 | * as portions of the ieee80211 subsystem header files. | 6 | * as portions of the ieee80211 subsystem header files. |
@@ -594,6 +594,7 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, | |||
594 | int index, cmd_index, err, len; | 594 | int index, cmd_index, err, len; |
595 | struct iwl_rx_cmd_buffer rxcb = { | 595 | struct iwl_rx_cmd_buffer rxcb = { |
596 | ._offset = offset, | 596 | ._offset = offset, |
597 | ._rx_page_order = trans_pcie->rx_page_order, | ||
597 | ._page = rxb->page, | 598 | ._page = rxb->page, |
598 | ._page_stolen = false, | 599 | ._page_stolen = false, |
599 | .truesize = max_len, | 600 | .truesize = max_len, |
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index c57641eb83d5..56d4f72500bc 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
@@ -75,6 +75,33 @@ | |||
75 | #include "iwl-agn-hw.h" | 75 | #include "iwl-agn-hw.h" |
76 | #include "internal.h" | 76 | #include "internal.h" |
77 | 77 | ||
78 | static void __iwl_trans_pcie_set_bits_mask(struct iwl_trans *trans, | ||
79 | u32 reg, u32 mask, u32 value) | ||
80 | { | ||
81 | u32 v; | ||
82 | |||
83 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
84 | WARN_ON_ONCE(value & ~mask); | ||
85 | #endif | ||
86 | |||
87 | v = iwl_read32(trans, reg); | ||
88 | v &= ~mask; | ||
89 | v |= value; | ||
90 | iwl_write32(trans, reg, v); | ||
91 | } | ||
92 | |||
93 | static inline void __iwl_trans_pcie_clear_bit(struct iwl_trans *trans, | ||
94 | u32 reg, u32 mask) | ||
95 | { | ||
96 | __iwl_trans_pcie_set_bits_mask(trans, reg, mask, 0); | ||
97 | } | ||
98 | |||
99 | static inline void __iwl_trans_pcie_set_bit(struct iwl_trans *trans, | ||
100 | u32 reg, u32 mask) | ||
101 | { | ||
102 | __iwl_trans_pcie_set_bits_mask(trans, reg, mask, mask); | ||
103 | } | ||
104 | |||
78 | static void iwl_pcie_set_pwr(struct iwl_trans *trans, bool vaux) | 105 | static void iwl_pcie_set_pwr(struct iwl_trans *trans, bool vaux) |
79 | { | 106 | { |
80 | if (vaux && pci_pme_capable(to_pci_dev(trans->dev), PCI_D3cold)) | 107 | if (vaux && pci_pme_capable(to_pci_dev(trans->dev), PCI_D3cold)) |
@@ -779,15 +806,16 @@ static int iwl_trans_pcie_resume(struct iwl_trans *trans) | |||
779 | } | 806 | } |
780 | #endif /* CONFIG_PM_SLEEP */ | 807 | #endif /* CONFIG_PM_SLEEP */ |
781 | 808 | ||
782 | static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent) | 809 | static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent, |
810 | unsigned long *flags) | ||
783 | { | 811 | { |
784 | int ret; | 812 | int ret; |
785 | 813 | struct iwl_trans_pcie *pcie_trans = IWL_TRANS_GET_PCIE_TRANS(trans); | |
786 | lockdep_assert_held(&trans->reg_lock); | 814 | spin_lock_irqsave(&pcie_trans->reg_lock, *flags); |
787 | 815 | ||
788 | /* this bit wakes up the NIC */ | 816 | /* this bit wakes up the NIC */ |
789 | __iwl_set_bit(trans, CSR_GP_CNTRL, | 817 | __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL, |
790 | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | 818 | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); |
791 | 819 | ||
792 | /* | 820 | /* |
793 | * These bits say the device is running, and should keep running for | 821 | * These bits say the device is running, and should keep running for |
@@ -819,18 +847,34 @@ static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent) | |||
819 | WARN_ONCE(1, | 847 | WARN_ONCE(1, |
820 | "Timeout waiting for hardware access (CSR_GP_CNTRL 0x%08x)\n", | 848 | "Timeout waiting for hardware access (CSR_GP_CNTRL 0x%08x)\n", |
821 | val); | 849 | val); |
850 | spin_unlock_irqrestore(&pcie_trans->reg_lock, *flags); | ||
822 | return false; | 851 | return false; |
823 | } | 852 | } |
824 | } | 853 | } |
825 | 854 | ||
855 | /* | ||
856 | * Fool sparse by faking we release the lock - sparse will | ||
857 | * track nic_access anyway. | ||
858 | */ | ||
859 | __release(&pcie_trans->reg_lock); | ||
826 | return true; | 860 | return true; |
827 | } | 861 | } |
828 | 862 | ||
829 | static void iwl_trans_pcie_release_nic_access(struct iwl_trans *trans) | 863 | static void iwl_trans_pcie_release_nic_access(struct iwl_trans *trans, |
864 | unsigned long *flags) | ||
830 | { | 865 | { |
831 | lockdep_assert_held(&trans->reg_lock); | 866 | struct iwl_trans_pcie *pcie_trans = IWL_TRANS_GET_PCIE_TRANS(trans); |
832 | __iwl_clear_bit(trans, CSR_GP_CNTRL, | 867 | |
833 | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | 868 | lockdep_assert_held(&pcie_trans->reg_lock); |
869 | |||
870 | /* | ||
871 | * Fool sparse by faking we acquiring the lock - sparse will | ||
872 | * track nic_access anyway. | ||
873 | */ | ||
874 | __acquire(&pcie_trans->reg_lock); | ||
875 | |||
876 | __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL, | ||
877 | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | ||
834 | /* | 878 | /* |
835 | * Above we read the CSR_GP_CNTRL register, which will flush | 879 | * Above we read the CSR_GP_CNTRL register, which will flush |
836 | * any previous writes, but we need the write that clears the | 880 | * any previous writes, but we need the write that clears the |
@@ -838,6 +882,7 @@ static void iwl_trans_pcie_release_nic_access(struct iwl_trans *trans) | |||
838 | * scheduled on different CPUs (after we drop reg_lock). | 882 | * scheduled on different CPUs (after we drop reg_lock). |
839 | */ | 883 | */ |
840 | mmiowb(); | 884 | mmiowb(); |
885 | spin_unlock_irqrestore(&pcie_trans->reg_lock, *flags); | ||
841 | } | 886 | } |
842 | 887 | ||
843 | static int iwl_trans_pcie_read_mem(struct iwl_trans *trans, u32 addr, | 888 | static int iwl_trans_pcie_read_mem(struct iwl_trans *trans, u32 addr, |
@@ -847,16 +892,14 @@ static int iwl_trans_pcie_read_mem(struct iwl_trans *trans, u32 addr, | |||
847 | int offs, ret = 0; | 892 | int offs, ret = 0; |
848 | u32 *vals = buf; | 893 | u32 *vals = buf; |
849 | 894 | ||
850 | spin_lock_irqsave(&trans->reg_lock, flags); | 895 | if (iwl_trans_grab_nic_access(trans, false, &flags)) { |
851 | if (iwl_trans_grab_nic_access(trans, false)) { | ||
852 | iwl_write32(trans, HBUS_TARG_MEM_RADDR, addr); | 896 | iwl_write32(trans, HBUS_TARG_MEM_RADDR, addr); |
853 | for (offs = 0; offs < dwords; offs++) | 897 | for (offs = 0; offs < dwords; offs++) |
854 | vals[offs] = iwl_read32(trans, HBUS_TARG_MEM_RDAT); | 898 | vals[offs] = iwl_read32(trans, HBUS_TARG_MEM_RDAT); |
855 | iwl_trans_release_nic_access(trans); | 899 | iwl_trans_release_nic_access(trans, &flags); |
856 | } else { | 900 | } else { |
857 | ret = -EBUSY; | 901 | ret = -EBUSY; |
858 | } | 902 | } |
859 | spin_unlock_irqrestore(&trans->reg_lock, flags); | ||
860 | return ret; | 903 | return ret; |
861 | } | 904 | } |
862 | 905 | ||
@@ -867,17 +910,15 @@ static int iwl_trans_pcie_write_mem(struct iwl_trans *trans, u32 addr, | |||
867 | int offs, ret = 0; | 910 | int offs, ret = 0; |
868 | u32 *vals = buf; | 911 | u32 *vals = buf; |
869 | 912 | ||
870 | spin_lock_irqsave(&trans->reg_lock, flags); | 913 | if (iwl_trans_grab_nic_access(trans, false, &flags)) { |
871 | if (iwl_trans_grab_nic_access(trans, false)) { | ||
872 | iwl_write32(trans, HBUS_TARG_MEM_WADDR, addr); | 914 | iwl_write32(trans, HBUS_TARG_MEM_WADDR, addr); |
873 | for (offs = 0; offs < dwords; offs++) | 915 | for (offs = 0; offs < dwords; offs++) |
874 | iwl_write32(trans, HBUS_TARG_MEM_WDAT, | 916 | iwl_write32(trans, HBUS_TARG_MEM_WDAT, |
875 | vals ? vals[offs] : 0); | 917 | vals ? vals[offs] : 0); |
876 | iwl_trans_release_nic_access(trans); | 918 | iwl_trans_release_nic_access(trans, &flags); |
877 | } else { | 919 | } else { |
878 | ret = -EBUSY; | 920 | ret = -EBUSY; |
879 | } | 921 | } |
880 | spin_unlock_irqrestore(&trans->reg_lock, flags); | ||
881 | return ret; | 922 | return ret; |
882 | } | 923 | } |
883 | 924 | ||
@@ -952,6 +993,17 @@ static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans) | |||
952 | return ret; | 993 | return ret; |
953 | } | 994 | } |
954 | 995 | ||
996 | static void iwl_trans_pcie_set_bits_mask(struct iwl_trans *trans, u32 reg, | ||
997 | u32 mask, u32 value) | ||
998 | { | ||
999 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | ||
1000 | unsigned long flags; | ||
1001 | |||
1002 | spin_lock_irqsave(&trans_pcie->reg_lock, flags); | ||
1003 | __iwl_trans_pcie_set_bits_mask(trans, reg, mask, value); | ||
1004 | spin_unlock_irqrestore(&trans_pcie->reg_lock, flags); | ||
1005 | } | ||
1006 | |||
955 | static const char *get_fh_string(int cmd) | 1007 | static const char *get_fh_string(int cmd) |
956 | { | 1008 | { |
957 | #define IWL_CMD(x) case x: return #x | 1009 | #define IWL_CMD(x) case x: return #x |
@@ -1405,7 +1457,8 @@ static const struct iwl_trans_ops trans_ops_pcie = { | |||
1405 | .configure = iwl_trans_pcie_configure, | 1457 | .configure = iwl_trans_pcie_configure, |
1406 | .set_pmi = iwl_trans_pcie_set_pmi, | 1458 | .set_pmi = iwl_trans_pcie_set_pmi, |
1407 | .grab_nic_access = iwl_trans_pcie_grab_nic_access, | 1459 | .grab_nic_access = iwl_trans_pcie_grab_nic_access, |
1408 | .release_nic_access = iwl_trans_pcie_release_nic_access | 1460 | .release_nic_access = iwl_trans_pcie_release_nic_access, |
1461 | .set_bits_mask = iwl_trans_pcie_set_bits_mask, | ||
1409 | }; | 1462 | }; |
1410 | 1463 | ||
1411 | struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, | 1464 | struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, |
@@ -1429,6 +1482,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, | |||
1429 | trans->cfg = cfg; | 1482 | trans->cfg = cfg; |
1430 | trans_pcie->trans = trans; | 1483 | trans_pcie->trans = trans; |
1431 | spin_lock_init(&trans_pcie->irq_lock); | 1484 | spin_lock_init(&trans_pcie->irq_lock); |
1485 | spin_lock_init(&trans_pcie->reg_lock); | ||
1432 | init_waitqueue_head(&trans_pcie->ucode_write_waitq); | 1486 | init_waitqueue_head(&trans_pcie->ucode_write_waitq); |
1433 | 1487 | ||
1434 | /* W/A - seems to solve weird behavior. We need to remove this if we | 1488 | /* W/A - seems to solve weird behavior. We need to remove this if we |
@@ -1495,7 +1549,6 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, | |||
1495 | 1549 | ||
1496 | /* Initialize the wait queue for commands */ | 1550 | /* Initialize the wait queue for commands */ |
1497 | init_waitqueue_head(&trans_pcie->wait_command_queue); | 1551 | init_waitqueue_head(&trans_pcie->wait_command_queue); |
1498 | spin_lock_init(&trans->reg_lock); | ||
1499 | 1552 | ||
1500 | snprintf(trans->dev_cmd_pool_name, sizeof(trans->dev_cmd_pool_name), | 1553 | snprintf(trans->dev_cmd_pool_name, sizeof(trans->dev_cmd_pool_name), |
1501 | "iwl_cmd_pool:%s", dev_name(trans->dev)); | 1554 | "iwl_cmd_pool:%s", dev_name(trans->dev)); |
diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index a93f06762b96..041127ad372a 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * Portions of this file are derived from the ipw3945 project, as well | 5 | * Portions of this file are derived from the ipw3945 project, as well |
6 | * as portions of the ieee80211 subsystem header files. | 6 | * as portions of the ieee80211 subsystem header files. |
diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c index 7b0ae2407083..25596ab0c576 100644 --- a/drivers/net/wireless/mwifiex/11n.c +++ b/drivers/net/wireless/mwifiex/11n.c | |||
@@ -400,45 +400,6 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, | |||
400 | } | 400 | } |
401 | 401 | ||
402 | /* | 402 | /* |
403 | * This function reconfigures the Tx buffer size in firmware. | ||
404 | * | ||
405 | * This function prepares a firmware command and issues it, if | ||
406 | * the current Tx buffer size is different from the one requested. | ||
407 | * Maximum configurable Tx buffer size is limited by the HT capability | ||
408 | * field value. | ||
409 | */ | ||
410 | void | ||
411 | mwifiex_cfg_tx_buf(struct mwifiex_private *priv, | ||
412 | struct mwifiex_bssdescriptor *bss_desc) | ||
413 | { | ||
414 | u16 max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_2K; | ||
415 | u16 tx_buf, curr_tx_buf_size = 0; | ||
416 | |||
417 | if (bss_desc->bcn_ht_cap) { | ||
418 | if (le16_to_cpu(bss_desc->bcn_ht_cap->cap_info) & | ||
419 | IEEE80211_HT_CAP_MAX_AMSDU) | ||
420 | max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_8K; | ||
421 | else | ||
422 | max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_4K; | ||
423 | } | ||
424 | |||
425 | tx_buf = min(priv->adapter->max_tx_buf_size, max_amsdu); | ||
426 | |||
427 | dev_dbg(priv->adapter->dev, "info: max_amsdu=%d, max_tx_buf=%d\n", | ||
428 | max_amsdu, priv->adapter->max_tx_buf_size); | ||
429 | |||
430 | if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_2K) | ||
431 | curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; | ||
432 | else if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_4K) | ||
433 | curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K; | ||
434 | else if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_8K) | ||
435 | curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_8K; | ||
436 | if (curr_tx_buf_size != tx_buf) | ||
437 | mwifiex_send_cmd_async(priv, HostCmd_CMD_RECONFIGURE_TX_BUFF, | ||
438 | HostCmd_ACT_GEN_SET, 0, &tx_buf); | ||
439 | } | ||
440 | |||
441 | /* | ||
442 | * This function checks if the given pointer is valid entry of | 403 | * This function checks if the given pointer is valid entry of |
443 | * Tx BA Stream table. | 404 | * Tx BA Stream table. |
444 | */ | 405 | */ |
diff --git a/drivers/net/wireless/mwifiex/11n.h b/drivers/net/wireless/mwifiex/11n.h index 46006a54a656..29a4c02479d6 100644 --- a/drivers/net/wireless/mwifiex/11n.h +++ b/drivers/net/wireless/mwifiex/11n.h | |||
@@ -34,8 +34,6 @@ int mwifiex_cmd_11n_cfg(struct host_cmd_ds_command *cmd, u16 cmd_action, | |||
34 | int mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, | 34 | int mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, |
35 | struct mwifiex_bssdescriptor *bss_desc, | 35 | struct mwifiex_bssdescriptor *bss_desc, |
36 | u8 **buffer); | 36 | u8 **buffer); |
37 | void mwifiex_cfg_tx_buf(struct mwifiex_private *priv, | ||
38 | struct mwifiex_bssdescriptor *bss_desc); | ||
39 | void mwifiex_fill_cap_info(struct mwifiex_private *, u8 radio_type, | 37 | void mwifiex_fill_cap_info(struct mwifiex_private *, u8 radio_type, |
40 | struct mwifiex_ie_types_htcap *); | 38 | struct mwifiex_ie_types_htcap *); |
41 | int mwifiex_set_get_11n_htcap_cfg(struct mwifiex_private *priv, | 39 | int mwifiex_set_get_11n_htcap_cfg(struct mwifiex_private *priv, |
diff --git a/drivers/net/wireless/mwifiex/README b/drivers/net/wireless/mwifiex/README index b55badef4660..3d64613ebb29 100644 --- a/drivers/net/wireless/mwifiex/README +++ b/drivers/net/wireless/mwifiex/README | |||
@@ -121,7 +121,6 @@ info | |||
121 | wmm_ac_vi = <number of packets sent to device from WMM AcVi queue> | 121 | wmm_ac_vi = <number of packets sent to device from WMM AcVi queue> |
122 | wmm_ac_be = <number of packets sent to device from WMM AcBE queue> | 122 | wmm_ac_be = <number of packets sent to device from WMM AcBE queue> |
123 | wmm_ac_bk = <number of packets sent to device from WMM AcBK queue> | 123 | wmm_ac_bk = <number of packets sent to device from WMM AcBK queue> |
124 | max_tx_buf_size = <maximum Tx buffer size> | ||
125 | tx_buf_size = <current Tx buffer size> | 124 | tx_buf_size = <current Tx buffer size> |
126 | curr_tx_buf_size = <current Tx buffer size> | 125 | curr_tx_buf_size = <current Tx buffer size> |
127 | ps_mode = <0/1, CAM mode/PS mode> | 126 | ps_mode = <0/1, CAM mode/PS mode> |
diff --git a/drivers/net/wireless/mwifiex/debugfs.c b/drivers/net/wireless/mwifiex/debugfs.c index 46e34aa65d1c..753b5682d53f 100644 --- a/drivers/net/wireless/mwifiex/debugfs.c +++ b/drivers/net/wireless/mwifiex/debugfs.c | |||
@@ -58,8 +58,6 @@ static struct mwifiex_debug_data items[] = { | |||
58 | item_addr(packets_out[WMM_AC_BE]), 1}, | 58 | item_addr(packets_out[WMM_AC_BE]), 1}, |
59 | {"wmm_ac_bk", item_size(packets_out[WMM_AC_BK]), | 59 | {"wmm_ac_bk", item_size(packets_out[WMM_AC_BK]), |
60 | item_addr(packets_out[WMM_AC_BK]), 1}, | 60 | item_addr(packets_out[WMM_AC_BK]), 1}, |
61 | {"max_tx_buf_size", item_size(max_tx_buf_size), | ||
62 | item_addr(max_tx_buf_size), 1}, | ||
63 | {"tx_buf_size", item_size(tx_buf_size), | 61 | {"tx_buf_size", item_size(tx_buf_size), |
64 | item_addr(tx_buf_size), 1}, | 62 | item_addr(tx_buf_size), 1}, |
65 | {"curr_tx_buf_size", item_size(curr_tx_buf_size), | 63 | {"curr_tx_buf_size", item_size(curr_tx_buf_size), |
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 84848c33b7f0..e38aa9b3663d 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c | |||
@@ -314,7 +314,6 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) | |||
314 | 314 | ||
315 | adapter->pm_wakeup_fw_try = false; | 315 | adapter->pm_wakeup_fw_try = false; |
316 | 316 | ||
317 | adapter->max_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; | ||
318 | adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; | 317 | adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; |
319 | adapter->curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; | 318 | adapter->curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; |
320 | 319 | ||
diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h index 6095b3e53f4e..f3d9d0445529 100644 --- a/drivers/net/wireless/mwifiex/ioctl.h +++ b/drivers/net/wireless/mwifiex/ioctl.h | |||
@@ -178,7 +178,6 @@ struct mwifiex_ds_tx_ba_stream_tbl { | |||
178 | struct mwifiex_debug_info { | 178 | struct mwifiex_debug_info { |
179 | u32 int_counter; | 179 | u32 int_counter; |
180 | u32 packets_out[MAX_NUM_TID]; | 180 | u32 packets_out[MAX_NUM_TID]; |
181 | u32 max_tx_buf_size; | ||
182 | u32 tx_buf_size; | 181 | u32 tx_buf_size; |
183 | u32 curr_tx_buf_size; | 182 | u32 curr_tx_buf_size; |
184 | u32 tx_tbl_num; | 183 | u32 tx_tbl_num; |
diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c index 893d809ba83c..a537297866c6 100644 --- a/drivers/net/wireless/mwifiex/join.c +++ b/drivers/net/wireless/mwifiex/join.c | |||
@@ -157,8 +157,8 @@ static int mwifiex_get_common_rates(struct mwifiex_private *priv, u8 *rate1, | |||
157 | 157 | ||
158 | memset(rate1, 0, rate1_size); | 158 | memset(rate1, 0, rate1_size); |
159 | 159 | ||
160 | for (i = 0; rate2[i] && i < rate2_size; i++) { | 160 | for (i = 0; i < rate2_size && rate2[i]; i++) { |
161 | for (j = 0; tmp[j] && j < rate1_size; j++) { | 161 | for (j = 0; j < rate1_size && tmp[j]; j++) { |
162 | /* Check common rate, excluding the bit for | 162 | /* Check common rate, excluding the bit for |
163 | basic rate */ | 163 | basic rate */ |
164 | if ((rate2[i] & 0x7F) == (tmp[j] & 0x7F)) { | 164 | if ((rate2[i] & 0x7F) == (tmp[j] & 0x7F)) { |
@@ -398,8 +398,6 @@ int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv, | |||
398 | 398 | ||
399 | pos = (u8 *) assoc; | 399 | pos = (u8 *) assoc; |
400 | 400 | ||
401 | mwifiex_cfg_tx_buf(priv, bss_desc); | ||
402 | |||
403 | cmd->command = cpu_to_le16(HostCmd_CMD_802_11_ASSOCIATE); | 401 | cmd->command = cpu_to_le16(HostCmd_CMD_802_11_ASSOCIATE); |
404 | 402 | ||
405 | /* Save so we know which BSS Desc to use in the response handler */ | 403 | /* Save so we know which BSS Desc to use in the response handler */ |
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 51044e3ea89b..ac799a046eb7 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h | |||
@@ -631,7 +631,6 @@ struct mwifiex_adapter { | |||
631 | /* spin lock for main process */ | 631 | /* spin lock for main process */ |
632 | spinlock_t main_proc_lock; | 632 | spinlock_t main_proc_lock; |
633 | u32 mwifiex_processing; | 633 | u32 mwifiex_processing; |
634 | u16 max_tx_buf_size; | ||
635 | u16 tx_buf_size; | 634 | u16 tx_buf_size; |
636 | u16 curr_tx_buf_size; | 635 | u16 curr_tx_buf_size; |
637 | u32 ioport; | 636 | u32 ioport; |
diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index 237949c070cc..df88e65595c8 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c | |||
@@ -846,8 +846,8 @@ static int mwifiex_pcie_send_data_complete(struct mwifiex_adapter *adapter) | |||
846 | 846 | ||
847 | card->tx_buf_list[wrdoneidx] = NULL; | 847 | card->tx_buf_list[wrdoneidx] = NULL; |
848 | card->txbd_ring[wrdoneidx]->paddr = 0; | 848 | card->txbd_ring[wrdoneidx]->paddr = 0; |
849 | card->rxbd_ring[wrdoneidx]->len = 0; | 849 | card->txbd_ring[wrdoneidx]->len = 0; |
850 | card->rxbd_ring[wrdoneidx]->flags = 0; | 850 | card->txbd_ring[wrdoneidx]->flags = 0; |
851 | card->txbd_rdptr++; | 851 | card->txbd_rdptr++; |
852 | 852 | ||
853 | if ((card->txbd_rdptr & MWIFIEX_TXBD_MASK) == num_tx_buffs) | 853 | if ((card->txbd_rdptr & MWIFIEX_TXBD_MASK) == num_tx_buffs) |
@@ -1985,6 +1985,7 @@ static int mwifiex_pcie_init(struct mwifiex_adapter *adapter) | |||
1985 | card->pci_mmap = pci_iomap(pdev, 0, 0); | 1985 | card->pci_mmap = pci_iomap(pdev, 0, 0); |
1986 | if (!card->pci_mmap) { | 1986 | if (!card->pci_mmap) { |
1987 | dev_err(adapter->dev, "iomap(0) error\n"); | 1987 | dev_err(adapter->dev, "iomap(0) error\n"); |
1988 | ret = -EIO; | ||
1988 | goto err_iomap0; | 1989 | goto err_iomap0; |
1989 | } | 1990 | } |
1990 | ret = pci_request_region(pdev, 2, DRV_NAME); | 1991 | ret = pci_request_region(pdev, 2, DRV_NAME); |
@@ -1995,6 +1996,7 @@ static int mwifiex_pcie_init(struct mwifiex_adapter *adapter) | |||
1995 | card->pci_mmap1 = pci_iomap(pdev, 2, 0); | 1996 | card->pci_mmap1 = pci_iomap(pdev, 2, 0); |
1996 | if (!card->pci_mmap1) { | 1997 | if (!card->pci_mmap1) { |
1997 | dev_err(adapter->dev, "iomap(2) error\n"); | 1998 | dev_err(adapter->dev, "iomap(2) error\n"); |
1999 | ret = -EIO; | ||
1998 | goto err_iomap2; | 2000 | goto err_iomap2; |
1999 | } | 2001 | } |
2000 | 2002 | ||
diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index 31d7b2bdaa31..d3fb9a14580a 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c | |||
@@ -332,7 +332,7 @@ mwifiex_write_data_sync(struct mwifiex_adapter *adapter, | |||
332 | u8 *buffer, u32 pkt_len, u32 port) | 332 | u8 *buffer, u32 pkt_len, u32 port) |
333 | { | 333 | { |
334 | struct sdio_mmc_card *card = adapter->card; | 334 | struct sdio_mmc_card *card = adapter->card; |
335 | int ret = -1; | 335 | int ret; |
336 | u8 blk_mode = | 336 | u8 blk_mode = |
337 | (port & MWIFIEX_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE; | 337 | (port & MWIFIEX_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE; |
338 | u32 blk_size = (blk_mode == BLOCK_MODE) ? MWIFIEX_SDIO_BLOCK_SIZE : 1; | 338 | u32 blk_size = (blk_mode == BLOCK_MODE) ? MWIFIEX_SDIO_BLOCK_SIZE : 1; |
@@ -350,8 +350,7 @@ mwifiex_write_data_sync(struct mwifiex_adapter *adapter, | |||
350 | 350 | ||
351 | sdio_claim_host(card->func); | 351 | sdio_claim_host(card->func); |
352 | 352 | ||
353 | if (!sdio_writesb(card->func, ioport, buffer, blk_cnt * blk_size)) | 353 | ret = sdio_writesb(card->func, ioport, buffer, blk_cnt * blk_size); |
354 | ret = 0; | ||
355 | 354 | ||
356 | sdio_release_host(card->func); | 355 | sdio_release_host(card->func); |
357 | 356 | ||
@@ -365,7 +364,7 @@ static int mwifiex_read_data_sync(struct mwifiex_adapter *adapter, u8 *buffer, | |||
365 | u32 len, u32 port, u8 claim) | 364 | u32 len, u32 port, u8 claim) |
366 | { | 365 | { |
367 | struct sdio_mmc_card *card = adapter->card; | 366 | struct sdio_mmc_card *card = adapter->card; |
368 | int ret = -1; | 367 | int ret; |
369 | u8 blk_mode = (port & MWIFIEX_SDIO_BYTE_MODE_MASK) ? BYTE_MODE | 368 | u8 blk_mode = (port & MWIFIEX_SDIO_BYTE_MODE_MASK) ? BYTE_MODE |
370 | : BLOCK_MODE; | 369 | : BLOCK_MODE; |
371 | u32 blk_size = (blk_mode == BLOCK_MODE) ? MWIFIEX_SDIO_BLOCK_SIZE : 1; | 370 | u32 blk_size = (blk_mode == BLOCK_MODE) ? MWIFIEX_SDIO_BLOCK_SIZE : 1; |
@@ -376,8 +375,7 @@ static int mwifiex_read_data_sync(struct mwifiex_adapter *adapter, u8 *buffer, | |||
376 | if (claim) | 375 | if (claim) |
377 | sdio_claim_host(card->func); | 376 | sdio_claim_host(card->func); |
378 | 377 | ||
379 | if (!sdio_readsb(card->func, buffer, ioport, blk_cnt * blk_size)) | 378 | ret = sdio_readsb(card->func, buffer, ioport, blk_cnt * blk_size); |
380 | ret = 0; | ||
381 | 379 | ||
382 | if (claim) | 380 | if (claim) |
383 | sdio_release_host(card->func); | 381 | sdio_release_host(card->func); |
diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index 65c12eb3e5e7..847056415ac9 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c | |||
@@ -935,9 +935,8 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no, | |||
935 | / MWIFIEX_SDIO_BLOCK_SIZE) | 935 | / MWIFIEX_SDIO_BLOCK_SIZE) |
936 | * MWIFIEX_SDIO_BLOCK_SIZE; | 936 | * MWIFIEX_SDIO_BLOCK_SIZE; |
937 | adapter->curr_tx_buf_size = adapter->tx_buf_size; | 937 | adapter->curr_tx_buf_size = adapter->tx_buf_size; |
938 | dev_dbg(adapter->dev, | 938 | dev_dbg(adapter->dev, "cmd: curr_tx_buf_size=%d\n", |
939 | "cmd: max_tx_buf_size=%d, tx_buf_size=%d\n", | 939 | adapter->curr_tx_buf_size); |
940 | adapter->max_tx_buf_size, adapter->tx_buf_size); | ||
941 | 940 | ||
942 | if (adapter->if_ops.update_mp_end_port) | 941 | if (adapter->if_ops.update_mp_end_port) |
943 | adapter->if_ops.update_mp_end_port(adapter, | 942 | adapter->if_ops.update_mp_end_port(adapter, |
diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c index 5d4a10a8a005..f90fe21e5bfd 100644 --- a/drivers/net/wireless/mwifiex/usb.c +++ b/drivers/net/wireless/mwifiex/usb.c | |||
@@ -672,7 +672,7 @@ static int mwifiex_write_data_sync(struct mwifiex_adapter *adapter, u8 *pbuf, | |||
672 | *len, &actual_length, timeout); | 672 | *len, &actual_length, timeout); |
673 | if (ret) { | 673 | if (ret) { |
674 | dev_err(adapter->dev, "usb_bulk_msg for tx failed: %d\n", ret); | 674 | dev_err(adapter->dev, "usb_bulk_msg for tx failed: %d\n", ret); |
675 | ret = -1; | 675 | return ret; |
676 | } | 676 | } |
677 | 677 | ||
678 | *len = actual_length; | 678 | *len = actual_length; |
@@ -691,7 +691,7 @@ static int mwifiex_read_data_sync(struct mwifiex_adapter *adapter, u8 *pbuf, | |||
691 | *len, &actual_length, timeout); | 691 | *len, &actual_length, timeout); |
692 | if (ret) { | 692 | if (ret) { |
693 | dev_err(adapter->dev, "usb_bulk_msg for rx failed: %d\n", ret); | 693 | dev_err(adapter->dev, "usb_bulk_msg for rx failed: %d\n", ret); |
694 | ret = -1; | 694 | return ret; |
695 | } | 695 | } |
696 | 696 | ||
697 | *len = actual_length; | 697 | *len = actual_length; |
diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c index 0982375ba3b1..21553976b550 100644 --- a/drivers/net/wireless/mwifiex/util.c +++ b/drivers/net/wireless/mwifiex/util.c | |||
@@ -91,7 +91,7 @@ int mwifiex_get_debug_info(struct mwifiex_private *priv, | |||
91 | memcpy(info->packets_out, | 91 | memcpy(info->packets_out, |
92 | priv->wmm.packets_out, | 92 | priv->wmm.packets_out, |
93 | sizeof(priv->wmm.packets_out)); | 93 | sizeof(priv->wmm.packets_out)); |
94 | info->max_tx_buf_size = (u32) adapter->max_tx_buf_size; | 94 | info->curr_tx_buf_size = (u32) adapter->curr_tx_buf_size; |
95 | info->tx_buf_size = (u32) adapter->tx_buf_size; | 95 | info->tx_buf_size = (u32) adapter->tx_buf_size; |
96 | info->rx_tbl_num = mwifiex_get_rx_reorder_tbl(priv, | 96 | info->rx_tbl_num = mwifiex_get_rx_reorder_tbl(priv, |
97 | info->rx_tbl); | 97 | info->rx_tbl); |
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 224cf917744a..2031130d860b 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c | |||
@@ -285,6 +285,9 @@ struct mwl8k_priv { | |||
285 | char *fw_pref; | 285 | char *fw_pref; |
286 | char *fw_alt; | 286 | char *fw_alt; |
287 | struct completion firmware_loading_complete; | 287 | struct completion firmware_loading_complete; |
288 | |||
289 | /* bitmap of running BSSes */ | ||
290 | u32 running_bsses; | ||
288 | }; | 291 | }; |
289 | 292 | ||
290 | #define MAX_WEP_KEY_LEN 13 | 293 | #define MAX_WEP_KEY_LEN 13 |
@@ -2156,6 +2159,8 @@ static void mwl8k_fw_unlock(struct ieee80211_hw *hw) | |||
2156 | } | 2159 | } |
2157 | } | 2160 | } |
2158 | 2161 | ||
2162 | static void mwl8k_enable_bsses(struct ieee80211_hw *hw, bool enable, | ||
2163 | u32 bitmap); | ||
2159 | 2164 | ||
2160 | /* | 2165 | /* |
2161 | * Command processing. | 2166 | * Command processing. |
@@ -2174,6 +2179,34 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) | |||
2174 | int rc; | 2179 | int rc; |
2175 | unsigned long timeout = 0; | 2180 | unsigned long timeout = 0; |
2176 | u8 buf[32]; | 2181 | u8 buf[32]; |
2182 | u32 bitmap = 0; | ||
2183 | |||
2184 | wiphy_dbg(hw->wiphy, "Posting %s [%d]\n", | ||
2185 | mwl8k_cmd_name(cmd->code, buf, sizeof(buf)), cmd->macid); | ||
2186 | |||
2187 | /* Before posting firmware commands that could change the hardware | ||
2188 | * characteristics, make sure that all BSSes are stopped temporary. | ||
2189 | * Enable these stopped BSSes after completion of the commands | ||
2190 | */ | ||
2191 | |||
2192 | rc = mwl8k_fw_lock(hw); | ||
2193 | if (rc) | ||
2194 | return rc; | ||
2195 | |||
2196 | if (priv->ap_fw && priv->running_bsses) { | ||
2197 | switch (le16_to_cpu(cmd->code)) { | ||
2198 | case MWL8K_CMD_SET_RF_CHANNEL: | ||
2199 | case MWL8K_CMD_RADIO_CONTROL: | ||
2200 | case MWL8K_CMD_RF_TX_POWER: | ||
2201 | case MWL8K_CMD_TX_POWER: | ||
2202 | case MWL8K_CMD_RF_ANTENNA: | ||
2203 | case MWL8K_CMD_RTS_THRESHOLD: | ||
2204 | case MWL8K_CMD_MIMO_CONFIG: | ||
2205 | bitmap = priv->running_bsses; | ||
2206 | mwl8k_enable_bsses(hw, false, bitmap); | ||
2207 | break; | ||
2208 | } | ||
2209 | } | ||
2177 | 2210 | ||
2178 | cmd->result = (__force __le16) 0xffff; | 2211 | cmd->result = (__force __le16) 0xffff; |
2179 | dma_size = le16_to_cpu(cmd->length); | 2212 | dma_size = le16_to_cpu(cmd->length); |
@@ -2182,13 +2215,6 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) | |||
2182 | if (pci_dma_mapping_error(priv->pdev, dma_addr)) | 2215 | if (pci_dma_mapping_error(priv->pdev, dma_addr)) |
2183 | return -ENOMEM; | 2216 | return -ENOMEM; |
2184 | 2217 | ||
2185 | rc = mwl8k_fw_lock(hw); | ||
2186 | if (rc) { | ||
2187 | pci_unmap_single(priv->pdev, dma_addr, dma_size, | ||
2188 | PCI_DMA_BIDIRECTIONAL); | ||
2189 | return rc; | ||
2190 | } | ||
2191 | |||
2192 | priv->hostcmd_wait = &cmd_wait; | 2218 | priv->hostcmd_wait = &cmd_wait; |
2193 | iowrite32(dma_addr, regs + MWL8K_HIU_GEN_PTR); | 2219 | iowrite32(dma_addr, regs + MWL8K_HIU_GEN_PTR); |
2194 | iowrite32(MWL8K_H2A_INT_DOORBELL, | 2220 | iowrite32(MWL8K_H2A_INT_DOORBELL, |
@@ -2201,7 +2227,6 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) | |||
2201 | 2227 | ||
2202 | priv->hostcmd_wait = NULL; | 2228 | priv->hostcmd_wait = NULL; |
2203 | 2229 | ||
2204 | mwl8k_fw_unlock(hw); | ||
2205 | 2230 | ||
2206 | pci_unmap_single(priv->pdev, dma_addr, dma_size, | 2231 | pci_unmap_single(priv->pdev, dma_addr, dma_size, |
2207 | PCI_DMA_BIDIRECTIONAL); | 2232 | PCI_DMA_BIDIRECTIONAL); |
@@ -2228,6 +2253,11 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) | |||
2228 | ms); | 2253 | ms); |
2229 | } | 2254 | } |
2230 | 2255 | ||
2256 | if (bitmap) | ||
2257 | mwl8k_enable_bsses(hw, true, bitmap); | ||
2258 | |||
2259 | mwl8k_fw_unlock(hw); | ||
2260 | |||
2231 | return rc; | 2261 | return rc; |
2232 | } | 2262 | } |
2233 | 2263 | ||
@@ -2489,7 +2519,7 @@ static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw) | |||
2489 | priv->hw_rev = cmd->hw_rev; | 2519 | priv->hw_rev = cmd->hw_rev; |
2490 | mwl8k_set_caps(hw, le32_to_cpu(cmd->caps)); | 2520 | mwl8k_set_caps(hw, le32_to_cpu(cmd->caps)); |
2491 | priv->ap_macids_supported = 0x000000ff; | 2521 | priv->ap_macids_supported = 0x000000ff; |
2492 | priv->sta_macids_supported = 0x00000000; | 2522 | priv->sta_macids_supported = 0x00000100; |
2493 | priv->num_ampdu_queues = le32_to_cpu(cmd->num_of_ampdu_queues); | 2523 | priv->num_ampdu_queues = le32_to_cpu(cmd->num_of_ampdu_queues); |
2494 | if (priv->num_ampdu_queues > MWL8K_MAX_AMPDU_QUEUES) { | 2524 | if (priv->num_ampdu_queues > MWL8K_MAX_AMPDU_QUEUES) { |
2495 | wiphy_warn(hw->wiphy, "fw reported %d ampdu queues" | 2525 | wiphy_warn(hw->wiphy, "fw reported %d ampdu queues" |
@@ -3508,7 +3538,10 @@ static int mwl8k_cmd_update_mac_addr(struct ieee80211_hw *hw, | |||
3508 | mac_type = MWL8K_MAC_TYPE_PRIMARY_AP; | 3538 | mac_type = MWL8K_MAC_TYPE_PRIMARY_AP; |
3509 | if (vif != NULL && vif->type == NL80211_IFTYPE_STATION) { | 3539 | if (vif != NULL && vif->type == NL80211_IFTYPE_STATION) { |
3510 | if (mwl8k_vif->macid + 1 == ffs(priv->sta_macids_supported)) | 3540 | if (mwl8k_vif->macid + 1 == ffs(priv->sta_macids_supported)) |
3511 | mac_type = MWL8K_MAC_TYPE_PRIMARY_CLIENT; | 3541 | if (priv->ap_fw) |
3542 | mac_type = MWL8K_MAC_TYPE_SECONDARY_CLIENT; | ||
3543 | else | ||
3544 | mac_type = MWL8K_MAC_TYPE_PRIMARY_CLIENT; | ||
3512 | else | 3545 | else |
3513 | mac_type = MWL8K_MAC_TYPE_SECONDARY_CLIENT; | 3546 | mac_type = MWL8K_MAC_TYPE_SECONDARY_CLIENT; |
3514 | } else if (vif != NULL && vif->type == NL80211_IFTYPE_AP) { | 3547 | } else if (vif != NULL && vif->type == NL80211_IFTYPE_AP) { |
@@ -3680,8 +3713,16 @@ static int mwl8k_cmd_bss_start(struct ieee80211_hw *hw, | |||
3680 | struct ieee80211_vif *vif, int enable) | 3713 | struct ieee80211_vif *vif, int enable) |
3681 | { | 3714 | { |
3682 | struct mwl8k_cmd_bss_start *cmd; | 3715 | struct mwl8k_cmd_bss_start *cmd; |
3716 | struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); | ||
3717 | struct mwl8k_priv *priv = hw->priv; | ||
3683 | int rc; | 3718 | int rc; |
3684 | 3719 | ||
3720 | if (enable && (priv->running_bsses & (1 << mwl8k_vif->macid))) | ||
3721 | return 0; | ||
3722 | |||
3723 | if (!enable && !(priv->running_bsses & (1 << mwl8k_vif->macid))) | ||
3724 | return 0; | ||
3725 | |||
3685 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | 3726 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); |
3686 | if (cmd == NULL) | 3727 | if (cmd == NULL) |
3687 | return -ENOMEM; | 3728 | return -ENOMEM; |
@@ -3693,9 +3734,31 @@ static int mwl8k_cmd_bss_start(struct ieee80211_hw *hw, | |||
3693 | rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); | 3734 | rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); |
3694 | kfree(cmd); | 3735 | kfree(cmd); |
3695 | 3736 | ||
3737 | if (!rc) { | ||
3738 | if (enable) | ||
3739 | priv->running_bsses |= (1 << mwl8k_vif->macid); | ||
3740 | else | ||
3741 | priv->running_bsses &= ~(1 << mwl8k_vif->macid); | ||
3742 | } | ||
3696 | return rc; | 3743 | return rc; |
3697 | } | 3744 | } |
3698 | 3745 | ||
3746 | static void mwl8k_enable_bsses(struct ieee80211_hw *hw, bool enable, u32 bitmap) | ||
3747 | { | ||
3748 | struct mwl8k_priv *priv = hw->priv; | ||
3749 | struct mwl8k_vif *mwl8k_vif, *tmp_vif; | ||
3750 | struct ieee80211_vif *vif; | ||
3751 | |||
3752 | list_for_each_entry_safe(mwl8k_vif, tmp_vif, &priv->vif_list, list) { | ||
3753 | vif = mwl8k_vif->vif; | ||
3754 | |||
3755 | if (!(bitmap & (1 << mwl8k_vif->macid))) | ||
3756 | continue; | ||
3757 | |||
3758 | if (vif->type == NL80211_IFTYPE_AP) | ||
3759 | mwl8k_cmd_bss_start(hw, vif, enable); | ||
3760 | } | ||
3761 | } | ||
3699 | /* | 3762 | /* |
3700 | * CMD_BASTREAM. | 3763 | * CMD_BASTREAM. |
3701 | */ | 3764 | */ |
@@ -4202,8 +4265,9 @@ static int mwl8k_set_key(struct ieee80211_hw *hw, | |||
4202 | u8 encr_type; | 4265 | u8 encr_type; |
4203 | u8 *addr; | 4266 | u8 *addr; |
4204 | struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); | 4267 | struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); |
4268 | struct mwl8k_priv *priv = hw->priv; | ||
4205 | 4269 | ||
4206 | if (vif->type == NL80211_IFTYPE_STATION) | 4270 | if (vif->type == NL80211_IFTYPE_STATION && !priv->ap_fw) |
4207 | return -EOPNOTSUPP; | 4271 | return -EOPNOTSUPP; |
4208 | 4272 | ||
4209 | if (sta == NULL) | 4273 | if (sta == NULL) |
@@ -4609,12 +4673,18 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw, | |||
4609 | break; | 4673 | break; |
4610 | case NL80211_IFTYPE_STATION: | 4674 | case NL80211_IFTYPE_STATION: |
4611 | if (priv->ap_fw && di->fw_image_sta) { | 4675 | if (priv->ap_fw && di->fw_image_sta) { |
4612 | /* we must load the sta fw to meet this request */ | 4676 | if (!list_empty(&priv->vif_list)) { |
4613 | if (!list_empty(&priv->vif_list)) | 4677 | wiphy_warn(hw->wiphy, "AP interface is running.\n" |
4614 | return -EBUSY; | 4678 | "Adding STA interface for WDS"); |
4615 | rc = mwl8k_reload_firmware(hw, di->fw_image_sta); | 4679 | } else { |
4616 | if (rc) | 4680 | /* we must load the sta fw to |
4617 | return rc; | 4681 | * meet this request. |
4682 | */ | ||
4683 | rc = mwl8k_reload_firmware(hw, | ||
4684 | di->fw_image_sta); | ||
4685 | if (rc) | ||
4686 | return rc; | ||
4687 | } | ||
4618 | } | 4688 | } |
4619 | macids_supported = priv->sta_macids_supported; | 4689 | macids_supported = priv->sta_macids_supported; |
4620 | break; | 4690 | break; |
@@ -4638,7 +4708,7 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw, | |||
4638 | /* Set the mac address. */ | 4708 | /* Set the mac address. */ |
4639 | mwl8k_cmd_set_mac_addr(hw, vif, vif->addr); | 4709 | mwl8k_cmd_set_mac_addr(hw, vif, vif->addr); |
4640 | 4710 | ||
4641 | if (priv->ap_fw) | 4711 | if (vif->type == NL80211_IFTYPE_AP) |
4642 | mwl8k_cmd_set_new_stn_add_self(hw, vif); | 4712 | mwl8k_cmd_set_new_stn_add_self(hw, vif); |
4643 | 4713 | ||
4644 | priv->macids_used |= 1 << mwl8k_vif->macid; | 4714 | priv->macids_used |= 1 << mwl8k_vif->macid; |
@@ -4663,7 +4733,7 @@ static void mwl8k_remove_interface(struct ieee80211_hw *hw, | |||
4663 | struct mwl8k_priv *priv = hw->priv; | 4733 | struct mwl8k_priv *priv = hw->priv; |
4664 | struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); | 4734 | struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); |
4665 | 4735 | ||
4666 | if (priv->ap_fw) | 4736 | if (vif->type == NL80211_IFTYPE_AP) |
4667 | mwl8k_cmd_set_new_stn_del(hw, vif, vif->addr); | 4737 | mwl8k_cmd_set_new_stn_del(hw, vif, vif->addr); |
4668 | 4738 | ||
4669 | mwl8k_cmd_del_mac_addr(hw, vif, vif->addr); | 4739 | mwl8k_cmd_del_mac_addr(hw, vif, vif->addr); |
@@ -4737,9 +4807,11 @@ static int mwl8k_config(struct ieee80211_hw *hw, u32 changed) | |||
4737 | if (rc) | 4807 | if (rc) |
4738 | goto out; | 4808 | goto out; |
4739 | 4809 | ||
4740 | rc = mwl8k_cmd_set_rf_channel(hw, conf); | 4810 | if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { |
4741 | if (rc) | 4811 | rc = mwl8k_cmd_set_rf_channel(hw, conf); |
4742 | goto out; | 4812 | if (rc) |
4813 | goto out; | ||
4814 | } | ||
4743 | 4815 | ||
4744 | if (conf->power_level > 18) | 4816 | if (conf->power_level > 18) |
4745 | conf->power_level = 18; | 4817 | conf->power_level = 18; |
@@ -4752,12 +4824,6 @@ static int mwl8k_config(struct ieee80211_hw *hw, u32 changed) | |||
4752 | goto out; | 4824 | goto out; |
4753 | } | 4825 | } |
4754 | 4826 | ||
4755 | rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_RX, 0x3); | ||
4756 | if (rc) | ||
4757 | wiphy_warn(hw->wiphy, "failed to set # of RX antennas"); | ||
4758 | rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_TX, 0x7); | ||
4759 | if (rc) | ||
4760 | wiphy_warn(hw->wiphy, "failed to set # of TX antennas"); | ||
4761 | 4827 | ||
4762 | } else { | 4828 | } else { |
4763 | rc = mwl8k_cmd_rf_tx_power(hw, conf->power_level); | 4829 | rc = mwl8k_cmd_rf_tx_power(hw, conf->power_level); |
@@ -4815,7 +4881,8 @@ mwl8k_bss_info_changed_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | |||
4815 | rcu_read_unlock(); | 4881 | rcu_read_unlock(); |
4816 | } | 4882 | } |
4817 | 4883 | ||
4818 | if ((changed & BSS_CHANGED_ASSOC) && vif->bss_conf.assoc) { | 4884 | if ((changed & BSS_CHANGED_ASSOC) && vif->bss_conf.assoc && |
4885 | !priv->ap_fw) { | ||
4819 | rc = mwl8k_cmd_set_rate(hw, vif, ap_legacy_rates, ap_mcs_rates); | 4886 | rc = mwl8k_cmd_set_rate(hw, vif, ap_legacy_rates, ap_mcs_rates); |
4820 | if (rc) | 4887 | if (rc) |
4821 | goto out; | 4888 | goto out; |
@@ -4823,6 +4890,25 @@ mwl8k_bss_info_changed_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | |||
4823 | rc = mwl8k_cmd_use_fixed_rate_sta(hw); | 4890 | rc = mwl8k_cmd_use_fixed_rate_sta(hw); |
4824 | if (rc) | 4891 | if (rc) |
4825 | goto out; | 4892 | goto out; |
4893 | } else { | ||
4894 | if ((changed & BSS_CHANGED_ASSOC) && vif->bss_conf.assoc && | ||
4895 | priv->ap_fw) { | ||
4896 | int idx; | ||
4897 | int rate; | ||
4898 | |||
4899 | /* Use AP firmware specific rate command. | ||
4900 | */ | ||
4901 | idx = ffs(vif->bss_conf.basic_rates); | ||
4902 | if (idx) | ||
4903 | idx--; | ||
4904 | |||
4905 | if (hw->conf.channel->band == IEEE80211_BAND_2GHZ) | ||
4906 | rate = mwl8k_rates_24[idx].hw_value; | ||
4907 | else | ||
4908 | rate = mwl8k_rates_50[idx].hw_value; | ||
4909 | |||
4910 | mwl8k_cmd_use_fixed_rate_ap(hw, rate, rate); | ||
4911 | } | ||
4826 | } | 4912 | } |
4827 | 4913 | ||
4828 | if (changed & BSS_CHANGED_ERP_PREAMBLE) { | 4914 | if (changed & BSS_CHANGED_ERP_PREAMBLE) { |
@@ -4832,13 +4918,13 @@ mwl8k_bss_info_changed_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | |||
4832 | goto out; | 4918 | goto out; |
4833 | } | 4919 | } |
4834 | 4920 | ||
4835 | if (changed & BSS_CHANGED_ERP_SLOT) { | 4921 | if ((changed & BSS_CHANGED_ERP_SLOT) && !priv->ap_fw) { |
4836 | rc = mwl8k_cmd_set_slot(hw, vif->bss_conf.use_short_slot); | 4922 | rc = mwl8k_cmd_set_slot(hw, vif->bss_conf.use_short_slot); |
4837 | if (rc) | 4923 | if (rc) |
4838 | goto out; | 4924 | goto out; |
4839 | } | 4925 | } |
4840 | 4926 | ||
4841 | if (vif->bss_conf.assoc && | 4927 | if (vif->bss_conf.assoc && !priv->ap_fw && |
4842 | (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_ERP_CTS_PROT | | 4928 | (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_ERP_CTS_PROT | |
4843 | BSS_CHANGED_HT))) { | 4929 | BSS_CHANGED_HT))) { |
4844 | rc = mwl8k_cmd_set_aid(hw, vif, ap_legacy_rates); | 4930 | rc = mwl8k_cmd_set_aid(hw, vif, ap_legacy_rates); |
@@ -4918,11 +5004,9 @@ static void | |||
4918 | mwl8k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | 5004 | mwl8k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
4919 | struct ieee80211_bss_conf *info, u32 changed) | 5005 | struct ieee80211_bss_conf *info, u32 changed) |
4920 | { | 5006 | { |
4921 | struct mwl8k_priv *priv = hw->priv; | 5007 | if (vif->type == NL80211_IFTYPE_STATION) |
4922 | |||
4923 | if (!priv->ap_fw) | ||
4924 | mwl8k_bss_info_changed_sta(hw, vif, info, changed); | 5008 | mwl8k_bss_info_changed_sta(hw, vif, info, changed); |
4925 | else | 5009 | if (vif->type == NL80211_IFTYPE_AP) |
4926 | mwl8k_bss_info_changed_ap(hw, vif, info, changed); | 5010 | mwl8k_bss_info_changed_ap(hw, vif, info, changed); |
4927 | } | 5011 | } |
4928 | 5012 | ||
@@ -5647,6 +5731,15 @@ static int mwl8k_probe_hw(struct ieee80211_hw *hw) | |||
5647 | goto err_free_irq; | 5731 | goto err_free_irq; |
5648 | } | 5732 | } |
5649 | 5733 | ||
5734 | /* Configure Antennas */ | ||
5735 | rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_RX, 0x3); | ||
5736 | if (rc) | ||
5737 | wiphy_warn(hw->wiphy, "failed to set # of RX antennas"); | ||
5738 | rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_TX, 0x7); | ||
5739 | if (rc) | ||
5740 | wiphy_warn(hw->wiphy, "failed to set # of TX antennas"); | ||
5741 | |||
5742 | |||
5650 | /* Disable interrupts */ | 5743 | /* Disable interrupts */ |
5651 | iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); | 5744 | iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); |
5652 | free_irq(priv->pdev->irq, hw); | 5745 | free_irq(priv->pdev->irq, hw); |
@@ -5734,6 +5827,7 @@ fail: | |||
5734 | 5827 | ||
5735 | static const struct ieee80211_iface_limit ap_if_limits[] = { | 5828 | static const struct ieee80211_iface_limit ap_if_limits[] = { |
5736 | { .max = 8, .types = BIT(NL80211_IFTYPE_AP) }, | 5829 | { .max = 8, .types = BIT(NL80211_IFTYPE_AP) }, |
5830 | { .max = 1, .types = BIT(NL80211_IFTYPE_STATION) }, | ||
5737 | }; | 5831 | }; |
5738 | 5832 | ||
5739 | static const struct ieee80211_iface_combination ap_if_comb = { | 5833 | static const struct ieee80211_iface_combination ap_if_comb = { |
@@ -5826,6 +5920,7 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv) | |||
5826 | 5920 | ||
5827 | if (priv->ap_macids_supported || priv->device_info->fw_image_ap) { | 5921 | if (priv->ap_macids_supported || priv->device_info->fw_image_ap) { |
5828 | hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP); | 5922 | hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP); |
5923 | hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_STATION); | ||
5829 | hw->wiphy->iface_combinations = &ap_if_comb; | 5924 | hw->wiphy->iface_combinations = &ap_if_comb; |
5830 | hw->wiphy->n_iface_combinations = 1; | 5925 | hw->wiphy->n_iface_combinations = 1; |
5831 | } | 5926 | } |
@@ -5948,6 +6043,8 @@ static int mwl8k_probe(struct pci_dev *pdev, | |||
5948 | 6043 | ||
5949 | priv->hw_restart_in_progress = false; | 6044 | priv->hw_restart_in_progress = false; |
5950 | 6045 | ||
6046 | priv->running_bsses = 0; | ||
6047 | |||
5951 | return rc; | 6048 | return rc; |
5952 | 6049 | ||
5953 | err_stop_firmware: | 6050 | err_stop_firmware: |
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index a5c694f23d33..a658b4bc7da2 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c | |||
@@ -80,7 +80,7 @@ static inline bool rt2800_is_305x_soc(struct rt2x00_dev *rt2x00dev) | |||
80 | rt2x00_rf(rt2x00dev, RF3022)) | 80 | rt2x00_rf(rt2x00dev, RF3022)) |
81 | return true; | 81 | return true; |
82 | 82 | ||
83 | NOTICE(rt2x00dev, "Unknown RF chipset on rt305x\n"); | 83 | WARNING(rt2x00dev, "Unknown RF chipset on rt305x\n"); |
84 | return false; | 84 | return false; |
85 | } | 85 | } |
86 | 86 | ||
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 0e8d1705e368..48a01aa21f1c 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c | |||
@@ -1152,6 +1152,7 @@ static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = { | |||
1152 | { PCI_DEVICE(0x1814, 0x3562) }, | 1152 | { PCI_DEVICE(0x1814, 0x3562) }, |
1153 | { PCI_DEVICE(0x1814, 0x3592) }, | 1153 | { PCI_DEVICE(0x1814, 0x3592) }, |
1154 | { PCI_DEVICE(0x1814, 0x3593) }, | 1154 | { PCI_DEVICE(0x1814, 0x3593) }, |
1155 | { PCI_DEVICE(0x1814, 0x359f) }, | ||
1155 | #endif | 1156 | #endif |
1156 | #ifdef CONFIG_RT2800PCI_RT53XX | 1157 | #ifdef CONFIG_RT2800PCI_RT53XX |
1157 | { PCI_DEVICE(0x1814, 0x5360) }, | 1158 | { PCI_DEVICE(0x1814, 0x5360) }, |
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 4721cada1591..42b5b659af16 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c | |||
@@ -540,9 +540,9 @@ rt2800usb_txdone_entry_check(struct queue_entry *entry, u32 reg) | |||
540 | tx_pid = rt2x00_get_field32(word, TXWI_W1_PACKETID); | 540 | tx_pid = rt2x00_get_field32(word, TXWI_W1_PACKETID); |
541 | 541 | ||
542 | if (wcid != tx_wcid || ack != tx_ack || (!is_agg && pid != tx_pid)) { | 542 | if (wcid != tx_wcid || ack != tx_ack || (!is_agg && pid != tx_pid)) { |
543 | WARNING(entry->queue->rt2x00dev, | 543 | DEBUG(entry->queue->rt2x00dev, |
544 | "TX status report missed for queue %d entry %d\n", | 544 | "TX status report missed for queue %d entry %d\n", |
545 | entry->queue->qid, entry->entry_idx); | 545 | entry->queue->qid, entry->entry_idx); |
546 | return TXDONE_UNKNOWN; | 546 | return TXDONE_UNKNOWN; |
547 | } | 547 | } |
548 | 548 | ||
@@ -968,6 +968,7 @@ static struct usb_device_id rt2800usb_device_table[] = { | |||
968 | { USB_DEVICE(0x07d1, 0x3c13) }, | 968 | { USB_DEVICE(0x07d1, 0x3c13) }, |
969 | { USB_DEVICE(0x07d1, 0x3c15) }, | 969 | { USB_DEVICE(0x07d1, 0x3c15) }, |
970 | { USB_DEVICE(0x07d1, 0x3c16) }, | 970 | { USB_DEVICE(0x07d1, 0x3c16) }, |
971 | { USB_DEVICE(0x07d1, 0x3c17) }, | ||
971 | { USB_DEVICE(0x2001, 0x3c1b) }, | 972 | { USB_DEVICE(0x2001, 0x3c1b) }, |
972 | /* Draytek */ | 973 | /* Draytek */ |
973 | { USB_DEVICE(0x07fa, 0x7712) }, | 974 | { USB_DEVICE(0x07fa, 0x7712) }, |
@@ -1115,6 +1116,7 @@ static struct usb_device_id rt2800usb_device_table[] = { | |||
1115 | /* Zyxel */ | 1116 | /* Zyxel */ |
1116 | { USB_DEVICE(0x0586, 0x3416) }, | 1117 | { USB_DEVICE(0x0586, 0x3416) }, |
1117 | { USB_DEVICE(0x0586, 0x3418) }, | 1118 | { USB_DEVICE(0x0586, 0x3418) }, |
1119 | { USB_DEVICE(0x0586, 0x341a) }, | ||
1118 | { USB_DEVICE(0x0586, 0x341e) }, | 1120 | { USB_DEVICE(0x0586, 0x341e) }, |
1119 | { USB_DEVICE(0x0586, 0x343e) }, | 1121 | { USB_DEVICE(0x0586, 0x343e) }, |
1120 | #ifdef CONFIG_RT2800USB_RT33XX | 1122 | #ifdef CONFIG_RT2800USB_RT33XX |
@@ -1166,6 +1168,7 @@ static struct usb_device_id rt2800usb_device_table[] = { | |||
1166 | #ifdef CONFIG_RT2800USB_RT53XX | 1168 | #ifdef CONFIG_RT2800USB_RT53XX |
1167 | /* Arcadyan */ | 1169 | /* Arcadyan */ |
1168 | { USB_DEVICE(0x043e, 0x7a12) }, | 1170 | { USB_DEVICE(0x043e, 0x7a12) }, |
1171 | { USB_DEVICE(0x043e, 0x7a32) }, | ||
1169 | /* Azurewave */ | 1172 | /* Azurewave */ |
1170 | { USB_DEVICE(0x13d3, 0x3329) }, | 1173 | { USB_DEVICE(0x13d3, 0x3329) }, |
1171 | { USB_DEVICE(0x13d3, 0x3365) }, | 1174 | { USB_DEVICE(0x13d3, 0x3365) }, |
@@ -1177,16 +1180,20 @@ static struct usb_device_id rt2800usb_device_table[] = { | |||
1177 | { USB_DEVICE(0x2001, 0x3c1e) }, | 1180 | { USB_DEVICE(0x2001, 0x3c1e) }, |
1178 | /* LG innotek */ | 1181 | /* LG innotek */ |
1179 | { USB_DEVICE(0x043e, 0x7a22) }, | 1182 | { USB_DEVICE(0x043e, 0x7a22) }, |
1183 | { USB_DEVICE(0x043e, 0x7a42) }, | ||
1180 | /* Panasonic */ | 1184 | /* Panasonic */ |
1181 | { USB_DEVICE(0x04da, 0x1801) }, | 1185 | { USB_DEVICE(0x04da, 0x1801) }, |
1182 | { USB_DEVICE(0x04da, 0x1800) }, | 1186 | { USB_DEVICE(0x04da, 0x1800) }, |
1187 | { USB_DEVICE(0x04da, 0x23f6) }, | ||
1183 | /* Philips */ | 1188 | /* Philips */ |
1184 | { USB_DEVICE(0x0471, 0x2104) }, | 1189 | { USB_DEVICE(0x0471, 0x2104) }, |
1190 | { USB_DEVICE(0x0471, 0x2126) }, | ||
1191 | { USB_DEVICE(0x0471, 0x2180) }, | ||
1192 | { USB_DEVICE(0x0471, 0x2181) }, | ||
1193 | { USB_DEVICE(0x0471, 0x2182) }, | ||
1185 | /* Ralink */ | 1194 | /* Ralink */ |
1186 | { USB_DEVICE(0x148f, 0x5370) }, | 1195 | { USB_DEVICE(0x148f, 0x5370) }, |
1187 | { USB_DEVICE(0x148f, 0x5372) }, | 1196 | { USB_DEVICE(0x148f, 0x5372) }, |
1188 | /* Unknown */ | ||
1189 | { USB_DEVICE(0x04da, 0x23f6) }, | ||
1190 | #endif | 1197 | #endif |
1191 | #ifdef CONFIG_RT2800USB_UNKNOWN | 1198 | #ifdef CONFIG_RT2800USB_UNKNOWN |
1192 | /* | 1199 | /* |
@@ -1223,7 +1230,6 @@ static struct usb_device_id rt2800usb_device_table[] = { | |||
1223 | { USB_DEVICE(0x18c5, 0x0008) }, | 1230 | { USB_DEVICE(0x18c5, 0x0008) }, |
1224 | /* D-Link */ | 1231 | /* D-Link */ |
1225 | { USB_DEVICE(0x07d1, 0x3c0b) }, | 1232 | { USB_DEVICE(0x07d1, 0x3c0b) }, |
1226 | { USB_DEVICE(0x07d1, 0x3c17) }, | ||
1227 | /* Encore */ | 1233 | /* Encore */ |
1228 | { USB_DEVICE(0x203d, 0x14a1) }, | 1234 | { USB_DEVICE(0x203d, 0x14a1) }, |
1229 | /* Gemtek */ | 1235 | /* Gemtek */ |
@@ -1261,8 +1267,6 @@ static struct usb_device_id rt2800usb_device_table[] = { | |||
1261 | { USB_DEVICE(0x083a, 0xc522) }, | 1267 | { USB_DEVICE(0x083a, 0xc522) }, |
1262 | { USB_DEVICE(0x083a, 0xd522) }, | 1268 | { USB_DEVICE(0x083a, 0xd522) }, |
1263 | { USB_DEVICE(0x083a, 0xf511) }, | 1269 | { USB_DEVICE(0x083a, 0xf511) }, |
1264 | /* Zyxel */ | ||
1265 | { USB_DEVICE(0x0586, 0x341a) }, | ||
1266 | #endif | 1270 | #endif |
1267 | { 0, } | 1271 | { 0, } |
1268 | }; | 1272 | }; |
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index b52512b8ac5f..9a3f31a543ce 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h | |||
@@ -88,11 +88,9 @@ | |||
88 | #define ERROR_PROBE(__msg, __args...) \ | 88 | #define ERROR_PROBE(__msg, __args...) \ |
89 | DEBUG_PRINTK_PROBE(KERN_ERR, "Error", __msg, ##__args) | 89 | DEBUG_PRINTK_PROBE(KERN_ERR, "Error", __msg, ##__args) |
90 | #define WARNING(__dev, __msg, __args...) \ | 90 | #define WARNING(__dev, __msg, __args...) \ |
91 | DEBUG_PRINTK(__dev, KERN_WARNING, "Warning", __msg, ##__args) | 91 | DEBUG_PRINTK_MSG(__dev, KERN_WARNING, "Warning", __msg, ##__args) |
92 | #define NOTICE(__dev, __msg, __args...) \ | ||
93 | DEBUG_PRINTK(__dev, KERN_NOTICE, "Notice", __msg, ##__args) | ||
94 | #define INFO(__dev, __msg, __args...) \ | 92 | #define INFO(__dev, __msg, __args...) \ |
95 | DEBUG_PRINTK(__dev, KERN_INFO, "Info", __msg, ##__args) | 93 | DEBUG_PRINTK_MSG(__dev, KERN_INFO, "Info", __msg, ##__args) |
96 | #define DEBUG(__dev, __msg, __args...) \ | 94 | #define DEBUG(__dev, __msg, __args...) \ |
97 | DEBUG_PRINTK(__dev, KERN_DEBUG, "Debug", __msg, ##__args) | 95 | DEBUG_PRINTK(__dev, KERN_DEBUG, "Debug", __msg, ##__args) |
98 | #define EEPROM(__dev, __msg, __args...) \ | 96 | #define EEPROM(__dev, __msg, __args...) \ |
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index b40a53857498..1031db66474a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c | |||
@@ -1236,7 +1236,8 @@ static inline void rt2x00lib_set_if_combinations(struct rt2x00_dev *rt2x00dev) | |||
1236 | */ | 1236 | */ |
1237 | if_limit = &rt2x00dev->if_limits_ap; | 1237 | if_limit = &rt2x00dev->if_limits_ap; |
1238 | if_limit->max = rt2x00dev->ops->max_ap_intf; | 1238 | if_limit->max = rt2x00dev->ops->max_ap_intf; |
1239 | if_limit->types = BIT(NL80211_IFTYPE_AP); | 1239 | if_limit->types = BIT(NL80211_IFTYPE_AP) | |
1240 | BIT(NL80211_IFTYPE_MESH_POINT); | ||
1240 | 1241 | ||
1241 | /* | 1242 | /* |
1242 | * Build up AP interface combinations structure. | 1243 | * Build up AP interface combinations structure. |
@@ -1446,7 +1447,7 @@ EXPORT_SYMBOL_GPL(rt2x00lib_remove_dev); | |||
1446 | #ifdef CONFIG_PM | 1447 | #ifdef CONFIG_PM |
1447 | int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, pm_message_t state) | 1448 | int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, pm_message_t state) |
1448 | { | 1449 | { |
1449 | NOTICE(rt2x00dev, "Going to sleep.\n"); | 1450 | DEBUG(rt2x00dev, "Going to sleep.\n"); |
1450 | 1451 | ||
1451 | /* | 1452 | /* |
1452 | * Prevent mac80211 from accessing driver while suspended. | 1453 | * Prevent mac80211 from accessing driver while suspended. |
@@ -1486,7 +1487,7 @@ EXPORT_SYMBOL_GPL(rt2x00lib_suspend); | |||
1486 | 1487 | ||
1487 | int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) | 1488 | int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) |
1488 | { | 1489 | { |
1489 | NOTICE(rt2x00dev, "Waking up.\n"); | 1490 | DEBUG(rt2x00dev, "Waking up.\n"); |
1490 | 1491 | ||
1491 | /* | 1492 | /* |
1492 | * Restore/enable extra components. | 1493 | * Restore/enable extra components. |
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index ed7a1bb3f245..20c6eccce5aa 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c | |||
@@ -731,9 +731,9 @@ int rt2x00mac_conf_tx(struct ieee80211_hw *hw, | |||
731 | queue->aifs = params->aifs; | 731 | queue->aifs = params->aifs; |
732 | queue->txop = params->txop; | 732 | queue->txop = params->txop; |
733 | 733 | ||
734 | INFO(rt2x00dev, | 734 | DEBUG(rt2x00dev, |
735 | "Configured TX queue %d - CWmin: %d, CWmax: %d, Aifs: %d, TXop: %d.\n", | 735 | "Configured TX queue %d - CWmin: %d, CWmax: %d, Aifs: %d, TXop: %d.\n", |
736 | queue_idx, queue->cw_min, queue->cw_max, queue->aifs, queue->txop); | 736 | queue_idx, queue->cw_min, queue->cw_max, queue->aifs, queue->txop); |
737 | 737 | ||
738 | return 0; | 738 | return 0; |
739 | } | 739 | } |
diff --git a/drivers/net/wireless/rtlwifi/rc.c b/drivers/net/wireless/rtlwifi/rc.c index c1e065f136ba..204f46c4510d 100644 --- a/drivers/net/wireless/rtlwifi/rc.c +++ b/drivers/net/wireless/rtlwifi/rc.c | |||
@@ -217,19 +217,6 @@ static void rtl_tx_status(void *ppriv, | |||
217 | } | 217 | } |
218 | } | 218 | } |
219 | 219 | ||
220 | static void rtl_rate_init(void *ppriv, | ||
221 | struct ieee80211_supported_band *sband, | ||
222 | struct ieee80211_sta *sta, void *priv_sta) | ||
223 | { | ||
224 | } | ||
225 | |||
226 | static void rtl_rate_update(void *ppriv, | ||
227 | struct ieee80211_supported_band *sband, | ||
228 | struct ieee80211_sta *sta, void *priv_sta, | ||
229 | u32 changed) | ||
230 | { | ||
231 | } | ||
232 | |||
233 | static void *rtl_rate_alloc(struct ieee80211_hw *hw, | 220 | static void *rtl_rate_alloc(struct ieee80211_hw *hw, |
234 | struct dentry *debugfsdir) | 221 | struct dentry *debugfsdir) |
235 | { | 222 | { |
@@ -274,8 +261,6 @@ static struct rate_control_ops rtl_rate_ops = { | |||
274 | .free = rtl_rate_free, | 261 | .free = rtl_rate_free, |
275 | .alloc_sta = rtl_rate_alloc_sta, | 262 | .alloc_sta = rtl_rate_alloc_sta, |
276 | .free_sta = rtl_rate_free_sta, | 263 | .free_sta = rtl_rate_free_sta, |
277 | .rate_init = rtl_rate_init, | ||
278 | .rate_update = rtl_rate_update, | ||
279 | .tx_status = rtl_tx_status, | 264 | .tx_status = rtl_tx_status, |
280 | .get_rate = rtl_get_rate, | 265 | .get_rate = rtl_get_rate, |
281 | }; | 266 | }; |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c index 1cdf5a271c9f..b793a659a465 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c | |||
@@ -669,7 +669,8 @@ static void rtl92c_dm_txpower_tracking_callback_thermalmeter(struct ieee80211_hw | |||
669 | u8 thermalvalue, delta, delta_lck, delta_iqk; | 669 | u8 thermalvalue, delta, delta_lck, delta_iqk; |
670 | long ele_a, ele_d, temp_cck, val_x, value32; | 670 | long ele_a, ele_d, temp_cck, val_x, value32; |
671 | long val_y, ele_c = 0; | 671 | long val_y, ele_c = 0; |
672 | u8 ofdm_index[2], cck_index = 0, ofdm_index_old[2], cck_index_old = 0; | 672 | u8 ofdm_index[2], ofdm_index_old[2], cck_index_old = 0; |
673 | s8 cck_index = 0; | ||
673 | int i; | 674 | int i; |
674 | bool is2t = IS_92C_SERIAL(rtlhal->version); | 675 | bool is2t = IS_92C_SERIAL(rtlhal->version); |
675 | s8 txpwr_level[2] = {0, 0}; | 676 | s8 txpwr_level[2] = {0, 0}; |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c index b7e6607e6b6d..d9e659f92767 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c | |||
@@ -76,7 +76,7 @@ static int rtl92cu_init_sw_vars(struct ieee80211_hw *hw) | |||
76 | GFP_KERNEL, hw, rtl_fw_cb); | 76 | GFP_KERNEL, hw, rtl_fw_cb); |
77 | 77 | ||
78 | 78 | ||
79 | return 0; | 79 | return err; |
80 | } | 80 | } |
81 | 81 | ||
82 | static void rtl92cu_deinit_sw_vars(struct ieee80211_hw *hw) | 82 | static void rtl92cu_deinit_sw_vars(struct ieee80211_hw *hw) |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/dm.c b/drivers/net/wireless/rtlwifi/rtl8192de/dm.c index fd8df233ff22..5251fb8a111e 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/dm.c | |||
@@ -841,9 +841,9 @@ static void rtl92d_dm_txpower_tracking_callback_thermalmeter( | |||
841 | long ele_a = 0, ele_d, temp_cck, val_x, value32; | 841 | long ele_a = 0, ele_d, temp_cck, val_x, value32; |
842 | long val_y, ele_c = 0; | 842 | long val_y, ele_c = 0; |
843 | u8 ofdm_index[2]; | 843 | u8 ofdm_index[2]; |
844 | u8 cck_index = 0; | 844 | s8 cck_index = 0; |
845 | u8 ofdm_index_old[2]; | 845 | u8 ofdm_index_old[2]; |
846 | u8 cck_index_old = 0; | 846 | s8 cck_index_old = 0; |
847 | u8 index; | 847 | u8 index; |
848 | int i; | 848 | int i; |
849 | bool is2t = IS_92D_SINGLEPHY(rtlhal->version); | 849 | bool is2t = IS_92D_SINGLEPHY(rtlhal->version); |
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/fw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/fw.c index f55b1767ef57..35cb8f83eed4 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/fw.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/fw.c | |||
@@ -252,7 +252,7 @@ static void _rtl8723ae_fill_h2c_command(struct ieee80211_hw *hw, | |||
252 | u16 box_reg = 0, box_extreg = 0; | 252 | u16 box_reg = 0, box_extreg = 0; |
253 | u8 u1tmp; | 253 | u8 u1tmp; |
254 | bool isfw_rd = false; | 254 | bool isfw_rd = false; |
255 | bool bwrite_sucess = false; | 255 | bool bwrite_success = false; |
256 | u8 wait_h2c_limmit = 100; | 256 | u8 wait_h2c_limmit = 100; |
257 | u8 wait_writeh2c_limmit = 100; | 257 | u8 wait_writeh2c_limmit = 100; |
258 | u8 boxcontent[4], boxextcontent[2]; | 258 | u8 boxcontent[4], boxextcontent[2]; |
@@ -291,7 +291,7 @@ static void _rtl8723ae_fill_h2c_command(struct ieee80211_hw *hw, | |||
291 | } | 291 | } |
292 | } | 292 | } |
293 | 293 | ||
294 | while (!bwrite_sucess) { | 294 | while (!bwrite_success) { |
295 | wait_writeh2c_limmit--; | 295 | wait_writeh2c_limmit--; |
296 | if (wait_writeh2c_limmit == 0) { | 296 | if (wait_writeh2c_limmit == 0) { |
297 | RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, | 297 | RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, |
@@ -429,7 +429,7 @@ static void _rtl8723ae_fill_h2c_command(struct ieee80211_hw *hw, | |||
429 | break; | 429 | break; |
430 | } | 430 | } |
431 | 431 | ||
432 | bwrite_sucess = true; | 432 | bwrite_success = true; |
433 | 433 | ||
434 | rtlhal->last_hmeboxnum = boxnum + 1; | 434 | rtlhal->last_hmeboxnum = boxnum + 1; |
435 | if (rtlhal->last_hmeboxnum == 4) | 435 | if (rtlhal->last_hmeboxnum == 4) |
@@ -512,7 +512,6 @@ static bool _rtl8723ae_cmd_send_packet(struct ieee80211_hw *hw, | |||
512 | struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); | 512 | struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); |
513 | struct rtl8192_tx_ring *ring; | 513 | struct rtl8192_tx_ring *ring; |
514 | struct rtl_tx_desc *pdesc; | 514 | struct rtl_tx_desc *pdesc; |
515 | u8 own; | ||
516 | unsigned long flags; | 515 | unsigned long flags; |
517 | struct sk_buff *pskb = NULL; | 516 | struct sk_buff *pskb = NULL; |
518 | 517 | ||
@@ -525,7 +524,6 @@ static bool _rtl8723ae_cmd_send_packet(struct ieee80211_hw *hw, | |||
525 | spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); | 524 | spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); |
526 | 525 | ||
527 | pdesc = &ring->desc[0]; | 526 | pdesc = &ring->desc[0]; |
528 | own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc, true, HW_DESC_OWN); | ||
529 | 527 | ||
530 | rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb); | 528 | rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb); |
531 | 529 | ||
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c b/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c index 887d521fe690..68c28340f791 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c | |||
@@ -1433,7 +1433,6 @@ static void _rtl8723ae_dm_bt_coexist_2_ant(struct ieee80211_hw *hw) | |||
1433 | struct rtl_priv *rtlpriv = rtl_priv(hw); | 1433 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
1434 | struct rtl_hal *rtlhal = rtl_hal(rtlpriv); | 1434 | struct rtl_hal *rtlhal = rtl_hal(rtlpriv); |
1435 | struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); | 1435 | struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); |
1436 | u8 bt_retry_cnt; | ||
1437 | u8 bt_info_original; | 1436 | u8 bt_info_original; |
1438 | RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, | 1437 | RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, |
1439 | "[BTCoex] Get bt info by fw!!\n"); | 1438 | "[BTCoex] Get bt info by fw!!\n"); |
@@ -1445,7 +1444,6 @@ static void _rtl8723ae_dm_bt_coexist_2_ant(struct ieee80211_hw *hw) | |||
1445 | "[BTCoex] c2h for btInfo not rcvd yet!!\n"); | 1444 | "[BTCoex] c2h for btInfo not rcvd yet!!\n"); |
1446 | } | 1445 | } |
1447 | 1446 | ||
1448 | bt_retry_cnt = rtlhal->hal_coex_8723.bt_retry_cnt; | ||
1449 | bt_info_original = rtlhal->hal_coex_8723.c2h_bt_info_original; | 1447 | bt_info_original = rtlhal->hal_coex_8723.c2h_bt_info_original; |
1450 | 1448 | ||
1451 | /* when bt inquiry or page scan, we have to set h2c 0x25 | 1449 | /* when bt inquiry or page scan, we have to set h2c 0x25 |
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c index 0a8c03863fb2..149804816ac4 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c | |||
@@ -703,11 +703,9 @@ static void _rtl8723ae_hw_configure(struct ieee80211_hw *hw) | |||
703 | struct rtl_priv *rtlpriv = rtl_priv(hw); | 703 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
704 | struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); | 704 | struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); |
705 | u8 reg_bw_opmode; | 705 | u8 reg_bw_opmode; |
706 | u32 reg_ratr, reg_prsr; | 706 | u32 reg_prsr; |
707 | 707 | ||
708 | reg_bw_opmode = BW_OPMODE_20MHZ; | 708 | reg_bw_opmode = BW_OPMODE_20MHZ; |
709 | reg_ratr = RATE_ALL_CCK | RATE_ALL_OFDM_AG | | ||
710 | RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS; | ||
711 | reg_prsr = RATE_ALL_CCK | RATE_ALL_OFDM_AG; | 709 | reg_prsr = RATE_ALL_CCK | RATE_ALL_OFDM_AG; |
712 | 710 | ||
713 | rtl_write_byte(rtlpriv, REG_INIRTS_RATE_SEL, 0x8); | 711 | rtl_write_byte(rtlpriv, REG_INIRTS_RATE_SEL, 0x8); |
@@ -2030,7 +2028,7 @@ bool rtl8723ae_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid) | |||
2030 | struct rtl_priv *rtlpriv = rtl_priv(hw); | 2028 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
2031 | struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); | 2029 | struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); |
2032 | struct rtl_phy *rtlphy = &(rtlpriv->phy); | 2030 | struct rtl_phy *rtlphy = &(rtlpriv->phy); |
2033 | enum rf_pwrstate e_rfpowerstate_toset, cur_rfstate; | 2031 | enum rf_pwrstate e_rfpowerstate_toset; |
2034 | u8 u1tmp; | 2032 | u8 u1tmp; |
2035 | bool actuallyset = false; | 2033 | bool actuallyset = false; |
2036 | 2034 | ||
@@ -2049,8 +2047,6 @@ bool rtl8723ae_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid) | |||
2049 | spin_unlock(&rtlpriv->locks.rf_ps_lock); | 2047 | spin_unlock(&rtlpriv->locks.rf_ps_lock); |
2050 | } | 2048 | } |
2051 | 2049 | ||
2052 | cur_rfstate = ppsc->rfpwr_state; | ||
2053 | |||
2054 | rtl_write_byte(rtlpriv, REG_GPIO_IO_SEL_2, | 2050 | rtl_write_byte(rtlpriv, REG_GPIO_IO_SEL_2, |
2055 | rtl_read_byte(rtlpriv, REG_GPIO_IO_SEL_2)&~(BIT(1))); | 2051 | rtl_read_byte(rtlpriv, REG_GPIO_IO_SEL_2)&~(BIT(1))); |
2056 | 2052 | ||
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c b/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c index 3d8536bb0d2b..eafbb18dd48e 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c | |||
@@ -614,17 +614,11 @@ bool rtl8723ae_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, | |||
614 | { | 614 | { |
615 | struct rtl_priv *rtlpriv = rtl_priv(hw); | 615 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
616 | int i; | 616 | int i; |
617 | bool rtstatus = true; | ||
618 | u32 *radioa_array_table; | 617 | u32 *radioa_array_table; |
619 | u32 *radiob_array_table; | 618 | u16 radioa_arraylen; |
620 | u16 radioa_arraylen, radiob_arraylen; | ||
621 | 619 | ||
622 | radioa_arraylen = Rtl8723ERADIOA_1TARRAYLENGTH; | 620 | radioa_arraylen = Rtl8723ERADIOA_1TARRAYLENGTH; |
623 | radioa_array_table = RTL8723E_RADIOA_1TARRAY; | 621 | radioa_array_table = RTL8723E_RADIOA_1TARRAY; |
624 | radiob_arraylen = RTL8723E_RADIOB_1TARRAYLENGTH; | ||
625 | radiob_array_table = RTL8723E_RADIOB_1TARRAY; | ||
626 | |||
627 | rtstatus = true; | ||
628 | 622 | ||
629 | switch (rfpath) { | 623 | switch (rfpath) { |
630 | case RF90_PATH_A: | 624 | case RF90_PATH_A: |
@@ -1531,11 +1525,8 @@ static void _rtl8723ae_phy_iq_calibrate(struct ieee80211_hw *hw, | |||
1531 | 0x522, 0x550, 0x551, 0x040 | 1525 | 0x522, 0x550, 0x551, 0x040 |
1532 | }; | 1526 | }; |
1533 | const u32 retrycount = 2; | 1527 | const u32 retrycount = 2; |
1534 | u32 bbvalue; | ||
1535 | 1528 | ||
1536 | if (t == 0) { | 1529 | if (t == 0) { |
1537 | bbvalue = rtl_get_bbreg(hw, 0x800, MASKDWORD); | ||
1538 | |||
1539 | phy_save_adda_regs(hw, adda_reg, rtlphy->adda_backup, 16); | 1530 | phy_save_adda_regs(hw, adda_reg, rtlphy->adda_backup, 16); |
1540 | phy_save_mac_regs(hw, iqk_mac_reg, rtlphy->iqk_mac_backup); | 1531 | phy_save_mac_regs(hw, iqk_mac_reg, rtlphy->iqk_mac_backup); |
1541 | } | 1532 | } |
@@ -1712,8 +1703,7 @@ void rtl8723ae_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery) | |||
1712 | long result[4][8]; | 1703 | long result[4][8]; |
1713 | u8 i, final_candidate; | 1704 | u8 i, final_candidate; |
1714 | bool patha_ok, pathb_ok; | 1705 | bool patha_ok, pathb_ok; |
1715 | long reg_e94, reg_e9c, reg_ea4, reg_eac, reg_eb4, reg_ebc, reg_ec4, | 1706 | long reg_e94, reg_e9c, reg_ea4, reg_eb4, reg_ebc, reg_tmp = 0; |
1716 | reg_ecc, reg_tmp = 0; | ||
1717 | bool is12simular, is13simular, is23simular; | 1707 | bool is12simular, is13simular, is23simular; |
1718 | bool start_conttx = false, singletone = false; | 1708 | bool start_conttx = false, singletone = false; |
1719 | u32 iqk_bb_reg[10] = { | 1709 | u32 iqk_bb_reg[10] = { |
@@ -1780,21 +1770,15 @@ void rtl8723ae_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery) | |||
1780 | reg_e94 = result[i][0]; | 1770 | reg_e94 = result[i][0]; |
1781 | reg_e9c = result[i][1]; | 1771 | reg_e9c = result[i][1]; |
1782 | reg_ea4 = result[i][2]; | 1772 | reg_ea4 = result[i][2]; |
1783 | reg_eac = result[i][3]; | ||
1784 | reg_eb4 = result[i][4]; | 1773 | reg_eb4 = result[i][4]; |
1785 | reg_ebc = result[i][5]; | 1774 | reg_ebc = result[i][5]; |
1786 | reg_ec4 = result[i][6]; | ||
1787 | reg_ecc = result[i][7]; | ||
1788 | } | 1775 | } |
1789 | if (final_candidate != 0xff) { | 1776 | if (final_candidate != 0xff) { |
1790 | rtlphy->reg_e94 = reg_e94 = result[final_candidate][0]; | 1777 | rtlphy->reg_e94 = reg_e94 = result[final_candidate][0]; |
1791 | rtlphy->reg_e9c = reg_e9c = result[final_candidate][1]; | 1778 | rtlphy->reg_e9c = reg_e9c = result[final_candidate][1]; |
1792 | reg_ea4 = result[final_candidate][2]; | 1779 | reg_ea4 = result[final_candidate][2]; |
1793 | reg_eac = result[final_candidate][3]; | ||
1794 | rtlphy->reg_eb4 = reg_eb4 = result[final_candidate][4]; | 1780 | rtlphy->reg_eb4 = reg_eb4 = result[final_candidate][4]; |
1795 | rtlphy->reg_ebc = reg_ebc = result[final_candidate][5]; | 1781 | rtlphy->reg_ebc = reg_ebc = result[final_candidate][5]; |
1796 | reg_ec4 = result[final_candidate][6]; | ||
1797 | reg_ecc = result[final_candidate][7]; | ||
1798 | patha_ok = pathb_ok = true; | 1782 | patha_ok = pathb_ok = true; |
1799 | } else { | 1783 | } else { |
1800 | rtlphy->reg_e94 = rtlphy->reg_eb4 = 0x100; | 1784 | rtlphy->reg_e94 = rtlphy->reg_eb4 = 0x100; |
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c index ce8ad12bce5b..b1fd2b328abf 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c | |||
@@ -244,7 +244,6 @@ static void _rtl8723ae_translate_rx_signal_stuff(struct ieee80211_hw *hw, | |||
244 | struct ieee80211_hdr *hdr; | 244 | struct ieee80211_hdr *hdr; |
245 | u8 *tmp_buf; | 245 | u8 *tmp_buf; |
246 | u8 *praddr; | 246 | u8 *praddr; |
247 | u8 *psaddr; | ||
248 | __le16 fc; | 247 | __le16 fc; |
249 | u16 type; | 248 | u16 type; |
250 | bool packet_matchbssid, packet_toself, packet_beacon = false; | 249 | bool packet_matchbssid, packet_toself, packet_beacon = false; |
@@ -255,7 +254,6 @@ static void _rtl8723ae_translate_rx_signal_stuff(struct ieee80211_hw *hw, | |||
255 | fc = hdr->frame_control; | 254 | fc = hdr->frame_control; |
256 | type = WLAN_FC_GET_TYPE(fc); | 255 | type = WLAN_FC_GET_TYPE(fc); |
257 | praddr = hdr->addr1; | 256 | praddr = hdr->addr1; |
258 | psaddr = ieee80211_get_SA(hdr); | ||
259 | 257 | ||
260 | packet_matchbssid = ((IEEE80211_FTYPE_CTL != type) && | 258 | packet_matchbssid = ((IEEE80211_FTYPE_CTL != type) && |
261 | (!compare_ether_addr(mac->bssid, | 259 | (!compare_ether_addr(mac->bssid, |
diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index 1535efda3d52..d42bbe21ba6e 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c | |||
@@ -825,8 +825,6 @@ static void _rtl_usb_transmit(struct ieee80211_hw *hw, struct sk_buff *skb, | |||
825 | u32 ep_num; | 825 | u32 ep_num; |
826 | struct urb *_urb = NULL; | 826 | struct urb *_urb = NULL; |
827 | struct sk_buff *_skb = NULL; | 827 | struct sk_buff *_skb = NULL; |
828 | struct sk_buff_head *skb_list; | ||
829 | struct usb_anchor *urb_list; | ||
830 | 828 | ||
831 | WARN_ON(NULL == rtlusb->usb_tx_aggregate_hdl); | 829 | WARN_ON(NULL == rtlusb->usb_tx_aggregate_hdl); |
832 | if (unlikely(IS_USB_STOP(rtlusb))) { | 830 | if (unlikely(IS_USB_STOP(rtlusb))) { |
@@ -836,7 +834,6 @@ static void _rtl_usb_transmit(struct ieee80211_hw *hw, struct sk_buff *skb, | |||
836 | return; | 834 | return; |
837 | } | 835 | } |
838 | ep_num = rtlusb->ep_map.ep_mapping[qnum]; | 836 | ep_num = rtlusb->ep_map.ep_mapping[qnum]; |
839 | skb_list = &rtlusb->tx_skb_queue[ep_num]; | ||
840 | _skb = skb; | 837 | _skb = skb; |
841 | _urb = _rtl_usb_tx_urb_setup(hw, _skb, ep_num); | 838 | _urb = _rtl_usb_tx_urb_setup(hw, _skb, ep_num); |
842 | if (unlikely(!_urb)) { | 839 | if (unlikely(!_urb)) { |
@@ -844,7 +841,6 @@ static void _rtl_usb_transmit(struct ieee80211_hw *hw, struct sk_buff *skb, | |||
844 | "Can't allocate urb. Drop skb!\n"); | 841 | "Can't allocate urb. Drop skb!\n"); |
845 | return; | 842 | return; |
846 | } | 843 | } |
847 | urb_list = &rtlusb->tx_pending[ep_num]; | ||
848 | _rtl_submit_tx_urb(hw, _urb); | 844 | _rtl_submit_tx_urb(hw, _urb); |
849 | } | 845 | } |
850 | 846 | ||
diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index 21a5f4f4a135..f13258a8d995 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h | |||
@@ -1702,7 +1702,7 @@ struct rtl_works { | |||
1702 | 1702 | ||
1703 | struct rtl_debug { | 1703 | struct rtl_debug { |
1704 | u32 dbgp_type[DBGP_TYPE_MAX]; | 1704 | u32 dbgp_type[DBGP_TYPE_MAX]; |
1705 | u32 global_debuglevel; | 1705 | int global_debuglevel; |
1706 | u64 global_debugcomponents; | 1706 | u64 global_debugcomponents; |
1707 | 1707 | ||
1708 | /* add for proc debug */ | 1708 | /* add for proc debug */ |
diff --git a/drivers/net/wireless/ti/wl1251/Kconfig b/drivers/net/wireless/ti/wl1251/Kconfig index 1fb65849414f..8fec4ed36ac2 100644 --- a/drivers/net/wireless/ti/wl1251/Kconfig +++ b/drivers/net/wireless/ti/wl1251/Kconfig | |||
@@ -1,6 +1,6 @@ | |||
1 | menuconfig WL1251 | 1 | menuconfig WL1251 |
2 | tristate "TI wl1251 driver support" | 2 | tristate "TI wl1251 driver support" |
3 | depends on MAC80211 && EXPERIMENTAL && GENERIC_HARDIRQS | 3 | depends on MAC80211 && GENERIC_HARDIRQS |
4 | select FW_LOADER | 4 | select FW_LOADER |
5 | select CRC7 | 5 | select CRC7 |
6 | ---help--- | 6 | ---help--- |
diff --git a/drivers/net/wireless/ti/wl12xx/Makefile b/drivers/net/wireless/ti/wl12xx/Makefile index da509aa7d009..e6a24056b3c8 100644 --- a/drivers/net/wireless/ti/wl12xx/Makefile +++ b/drivers/net/wireless/ti/wl12xx/Makefile | |||
@@ -1,3 +1,3 @@ | |||
1 | wl12xx-objs = main.o cmd.o acx.o debugfs.o | 1 | wl12xx-objs = main.o cmd.o acx.o debugfs.o scan.o event.o |
2 | 2 | ||
3 | obj-$(CONFIG_WL12XX) += wl12xx.o | 3 | obj-$(CONFIG_WL12XX) += wl12xx.o |
diff --git a/drivers/net/wireless/ti/wl12xx/cmd.c b/drivers/net/wireless/ti/wl12xx/cmd.c index 622206241e83..7dc9f965037d 100644 --- a/drivers/net/wireless/ti/wl12xx/cmd.c +++ b/drivers/net/wireless/ti/wl12xx/cmd.c | |||
@@ -284,3 +284,40 @@ int wl128x_cmd_radio_parms(struct wl1271 *wl) | |||
284 | kfree(radio_parms); | 284 | kfree(radio_parms); |
285 | return ret; | 285 | return ret; |
286 | } | 286 | } |
287 | |||
288 | int wl12xx_cmd_channel_switch(struct wl1271 *wl, | ||
289 | struct wl12xx_vif *wlvif, | ||
290 | struct ieee80211_channel_switch *ch_switch) | ||
291 | { | ||
292 | struct wl12xx_cmd_channel_switch *cmd; | ||
293 | int ret; | ||
294 | |||
295 | wl1271_debug(DEBUG_ACX, "cmd channel switch"); | ||
296 | |||
297 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
298 | if (!cmd) { | ||
299 | ret = -ENOMEM; | ||
300 | goto out; | ||
301 | } | ||
302 | |||
303 | cmd->role_id = wlvif->role_id; | ||
304 | cmd->channel = ch_switch->channel->hw_value; | ||
305 | cmd->switch_time = ch_switch->count; | ||
306 | cmd->stop_tx = ch_switch->block_tx; | ||
307 | |||
308 | /* FIXME: control from mac80211 in the future */ | ||
309 | /* Enable TX on the target channel */ | ||
310 | cmd->post_switch_tx_disable = 0; | ||
311 | |||
312 | ret = wl1271_cmd_send(wl, CMD_CHANNEL_SWITCH, cmd, sizeof(*cmd), 0); | ||
313 | if (ret < 0) { | ||
314 | wl1271_error("failed to send channel switch command"); | ||
315 | goto out_free; | ||
316 | } | ||
317 | |||
318 | out_free: | ||
319 | kfree(cmd); | ||
320 | |||
321 | out: | ||
322 | return ret; | ||
323 | } | ||
diff --git a/drivers/net/wireless/ti/wl12xx/cmd.h b/drivers/net/wireless/ti/wl12xx/cmd.h index 140a0e8829d5..32cbad54e993 100644 --- a/drivers/net/wireless/ti/wl12xx/cmd.h +++ b/drivers/net/wireless/ti/wl12xx/cmd.h | |||
@@ -103,10 +103,30 @@ struct wl1271_ext_radio_parms_cmd { | |||
103 | u8 padding[3]; | 103 | u8 padding[3]; |
104 | } __packed; | 104 | } __packed; |
105 | 105 | ||
106 | struct wl12xx_cmd_channel_switch { | ||
107 | struct wl1271_cmd_header header; | ||
108 | |||
109 | u8 role_id; | ||
110 | |||
111 | /* The new serving channel */ | ||
112 | u8 channel; | ||
113 | /* Relative time of the serving channel switch in TBTT units */ | ||
114 | u8 switch_time; | ||
115 | /* Stop the role TX, should expect it after radar detection */ | ||
116 | u8 stop_tx; | ||
117 | /* The target channel tx status 1-stopped 0-open*/ | ||
118 | u8 post_switch_tx_disable; | ||
119 | |||
120 | u8 padding[3]; | ||
121 | } __packed; | ||
122 | |||
106 | int wl1271_cmd_general_parms(struct wl1271 *wl); | 123 | int wl1271_cmd_general_parms(struct wl1271 *wl); |
107 | int wl128x_cmd_general_parms(struct wl1271 *wl); | 124 | int wl128x_cmd_general_parms(struct wl1271 *wl); |
108 | int wl1271_cmd_radio_parms(struct wl1271 *wl); | 125 | int wl1271_cmd_radio_parms(struct wl1271 *wl); |
109 | int wl128x_cmd_radio_parms(struct wl1271 *wl); | 126 | int wl128x_cmd_radio_parms(struct wl1271 *wl); |
110 | int wl1271_cmd_ext_radio_parms(struct wl1271 *wl); | 127 | int wl1271_cmd_ext_radio_parms(struct wl1271 *wl); |
128 | int wl12xx_cmd_channel_switch(struct wl1271 *wl, | ||
129 | struct wl12xx_vif *wlvif, | ||
130 | struct ieee80211_channel_switch *ch_switch); | ||
111 | 131 | ||
112 | #endif /* __WL12XX_CMD_H__ */ | 132 | #endif /* __WL12XX_CMD_H__ */ |
diff --git a/drivers/net/wireless/ti/wl12xx/event.c b/drivers/net/wireless/ti/wl12xx/event.c new file mode 100644 index 000000000000..6ac0ed751da8 --- /dev/null +++ b/drivers/net/wireless/ti/wl12xx/event.c | |||
@@ -0,0 +1,116 @@ | |||
1 | /* | ||
2 | * This file is part of wl12xx | ||
3 | * | ||
4 | * Copyright (C) 2012 Texas Instruments. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * version 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
18 | * 02110-1301 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include "event.h" | ||
23 | #include "scan.h" | ||
24 | #include "../wlcore/cmd.h" | ||
25 | #include "../wlcore/debug.h" | ||
26 | |||
27 | int wl12xx_wait_for_event(struct wl1271 *wl, enum wlcore_wait_event event, | ||
28 | bool *timeout) | ||
29 | { | ||
30 | u32 local_event; | ||
31 | |||
32 | switch (event) { | ||
33 | case WLCORE_EVENT_ROLE_STOP_COMPLETE: | ||
34 | local_event = ROLE_STOP_COMPLETE_EVENT_ID; | ||
35 | break; | ||
36 | |||
37 | case WLCORE_EVENT_PEER_REMOVE_COMPLETE: | ||
38 | local_event = PEER_REMOVE_COMPLETE_EVENT_ID; | ||
39 | break; | ||
40 | |||
41 | default: | ||
42 | /* event not implemented */ | ||
43 | return 0; | ||
44 | } | ||
45 | return wlcore_cmd_wait_for_event_or_timeout(wl, local_event, timeout); | ||
46 | } | ||
47 | |||
48 | int wl12xx_process_mailbox_events(struct wl1271 *wl) | ||
49 | { | ||
50 | struct wl12xx_event_mailbox *mbox = wl->mbox; | ||
51 | u32 vector; | ||
52 | |||
53 | |||
54 | vector = le32_to_cpu(mbox->events_vector); | ||
55 | vector &= ~(le32_to_cpu(mbox->events_mask)); | ||
56 | |||
57 | wl1271_debug(DEBUG_EVENT, "MBOX vector: 0x%x", vector); | ||
58 | |||
59 | if (vector & SCAN_COMPLETE_EVENT_ID) { | ||
60 | wl1271_debug(DEBUG_EVENT, "status: 0x%x", | ||
61 | mbox->scheduled_scan_status); | ||
62 | |||
63 | if (wl->scan_wlvif) | ||
64 | wl12xx_scan_completed(wl, wl->scan_wlvif); | ||
65 | } | ||
66 | |||
67 | if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) { | ||
68 | wl1271_debug(DEBUG_EVENT, | ||
69 | "PERIODIC_SCAN_REPORT_EVENT (status 0x%0x)", | ||
70 | mbox->scheduled_scan_status); | ||
71 | |||
72 | wlcore_scan_sched_scan_results(wl); | ||
73 | } | ||
74 | |||
75 | if (vector & PERIODIC_SCAN_COMPLETE_EVENT_ID) | ||
76 | wlcore_event_sched_scan_completed(wl, | ||
77 | mbox->scheduled_scan_status); | ||
78 | if (vector & SOFT_GEMINI_SENSE_EVENT_ID) | ||
79 | wlcore_event_soft_gemini_sense(wl, | ||
80 | mbox->soft_gemini_sense_info); | ||
81 | |||
82 | if (vector & BSS_LOSE_EVENT_ID) | ||
83 | wlcore_event_beacon_loss(wl, 0xff); | ||
84 | |||
85 | if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) | ||
86 | wlcore_event_rssi_trigger(wl, mbox->rssi_snr_trigger_metric); | ||
87 | |||
88 | if (vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID) | ||
89 | wlcore_event_ba_rx_constraint(wl, | ||
90 | BIT(mbox->role_id), | ||
91 | mbox->rx_ba_allowed); | ||
92 | |||
93 | if (vector & CHANNEL_SWITCH_COMPLETE_EVENT_ID) | ||
94 | wlcore_event_channel_switch(wl, 0xff, | ||
95 | mbox->channel_switch_status); | ||
96 | |||
97 | if (vector & DUMMY_PACKET_EVENT_ID) | ||
98 | wlcore_event_dummy_packet(wl); | ||
99 | |||
100 | /* | ||
101 | * "TX retries exceeded" has a different meaning according to mode. | ||
102 | * In AP mode the offending station is disconnected. | ||
103 | */ | ||
104 | if (vector & MAX_TX_RETRY_EVENT_ID) | ||
105 | wlcore_event_max_tx_failure(wl, | ||
106 | le16_to_cpu(mbox->sta_tx_retry_exceeded)); | ||
107 | |||
108 | if (vector & INACTIVE_STA_EVENT_ID) | ||
109 | wlcore_event_inactive_sta(wl, | ||
110 | le16_to_cpu(mbox->sta_aging_status)); | ||
111 | |||
112 | if (vector & REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID) | ||
113 | wlcore_event_roc_complete(wl); | ||
114 | |||
115 | return 0; | ||
116 | } | ||
diff --git a/drivers/net/wireless/ti/wl12xx/event.h b/drivers/net/wireless/ti/wl12xx/event.h new file mode 100644 index 000000000000..a5cc3fcd9eea --- /dev/null +++ b/drivers/net/wireless/ti/wl12xx/event.h | |||
@@ -0,0 +1,111 @@ | |||
1 | /* | ||
2 | * This file is part of wl12xx | ||
3 | * | ||
4 | * Copyright (C) 2012 Texas Instruments. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * version 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
18 | * 02110-1301 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #ifndef __WL12XX_EVENT_H__ | ||
23 | #define __WL12XX_EVENT_H__ | ||
24 | |||
25 | #include "../wlcore/wlcore.h" | ||
26 | |||
27 | enum { | ||
28 | MEASUREMENT_START_EVENT_ID = BIT(8), | ||
29 | MEASUREMENT_COMPLETE_EVENT_ID = BIT(9), | ||
30 | SCAN_COMPLETE_EVENT_ID = BIT(10), | ||
31 | WFD_DISCOVERY_COMPLETE_EVENT_ID = BIT(11), | ||
32 | AP_DISCOVERY_COMPLETE_EVENT_ID = BIT(12), | ||
33 | RESERVED1 = BIT(13), | ||
34 | PSPOLL_DELIVERY_FAILURE_EVENT_ID = BIT(14), | ||
35 | ROLE_STOP_COMPLETE_EVENT_ID = BIT(15), | ||
36 | RADAR_DETECTED_EVENT_ID = BIT(16), | ||
37 | CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(17), | ||
38 | BSS_LOSE_EVENT_ID = BIT(18), | ||
39 | REGAINED_BSS_EVENT_ID = BIT(19), | ||
40 | MAX_TX_RETRY_EVENT_ID = BIT(20), | ||
41 | DUMMY_PACKET_EVENT_ID = BIT(21), | ||
42 | SOFT_GEMINI_SENSE_EVENT_ID = BIT(22), | ||
43 | CHANGE_AUTO_MODE_TIMEOUT_EVENT_ID = BIT(23), | ||
44 | SOFT_GEMINI_AVALANCHE_EVENT_ID = BIT(24), | ||
45 | PLT_RX_CALIBRATION_COMPLETE_EVENT_ID = BIT(25), | ||
46 | INACTIVE_STA_EVENT_ID = BIT(26), | ||
47 | PEER_REMOVE_COMPLETE_EVENT_ID = BIT(27), | ||
48 | PERIODIC_SCAN_COMPLETE_EVENT_ID = BIT(28), | ||
49 | PERIODIC_SCAN_REPORT_EVENT_ID = BIT(29), | ||
50 | BA_SESSION_RX_CONSTRAINT_EVENT_ID = BIT(30), | ||
51 | REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID = BIT(31), | ||
52 | }; | ||
53 | |||
54 | struct wl12xx_event_mailbox { | ||
55 | __le32 events_vector; | ||
56 | __le32 events_mask; | ||
57 | __le32 reserved_1; | ||
58 | __le32 reserved_2; | ||
59 | |||
60 | u8 number_of_scan_results; | ||
61 | u8 scan_tag; | ||
62 | u8 completed_scan_status; | ||
63 | u8 reserved_3; | ||
64 | |||
65 | u8 soft_gemini_sense_info; | ||
66 | u8 soft_gemini_protective_info; | ||
67 | s8 rssi_snr_trigger_metric[NUM_OF_RSSI_SNR_TRIGGERS]; | ||
68 | u8 change_auto_mode_timeout; | ||
69 | u8 scheduled_scan_status; | ||
70 | u8 reserved4; | ||
71 | /* tuned channel (roc) */ | ||
72 | u8 roc_channel; | ||
73 | |||
74 | __le16 hlid_removed_bitmap; | ||
75 | |||
76 | /* bitmap of aged stations (by HLID) */ | ||
77 | __le16 sta_aging_status; | ||
78 | |||
79 | /* bitmap of stations (by HLID) which exceeded max tx retries */ | ||
80 | __le16 sta_tx_retry_exceeded; | ||
81 | |||
82 | /* discovery completed results */ | ||
83 | u8 discovery_tag; | ||
84 | u8 number_of_preq_results; | ||
85 | u8 number_of_prsp_results; | ||
86 | u8 reserved_5; | ||
87 | |||
88 | /* rx ba constraint */ | ||
89 | u8 role_id; /* 0xFF means any role. */ | ||
90 | u8 rx_ba_allowed; | ||
91 | u8 reserved_6[2]; | ||
92 | |||
93 | /* Channel switch results */ | ||
94 | |||
95 | u8 channel_switch_role_id; | ||
96 | u8 channel_switch_status; | ||
97 | u8 reserved_7[2]; | ||
98 | |||
99 | u8 ps_poll_delivery_failure_role_ids; | ||
100 | u8 stopped_role_ids; | ||
101 | u8 started_role_ids; | ||
102 | |||
103 | u8 reserved_8[9]; | ||
104 | } __packed; | ||
105 | |||
106 | int wl12xx_wait_for_event(struct wl1271 *wl, enum wlcore_wait_event event, | ||
107 | bool *timeout); | ||
108 | int wl12xx_process_mailbox_events(struct wl1271 *wl); | ||
109 | |||
110 | #endif | ||
111 | |||
diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c index e5f5f8f39144..3254bfc81a2a 100644 --- a/drivers/net/wireless/ti/wl12xx/main.c +++ b/drivers/net/wireless/ti/wl12xx/main.c | |||
@@ -38,6 +38,8 @@ | |||
38 | #include "reg.h" | 38 | #include "reg.h" |
39 | #include "cmd.h" | 39 | #include "cmd.h" |
40 | #include "acx.h" | 40 | #include "acx.h" |
41 | #include "scan.h" | ||
42 | #include "event.h" | ||
41 | #include "debugfs.h" | 43 | #include "debugfs.h" |
42 | 44 | ||
43 | static char *fref_param; | 45 | static char *fref_param; |
@@ -208,6 +210,8 @@ static struct wlcore_conf wl12xx_conf = { | |||
208 | .tmpl_short_retry_limit = 10, | 210 | .tmpl_short_retry_limit = 10, |
209 | .tmpl_long_retry_limit = 10, | 211 | .tmpl_long_retry_limit = 10, |
210 | .tx_watchdog_timeout = 5000, | 212 | .tx_watchdog_timeout = 5000, |
213 | .slow_link_thold = 3, | ||
214 | .fast_link_thold = 10, | ||
211 | }, | 215 | }, |
212 | .conn = { | 216 | .conn = { |
213 | .wake_up_event = CONF_WAKE_UP_EVENT_DTIM, | 217 | .wake_up_event = CONF_WAKE_UP_EVENT_DTIM, |
@@ -265,8 +269,10 @@ static struct wlcore_conf wl12xx_conf = { | |||
265 | .scan = { | 269 | .scan = { |
266 | .min_dwell_time_active = 7500, | 270 | .min_dwell_time_active = 7500, |
267 | .max_dwell_time_active = 30000, | 271 | .max_dwell_time_active = 30000, |
268 | .min_dwell_time_passive = 100000, | 272 | .min_dwell_time_active_long = 25000, |
269 | .max_dwell_time_passive = 100000, | 273 | .max_dwell_time_active_long = 50000, |
274 | .dwell_time_passive = 100000, | ||
275 | .dwell_time_dfs = 150000, | ||
270 | .num_probe_reqs = 2, | 276 | .num_probe_reqs = 2, |
271 | .split_scan_timeout = 50000, | 277 | .split_scan_timeout = 50000, |
272 | }, | 278 | }, |
@@ -368,6 +374,10 @@ static struct wlcore_conf wl12xx_conf = { | |||
368 | .increase_time = 1, | 374 | .increase_time = 1, |
369 | .window_size = 16, | 375 | .window_size = 16, |
370 | }, | 376 | }, |
377 | .recovery = { | ||
378 | .bug_on_recovery = 0, | ||
379 | .no_recovery = 0, | ||
380 | }, | ||
371 | }; | 381 | }; |
372 | 382 | ||
373 | static struct wl12xx_priv_conf wl12xx_default_priv_conf = { | 383 | static struct wl12xx_priv_conf wl12xx_default_priv_conf = { |
@@ -601,9 +611,9 @@ static int wl127x_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 len) | |||
601 | { | 611 | { |
602 | int ret; | 612 | int ret; |
603 | 613 | ||
604 | if (wl->chip.id != CHIP_ID_1283_PG20) { | 614 | if (wl->chip.id != CHIP_ID_128X_PG20) { |
605 | struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map; | 615 | struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map; |
606 | struct wl127x_rx_mem_pool_addr rx_mem_addr; | 616 | struct wl12xx_priv *priv = wl->priv; |
607 | 617 | ||
608 | /* | 618 | /* |
609 | * Choose the block we want to read | 619 | * Choose the block we want to read |
@@ -612,13 +622,13 @@ static int wl127x_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 len) | |||
612 | */ | 622 | */ |
613 | u32 mem_block = rx_desc & RX_MEM_BLOCK_MASK; | 623 | u32 mem_block = rx_desc & RX_MEM_BLOCK_MASK; |
614 | 624 | ||
615 | rx_mem_addr.addr = (mem_block << 8) + | 625 | priv->rx_mem_addr->addr = (mem_block << 8) + |
616 | le32_to_cpu(wl_mem_map->packet_memory_pool_start); | 626 | le32_to_cpu(wl_mem_map->packet_memory_pool_start); |
617 | 627 | ||
618 | rx_mem_addr.addr_extra = rx_mem_addr.addr + 4; | 628 | priv->rx_mem_addr->addr_extra = priv->rx_mem_addr->addr + 4; |
619 | 629 | ||
620 | ret = wlcore_write(wl, WL1271_SLV_REG_DATA, &rx_mem_addr, | 630 | ret = wlcore_write(wl, WL1271_SLV_REG_DATA, priv->rx_mem_addr, |
621 | sizeof(rx_mem_addr), false); | 631 | sizeof(*priv->rx_mem_addr), false); |
622 | if (ret < 0) | 632 | if (ret < 0) |
623 | return ret; | 633 | return ret; |
624 | } | 634 | } |
@@ -631,13 +641,15 @@ static int wl12xx_identify_chip(struct wl1271 *wl) | |||
631 | int ret = 0; | 641 | int ret = 0; |
632 | 642 | ||
633 | switch (wl->chip.id) { | 643 | switch (wl->chip.id) { |
634 | case CHIP_ID_1271_PG10: | 644 | case CHIP_ID_127X_PG10: |
635 | wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete", | 645 | wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete", |
636 | wl->chip.id); | 646 | wl->chip.id); |
637 | 647 | ||
638 | wl->quirks |= WLCORE_QUIRK_LEGACY_NVS | | 648 | wl->quirks |= WLCORE_QUIRK_LEGACY_NVS | |
639 | WLCORE_QUIRK_DUAL_PROBE_TMPL | | 649 | WLCORE_QUIRK_DUAL_PROBE_TMPL | |
640 | WLCORE_QUIRK_TKIP_HEADER_SPACE; | 650 | WLCORE_QUIRK_TKIP_HEADER_SPACE | |
651 | WLCORE_QUIRK_START_STA_FAILS | | ||
652 | WLCORE_QUIRK_AP_ZERO_SESSION_ID; | ||
641 | wl->sr_fw_name = WL127X_FW_NAME_SINGLE; | 653 | wl->sr_fw_name = WL127X_FW_NAME_SINGLE; |
642 | wl->mr_fw_name = WL127X_FW_NAME_MULTI; | 654 | wl->mr_fw_name = WL127X_FW_NAME_MULTI; |
643 | memcpy(&wl->conf.mem, &wl12xx_default_priv_conf.mem_wl127x, | 655 | memcpy(&wl->conf.mem, &wl12xx_default_priv_conf.mem_wl127x, |
@@ -646,18 +658,22 @@ static int wl12xx_identify_chip(struct wl1271 *wl) | |||
646 | /* read data preparation is only needed by wl127x */ | 658 | /* read data preparation is only needed by wl127x */ |
647 | wl->ops->prepare_read = wl127x_prepare_read; | 659 | wl->ops->prepare_read = wl127x_prepare_read; |
648 | 660 | ||
649 | wlcore_set_min_fw_ver(wl, WL127X_CHIP_VER, WL127X_IFTYPE_VER, | 661 | wlcore_set_min_fw_ver(wl, WL127X_CHIP_VER, |
650 | WL127X_MAJOR_VER, WL127X_SUBTYPE_VER, | 662 | WL127X_IFTYPE_SR_VER, WL127X_MAJOR_SR_VER, |
651 | WL127X_MINOR_VER); | 663 | WL127X_SUBTYPE_SR_VER, WL127X_MINOR_SR_VER, |
664 | WL127X_IFTYPE_MR_VER, WL127X_MAJOR_MR_VER, | ||
665 | WL127X_SUBTYPE_MR_VER, WL127X_MINOR_MR_VER); | ||
652 | break; | 666 | break; |
653 | 667 | ||
654 | case CHIP_ID_1271_PG20: | 668 | case CHIP_ID_127X_PG20: |
655 | wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)", | 669 | wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)", |
656 | wl->chip.id); | 670 | wl->chip.id); |
657 | 671 | ||
658 | wl->quirks |= WLCORE_QUIRK_LEGACY_NVS | | 672 | wl->quirks |= WLCORE_QUIRK_LEGACY_NVS | |
659 | WLCORE_QUIRK_DUAL_PROBE_TMPL | | 673 | WLCORE_QUIRK_DUAL_PROBE_TMPL | |
660 | WLCORE_QUIRK_TKIP_HEADER_SPACE; | 674 | WLCORE_QUIRK_TKIP_HEADER_SPACE | |
675 | WLCORE_QUIRK_START_STA_FAILS | | ||
676 | WLCORE_QUIRK_AP_ZERO_SESSION_ID; | ||
661 | wl->plt_fw_name = WL127X_PLT_FW_NAME; | 677 | wl->plt_fw_name = WL127X_PLT_FW_NAME; |
662 | wl->sr_fw_name = WL127X_FW_NAME_SINGLE; | 678 | wl->sr_fw_name = WL127X_FW_NAME_SINGLE; |
663 | wl->mr_fw_name = WL127X_FW_NAME_MULTI; | 679 | wl->mr_fw_name = WL127X_FW_NAME_MULTI; |
@@ -667,12 +683,14 @@ static int wl12xx_identify_chip(struct wl1271 *wl) | |||
667 | /* read data preparation is only needed by wl127x */ | 683 | /* read data preparation is only needed by wl127x */ |
668 | wl->ops->prepare_read = wl127x_prepare_read; | 684 | wl->ops->prepare_read = wl127x_prepare_read; |
669 | 685 | ||
670 | wlcore_set_min_fw_ver(wl, WL127X_CHIP_VER, WL127X_IFTYPE_VER, | 686 | wlcore_set_min_fw_ver(wl, WL127X_CHIP_VER, |
671 | WL127X_MAJOR_VER, WL127X_SUBTYPE_VER, | 687 | WL127X_IFTYPE_SR_VER, WL127X_MAJOR_SR_VER, |
672 | WL127X_MINOR_VER); | 688 | WL127X_SUBTYPE_SR_VER, WL127X_MINOR_SR_VER, |
689 | WL127X_IFTYPE_MR_VER, WL127X_MAJOR_MR_VER, | ||
690 | WL127X_SUBTYPE_MR_VER, WL127X_MINOR_MR_VER); | ||
673 | break; | 691 | break; |
674 | 692 | ||
675 | case CHIP_ID_1283_PG20: | 693 | case CHIP_ID_128X_PG20: |
676 | wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)", | 694 | wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)", |
677 | wl->chip.id); | 695 | wl->chip.id); |
678 | wl->plt_fw_name = WL128X_PLT_FW_NAME; | 696 | wl->plt_fw_name = WL128X_PLT_FW_NAME; |
@@ -682,19 +700,29 @@ static int wl12xx_identify_chip(struct wl1271 *wl) | |||
682 | /* wl128x requires TX blocksize alignment */ | 700 | /* wl128x requires TX blocksize alignment */ |
683 | wl->quirks |= WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN | | 701 | wl->quirks |= WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN | |
684 | WLCORE_QUIRK_DUAL_PROBE_TMPL | | 702 | WLCORE_QUIRK_DUAL_PROBE_TMPL | |
685 | WLCORE_QUIRK_TKIP_HEADER_SPACE; | 703 | WLCORE_QUIRK_TKIP_HEADER_SPACE | |
686 | 704 | WLCORE_QUIRK_START_STA_FAILS | | |
687 | wlcore_set_min_fw_ver(wl, WL128X_CHIP_VER, WL128X_IFTYPE_VER, | 705 | WLCORE_QUIRK_AP_ZERO_SESSION_ID; |
688 | WL128X_MAJOR_VER, WL128X_SUBTYPE_VER, | 706 | |
689 | WL128X_MINOR_VER); | 707 | wlcore_set_min_fw_ver(wl, WL128X_CHIP_VER, |
708 | WL128X_IFTYPE_SR_VER, WL128X_MAJOR_SR_VER, | ||
709 | WL128X_SUBTYPE_SR_VER, WL128X_MINOR_SR_VER, | ||
710 | WL128X_IFTYPE_MR_VER, WL128X_MAJOR_MR_VER, | ||
711 | WL128X_SUBTYPE_MR_VER, WL128X_MINOR_MR_VER); | ||
690 | break; | 712 | break; |
691 | case CHIP_ID_1283_PG10: | 713 | case CHIP_ID_128X_PG10: |
692 | default: | 714 | default: |
693 | wl1271_warning("unsupported chip id: 0x%x", wl->chip.id); | 715 | wl1271_warning("unsupported chip id: 0x%x", wl->chip.id); |
694 | ret = -ENODEV; | 716 | ret = -ENODEV; |
695 | goto out; | 717 | goto out; |
696 | } | 718 | } |
697 | 719 | ||
720 | /* common settings */ | ||
721 | wl->scan_templ_id_2_4 = CMD_TEMPL_APP_PROBE_REQ_2_4_LEGACY; | ||
722 | wl->scan_templ_id_5 = CMD_TEMPL_APP_PROBE_REQ_5_LEGACY; | ||
723 | wl->sched_scan_templ_id_2_4 = CMD_TEMPL_CFG_PROBE_REQ_2_4; | ||
724 | wl->sched_scan_templ_id_5 = CMD_TEMPL_CFG_PROBE_REQ_5; | ||
725 | wl->max_channels_5 = WL12XX_MAX_CHANNELS_5GHZ; | ||
698 | out: | 726 | out: |
699 | return ret; | 727 | return ret; |
700 | } | 728 | } |
@@ -1067,7 +1095,7 @@ static int wl12xx_pre_boot(struct wl1271 *wl) | |||
1067 | u32 clk; | 1095 | u32 clk; |
1068 | int selected_clock = -1; | 1096 | int selected_clock = -1; |
1069 | 1097 | ||
1070 | if (wl->chip.id == CHIP_ID_1283_PG20) { | 1098 | if (wl->chip.id == CHIP_ID_128X_PG20) { |
1071 | ret = wl128x_boot_clk(wl, &selected_clock); | 1099 | ret = wl128x_boot_clk(wl, &selected_clock); |
1072 | if (ret < 0) | 1100 | if (ret < 0) |
1073 | goto out; | 1101 | goto out; |
@@ -1098,7 +1126,7 @@ static int wl12xx_pre_boot(struct wl1271 *wl) | |||
1098 | 1126 | ||
1099 | wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk); | 1127 | wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk); |
1100 | 1128 | ||
1101 | if (wl->chip.id == CHIP_ID_1283_PG20) | 1129 | if (wl->chip.id == CHIP_ID_128X_PG20) |
1102 | clk |= ((selected_clock & 0x3) << 1) << 4; | 1130 | clk |= ((selected_clock & 0x3) << 1) << 4; |
1103 | else | 1131 | else |
1104 | clk |= (priv->ref_clock << 1) << 4; | 1132 | clk |= (priv->ref_clock << 1) << 4; |
@@ -1152,7 +1180,7 @@ static int wl12xx_pre_upload(struct wl1271 *wl) | |||
1152 | /* WL1271: The reference driver skips steps 7 to 10 (jumps directly | 1180 | /* WL1271: The reference driver skips steps 7 to 10 (jumps directly |
1153 | * to upload_fw) */ | 1181 | * to upload_fw) */ |
1154 | 1182 | ||
1155 | if (wl->chip.id == CHIP_ID_1283_PG20) { | 1183 | if (wl->chip.id == CHIP_ID_128X_PG20) { |
1156 | ret = wl12xx_top_reg_write(wl, SDIO_IO_DS, HCI_IO_DS_6MA); | 1184 | ret = wl12xx_top_reg_write(wl, SDIO_IO_DS, HCI_IO_DS_6MA); |
1157 | if (ret < 0) | 1185 | if (ret < 0) |
1158 | goto out; | 1186 | goto out; |
@@ -1219,6 +1247,23 @@ static int wl12xx_boot(struct wl1271 *wl) | |||
1219 | if (ret < 0) | 1247 | if (ret < 0) |
1220 | goto out; | 1248 | goto out; |
1221 | 1249 | ||
1250 | wl->event_mask = BSS_LOSE_EVENT_ID | | ||
1251 | REGAINED_BSS_EVENT_ID | | ||
1252 | SCAN_COMPLETE_EVENT_ID | | ||
1253 | ROLE_STOP_COMPLETE_EVENT_ID | | ||
1254 | RSSI_SNR_TRIGGER_0_EVENT_ID | | ||
1255 | PSPOLL_DELIVERY_FAILURE_EVENT_ID | | ||
1256 | SOFT_GEMINI_SENSE_EVENT_ID | | ||
1257 | PERIODIC_SCAN_REPORT_EVENT_ID | | ||
1258 | PERIODIC_SCAN_COMPLETE_EVENT_ID | | ||
1259 | DUMMY_PACKET_EVENT_ID | | ||
1260 | PEER_REMOVE_COMPLETE_EVENT_ID | | ||
1261 | BA_SESSION_RX_CONSTRAINT_EVENT_ID | | ||
1262 | REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID | | ||
1263 | INACTIVE_STA_EVENT_ID | | ||
1264 | MAX_TX_RETRY_EVENT_ID | | ||
1265 | CHANNEL_SWITCH_COMPLETE_EVENT_ID; | ||
1266 | |||
1222 | ret = wlcore_boot_run_firmware(wl); | 1267 | ret = wlcore_boot_run_firmware(wl); |
1223 | if (ret < 0) | 1268 | if (ret < 0) |
1224 | goto out; | 1269 | goto out; |
@@ -1261,7 +1306,7 @@ static void | |||
1261 | wl12xx_set_tx_desc_blocks(struct wl1271 *wl, struct wl1271_tx_hw_descr *desc, | 1306 | wl12xx_set_tx_desc_blocks(struct wl1271 *wl, struct wl1271_tx_hw_descr *desc, |
1262 | u32 blks, u32 spare_blks) | 1307 | u32 blks, u32 spare_blks) |
1263 | { | 1308 | { |
1264 | if (wl->chip.id == CHIP_ID_1283_PG20) { | 1309 | if (wl->chip.id == CHIP_ID_128X_PG20) { |
1265 | desc->wl128x_mem.total_mem_blocks = blks; | 1310 | desc->wl128x_mem.total_mem_blocks = blks; |
1266 | } else { | 1311 | } else { |
1267 | desc->wl127x_mem.extra_blocks = spare_blks; | 1312 | desc->wl127x_mem.extra_blocks = spare_blks; |
@@ -1275,7 +1320,7 @@ wl12xx_set_tx_desc_data_len(struct wl1271 *wl, struct wl1271_tx_hw_descr *desc, | |||
1275 | { | 1320 | { |
1276 | u32 aligned_len = wlcore_calc_packet_alignment(wl, skb->len); | 1321 | u32 aligned_len = wlcore_calc_packet_alignment(wl, skb->len); |
1277 | 1322 | ||
1278 | if (wl->chip.id == CHIP_ID_1283_PG20) { | 1323 | if (wl->chip.id == CHIP_ID_128X_PG20) { |
1279 | desc->wl128x_mem.extra_bytes = aligned_len - skb->len; | 1324 | desc->wl128x_mem.extra_bytes = aligned_len - skb->len; |
1280 | desc->length = cpu_to_le16(aligned_len >> 2); | 1325 | desc->length = cpu_to_le16(aligned_len >> 2); |
1281 | 1326 | ||
@@ -1339,7 +1384,7 @@ static int wl12xx_hw_init(struct wl1271 *wl) | |||
1339 | { | 1384 | { |
1340 | int ret; | 1385 | int ret; |
1341 | 1386 | ||
1342 | if (wl->chip.id == CHIP_ID_1283_PG20) { | 1387 | if (wl->chip.id == CHIP_ID_128X_PG20) { |
1343 | u32 host_cfg_bitmap = HOST_IF_CFG_RX_FIFO_ENABLE; | 1388 | u32 host_cfg_bitmap = HOST_IF_CFG_RX_FIFO_ENABLE; |
1344 | 1389 | ||
1345 | ret = wl128x_cmd_general_parms(wl); | 1390 | ret = wl128x_cmd_general_parms(wl); |
@@ -1394,22 +1439,6 @@ static u32 wl12xx_sta_get_ap_rate_mask(struct wl1271 *wl, | |||
1394 | return wlvif->rate_set; | 1439 | return wlvif->rate_set; |
1395 | } | 1440 | } |
1396 | 1441 | ||
1397 | static int wl12xx_identify_fw(struct wl1271 *wl) | ||
1398 | { | ||
1399 | unsigned int *fw_ver = wl->chip.fw_ver; | ||
1400 | |||
1401 | /* Only new station firmwares support routing fw logs to the host */ | ||
1402 | if ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) && | ||
1403 | (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_FWLOG_STA_MIN)) | ||
1404 | wl->quirks |= WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED; | ||
1405 | |||
1406 | /* This feature is not yet supported for AP mode */ | ||
1407 | if (fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP) | ||
1408 | wl->quirks |= WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED; | ||
1409 | |||
1410 | return 0; | ||
1411 | } | ||
1412 | |||
1413 | static void wl12xx_conf_init(struct wl1271 *wl) | 1442 | static void wl12xx_conf_init(struct wl1271 *wl) |
1414 | { | 1443 | { |
1415 | struct wl12xx_priv *priv = wl->priv; | 1444 | struct wl12xx_priv *priv = wl->priv; |
@@ -1426,7 +1455,7 @@ static bool wl12xx_mac_in_fuse(struct wl1271 *wl) | |||
1426 | bool supported = false; | 1455 | bool supported = false; |
1427 | u8 major, minor; | 1456 | u8 major, minor; |
1428 | 1457 | ||
1429 | if (wl->chip.id == CHIP_ID_1283_PG20) { | 1458 | if (wl->chip.id == CHIP_ID_128X_PG20) { |
1430 | major = WL128X_PG_GET_MAJOR(wl->hw_pg_ver); | 1459 | major = WL128X_PG_GET_MAJOR(wl->hw_pg_ver); |
1431 | minor = WL128X_PG_GET_MINOR(wl->hw_pg_ver); | 1460 | minor = WL128X_PG_GET_MINOR(wl->hw_pg_ver); |
1432 | 1461 | ||
@@ -1482,7 +1511,7 @@ static int wl12xx_get_pg_ver(struct wl1271 *wl, s8 *ver) | |||
1482 | u16 die_info; | 1511 | u16 die_info; |
1483 | int ret; | 1512 | int ret; |
1484 | 1513 | ||
1485 | if (wl->chip.id == CHIP_ID_1283_PG20) | 1514 | if (wl->chip.id == CHIP_ID_128X_PG20) |
1486 | ret = wl12xx_top_reg_read(wl, WL128X_REG_FUSE_DATA_2_1, | 1515 | ret = wl12xx_top_reg_read(wl, WL128X_REG_FUSE_DATA_2_1, |
1487 | &die_info); | 1516 | &die_info); |
1488 | else | 1517 | else |
@@ -1589,16 +1618,46 @@ static int wl12xx_set_key(struct wl1271 *wl, enum set_key_cmd cmd, | |||
1589 | return wlcore_set_key(wl, cmd, vif, sta, key_conf); | 1618 | return wlcore_set_key(wl, cmd, vif, sta, key_conf); |
1590 | } | 1619 | } |
1591 | 1620 | ||
1621 | static int wl12xx_set_peer_cap(struct wl1271 *wl, | ||
1622 | struct ieee80211_sta_ht_cap *ht_cap, | ||
1623 | bool allow_ht_operation, | ||
1624 | u32 rate_set, u8 hlid) | ||
1625 | { | ||
1626 | return wl1271_acx_set_ht_capabilities(wl, ht_cap, allow_ht_operation, | ||
1627 | hlid); | ||
1628 | } | ||
1629 | |||
1630 | static bool wl12xx_lnk_high_prio(struct wl1271 *wl, u8 hlid, | ||
1631 | struct wl1271_link *lnk) | ||
1632 | { | ||
1633 | u8 thold; | ||
1634 | |||
1635 | if (test_bit(hlid, (unsigned long *)&wl->fw_fast_lnk_map)) | ||
1636 | thold = wl->conf.tx.fast_link_thold; | ||
1637 | else | ||
1638 | thold = wl->conf.tx.slow_link_thold; | ||
1639 | |||
1640 | return lnk->allocated_pkts < thold; | ||
1641 | } | ||
1642 | |||
1643 | static bool wl12xx_lnk_low_prio(struct wl1271 *wl, u8 hlid, | ||
1644 | struct wl1271_link *lnk) | ||
1645 | { | ||
1646 | /* any link is good for low priority */ | ||
1647 | return true; | ||
1648 | } | ||
1649 | |||
1592 | static int wl12xx_setup(struct wl1271 *wl); | 1650 | static int wl12xx_setup(struct wl1271 *wl); |
1593 | 1651 | ||
1594 | static struct wlcore_ops wl12xx_ops = { | 1652 | static struct wlcore_ops wl12xx_ops = { |
1595 | .setup = wl12xx_setup, | 1653 | .setup = wl12xx_setup, |
1596 | .identify_chip = wl12xx_identify_chip, | 1654 | .identify_chip = wl12xx_identify_chip, |
1597 | .identify_fw = wl12xx_identify_fw, | ||
1598 | .boot = wl12xx_boot, | 1655 | .boot = wl12xx_boot, |
1599 | .plt_init = wl12xx_plt_init, | 1656 | .plt_init = wl12xx_plt_init, |
1600 | .trigger_cmd = wl12xx_trigger_cmd, | 1657 | .trigger_cmd = wl12xx_trigger_cmd, |
1601 | .ack_event = wl12xx_ack_event, | 1658 | .ack_event = wl12xx_ack_event, |
1659 | .wait_for_event = wl12xx_wait_for_event, | ||
1660 | .process_mailbox_events = wl12xx_process_mailbox_events, | ||
1602 | .calc_tx_blocks = wl12xx_calc_tx_blocks, | 1661 | .calc_tx_blocks = wl12xx_calc_tx_blocks, |
1603 | .set_tx_desc_blocks = wl12xx_set_tx_desc_blocks, | 1662 | .set_tx_desc_blocks = wl12xx_set_tx_desc_blocks, |
1604 | .set_tx_desc_data_len = wl12xx_set_tx_desc_data_len, | 1663 | .set_tx_desc_data_len = wl12xx_set_tx_desc_data_len, |
@@ -1615,9 +1674,17 @@ static struct wlcore_ops wl12xx_ops = { | |||
1615 | .set_rx_csum = NULL, | 1674 | .set_rx_csum = NULL, |
1616 | .ap_get_mimo_wide_rate_mask = NULL, | 1675 | .ap_get_mimo_wide_rate_mask = NULL, |
1617 | .debugfs_init = wl12xx_debugfs_add_files, | 1676 | .debugfs_init = wl12xx_debugfs_add_files, |
1677 | .scan_start = wl12xx_scan_start, | ||
1678 | .scan_stop = wl12xx_scan_stop, | ||
1679 | .sched_scan_start = wl12xx_sched_scan_start, | ||
1680 | .sched_scan_stop = wl12xx_scan_sched_scan_stop, | ||
1618 | .get_spare_blocks = wl12xx_get_spare_blocks, | 1681 | .get_spare_blocks = wl12xx_get_spare_blocks, |
1619 | .set_key = wl12xx_set_key, | 1682 | .set_key = wl12xx_set_key, |
1683 | .channel_switch = wl12xx_cmd_channel_switch, | ||
1620 | .pre_pkt_send = NULL, | 1684 | .pre_pkt_send = NULL, |
1685 | .set_peer_cap = wl12xx_set_peer_cap, | ||
1686 | .lnk_high_prio = wl12xx_lnk_high_prio, | ||
1687 | .lnk_low_prio = wl12xx_lnk_low_prio, | ||
1621 | }; | 1688 | }; |
1622 | 1689 | ||
1623 | static struct ieee80211_sta_ht_cap wl12xx_ht_cap = { | 1690 | static struct ieee80211_sta_ht_cap wl12xx_ht_cap = { |
@@ -1641,6 +1708,7 @@ static int wl12xx_setup(struct wl1271 *wl) | |||
1641 | wl->rtable = wl12xx_rtable; | 1708 | wl->rtable = wl12xx_rtable; |
1642 | wl->num_tx_desc = WL12XX_NUM_TX_DESCRIPTORS; | 1709 | wl->num_tx_desc = WL12XX_NUM_TX_DESCRIPTORS; |
1643 | wl->num_rx_desc = WL12XX_NUM_RX_DESCRIPTORS; | 1710 | wl->num_rx_desc = WL12XX_NUM_RX_DESCRIPTORS; |
1711 | wl->num_channels = 1; | ||
1644 | wl->num_mac_addr = WL12XX_NUM_MAC_ADDRESSES; | 1712 | wl->num_mac_addr = WL12XX_NUM_MAC_ADDRESSES; |
1645 | wl->band_rate_to_idx = wl12xx_band_rate_to_idx; | 1713 | wl->band_rate_to_idx = wl12xx_band_rate_to_idx; |
1646 | wl->hw_tx_rate_tbl_size = WL12XX_CONF_HW_RXTX_RATE_MAX; | 1714 | wl->hw_tx_rate_tbl_size = WL12XX_CONF_HW_RXTX_RATE_MAX; |
@@ -1693,6 +1761,10 @@ static int wl12xx_setup(struct wl1271 *wl) | |||
1693 | wl1271_error("Invalid tcxo parameter %s", tcxo_param); | 1761 | wl1271_error("Invalid tcxo parameter %s", tcxo_param); |
1694 | } | 1762 | } |
1695 | 1763 | ||
1764 | priv->rx_mem_addr = kmalloc(sizeof(*priv->rx_mem_addr), GFP_KERNEL); | ||
1765 | if (!priv->rx_mem_addr) | ||
1766 | return -ENOMEM; | ||
1767 | |||
1696 | return 0; | 1768 | return 0; |
1697 | } | 1769 | } |
1698 | 1770 | ||
@@ -1703,7 +1775,8 @@ static int wl12xx_probe(struct platform_device *pdev) | |||
1703 | int ret; | 1775 | int ret; |
1704 | 1776 | ||
1705 | hw = wlcore_alloc_hw(sizeof(struct wl12xx_priv), | 1777 | hw = wlcore_alloc_hw(sizeof(struct wl12xx_priv), |
1706 | WL12XX_AGGR_BUFFER_SIZE); | 1778 | WL12XX_AGGR_BUFFER_SIZE, |
1779 | sizeof(struct wl12xx_event_mailbox)); | ||
1707 | if (IS_ERR(hw)) { | 1780 | if (IS_ERR(hw)) { |
1708 | wl1271_error("can't allocate hw"); | 1781 | wl1271_error("can't allocate hw"); |
1709 | ret = PTR_ERR(hw); | 1782 | ret = PTR_ERR(hw); |
@@ -1725,6 +1798,21 @@ out: | |||
1725 | return ret; | 1798 | return ret; |
1726 | } | 1799 | } |
1727 | 1800 | ||
1801 | static int wl12xx_remove(struct platform_device *pdev) | ||
1802 | { | ||
1803 | struct wl1271 *wl = platform_get_drvdata(pdev); | ||
1804 | struct wl12xx_priv *priv; | ||
1805 | |||
1806 | if (!wl) | ||
1807 | goto out; | ||
1808 | priv = wl->priv; | ||
1809 | |||
1810 | kfree(priv->rx_mem_addr); | ||
1811 | |||
1812 | out: | ||
1813 | return wlcore_remove(pdev); | ||
1814 | } | ||
1815 | |||
1728 | static const struct platform_device_id wl12xx_id_table[] = { | 1816 | static const struct platform_device_id wl12xx_id_table[] = { |
1729 | { "wl12xx", 0 }, | 1817 | { "wl12xx", 0 }, |
1730 | { } /* Terminating Entry */ | 1818 | { } /* Terminating Entry */ |
@@ -1733,7 +1821,7 @@ MODULE_DEVICE_TABLE(platform, wl12xx_id_table); | |||
1733 | 1821 | ||
1734 | static struct platform_driver wl12xx_driver = { | 1822 | static struct platform_driver wl12xx_driver = { |
1735 | .probe = wl12xx_probe, | 1823 | .probe = wl12xx_probe, |
1736 | .remove = wlcore_remove, | 1824 | .remove = wl12xx_remove, |
1737 | .id_table = wl12xx_id_table, | 1825 | .id_table = wl12xx_id_table, |
1738 | .driver = { | 1826 | .driver = { |
1739 | .name = "wl12xx_driver", | 1827 | .name = "wl12xx_driver", |
diff --git a/drivers/net/wireless/ti/wl12xx/scan.c b/drivers/net/wireless/ti/wl12xx/scan.c new file mode 100644 index 000000000000..affdb3ec6225 --- /dev/null +++ b/drivers/net/wireless/ti/wl12xx/scan.c | |||
@@ -0,0 +1,501 @@ | |||
1 | /* | ||
2 | * This file is part of wl12xx | ||
3 | * | ||
4 | * Copyright (C) 2012 Texas Instruments. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * version 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
18 | * 02110-1301 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include <linux/ieee80211.h> | ||
23 | #include "scan.h" | ||
24 | #include "../wlcore/debug.h" | ||
25 | #include "../wlcore/tx.h" | ||
26 | |||
27 | static int wl1271_get_scan_channels(struct wl1271 *wl, | ||
28 | struct cfg80211_scan_request *req, | ||
29 | struct basic_scan_channel_params *channels, | ||
30 | enum ieee80211_band band, bool passive) | ||
31 | { | ||
32 | struct conf_scan_settings *c = &wl->conf.scan; | ||
33 | int i, j; | ||
34 | u32 flags; | ||
35 | |||
36 | for (i = 0, j = 0; | ||
37 | i < req->n_channels && j < WL1271_SCAN_MAX_CHANNELS; | ||
38 | i++) { | ||
39 | flags = req->channels[i]->flags; | ||
40 | |||
41 | if (!test_bit(i, wl->scan.scanned_ch) && | ||
42 | !(flags & IEEE80211_CHAN_DISABLED) && | ||
43 | (req->channels[i]->band == band) && | ||
44 | /* | ||
45 | * In passive scans, we scan all remaining | ||
46 | * channels, even if not marked as such. | ||
47 | * In active scans, we only scan channels not | ||
48 | * marked as passive. | ||
49 | */ | ||
50 | (passive || !(flags & IEEE80211_CHAN_PASSIVE_SCAN))) { | ||
51 | wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ", | ||
52 | req->channels[i]->band, | ||
53 | req->channels[i]->center_freq); | ||
54 | wl1271_debug(DEBUG_SCAN, "hw_value %d, flags %X", | ||
55 | req->channels[i]->hw_value, | ||
56 | req->channels[i]->flags); | ||
57 | wl1271_debug(DEBUG_SCAN, | ||
58 | "max_antenna_gain %d, max_power %d", | ||
59 | req->channels[i]->max_antenna_gain, | ||
60 | req->channels[i]->max_power); | ||
61 | wl1271_debug(DEBUG_SCAN, "beacon_found %d", | ||
62 | req->channels[i]->beacon_found); | ||
63 | |||
64 | if (!passive) { | ||
65 | channels[j].min_duration = | ||
66 | cpu_to_le32(c->min_dwell_time_active); | ||
67 | channels[j].max_duration = | ||
68 | cpu_to_le32(c->max_dwell_time_active); | ||
69 | } else { | ||
70 | channels[j].min_duration = | ||
71 | cpu_to_le32(c->dwell_time_passive); | ||
72 | channels[j].max_duration = | ||
73 | cpu_to_le32(c->dwell_time_passive); | ||
74 | } | ||
75 | channels[j].early_termination = 0; | ||
76 | channels[j].tx_power_att = req->channels[i]->max_power; | ||
77 | channels[j].channel = req->channels[i]->hw_value; | ||
78 | |||
79 | memset(&channels[j].bssid_lsb, 0xff, 4); | ||
80 | memset(&channels[j].bssid_msb, 0xff, 2); | ||
81 | |||
82 | /* Mark the channels we already used */ | ||
83 | set_bit(i, wl->scan.scanned_ch); | ||
84 | |||
85 | j++; | ||
86 | } | ||
87 | } | ||
88 | |||
89 | return j; | ||
90 | } | ||
91 | |||
92 | #define WL1271_NOTHING_TO_SCAN 1 | ||
93 | |||
94 | static int wl1271_scan_send(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
95 | enum ieee80211_band band, | ||
96 | bool passive, u32 basic_rate) | ||
97 | { | ||
98 | struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); | ||
99 | struct wl1271_cmd_scan *cmd; | ||
100 | struct wl1271_cmd_trigger_scan_to *trigger; | ||
101 | int ret; | ||
102 | u16 scan_options = 0; | ||
103 | |||
104 | /* skip active scans if we don't have SSIDs */ | ||
105 | if (!passive && wl->scan.req->n_ssids == 0) | ||
106 | return WL1271_NOTHING_TO_SCAN; | ||
107 | |||
108 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
109 | trigger = kzalloc(sizeof(*trigger), GFP_KERNEL); | ||
110 | if (!cmd || !trigger) { | ||
111 | ret = -ENOMEM; | ||
112 | goto out; | ||
113 | } | ||
114 | |||
115 | if (wl->conf.scan.split_scan_timeout) | ||
116 | scan_options |= WL1271_SCAN_OPT_SPLIT_SCAN; | ||
117 | |||
118 | if (passive) | ||
119 | scan_options |= WL1271_SCAN_OPT_PASSIVE; | ||
120 | |||
121 | cmd->params.role_id = wlvif->role_id; | ||
122 | |||
123 | if (WARN_ON(cmd->params.role_id == WL12XX_INVALID_ROLE_ID)) { | ||
124 | ret = -EINVAL; | ||
125 | goto out; | ||
126 | } | ||
127 | |||
128 | cmd->params.scan_options = cpu_to_le16(scan_options); | ||
129 | |||
130 | cmd->params.n_ch = wl1271_get_scan_channels(wl, wl->scan.req, | ||
131 | cmd->channels, | ||
132 | band, passive); | ||
133 | if (cmd->params.n_ch == 0) { | ||
134 | ret = WL1271_NOTHING_TO_SCAN; | ||
135 | goto out; | ||
136 | } | ||
137 | |||
138 | cmd->params.tx_rate = cpu_to_le32(basic_rate); | ||
139 | cmd->params.n_probe_reqs = wl->conf.scan.num_probe_reqs; | ||
140 | cmd->params.tid_trigger = CONF_TX_AC_ANY_TID; | ||
141 | cmd->params.scan_tag = WL1271_SCAN_DEFAULT_TAG; | ||
142 | |||
143 | if (band == IEEE80211_BAND_2GHZ) | ||
144 | cmd->params.band = WL1271_SCAN_BAND_2_4_GHZ; | ||
145 | else | ||
146 | cmd->params.band = WL1271_SCAN_BAND_5_GHZ; | ||
147 | |||
148 | if (wl->scan.ssid_len && wl->scan.ssid) { | ||
149 | cmd->params.ssid_len = wl->scan.ssid_len; | ||
150 | memcpy(cmd->params.ssid, wl->scan.ssid, wl->scan.ssid_len); | ||
151 | } | ||
152 | |||
153 | memcpy(cmd->addr, vif->addr, ETH_ALEN); | ||
154 | |||
155 | ret = wl12xx_cmd_build_probe_req(wl, wlvif, | ||
156 | cmd->params.role_id, band, | ||
157 | wl->scan.ssid, wl->scan.ssid_len, | ||
158 | wl->scan.req->ie, | ||
159 | wl->scan.req->ie_len, false); | ||
160 | if (ret < 0) { | ||
161 | wl1271_error("PROBE request template failed"); | ||
162 | goto out; | ||
163 | } | ||
164 | |||
165 | trigger->timeout = cpu_to_le32(wl->conf.scan.split_scan_timeout); | ||
166 | ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger, | ||
167 | sizeof(*trigger), 0); | ||
168 | if (ret < 0) { | ||
169 | wl1271_error("trigger scan to failed for hw scan"); | ||
170 | goto out; | ||
171 | } | ||
172 | |||
173 | wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd)); | ||
174 | |||
175 | ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0); | ||
176 | if (ret < 0) { | ||
177 | wl1271_error("SCAN failed"); | ||
178 | goto out; | ||
179 | } | ||
180 | |||
181 | out: | ||
182 | kfree(cmd); | ||
183 | kfree(trigger); | ||
184 | return ret; | ||
185 | } | ||
186 | |||
187 | int wl12xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif) | ||
188 | { | ||
189 | struct wl1271_cmd_header *cmd = NULL; | ||
190 | int ret = 0; | ||
191 | |||
192 | if (WARN_ON(wl->scan.state == WL1271_SCAN_STATE_IDLE)) | ||
193 | return -EINVAL; | ||
194 | |||
195 | wl1271_debug(DEBUG_CMD, "cmd scan stop"); | ||
196 | |||
197 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
198 | if (!cmd) { | ||
199 | ret = -ENOMEM; | ||
200 | goto out; | ||
201 | } | ||
202 | |||
203 | ret = wl1271_cmd_send(wl, CMD_STOP_SCAN, cmd, | ||
204 | sizeof(*cmd), 0); | ||
205 | if (ret < 0) { | ||
206 | wl1271_error("cmd stop_scan failed"); | ||
207 | goto out; | ||
208 | } | ||
209 | out: | ||
210 | kfree(cmd); | ||
211 | return ret; | ||
212 | } | ||
213 | |||
214 | void wl1271_scan_stm(struct wl1271 *wl, struct wl12xx_vif *wlvif) | ||
215 | { | ||
216 | int ret = 0; | ||
217 | enum ieee80211_band band; | ||
218 | u32 rate, mask; | ||
219 | |||
220 | switch (wl->scan.state) { | ||
221 | case WL1271_SCAN_STATE_IDLE: | ||
222 | break; | ||
223 | |||
224 | case WL1271_SCAN_STATE_2GHZ_ACTIVE: | ||
225 | band = IEEE80211_BAND_2GHZ; | ||
226 | mask = wlvif->bitrate_masks[band]; | ||
227 | if (wl->scan.req->no_cck) { | ||
228 | mask &= ~CONF_TX_CCK_RATES; | ||
229 | if (!mask) | ||
230 | mask = CONF_TX_RATE_MASK_BASIC_P2P; | ||
231 | } | ||
232 | rate = wl1271_tx_min_rate_get(wl, mask); | ||
233 | ret = wl1271_scan_send(wl, wlvif, band, false, rate); | ||
234 | if (ret == WL1271_NOTHING_TO_SCAN) { | ||
235 | wl->scan.state = WL1271_SCAN_STATE_2GHZ_PASSIVE; | ||
236 | wl1271_scan_stm(wl, wlvif); | ||
237 | } | ||
238 | |||
239 | break; | ||
240 | |||
241 | case WL1271_SCAN_STATE_2GHZ_PASSIVE: | ||
242 | band = IEEE80211_BAND_2GHZ; | ||
243 | mask = wlvif->bitrate_masks[band]; | ||
244 | if (wl->scan.req->no_cck) { | ||
245 | mask &= ~CONF_TX_CCK_RATES; | ||
246 | if (!mask) | ||
247 | mask = CONF_TX_RATE_MASK_BASIC_P2P; | ||
248 | } | ||
249 | rate = wl1271_tx_min_rate_get(wl, mask); | ||
250 | ret = wl1271_scan_send(wl, wlvif, band, true, rate); | ||
251 | if (ret == WL1271_NOTHING_TO_SCAN) { | ||
252 | if (wl->enable_11a) | ||
253 | wl->scan.state = WL1271_SCAN_STATE_5GHZ_ACTIVE; | ||
254 | else | ||
255 | wl->scan.state = WL1271_SCAN_STATE_DONE; | ||
256 | wl1271_scan_stm(wl, wlvif); | ||
257 | } | ||
258 | |||
259 | break; | ||
260 | |||
261 | case WL1271_SCAN_STATE_5GHZ_ACTIVE: | ||
262 | band = IEEE80211_BAND_5GHZ; | ||
263 | rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]); | ||
264 | ret = wl1271_scan_send(wl, wlvif, band, false, rate); | ||
265 | if (ret == WL1271_NOTHING_TO_SCAN) { | ||
266 | wl->scan.state = WL1271_SCAN_STATE_5GHZ_PASSIVE; | ||
267 | wl1271_scan_stm(wl, wlvif); | ||
268 | } | ||
269 | |||
270 | break; | ||
271 | |||
272 | case WL1271_SCAN_STATE_5GHZ_PASSIVE: | ||
273 | band = IEEE80211_BAND_5GHZ; | ||
274 | rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]); | ||
275 | ret = wl1271_scan_send(wl, wlvif, band, true, rate); | ||
276 | if (ret == WL1271_NOTHING_TO_SCAN) { | ||
277 | wl->scan.state = WL1271_SCAN_STATE_DONE; | ||
278 | wl1271_scan_stm(wl, wlvif); | ||
279 | } | ||
280 | |||
281 | break; | ||
282 | |||
283 | case WL1271_SCAN_STATE_DONE: | ||
284 | wl->scan.failed = false; | ||
285 | cancel_delayed_work(&wl->scan_complete_work); | ||
286 | ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, | ||
287 | msecs_to_jiffies(0)); | ||
288 | break; | ||
289 | |||
290 | default: | ||
291 | wl1271_error("invalid scan state"); | ||
292 | break; | ||
293 | } | ||
294 | |||
295 | if (ret < 0) { | ||
296 | cancel_delayed_work(&wl->scan_complete_work); | ||
297 | ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, | ||
298 | msecs_to_jiffies(0)); | ||
299 | } | ||
300 | } | ||
301 | |||
302 | static void wl12xx_adjust_channels(struct wl1271_cmd_sched_scan_config *cmd, | ||
303 | struct wlcore_scan_channels *cmd_channels) | ||
304 | { | ||
305 | memcpy(cmd->passive, cmd_channels->passive, sizeof(cmd->passive)); | ||
306 | memcpy(cmd->active, cmd_channels->active, sizeof(cmd->active)); | ||
307 | cmd->dfs = cmd_channels->dfs; | ||
308 | cmd->n_pactive_ch = cmd_channels->passive_active; | ||
309 | |||
310 | memcpy(cmd->channels_2, cmd_channels->channels_2, | ||
311 | sizeof(cmd->channels_2)); | ||
312 | memcpy(cmd->channels_5, cmd_channels->channels_5, | ||
313 | sizeof(cmd->channels_2)); | ||
314 | /* channels_4 are not supported, so no need to copy them */ | ||
315 | } | ||
316 | |||
317 | int wl1271_scan_sched_scan_config(struct wl1271 *wl, | ||
318 | struct wl12xx_vif *wlvif, | ||
319 | struct cfg80211_sched_scan_request *req, | ||
320 | struct ieee80211_sched_scan_ies *ies) | ||
321 | { | ||
322 | struct wl1271_cmd_sched_scan_config *cfg = NULL; | ||
323 | struct wlcore_scan_channels *cfg_channels = NULL; | ||
324 | struct conf_sched_scan_settings *c = &wl->conf.sched_scan; | ||
325 | int i, ret; | ||
326 | bool force_passive = !req->n_ssids; | ||
327 | |||
328 | wl1271_debug(DEBUG_CMD, "cmd sched_scan scan config"); | ||
329 | |||
330 | cfg = kzalloc(sizeof(*cfg), GFP_KERNEL); | ||
331 | if (!cfg) | ||
332 | return -ENOMEM; | ||
333 | |||
334 | cfg->role_id = wlvif->role_id; | ||
335 | cfg->rssi_threshold = c->rssi_threshold; | ||
336 | cfg->snr_threshold = c->snr_threshold; | ||
337 | cfg->n_probe_reqs = c->num_probe_reqs; | ||
338 | /* cycles set to 0 it means infinite (until manually stopped) */ | ||
339 | cfg->cycles = 0; | ||
340 | /* report APs when at least 1 is found */ | ||
341 | cfg->report_after = 1; | ||
342 | /* don't stop scanning automatically when something is found */ | ||
343 | cfg->terminate = 0; | ||
344 | cfg->tag = WL1271_SCAN_DEFAULT_TAG; | ||
345 | /* don't filter on BSS type */ | ||
346 | cfg->bss_type = SCAN_BSS_TYPE_ANY; | ||
347 | /* currently NL80211 supports only a single interval */ | ||
348 | for (i = 0; i < SCAN_MAX_CYCLE_INTERVALS; i++) | ||
349 | cfg->intervals[i] = cpu_to_le32(req->interval); | ||
350 | |||
351 | cfg->ssid_len = 0; | ||
352 | ret = wlcore_scan_sched_scan_ssid_list(wl, wlvif, req); | ||
353 | if (ret < 0) | ||
354 | goto out; | ||
355 | |||
356 | cfg->filter_type = ret; | ||
357 | |||
358 | wl1271_debug(DEBUG_SCAN, "filter_type = %d", cfg->filter_type); | ||
359 | |||
360 | cfg_channels = kzalloc(sizeof(*cfg_channels), GFP_KERNEL); | ||
361 | if (!cfg_channels) { | ||
362 | ret = -ENOMEM; | ||
363 | goto out; | ||
364 | } | ||
365 | |||
366 | if (!wlcore_set_scan_chan_params(wl, cfg_channels, req->channels, | ||
367 | req->n_channels, req->n_ssids, | ||
368 | SCAN_TYPE_PERIODIC)) { | ||
369 | wl1271_error("scan channel list is empty"); | ||
370 | ret = -EINVAL; | ||
371 | goto out; | ||
372 | } | ||
373 | wl12xx_adjust_channels(cfg, cfg_channels); | ||
374 | |||
375 | if (!force_passive && cfg->active[0]) { | ||
376 | u8 band = IEEE80211_BAND_2GHZ; | ||
377 | ret = wl12xx_cmd_build_probe_req(wl, wlvif, | ||
378 | wlvif->role_id, band, | ||
379 | req->ssids[0].ssid, | ||
380 | req->ssids[0].ssid_len, | ||
381 | ies->ie[band], | ||
382 | ies->len[band], true); | ||
383 | if (ret < 0) { | ||
384 | wl1271_error("2.4GHz PROBE request template failed"); | ||
385 | goto out; | ||
386 | } | ||
387 | } | ||
388 | |||
389 | if (!force_passive && cfg->active[1]) { | ||
390 | u8 band = IEEE80211_BAND_5GHZ; | ||
391 | ret = wl12xx_cmd_build_probe_req(wl, wlvif, | ||
392 | wlvif->role_id, band, | ||
393 | req->ssids[0].ssid, | ||
394 | req->ssids[0].ssid_len, | ||
395 | ies->ie[band], | ||
396 | ies->len[band], true); | ||
397 | if (ret < 0) { | ||
398 | wl1271_error("5GHz PROBE request template failed"); | ||
399 | goto out; | ||
400 | } | ||
401 | } | ||
402 | |||
403 | wl1271_dump(DEBUG_SCAN, "SCAN_CFG: ", cfg, sizeof(*cfg)); | ||
404 | |||
405 | ret = wl1271_cmd_send(wl, CMD_CONNECTION_SCAN_CFG, cfg, | ||
406 | sizeof(*cfg), 0); | ||
407 | if (ret < 0) { | ||
408 | wl1271_error("SCAN configuration failed"); | ||
409 | goto out; | ||
410 | } | ||
411 | out: | ||
412 | kfree(cfg_channels); | ||
413 | kfree(cfg); | ||
414 | return ret; | ||
415 | } | ||
416 | |||
417 | int wl1271_scan_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif) | ||
418 | { | ||
419 | struct wl1271_cmd_sched_scan_start *start; | ||
420 | int ret = 0; | ||
421 | |||
422 | wl1271_debug(DEBUG_CMD, "cmd periodic scan start"); | ||
423 | |||
424 | if (wlvif->bss_type != BSS_TYPE_STA_BSS) | ||
425 | return -EOPNOTSUPP; | ||
426 | |||
427 | if ((wl->quirks & WLCORE_QUIRK_NO_SCHED_SCAN_WHILE_CONN) && | ||
428 | test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags)) | ||
429 | return -EBUSY; | ||
430 | |||
431 | start = kzalloc(sizeof(*start), GFP_KERNEL); | ||
432 | if (!start) | ||
433 | return -ENOMEM; | ||
434 | |||
435 | start->role_id = wlvif->role_id; | ||
436 | start->tag = WL1271_SCAN_DEFAULT_TAG; | ||
437 | |||
438 | ret = wl1271_cmd_send(wl, CMD_START_PERIODIC_SCAN, start, | ||
439 | sizeof(*start), 0); | ||
440 | if (ret < 0) { | ||
441 | wl1271_error("failed to send scan start command"); | ||
442 | goto out_free; | ||
443 | } | ||
444 | |||
445 | out_free: | ||
446 | kfree(start); | ||
447 | return ret; | ||
448 | } | ||
449 | |||
450 | int wl12xx_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
451 | struct cfg80211_sched_scan_request *req, | ||
452 | struct ieee80211_sched_scan_ies *ies) | ||
453 | { | ||
454 | int ret; | ||
455 | |||
456 | ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies); | ||
457 | if (ret < 0) | ||
458 | return ret; | ||
459 | |||
460 | return wl1271_scan_sched_scan_start(wl, wlvif); | ||
461 | } | ||
462 | |||
463 | void wl12xx_scan_sched_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif) | ||
464 | { | ||
465 | struct wl1271_cmd_sched_scan_stop *stop; | ||
466 | int ret = 0; | ||
467 | |||
468 | wl1271_debug(DEBUG_CMD, "cmd periodic scan stop"); | ||
469 | |||
470 | /* FIXME: what to do if alloc'ing to stop fails? */ | ||
471 | stop = kzalloc(sizeof(*stop), GFP_KERNEL); | ||
472 | if (!stop) { | ||
473 | wl1271_error("failed to alloc memory to send sched scan stop"); | ||
474 | return; | ||
475 | } | ||
476 | |||
477 | stop->role_id = wlvif->role_id; | ||
478 | stop->tag = WL1271_SCAN_DEFAULT_TAG; | ||
479 | |||
480 | ret = wl1271_cmd_send(wl, CMD_STOP_PERIODIC_SCAN, stop, | ||
481 | sizeof(*stop), 0); | ||
482 | if (ret < 0) { | ||
483 | wl1271_error("failed to send sched scan stop command"); | ||
484 | goto out_free; | ||
485 | } | ||
486 | |||
487 | out_free: | ||
488 | kfree(stop); | ||
489 | } | ||
490 | |||
491 | int wl12xx_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
492 | struct cfg80211_scan_request *req) | ||
493 | { | ||
494 | wl1271_scan_stm(wl, wlvif); | ||
495 | return 0; | ||
496 | } | ||
497 | |||
498 | void wl12xx_scan_completed(struct wl1271 *wl, struct wl12xx_vif *wlvif) | ||
499 | { | ||
500 | wl1271_scan_stm(wl, wlvif); | ||
501 | } | ||
diff --git a/drivers/net/wireless/ti/wl12xx/scan.h b/drivers/net/wireless/ti/wl12xx/scan.h new file mode 100644 index 000000000000..264af7ac2785 --- /dev/null +++ b/drivers/net/wireless/ti/wl12xx/scan.h | |||
@@ -0,0 +1,140 @@ | |||
1 | /* | ||
2 | * This file is part of wl12xx | ||
3 | * | ||
4 | * Copyright (C) 2012 Texas Instruments. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * version 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
18 | * 02110-1301 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #ifndef __WL12XX_SCAN_H__ | ||
23 | #define __WL12XX_SCAN_H__ | ||
24 | |||
25 | #include "../wlcore/wlcore.h" | ||
26 | #include "../wlcore/cmd.h" | ||
27 | #include "../wlcore/scan.h" | ||
28 | |||
29 | #define WL12XX_MAX_CHANNELS_5GHZ 23 | ||
30 | |||
31 | struct basic_scan_params { | ||
32 | /* Scan option flags (WL1271_SCAN_OPT_*) */ | ||
33 | __le16 scan_options; | ||
34 | u8 role_id; | ||
35 | /* Number of scan channels in the list (maximum 30) */ | ||
36 | u8 n_ch; | ||
37 | /* This field indicates the number of probe requests to send | ||
38 | per channel for an active scan */ | ||
39 | u8 n_probe_reqs; | ||
40 | u8 tid_trigger; | ||
41 | u8 ssid_len; | ||
42 | u8 use_ssid_list; | ||
43 | |||
44 | /* Rate bit field for sending the probes */ | ||
45 | __le32 tx_rate; | ||
46 | |||
47 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | ||
48 | /* Band to scan */ | ||
49 | u8 band; | ||
50 | |||
51 | u8 scan_tag; | ||
52 | u8 padding2[2]; | ||
53 | } __packed; | ||
54 | |||
55 | struct basic_scan_channel_params { | ||
56 | /* Duration in TU to wait for frames on a channel for active scan */ | ||
57 | __le32 min_duration; | ||
58 | __le32 max_duration; | ||
59 | __le32 bssid_lsb; | ||
60 | __le16 bssid_msb; | ||
61 | u8 early_termination; | ||
62 | u8 tx_power_att; | ||
63 | u8 channel; | ||
64 | /* FW internal use only! */ | ||
65 | u8 dfs_candidate; | ||
66 | u8 activity_detected; | ||
67 | u8 pad; | ||
68 | } __packed; | ||
69 | |||
70 | struct wl1271_cmd_scan { | ||
71 | struct wl1271_cmd_header header; | ||
72 | |||
73 | struct basic_scan_params params; | ||
74 | struct basic_scan_channel_params channels[WL1271_SCAN_MAX_CHANNELS]; | ||
75 | |||
76 | /* src mac address */ | ||
77 | u8 addr[ETH_ALEN]; | ||
78 | u8 padding[2]; | ||
79 | } __packed; | ||
80 | |||
81 | struct wl1271_cmd_sched_scan_config { | ||
82 | struct wl1271_cmd_header header; | ||
83 | |||
84 | __le32 intervals[SCAN_MAX_CYCLE_INTERVALS]; | ||
85 | |||
86 | s8 rssi_threshold; /* for filtering (in dBm) */ | ||
87 | s8 snr_threshold; /* for filtering (in dB) */ | ||
88 | |||
89 | u8 cycles; /* maximum number of scan cycles */ | ||
90 | u8 report_after; /* report when this number of results are received */ | ||
91 | u8 terminate; /* stop scanning after reporting */ | ||
92 | |||
93 | u8 tag; | ||
94 | u8 bss_type; /* for filtering */ | ||
95 | u8 filter_type; | ||
96 | |||
97 | u8 ssid_len; /* For SCAN_SSID_FILTER_SPECIFIC */ | ||
98 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | ||
99 | |||
100 | u8 n_probe_reqs; /* Number of probes requests per channel */ | ||
101 | |||
102 | u8 passive[SCAN_MAX_BANDS]; | ||
103 | u8 active[SCAN_MAX_BANDS]; | ||
104 | |||
105 | u8 dfs; | ||
106 | |||
107 | u8 n_pactive_ch; /* number of pactive (passive until fw detects energy) | ||
108 | channels in BG band */ | ||
109 | u8 role_id; | ||
110 | u8 padding[1]; | ||
111 | struct conn_scan_ch_params channels_2[MAX_CHANNELS_2GHZ]; | ||
112 | struct conn_scan_ch_params channels_5[WL12XX_MAX_CHANNELS_5GHZ]; | ||
113 | struct conn_scan_ch_params channels_4[MAX_CHANNELS_4GHZ]; | ||
114 | } __packed; | ||
115 | |||
116 | struct wl1271_cmd_sched_scan_start { | ||
117 | struct wl1271_cmd_header header; | ||
118 | |||
119 | u8 tag; | ||
120 | u8 role_id; | ||
121 | u8 padding[2]; | ||
122 | } __packed; | ||
123 | |||
124 | struct wl1271_cmd_sched_scan_stop { | ||
125 | struct wl1271_cmd_header header; | ||
126 | |||
127 | u8 tag; | ||
128 | u8 role_id; | ||
129 | u8 padding[2]; | ||
130 | } __packed; | ||
131 | |||
132 | int wl12xx_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
133 | struct cfg80211_scan_request *req); | ||
134 | int wl12xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif); | ||
135 | void wl12xx_scan_completed(struct wl1271 *wl, struct wl12xx_vif *wlvif); | ||
136 | int wl12xx_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
137 | struct cfg80211_sched_scan_request *req, | ||
138 | struct ieee80211_sched_scan_ies *ies); | ||
139 | void wl12xx_scan_sched_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif); | ||
140 | #endif | ||
diff --git a/drivers/net/wireless/ti/wl12xx/wl12xx.h b/drivers/net/wireless/ti/wl12xx/wl12xx.h index 7182bbf6625d..d4552857480c 100644 --- a/drivers/net/wireless/ti/wl12xx/wl12xx.h +++ b/drivers/net/wireless/ti/wl12xx/wl12xx.h | |||
@@ -24,19 +24,37 @@ | |||
24 | 24 | ||
25 | #include "conf.h" | 25 | #include "conf.h" |
26 | 26 | ||
27 | /* minimum FW required for driver for wl127x */ | 27 | /* WiLink 6/7 chip IDs */ |
28 | #define CHIP_ID_127X_PG10 (0x04030101) | ||
29 | #define CHIP_ID_127X_PG20 (0x04030111) | ||
30 | #define CHIP_ID_128X_PG10 (0x05030101) | ||
31 | #define CHIP_ID_128X_PG20 (0x05030111) | ||
32 | |||
33 | /* FW chip version for wl127x */ | ||
28 | #define WL127X_CHIP_VER 6 | 34 | #define WL127X_CHIP_VER 6 |
29 | #define WL127X_IFTYPE_VER 3 | 35 | /* minimum single-role FW version for wl127x */ |
30 | #define WL127X_MAJOR_VER 10 | 36 | #define WL127X_IFTYPE_SR_VER 3 |
31 | #define WL127X_SUBTYPE_VER 2 | 37 | #define WL127X_MAJOR_SR_VER 10 |
32 | #define WL127X_MINOR_VER 115 | 38 | #define WL127X_SUBTYPE_SR_VER WLCORE_FW_VER_IGNORE |
39 | #define WL127X_MINOR_SR_VER 115 | ||
40 | /* minimum multi-role FW version for wl127x */ | ||
41 | #define WL127X_IFTYPE_MR_VER 5 | ||
42 | #define WL127X_MAJOR_MR_VER 7 | ||
43 | #define WL127X_SUBTYPE_MR_VER WLCORE_FW_VER_IGNORE | ||
44 | #define WL127X_MINOR_MR_VER 115 | ||
33 | 45 | ||
34 | /* minimum FW required for driver for wl128x */ | 46 | /* FW chip version for wl128x */ |
35 | #define WL128X_CHIP_VER 7 | 47 | #define WL128X_CHIP_VER 7 |
36 | #define WL128X_IFTYPE_VER 3 | 48 | /* minimum single-role FW version for wl128x */ |
37 | #define WL128X_MAJOR_VER 10 | 49 | #define WL128X_IFTYPE_SR_VER 3 |
38 | #define WL128X_SUBTYPE_VER 2 | 50 | #define WL128X_MAJOR_SR_VER 10 |
39 | #define WL128X_MINOR_VER 115 | 51 | #define WL128X_SUBTYPE_SR_VER WLCORE_FW_VER_IGNORE |
52 | #define WL128X_MINOR_SR_VER 115 | ||
53 | /* minimum multi-role FW version for wl128x */ | ||
54 | #define WL128X_IFTYPE_MR_VER 5 | ||
55 | #define WL128X_MAJOR_MR_VER 7 | ||
56 | #define WL128X_SUBTYPE_MR_VER WLCORE_FW_VER_IGNORE | ||
57 | #define WL128X_MINOR_MR_VER 42 | ||
40 | 58 | ||
41 | #define WL12XX_AGGR_BUFFER_SIZE (4 * PAGE_SIZE) | 59 | #define WL12XX_AGGR_BUFFER_SIZE (4 * PAGE_SIZE) |
42 | 60 | ||
@@ -55,6 +73,8 @@ struct wl12xx_priv { | |||
55 | 73 | ||
56 | int ref_clock; | 74 | int ref_clock; |
57 | int tcxo_clock; | 75 | int tcxo_clock; |
76 | |||
77 | struct wl127x_rx_mem_pool_addr *rx_mem_addr; | ||
58 | }; | 78 | }; |
59 | 79 | ||
60 | #endif /* __WL12XX_PRIV_H__ */ | 80 | #endif /* __WL12XX_PRIV_H__ */ |
diff --git a/drivers/net/wireless/ti/wl18xx/Makefile b/drivers/net/wireless/ti/wl18xx/Makefile index 67c098734c7f..ae2b81735785 100644 --- a/drivers/net/wireless/ti/wl18xx/Makefile +++ b/drivers/net/wireless/ti/wl18xx/Makefile | |||
@@ -1,3 +1,3 @@ | |||
1 | wl18xx-objs = main.o acx.o tx.o io.o debugfs.o | 1 | wl18xx-objs = main.o acx.o tx.o io.o debugfs.o scan.o cmd.o event.o |
2 | 2 | ||
3 | obj-$(CONFIG_WL18XX) += wl18xx.o | 3 | obj-$(CONFIG_WL18XX) += wl18xx.o |
diff --git a/drivers/net/wireless/ti/wl18xx/acx.c b/drivers/net/wireless/ti/wl18xx/acx.c index 72840e23bf59..a169bb5a5dbf 100644 --- a/drivers/net/wireless/ti/wl18xx/acx.c +++ b/drivers/net/wireless/ti/wl18xx/acx.c | |||
@@ -75,7 +75,7 @@ int wl18xx_acx_set_checksum_state(struct wl1271 *wl) | |||
75 | 75 | ||
76 | acx->checksum_state = CHECKSUM_OFFLOAD_ENABLED; | 76 | acx->checksum_state = CHECKSUM_OFFLOAD_ENABLED; |
77 | 77 | ||
78 | ret = wl1271_cmd_configure(wl, ACX_CHECKSUM_CONFIG, acx, sizeof(*acx)); | 78 | ret = wl1271_cmd_configure(wl, ACX_CSUM_CONFIG, acx, sizeof(*acx)); |
79 | if (ret < 0) { | 79 | if (ret < 0) { |
80 | wl1271_warning("failed to set Tx checksum state: %d", ret); | 80 | wl1271_warning("failed to set Tx checksum state: %d", ret); |
81 | goto out; | 81 | goto out; |
@@ -109,3 +109,88 @@ out: | |||
109 | kfree(acx); | 109 | kfree(acx); |
110 | return ret; | 110 | return ret; |
111 | } | 111 | } |
112 | |||
113 | int wl18xx_acx_peer_ht_operation_mode(struct wl1271 *wl, u8 hlid, bool wide) | ||
114 | { | ||
115 | struct wlcore_peer_ht_operation_mode *acx; | ||
116 | int ret; | ||
117 | |||
118 | wl1271_debug(DEBUG_ACX, "acx peer ht operation mode hlid %d bw %d", | ||
119 | hlid, wide); | ||
120 | |||
121 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
122 | if (!acx) { | ||
123 | ret = -ENOMEM; | ||
124 | goto out; | ||
125 | } | ||
126 | |||
127 | acx->hlid = hlid; | ||
128 | acx->bandwidth = wide ? WLCORE_BANDWIDTH_40MHZ : WLCORE_BANDWIDTH_20MHZ; | ||
129 | |||
130 | ret = wl1271_cmd_configure(wl, ACX_PEER_HT_OPERATION_MODE_CFG, acx, | ||
131 | sizeof(*acx)); | ||
132 | |||
133 | if (ret < 0) { | ||
134 | wl1271_warning("acx peer ht operation mode failed: %d", ret); | ||
135 | goto out; | ||
136 | } | ||
137 | |||
138 | out: | ||
139 | kfree(acx); | ||
140 | return ret; | ||
141 | |||
142 | } | ||
143 | |||
144 | /* | ||
145 | * this command is basically the same as wl1271_acx_ht_capabilities, | ||
146 | * with the addition of supported rates. they should be unified in | ||
147 | * the next fw api change | ||
148 | */ | ||
149 | int wl18xx_acx_set_peer_cap(struct wl1271 *wl, | ||
150 | struct ieee80211_sta_ht_cap *ht_cap, | ||
151 | bool allow_ht_operation, | ||
152 | u32 rate_set, u8 hlid) | ||
153 | { | ||
154 | struct wlcore_acx_peer_cap *acx; | ||
155 | int ret = 0; | ||
156 | u32 ht_capabilites = 0; | ||
157 | |||
158 | wl1271_debug(DEBUG_ACX, | ||
159 | "acx set cap ht_supp: %d ht_cap: %d rates: 0x%x", | ||
160 | ht_cap->ht_supported, ht_cap->cap, rate_set); | ||
161 | |||
162 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
163 | if (!acx) { | ||
164 | ret = -ENOMEM; | ||
165 | goto out; | ||
166 | } | ||
167 | |||
168 | if (allow_ht_operation && ht_cap->ht_supported) { | ||
169 | /* no need to translate capabilities - use the spec values */ | ||
170 | ht_capabilites = ht_cap->cap; | ||
171 | |||
172 | /* | ||
173 | * this bit is not employed by the spec but only by FW to | ||
174 | * indicate peer HT support | ||
175 | */ | ||
176 | ht_capabilites |= WL12XX_HT_CAP_HT_OPERATION; | ||
177 | |||
178 | /* get data from A-MPDU parameters field */ | ||
179 | acx->ampdu_max_length = ht_cap->ampdu_factor; | ||
180 | acx->ampdu_min_spacing = ht_cap->ampdu_density; | ||
181 | } | ||
182 | |||
183 | acx->hlid = hlid; | ||
184 | acx->ht_capabilites = cpu_to_le32(ht_capabilites); | ||
185 | acx->supported_rates = cpu_to_le32(rate_set); | ||
186 | |||
187 | ret = wl1271_cmd_configure(wl, ACX_PEER_CAP, acx, sizeof(*acx)); | ||
188 | if (ret < 0) { | ||
189 | wl1271_warning("acx ht capabilities setting failed: %d", ret); | ||
190 | goto out; | ||
191 | } | ||
192 | |||
193 | out: | ||
194 | kfree(acx); | ||
195 | return ret; | ||
196 | } | ||
diff --git a/drivers/net/wireless/ti/wl18xx/acx.h b/drivers/net/wireless/ti/wl18xx/acx.h index e2609a6b7341..0e636def1217 100644 --- a/drivers/net/wireless/ti/wl18xx/acx.h +++ b/drivers/net/wireless/ti/wl18xx/acx.h | |||
@@ -26,7 +26,13 @@ | |||
26 | #include "../wlcore/acx.h" | 26 | #include "../wlcore/acx.h" |
27 | 27 | ||
28 | enum { | 28 | enum { |
29 | ACX_CLEAR_STATISTICS = 0x0047, | 29 | ACX_NS_IPV6_FILTER = 0x0050, |
30 | ACX_PEER_HT_OPERATION_MODE_CFG = 0x0051, | ||
31 | ACX_CSUM_CONFIG = 0x0052, | ||
32 | ACX_SIM_CONFIG = 0x0053, | ||
33 | ACX_CLEAR_STATISTICS = 0x0054, | ||
34 | ACX_AUTO_RX_STREAMING = 0x0055, | ||
35 | ACX_PEER_CAP = 0x0056 | ||
30 | }; | 36 | }; |
31 | 37 | ||
32 | /* numbers of bits the length field takes (add 1 for the actual number) */ | 38 | /* numbers of bits the length field takes (add 1 for the actual number) */ |
@@ -278,10 +284,57 @@ struct wl18xx_acx_clear_statistics { | |||
278 | struct acx_header header; | 284 | struct acx_header header; |
279 | }; | 285 | }; |
280 | 286 | ||
287 | enum wlcore_bandwidth { | ||
288 | WLCORE_BANDWIDTH_20MHZ, | ||
289 | WLCORE_BANDWIDTH_40MHZ, | ||
290 | }; | ||
291 | |||
292 | struct wlcore_peer_ht_operation_mode { | ||
293 | struct acx_header header; | ||
294 | |||
295 | u8 hlid; | ||
296 | u8 bandwidth; /* enum wlcore_bandwidth */ | ||
297 | u8 padding[2]; | ||
298 | }; | ||
299 | |||
300 | /* | ||
301 | * ACX_PEER_CAP | ||
302 | * this struct is very similar to wl1271_acx_ht_capabilities, with the | ||
303 | * addition of supported rates | ||
304 | */ | ||
305 | struct wlcore_acx_peer_cap { | ||
306 | struct acx_header header; | ||
307 | |||
308 | /* bitmask of capability bits supported by the peer */ | ||
309 | __le32 ht_capabilites; | ||
310 | |||
311 | /* rates supported by the remote peer */ | ||
312 | __le32 supported_rates; | ||
313 | |||
314 | /* Indicates to which link these capabilities apply. */ | ||
315 | u8 hlid; | ||
316 | |||
317 | /* | ||
318 | * This the maximum A-MPDU length supported by the AP. The FW may not | ||
319 | * exceed this length when sending A-MPDUs | ||
320 | */ | ||
321 | u8 ampdu_max_length; | ||
322 | |||
323 | /* This is the minimal spacing required when sending A-MPDUs to the AP*/ | ||
324 | u8 ampdu_min_spacing; | ||
325 | |||
326 | u8 padding; | ||
327 | } __packed; | ||
328 | |||
281 | int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap, | 329 | int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap, |
282 | u32 sdio_blk_size, u32 extra_mem_blks, | 330 | u32 sdio_blk_size, u32 extra_mem_blks, |
283 | u32 len_field_size); | 331 | u32 len_field_size); |
284 | int wl18xx_acx_set_checksum_state(struct wl1271 *wl); | 332 | int wl18xx_acx_set_checksum_state(struct wl1271 *wl); |
285 | int wl18xx_acx_clear_statistics(struct wl1271 *wl); | 333 | int wl18xx_acx_clear_statistics(struct wl1271 *wl); |
334 | int wl18xx_acx_peer_ht_operation_mode(struct wl1271 *wl, u8 hlid, bool wide); | ||
335 | int wl18xx_acx_set_peer_cap(struct wl1271 *wl, | ||
336 | struct ieee80211_sta_ht_cap *ht_cap, | ||
337 | bool allow_ht_operation, | ||
338 | u32 rate_set, u8 hlid); | ||
286 | 339 | ||
287 | #endif /* __WL18XX_ACX_H__ */ | 340 | #endif /* __WL18XX_ACX_H__ */ |
diff --git a/drivers/net/wireless/ti/wl18xx/cmd.c b/drivers/net/wireless/ti/wl18xx/cmd.c new file mode 100644 index 000000000000..1d1f6cc7a50a --- /dev/null +++ b/drivers/net/wireless/ti/wl18xx/cmd.c | |||
@@ -0,0 +1,80 @@ | |||
1 | /* | ||
2 | * This file is part of wl18xx | ||
3 | * | ||
4 | * Copyright (C) 2011 Texas Instruments Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * version 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
18 | * 02110-1301 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include "../wlcore/cmd.h" | ||
23 | #include "../wlcore/debug.h" | ||
24 | #include "../wlcore/hw_ops.h" | ||
25 | |||
26 | #include "cmd.h" | ||
27 | |||
28 | int wl18xx_cmd_channel_switch(struct wl1271 *wl, | ||
29 | struct wl12xx_vif *wlvif, | ||
30 | struct ieee80211_channel_switch *ch_switch) | ||
31 | { | ||
32 | struct wl18xx_cmd_channel_switch *cmd; | ||
33 | u32 supported_rates; | ||
34 | int ret; | ||
35 | |||
36 | wl1271_debug(DEBUG_ACX, "cmd channel switch"); | ||
37 | |||
38 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
39 | if (!cmd) { | ||
40 | ret = -ENOMEM; | ||
41 | goto out; | ||
42 | } | ||
43 | |||
44 | cmd->role_id = wlvif->role_id; | ||
45 | cmd->channel = ch_switch->channel->hw_value; | ||
46 | cmd->switch_time = ch_switch->count; | ||
47 | cmd->stop_tx = ch_switch->block_tx; | ||
48 | |||
49 | switch (ch_switch->channel->band) { | ||
50 | case IEEE80211_BAND_2GHZ: | ||
51 | cmd->band = WLCORE_BAND_2_4GHZ; | ||
52 | break; | ||
53 | case IEEE80211_BAND_5GHZ: | ||
54 | cmd->band = WLCORE_BAND_5GHZ; | ||
55 | break; | ||
56 | default: | ||
57 | wl1271_error("invalid channel switch band: %d", | ||
58 | ch_switch->channel->band); | ||
59 | ret = -EINVAL; | ||
60 | goto out_free; | ||
61 | } | ||
62 | |||
63 | supported_rates = CONF_TX_ENABLED_RATES | CONF_TX_MCS_RATES | | ||
64 | wlcore_hw_sta_get_ap_rate_mask(wl, wlvif); | ||
65 | if (wlvif->p2p) | ||
66 | supported_rates &= ~CONF_TX_CCK_RATES; | ||
67 | cmd->local_supported_rates = cpu_to_le32(supported_rates); | ||
68 | cmd->channel_type = wlvif->channel_type; | ||
69 | |||
70 | ret = wl1271_cmd_send(wl, CMD_CHANNEL_SWITCH, cmd, sizeof(*cmd), 0); | ||
71 | if (ret < 0) { | ||
72 | wl1271_error("failed to send channel switch command"); | ||
73 | goto out_free; | ||
74 | } | ||
75 | |||
76 | out_free: | ||
77 | kfree(cmd); | ||
78 | out: | ||
79 | return ret; | ||
80 | } | ||
diff --git a/drivers/net/wireless/ti/wl18xx/cmd.h b/drivers/net/wireless/ti/wl18xx/cmd.h new file mode 100644 index 000000000000..6687d10899ac --- /dev/null +++ b/drivers/net/wireless/ti/wl18xx/cmd.h | |||
@@ -0,0 +1,52 @@ | |||
1 | /* | ||
2 | * This file is part of wl18xx | ||
3 | * | ||
4 | * Copyright (C) 2011 Texas Instruments. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * version 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
18 | * 02110-1301 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #ifndef __WL18XX_CMD_H__ | ||
23 | #define __WL18XX_CMD_H__ | ||
24 | |||
25 | #include "../wlcore/wlcore.h" | ||
26 | #include "../wlcore/acx.h" | ||
27 | |||
28 | struct wl18xx_cmd_channel_switch { | ||
29 | struct wl1271_cmd_header header; | ||
30 | |||
31 | u8 role_id; | ||
32 | |||
33 | /* The new serving channel */ | ||
34 | u8 channel; | ||
35 | /* Relative time of the serving channel switch in TBTT units */ | ||
36 | u8 switch_time; | ||
37 | /* Stop the role TX, should expect it after radar detection */ | ||
38 | u8 stop_tx; | ||
39 | |||
40 | __le32 local_supported_rates; | ||
41 | |||
42 | u8 channel_type; | ||
43 | u8 band; | ||
44 | |||
45 | u8 padding[2]; | ||
46 | } __packed; | ||
47 | |||
48 | int wl18xx_cmd_channel_switch(struct wl1271 *wl, | ||
49 | struct wl12xx_vif *wlvif, | ||
50 | struct ieee80211_channel_switch *ch_switch); | ||
51 | |||
52 | #endif | ||
diff --git a/drivers/net/wireless/ti/wl18xx/conf.h b/drivers/net/wireless/ti/wl18xx/conf.h index 4d426cc20274..b5f114857191 100644 --- a/drivers/net/wireless/ti/wl18xx/conf.h +++ b/drivers/net/wireless/ti/wl18xx/conf.h | |||
@@ -23,20 +23,21 @@ | |||
23 | #define __WL18XX_CONF_H__ | 23 | #define __WL18XX_CONF_H__ |
24 | 24 | ||
25 | #define WL18XX_CONF_MAGIC 0x10e100ca | 25 | #define WL18XX_CONF_MAGIC 0x10e100ca |
26 | #define WL18XX_CONF_VERSION (WLCORE_CONF_VERSION | 0x0003) | 26 | #define WL18XX_CONF_VERSION (WLCORE_CONF_VERSION | 0x0005) |
27 | #define WL18XX_CONF_MASK 0x0000ffff | 27 | #define WL18XX_CONF_MASK 0x0000ffff |
28 | #define WL18XX_CONF_SIZE (WLCORE_CONF_SIZE + \ | 28 | #define WL18XX_CONF_SIZE (WLCORE_CONF_SIZE + \ |
29 | sizeof(struct wl18xx_priv_conf)) | 29 | sizeof(struct wl18xx_priv_conf)) |
30 | 30 | ||
31 | #define NUM_OF_CHANNELS_11_ABG 150 | 31 | #define NUM_OF_CHANNELS_11_ABG 150 |
32 | #define NUM_OF_CHANNELS_11_P 7 | 32 | #define NUM_OF_CHANNELS_11_P 7 |
33 | #define WL18XX_NUM_OF_SUB_BANDS 9 | ||
34 | #define SRF_TABLE_LEN 16 | 33 | #define SRF_TABLE_LEN 16 |
35 | #define PIN_MUXING_SIZE 2 | 34 | #define PIN_MUXING_SIZE 2 |
35 | #define WL18XX_TRACE_LOSS_GAPS_TX 10 | ||
36 | #define WL18XX_TRACE_LOSS_GAPS_RX 18 | ||
36 | 37 | ||
37 | struct wl18xx_mac_and_phy_params { | 38 | struct wl18xx_mac_and_phy_params { |
38 | u8 phy_standalone; | 39 | u8 phy_standalone; |
39 | u8 rdl; | 40 | u8 spare0; |
40 | u8 enable_clpc; | 41 | u8 enable_clpc; |
41 | u8 enable_tx_low_pwr_on_siso_rdl; | 42 | u8 enable_tx_low_pwr_on_siso_rdl; |
42 | u8 auto_detect; | 43 | u8 auto_detect; |
@@ -69,18 +70,26 @@ struct wl18xx_mac_and_phy_params { | |||
69 | u8 pwr_limit_reference_11_abg; | 70 | u8 pwr_limit_reference_11_abg; |
70 | u8 per_chan_pwr_limit_arr_11p[NUM_OF_CHANNELS_11_P]; | 71 | u8 per_chan_pwr_limit_arr_11p[NUM_OF_CHANNELS_11_P]; |
71 | u8 pwr_limit_reference_11p; | 72 | u8 pwr_limit_reference_11p; |
72 | u8 per_sub_band_tx_trace_loss[WL18XX_NUM_OF_SUB_BANDS]; | 73 | u8 spare1[9]; |
73 | u8 per_sub_band_rx_trace_loss[WL18XX_NUM_OF_SUB_BANDS]; | 74 | u8 spare2[9]; |
74 | u8 primary_clock_setting_time; | 75 | u8 primary_clock_setting_time; |
75 | u8 clock_valid_on_wake_up; | 76 | u8 clock_valid_on_wake_up; |
76 | u8 secondary_clock_setting_time; | 77 | u8 secondary_clock_setting_time; |
77 | u8 board_type; | 78 | u8 board_type; |
78 | /* enable point saturation */ | 79 | /* enable point saturation */ |
79 | u8 psat; | 80 | u8 psat; |
80 | /* low/medium/high Tx power in dBm */ | 81 | /* low/medium/high Tx power in dBm for STA-HP BG */ |
81 | s8 low_power_val; | 82 | s8 low_power_val; |
82 | s8 med_power_val; | 83 | s8 med_power_val; |
83 | s8 high_power_val; | 84 | s8 high_power_val; |
85 | s8 per_sub_band_tx_trace_loss[WL18XX_TRACE_LOSS_GAPS_TX]; | ||
86 | s8 per_sub_band_rx_trace_loss[WL18XX_TRACE_LOSS_GAPS_RX]; | ||
87 | u8 tx_rf_margin; | ||
88 | /* low/medium/high Tx power in dBm for other role */ | ||
89 | s8 low_power_val_2nd; | ||
90 | s8 med_power_val_2nd; | ||
91 | s8 high_power_val_2nd; | ||
92 | |||
84 | u8 padding[1]; | 93 | u8 padding[1]; |
85 | } __packed; | 94 | } __packed; |
86 | 95 | ||
diff --git a/drivers/net/wireless/ti/wl18xx/event.c b/drivers/net/wireless/ti/wl18xx/event.c new file mode 100644 index 000000000000..c9199d7804c6 --- /dev/null +++ b/drivers/net/wireless/ti/wl18xx/event.c | |||
@@ -0,0 +1,111 @@ | |||
1 | /* | ||
2 | * This file is part of wl12xx | ||
3 | * | ||
4 | * Copyright (C) 2012 Texas Instruments. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * version 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
18 | * 02110-1301 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include "event.h" | ||
23 | #include "scan.h" | ||
24 | #include "../wlcore/cmd.h" | ||
25 | #include "../wlcore/debug.h" | ||
26 | |||
27 | int wl18xx_wait_for_event(struct wl1271 *wl, enum wlcore_wait_event event, | ||
28 | bool *timeout) | ||
29 | { | ||
30 | u32 local_event; | ||
31 | |||
32 | switch (event) { | ||
33 | case WLCORE_EVENT_PEER_REMOVE_COMPLETE: | ||
34 | local_event = PEER_REMOVE_COMPLETE_EVENT_ID; | ||
35 | break; | ||
36 | |||
37 | case WLCORE_EVENT_DFS_CONFIG_COMPLETE: | ||
38 | local_event = DFS_CHANNELS_CONFIG_COMPLETE_EVENT; | ||
39 | break; | ||
40 | |||
41 | default: | ||
42 | /* event not implemented */ | ||
43 | return 0; | ||
44 | } | ||
45 | return wlcore_cmd_wait_for_event_or_timeout(wl, local_event, timeout); | ||
46 | } | ||
47 | |||
48 | int wl18xx_process_mailbox_events(struct wl1271 *wl) | ||
49 | { | ||
50 | struct wl18xx_event_mailbox *mbox = wl->mbox; | ||
51 | u32 vector; | ||
52 | |||
53 | vector = le32_to_cpu(mbox->events_vector); | ||
54 | wl1271_debug(DEBUG_EVENT, "MBOX vector: 0x%x", vector); | ||
55 | |||
56 | if (vector & SCAN_COMPLETE_EVENT_ID) { | ||
57 | wl1271_debug(DEBUG_EVENT, "scan results: %d", | ||
58 | mbox->number_of_scan_results); | ||
59 | |||
60 | if (wl->scan_wlvif) | ||
61 | wl18xx_scan_completed(wl, wl->scan_wlvif); | ||
62 | } | ||
63 | |||
64 | if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) { | ||
65 | wl1271_debug(DEBUG_EVENT, | ||
66 | "PERIODIC_SCAN_REPORT_EVENT (results %d)", | ||
67 | mbox->number_of_sched_scan_results); | ||
68 | |||
69 | wlcore_scan_sched_scan_results(wl); | ||
70 | } | ||
71 | |||
72 | if (vector & PERIODIC_SCAN_COMPLETE_EVENT_ID) | ||
73 | wlcore_event_sched_scan_completed(wl, 1); | ||
74 | |||
75 | if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) | ||
76 | wlcore_event_rssi_trigger(wl, mbox->rssi_snr_trigger_metric); | ||
77 | |||
78 | if (vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID) | ||
79 | wlcore_event_ba_rx_constraint(wl, | ||
80 | le16_to_cpu(mbox->rx_ba_role_id_bitmap), | ||
81 | le16_to_cpu(mbox->rx_ba_allowed_bitmap)); | ||
82 | |||
83 | if (vector & BSS_LOSS_EVENT_ID) | ||
84 | wlcore_event_beacon_loss(wl, | ||
85 | le16_to_cpu(mbox->bss_loss_bitmap)); | ||
86 | |||
87 | if (vector & CHANNEL_SWITCH_COMPLETE_EVENT_ID) | ||
88 | wlcore_event_channel_switch(wl, | ||
89 | le16_to_cpu(mbox->channel_switch_role_id_bitmap), | ||
90 | true); | ||
91 | |||
92 | if (vector & DUMMY_PACKET_EVENT_ID) | ||
93 | wlcore_event_dummy_packet(wl); | ||
94 | |||
95 | /* | ||
96 | * "TX retries exceeded" has a different meaning according to mode. | ||
97 | * In AP mode the offending station is disconnected. | ||
98 | */ | ||
99 | if (vector & MAX_TX_FAILURE_EVENT_ID) | ||
100 | wlcore_event_max_tx_failure(wl, | ||
101 | le32_to_cpu(mbox->tx_retry_exceeded_bitmap)); | ||
102 | |||
103 | if (vector & INACTIVE_STA_EVENT_ID) | ||
104 | wlcore_event_inactive_sta(wl, | ||
105 | le32_to_cpu(mbox->inactive_sta_bitmap)); | ||
106 | |||
107 | if (vector & REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID) | ||
108 | wlcore_event_roc_complete(wl); | ||
109 | |||
110 | return 0; | ||
111 | } | ||
diff --git a/drivers/net/wireless/ti/wl18xx/event.h b/drivers/net/wireless/ti/wl18xx/event.h new file mode 100644 index 000000000000..398f3d2c0a6c --- /dev/null +++ b/drivers/net/wireless/ti/wl18xx/event.h | |||
@@ -0,0 +1,77 @@ | |||
1 | /* | ||
2 | * This file is part of wl18xx | ||
3 | * | ||
4 | * Copyright (C) 2012 Texas Instruments. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * version 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
18 | * 02110-1301 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #ifndef __WL18XX_EVENT_H__ | ||
23 | #define __WL18XX_EVENT_H__ | ||
24 | |||
25 | #include "../wlcore/wlcore.h" | ||
26 | |||
27 | enum { | ||
28 | SCAN_COMPLETE_EVENT_ID = BIT(8), | ||
29 | RADAR_DETECTED_EVENT_ID = BIT(9), | ||
30 | CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(10), | ||
31 | BSS_LOSS_EVENT_ID = BIT(11), | ||
32 | MAX_TX_FAILURE_EVENT_ID = BIT(12), | ||
33 | DUMMY_PACKET_EVENT_ID = BIT(13), | ||
34 | INACTIVE_STA_EVENT_ID = BIT(14), | ||
35 | PEER_REMOVE_COMPLETE_EVENT_ID = BIT(15), | ||
36 | PERIODIC_SCAN_COMPLETE_EVENT_ID = BIT(16), | ||
37 | BA_SESSION_RX_CONSTRAINT_EVENT_ID = BIT(17), | ||
38 | REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID = BIT(18), | ||
39 | DFS_CHANNELS_CONFIG_COMPLETE_EVENT = BIT(19), | ||
40 | PERIODIC_SCAN_REPORT_EVENT_ID = BIT(20), | ||
41 | }; | ||
42 | |||
43 | struct wl18xx_event_mailbox { | ||
44 | __le32 events_vector; | ||
45 | |||
46 | u8 number_of_scan_results; | ||
47 | u8 number_of_sched_scan_results; | ||
48 | |||
49 | __le16 channel_switch_role_id_bitmap; | ||
50 | |||
51 | s8 rssi_snr_trigger_metric[NUM_OF_RSSI_SNR_TRIGGERS]; | ||
52 | |||
53 | /* bitmap of removed links */ | ||
54 | __le32 hlid_removed_bitmap; | ||
55 | |||
56 | /* rx ba constraint */ | ||
57 | __le16 rx_ba_role_id_bitmap; /* 0xfff means any role. */ | ||
58 | __le16 rx_ba_allowed_bitmap; | ||
59 | |||
60 | /* bitmap of roc completed (by role id) */ | ||
61 | __le16 roc_completed_bitmap; | ||
62 | |||
63 | /* bitmap of stations (by role id) with bss loss */ | ||
64 | __le16 bss_loss_bitmap; | ||
65 | |||
66 | /* bitmap of stations (by HLID) which exceeded max tx retries */ | ||
67 | __le32 tx_retry_exceeded_bitmap; | ||
68 | |||
69 | /* bitmap of inactive stations (by HLID) */ | ||
70 | __le32 inactive_sta_bitmap; | ||
71 | } __packed; | ||
72 | |||
73 | int wl18xx_wait_for_event(struct wl1271 *wl, enum wlcore_wait_event event, | ||
74 | bool *timeout); | ||
75 | int wl18xx_process_mailbox_events(struct wl1271 *wl); | ||
76 | |||
77 | #endif | ||
diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c index 8d8c1f8c63b7..0be1cfc17a86 100644 --- a/drivers/net/wireless/ti/wl18xx/main.c +++ b/drivers/net/wireless/ti/wl18xx/main.c | |||
@@ -34,10 +34,13 @@ | |||
34 | 34 | ||
35 | #include "reg.h" | 35 | #include "reg.h" |
36 | #include "conf.h" | 36 | #include "conf.h" |
37 | #include "cmd.h" | ||
37 | #include "acx.h" | 38 | #include "acx.h" |
38 | #include "tx.h" | 39 | #include "tx.h" |
39 | #include "wl18xx.h" | 40 | #include "wl18xx.h" |
40 | #include "io.h" | 41 | #include "io.h" |
42 | #include "scan.h" | ||
43 | #include "event.h" | ||
41 | #include "debugfs.h" | 44 | #include "debugfs.h" |
42 | 45 | ||
43 | #define WL18XX_RX_CHECKSUM_MASK 0x40 | 46 | #define WL18XX_RX_CHECKSUM_MASK 0x40 |
@@ -334,6 +337,8 @@ static struct wlcore_conf wl18xx_conf = { | |||
334 | .tmpl_short_retry_limit = 10, | 337 | .tmpl_short_retry_limit = 10, |
335 | .tmpl_long_retry_limit = 10, | 338 | .tmpl_long_retry_limit = 10, |
336 | .tx_watchdog_timeout = 5000, | 339 | .tx_watchdog_timeout = 5000, |
340 | .slow_link_thold = 3, | ||
341 | .fast_link_thold = 30, | ||
337 | }, | 342 | }, |
338 | .conn = { | 343 | .conn = { |
339 | .wake_up_event = CONF_WAKE_UP_EVENT_DTIM, | 344 | .wake_up_event = CONF_WAKE_UP_EVENT_DTIM, |
@@ -391,8 +396,10 @@ static struct wlcore_conf wl18xx_conf = { | |||
391 | .scan = { | 396 | .scan = { |
392 | .min_dwell_time_active = 7500, | 397 | .min_dwell_time_active = 7500, |
393 | .max_dwell_time_active = 30000, | 398 | .max_dwell_time_active = 30000, |
394 | .min_dwell_time_passive = 100000, | 399 | .min_dwell_time_active_long = 25000, |
395 | .max_dwell_time_passive = 100000, | 400 | .max_dwell_time_active_long = 50000, |
401 | .dwell_time_passive = 100000, | ||
402 | .dwell_time_dfs = 150000, | ||
396 | .num_probe_reqs = 2, | 403 | .num_probe_reqs = 2, |
397 | .split_scan_timeout = 50000, | 404 | .split_scan_timeout = 50000, |
398 | }, | 405 | }, |
@@ -489,6 +496,10 @@ static struct wlcore_conf wl18xx_conf = { | |||
489 | .increase_time = 1, | 496 | .increase_time = 1, |
490 | .window_size = 16, | 497 | .window_size = 16, |
491 | }, | 498 | }, |
499 | .recovery = { | ||
500 | .bug_on_recovery = 0, | ||
501 | .no_recovery = 0, | ||
502 | }, | ||
492 | }; | 503 | }; |
493 | 504 | ||
494 | static struct wl18xx_priv_conf wl18xx_default_priv_conf = { | 505 | static struct wl18xx_priv_conf wl18xx_default_priv_conf = { |
@@ -501,7 +512,6 @@ static struct wl18xx_priv_conf wl18xx_default_priv_conf = { | |||
501 | .clock_valid_on_wake_up = 0x00, | 512 | .clock_valid_on_wake_up = 0x00, |
502 | .secondary_clock_setting_time = 0x05, | 513 | .secondary_clock_setting_time = 0x05, |
503 | .board_type = BOARD_TYPE_HDK_18XX, | 514 | .board_type = BOARD_TYPE_HDK_18XX, |
504 | .rdl = 0x01, | ||
505 | .auto_detect = 0x00, | 515 | .auto_detect = 0x00, |
506 | .dedicated_fem = FEM_NONE, | 516 | .dedicated_fem = FEM_NONE, |
507 | .low_band_component = COMPONENT_3_WAY_SWITCH, | 517 | .low_band_component = COMPONENT_3_WAY_SWITCH, |
@@ -517,14 +527,39 @@ static struct wl18xx_priv_conf wl18xx_default_priv_conf = { | |||
517 | .enable_clpc = 0x00, | 527 | .enable_clpc = 0x00, |
518 | .enable_tx_low_pwr_on_siso_rdl = 0x00, | 528 | .enable_tx_low_pwr_on_siso_rdl = 0x00, |
519 | .rx_profile = 0x00, | 529 | .rx_profile = 0x00, |
520 | .pwr_limit_reference_11_abg = 0xc8, | 530 | .pwr_limit_reference_11_abg = 0x64, |
531 | .per_chan_pwr_limit_arr_11abg = { | ||
532 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
533 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
534 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
535 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
536 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
537 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
538 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
539 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
540 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
541 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
542 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
543 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
544 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
545 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
546 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
547 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
548 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, | ||
549 | .pwr_limit_reference_11p = 0x64, | ||
550 | .per_chan_pwr_limit_arr_11p = { 0xff, 0xff, 0xff, 0xff, | ||
551 | 0xff, 0xff, 0xff }, | ||
521 | .psat = 0, | 552 | .psat = 0, |
522 | .low_power_val = 0x00, | 553 | .low_power_val = 0x08, |
523 | .med_power_val = 0x0a, | 554 | .med_power_val = 0x12, |
524 | .high_power_val = 0x1e, | 555 | .high_power_val = 0x18, |
556 | .low_power_val_2nd = 0x05, | ||
557 | .med_power_val_2nd = 0x0a, | ||
558 | .high_power_val_2nd = 0x14, | ||
525 | .external_pa_dc2dc = 0, | 559 | .external_pa_dc2dc = 0, |
526 | .number_of_assembled_ant2_4 = 1, | 560 | .number_of_assembled_ant2_4 = 2, |
527 | .number_of_assembled_ant5 = 1, | 561 | .number_of_assembled_ant5 = 1, |
562 | .tx_rf_margin = 1, | ||
528 | }, | 563 | }, |
529 | }; | 564 | }; |
530 | 565 | ||
@@ -595,7 +630,7 @@ static const struct wl18xx_clk_cfg wl18xx_clk_table[NUM_CLOCK_CONFIGS] = { | |||
595 | }; | 630 | }; |
596 | 631 | ||
597 | /* TODO: maybe move to a new header file? */ | 632 | /* TODO: maybe move to a new header file? */ |
598 | #define WL18XX_FW_NAME "ti-connectivity/wl18xx-fw.bin" | 633 | #define WL18XX_FW_NAME "ti-connectivity/wl18xx-fw-2.bin" |
599 | 634 | ||
600 | static int wl18xx_identify_chip(struct wl1271 *wl) | 635 | static int wl18xx_identify_chip(struct wl1271 *wl) |
601 | { | 636 | { |
@@ -608,15 +643,18 @@ static int wl18xx_identify_chip(struct wl1271 *wl) | |||
608 | wl->sr_fw_name = WL18XX_FW_NAME; | 643 | wl->sr_fw_name = WL18XX_FW_NAME; |
609 | /* wl18xx uses the same firmware for PLT */ | 644 | /* wl18xx uses the same firmware for PLT */ |
610 | wl->plt_fw_name = WL18XX_FW_NAME; | 645 | wl->plt_fw_name = WL18XX_FW_NAME; |
611 | wl->quirks |= WLCORE_QUIRK_NO_ELP | | 646 | wl->quirks |= WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN | |
612 | WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN | | ||
613 | WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN | | 647 | WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN | |
614 | WLCORE_QUIRK_NO_SCHED_SCAN_WHILE_CONN | | 648 | WLCORE_QUIRK_NO_SCHED_SCAN_WHILE_CONN | |
615 | WLCORE_QUIRK_TX_PAD_LAST_FRAME; | 649 | WLCORE_QUIRK_TX_PAD_LAST_FRAME | |
616 | 650 | WLCORE_QUIRK_REGDOMAIN_CONF | | |
617 | wlcore_set_min_fw_ver(wl, WL18XX_CHIP_VER, WL18XX_IFTYPE_VER, | 651 | WLCORE_QUIRK_DUAL_PROBE_TMPL; |
618 | WL18XX_MAJOR_VER, WL18XX_SUBTYPE_VER, | 652 | |
619 | WL18XX_MINOR_VER); | 653 | wlcore_set_min_fw_ver(wl, WL18XX_CHIP_VER, |
654 | WL18XX_IFTYPE_VER, WL18XX_MAJOR_VER, | ||
655 | WL18XX_SUBTYPE_VER, WL18XX_MINOR_VER, | ||
656 | /* there's no separate multi-role FW */ | ||
657 | 0, 0, 0, 0); | ||
620 | break; | 658 | break; |
621 | case CHIP_ID_185x_PG10: | 659 | case CHIP_ID_185x_PG10: |
622 | wl1271_warning("chip id 0x%x (185x PG10) is deprecated", | 660 | wl1271_warning("chip id 0x%x (185x PG10) is deprecated", |
@@ -630,6 +668,11 @@ static int wl18xx_identify_chip(struct wl1271 *wl) | |||
630 | goto out; | 668 | goto out; |
631 | } | 669 | } |
632 | 670 | ||
671 | wl->scan_templ_id_2_4 = CMD_TEMPL_CFG_PROBE_REQ_2_4; | ||
672 | wl->scan_templ_id_5 = CMD_TEMPL_CFG_PROBE_REQ_5; | ||
673 | wl->sched_scan_templ_id_2_4 = CMD_TEMPL_PROBE_REQ_2_4_PERIODIC; | ||
674 | wl->sched_scan_templ_id_5 = CMD_TEMPL_PROBE_REQ_5_PERIODIC; | ||
675 | wl->max_channels_5 = WL18XX_MAX_CHANNELS_5GHZ; | ||
633 | out: | 676 | out: |
634 | return ret; | 677 | return ret; |
635 | } | 678 | } |
@@ -843,6 +886,20 @@ static int wl18xx_boot(struct wl1271 *wl) | |||
843 | if (ret < 0) | 886 | if (ret < 0) |
844 | goto out; | 887 | goto out; |
845 | 888 | ||
889 | wl->event_mask = BSS_LOSS_EVENT_ID | | ||
890 | SCAN_COMPLETE_EVENT_ID | | ||
891 | RSSI_SNR_TRIGGER_0_EVENT_ID | | ||
892 | PERIODIC_SCAN_COMPLETE_EVENT_ID | | ||
893 | PERIODIC_SCAN_REPORT_EVENT_ID | | ||
894 | DUMMY_PACKET_EVENT_ID | | ||
895 | PEER_REMOVE_COMPLETE_EVENT_ID | | ||
896 | BA_SESSION_RX_CONSTRAINT_EVENT_ID | | ||
897 | REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID | | ||
898 | INACTIVE_STA_EVENT_ID | | ||
899 | MAX_TX_FAILURE_EVENT_ID | | ||
900 | CHANNEL_SWITCH_COMPLETE_EVENT_ID | | ||
901 | DFS_CHANNELS_CONFIG_COMPLETE_EVENT; | ||
902 | |||
846 | ret = wlcore_boot_run_firmware(wl); | 903 | ret = wlcore_boot_run_firmware(wl); |
847 | if (ret < 0) | 904 | if (ret < 0) |
848 | goto out; | 905 | goto out; |
@@ -964,7 +1021,7 @@ static int wl18xx_hw_init(struct wl1271 *wl) | |||
964 | 1021 | ||
965 | /* (re)init private structures. Relevant on recovery as well. */ | 1022 | /* (re)init private structures. Relevant on recovery as well. */ |
966 | priv->last_fw_rls_idx = 0; | 1023 | priv->last_fw_rls_idx = 0; |
967 | priv->extra_spare_vif_count = 0; | 1024 | priv->extra_spare_key_count = 0; |
968 | 1025 | ||
969 | /* set the default amount of spare blocks in the bitmap */ | 1026 | /* set the default amount of spare blocks in the bitmap */ |
970 | ret = wl18xx_set_host_cfg_bitmap(wl, WL18XX_TX_HW_BLOCK_SPARE); | 1027 | ret = wl18xx_set_host_cfg_bitmap(wl, WL18XX_TX_HW_BLOCK_SPARE); |
@@ -1022,7 +1079,12 @@ static bool wl18xx_is_mimo_supported(struct wl1271 *wl) | |||
1022 | { | 1079 | { |
1023 | struct wl18xx_priv *priv = wl->priv; | 1080 | struct wl18xx_priv *priv = wl->priv; |
1024 | 1081 | ||
1025 | return priv->conf.phy.number_of_assembled_ant2_4 >= 2; | 1082 | /* only support MIMO with multiple antennas, and when SISO |
1083 | * is not forced through config | ||
1084 | */ | ||
1085 | return (priv->conf.phy.number_of_assembled_ant2_4 >= 2) && | ||
1086 | (priv->conf.ht.mode != HT_MODE_WIDE) && | ||
1087 | (priv->conf.ht.mode != HT_MODE_SISO20); | ||
1026 | } | 1088 | } |
1027 | 1089 | ||
1028 | /* | 1090 | /* |
@@ -1223,8 +1285,8 @@ static int wl18xx_get_spare_blocks(struct wl1271 *wl, bool is_gem) | |||
1223 | { | 1285 | { |
1224 | struct wl18xx_priv *priv = wl->priv; | 1286 | struct wl18xx_priv *priv = wl->priv; |
1225 | 1287 | ||
1226 | /* If we have VIFs requiring extra spare, indulge them */ | 1288 | /* If we have keys requiring extra spare, indulge them */ |
1227 | if (priv->extra_spare_vif_count) | 1289 | if (priv->extra_spare_key_count) |
1228 | return WL18XX_TX_HW_EXTRA_BLOCK_SPARE; | 1290 | return WL18XX_TX_HW_EXTRA_BLOCK_SPARE; |
1229 | 1291 | ||
1230 | return WL18XX_TX_HW_BLOCK_SPARE; | 1292 | return WL18XX_TX_HW_BLOCK_SPARE; |
@@ -1236,42 +1298,48 @@ static int wl18xx_set_key(struct wl1271 *wl, enum set_key_cmd cmd, | |||
1236 | struct ieee80211_key_conf *key_conf) | 1298 | struct ieee80211_key_conf *key_conf) |
1237 | { | 1299 | { |
1238 | struct wl18xx_priv *priv = wl->priv; | 1300 | struct wl18xx_priv *priv = wl->priv; |
1239 | bool change_spare = false; | 1301 | bool change_spare = false, special_enc; |
1240 | int ret; | 1302 | int ret; |
1241 | 1303 | ||
1304 | wl1271_debug(DEBUG_CRYPT, "extra spare keys before: %d", | ||
1305 | priv->extra_spare_key_count); | ||
1306 | |||
1307 | special_enc = key_conf->cipher == WL1271_CIPHER_SUITE_GEM || | ||
1308 | key_conf->cipher == WLAN_CIPHER_SUITE_TKIP; | ||
1309 | |||
1310 | ret = wlcore_set_key(wl, cmd, vif, sta, key_conf); | ||
1311 | if (ret < 0) | ||
1312 | goto out; | ||
1313 | |||
1242 | /* | 1314 | /* |
1243 | * when adding the first or removing the last GEM/TKIP interface, | 1315 | * when adding the first or removing the last GEM/TKIP key, |
1244 | * we have to adjust the number of spare blocks. | 1316 | * we have to adjust the number of spare blocks. |
1245 | */ | 1317 | */ |
1246 | change_spare = (key_conf->cipher == WL1271_CIPHER_SUITE_GEM || | 1318 | if (special_enc) { |
1247 | key_conf->cipher == WLAN_CIPHER_SUITE_TKIP) && | 1319 | if (cmd == SET_KEY) { |
1248 | ((priv->extra_spare_vif_count == 0 && cmd == SET_KEY) || | 1320 | /* first key */ |
1249 | (priv->extra_spare_vif_count == 1 && cmd == DISABLE_KEY)); | 1321 | change_spare = (priv->extra_spare_key_count == 0); |
1322 | priv->extra_spare_key_count++; | ||
1323 | } else if (cmd == DISABLE_KEY) { | ||
1324 | /* last key */ | ||
1325 | change_spare = (priv->extra_spare_key_count == 1); | ||
1326 | priv->extra_spare_key_count--; | ||
1327 | } | ||
1328 | } | ||
1250 | 1329 | ||
1251 | /* no need to change spare - just regular set_key */ | 1330 | wl1271_debug(DEBUG_CRYPT, "extra spare keys after: %d", |
1252 | if (!change_spare) | 1331 | priv->extra_spare_key_count); |
1253 | return wlcore_set_key(wl, cmd, vif, sta, key_conf); | ||
1254 | 1332 | ||
1255 | ret = wlcore_set_key(wl, cmd, vif, sta, key_conf); | 1333 | if (!change_spare) |
1256 | if (ret < 0) | ||
1257 | goto out; | 1334 | goto out; |
1258 | 1335 | ||
1259 | /* key is now set, change the spare blocks */ | 1336 | /* key is now set, change the spare blocks */ |
1260 | if (cmd == SET_KEY) { | 1337 | if (priv->extra_spare_key_count) |
1261 | ret = wl18xx_set_host_cfg_bitmap(wl, | 1338 | ret = wl18xx_set_host_cfg_bitmap(wl, |
1262 | WL18XX_TX_HW_EXTRA_BLOCK_SPARE); | 1339 | WL18XX_TX_HW_EXTRA_BLOCK_SPARE); |
1263 | if (ret < 0) | 1340 | else |
1264 | goto out; | ||
1265 | |||
1266 | priv->extra_spare_vif_count++; | ||
1267 | } else { | ||
1268 | ret = wl18xx_set_host_cfg_bitmap(wl, | 1341 | ret = wl18xx_set_host_cfg_bitmap(wl, |
1269 | WL18XX_TX_HW_BLOCK_SPARE); | 1342 | WL18XX_TX_HW_BLOCK_SPARE); |
1270 | if (ret < 0) | ||
1271 | goto out; | ||
1272 | |||
1273 | priv->extra_spare_vif_count--; | ||
1274 | } | ||
1275 | 1343 | ||
1276 | out: | 1344 | out: |
1277 | return ret; | 1345 | return ret; |
@@ -1296,6 +1364,92 @@ static u32 wl18xx_pre_pkt_send(struct wl1271 *wl, | |||
1296 | return buf_offset; | 1364 | return buf_offset; |
1297 | } | 1365 | } |
1298 | 1366 | ||
1367 | static void wl18xx_sta_rc_update(struct wl1271 *wl, | ||
1368 | struct wl12xx_vif *wlvif, | ||
1369 | struct ieee80211_sta *sta, | ||
1370 | u32 changed) | ||
1371 | { | ||
1372 | bool wide = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
1373 | |||
1374 | wl1271_debug(DEBUG_MAC80211, "mac80211 sta_rc_update wide %d", wide); | ||
1375 | |||
1376 | if (!(changed & IEEE80211_RC_BW_CHANGED)) | ||
1377 | return; | ||
1378 | |||
1379 | mutex_lock(&wl->mutex); | ||
1380 | |||
1381 | /* sanity */ | ||
1382 | if (WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS)) | ||
1383 | goto out; | ||
1384 | |||
1385 | /* ignore the change before association */ | ||
1386 | if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) | ||
1387 | goto out; | ||
1388 | |||
1389 | /* | ||
1390 | * If we started out as wide, we can change the operation mode. If we | ||
1391 | * thought this was a 20mhz AP, we have to reconnect | ||
1392 | */ | ||
1393 | if (wlvif->sta.role_chan_type == NL80211_CHAN_HT40MINUS || | ||
1394 | wlvif->sta.role_chan_type == NL80211_CHAN_HT40PLUS) | ||
1395 | wl18xx_acx_peer_ht_operation_mode(wl, wlvif->sta.hlid, wide); | ||
1396 | else | ||
1397 | ieee80211_connection_loss(wl12xx_wlvif_to_vif(wlvif)); | ||
1398 | |||
1399 | out: | ||
1400 | mutex_unlock(&wl->mutex); | ||
1401 | } | ||
1402 | |||
1403 | static int wl18xx_set_peer_cap(struct wl1271 *wl, | ||
1404 | struct ieee80211_sta_ht_cap *ht_cap, | ||
1405 | bool allow_ht_operation, | ||
1406 | u32 rate_set, u8 hlid) | ||
1407 | { | ||
1408 | return wl18xx_acx_set_peer_cap(wl, ht_cap, allow_ht_operation, | ||
1409 | rate_set, hlid); | ||
1410 | } | ||
1411 | |||
1412 | static bool wl18xx_lnk_high_prio(struct wl1271 *wl, u8 hlid, | ||
1413 | struct wl1271_link *lnk) | ||
1414 | { | ||
1415 | u8 thold; | ||
1416 | struct wl18xx_fw_status_priv *status_priv = | ||
1417 | (struct wl18xx_fw_status_priv *)wl->fw_status_2->priv; | ||
1418 | u32 suspend_bitmap = le32_to_cpu(status_priv->link_suspend_bitmap); | ||
1419 | |||
1420 | /* suspended links are never high priority */ | ||
1421 | if (test_bit(hlid, (unsigned long *)&suspend_bitmap)) | ||
1422 | return false; | ||
1423 | |||
1424 | /* the priority thresholds are taken from FW */ | ||
1425 | if (test_bit(hlid, (unsigned long *)&wl->fw_fast_lnk_map) && | ||
1426 | !test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map)) | ||
1427 | thold = status_priv->tx_fast_link_prio_threshold; | ||
1428 | else | ||
1429 | thold = status_priv->tx_slow_link_prio_threshold; | ||
1430 | |||
1431 | return lnk->allocated_pkts < thold; | ||
1432 | } | ||
1433 | |||
1434 | static bool wl18xx_lnk_low_prio(struct wl1271 *wl, u8 hlid, | ||
1435 | struct wl1271_link *lnk) | ||
1436 | { | ||
1437 | u8 thold; | ||
1438 | struct wl18xx_fw_status_priv *status_priv = | ||
1439 | (struct wl18xx_fw_status_priv *)wl->fw_status_2->priv; | ||
1440 | u32 suspend_bitmap = le32_to_cpu(status_priv->link_suspend_bitmap); | ||
1441 | |||
1442 | if (test_bit(hlid, (unsigned long *)&suspend_bitmap)) | ||
1443 | thold = status_priv->tx_suspend_threshold; | ||
1444 | else if (test_bit(hlid, (unsigned long *)&wl->fw_fast_lnk_map) && | ||
1445 | !test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map)) | ||
1446 | thold = status_priv->tx_fast_stop_threshold; | ||
1447 | else | ||
1448 | thold = status_priv->tx_slow_stop_threshold; | ||
1449 | |||
1450 | return lnk->allocated_pkts < thold; | ||
1451 | } | ||
1452 | |||
1299 | static int wl18xx_setup(struct wl1271 *wl); | 1453 | static int wl18xx_setup(struct wl1271 *wl); |
1300 | 1454 | ||
1301 | static struct wlcore_ops wl18xx_ops = { | 1455 | static struct wlcore_ops wl18xx_ops = { |
@@ -1305,6 +1459,8 @@ static struct wlcore_ops wl18xx_ops = { | |||
1305 | .plt_init = wl18xx_plt_init, | 1459 | .plt_init = wl18xx_plt_init, |
1306 | .trigger_cmd = wl18xx_trigger_cmd, | 1460 | .trigger_cmd = wl18xx_trigger_cmd, |
1307 | .ack_event = wl18xx_ack_event, | 1461 | .ack_event = wl18xx_ack_event, |
1462 | .wait_for_event = wl18xx_wait_for_event, | ||
1463 | .process_mailbox_events = wl18xx_process_mailbox_events, | ||
1308 | .calc_tx_blocks = wl18xx_calc_tx_blocks, | 1464 | .calc_tx_blocks = wl18xx_calc_tx_blocks, |
1309 | .set_tx_desc_blocks = wl18xx_set_tx_desc_blocks, | 1465 | .set_tx_desc_blocks = wl18xx_set_tx_desc_blocks, |
1310 | .set_tx_desc_data_len = wl18xx_set_tx_desc_data_len, | 1466 | .set_tx_desc_data_len = wl18xx_set_tx_desc_data_len, |
@@ -1320,16 +1476,26 @@ static struct wlcore_ops wl18xx_ops = { | |||
1320 | .ap_get_mimo_wide_rate_mask = wl18xx_ap_get_mimo_wide_rate_mask, | 1476 | .ap_get_mimo_wide_rate_mask = wl18xx_ap_get_mimo_wide_rate_mask, |
1321 | .get_mac = wl18xx_get_mac, | 1477 | .get_mac = wl18xx_get_mac, |
1322 | .debugfs_init = wl18xx_debugfs_add_files, | 1478 | .debugfs_init = wl18xx_debugfs_add_files, |
1479 | .scan_start = wl18xx_scan_start, | ||
1480 | .scan_stop = wl18xx_scan_stop, | ||
1481 | .sched_scan_start = wl18xx_sched_scan_start, | ||
1482 | .sched_scan_stop = wl18xx_scan_sched_scan_stop, | ||
1323 | .handle_static_data = wl18xx_handle_static_data, | 1483 | .handle_static_data = wl18xx_handle_static_data, |
1324 | .get_spare_blocks = wl18xx_get_spare_blocks, | 1484 | .get_spare_blocks = wl18xx_get_spare_blocks, |
1325 | .set_key = wl18xx_set_key, | 1485 | .set_key = wl18xx_set_key, |
1486 | .channel_switch = wl18xx_cmd_channel_switch, | ||
1326 | .pre_pkt_send = wl18xx_pre_pkt_send, | 1487 | .pre_pkt_send = wl18xx_pre_pkt_send, |
1488 | .sta_rc_update = wl18xx_sta_rc_update, | ||
1489 | .set_peer_cap = wl18xx_set_peer_cap, | ||
1490 | .lnk_high_prio = wl18xx_lnk_high_prio, | ||
1491 | .lnk_low_prio = wl18xx_lnk_low_prio, | ||
1327 | }; | 1492 | }; |
1328 | 1493 | ||
1329 | /* HT cap appropriate for wide channels in 2Ghz */ | 1494 | /* HT cap appropriate for wide channels in 2Ghz */ |
1330 | static struct ieee80211_sta_ht_cap wl18xx_siso40_ht_cap_2ghz = { | 1495 | static struct ieee80211_sta_ht_cap wl18xx_siso40_ht_cap_2ghz = { |
1331 | .cap = IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40 | | 1496 | .cap = IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40 | |
1332 | IEEE80211_HT_CAP_SUP_WIDTH_20_40 | IEEE80211_HT_CAP_DSSSCCK40, | 1497 | IEEE80211_HT_CAP_SUP_WIDTH_20_40 | IEEE80211_HT_CAP_DSSSCCK40 | |
1498 | IEEE80211_HT_CAP_GRN_FLD, | ||
1333 | .ht_supported = true, | 1499 | .ht_supported = true, |
1334 | .ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K, | 1500 | .ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K, |
1335 | .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, | 1501 | .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, |
@@ -1343,7 +1509,8 @@ static struct ieee80211_sta_ht_cap wl18xx_siso40_ht_cap_2ghz = { | |||
1343 | /* HT cap appropriate for wide channels in 5Ghz */ | 1509 | /* HT cap appropriate for wide channels in 5Ghz */ |
1344 | static struct ieee80211_sta_ht_cap wl18xx_siso40_ht_cap_5ghz = { | 1510 | static struct ieee80211_sta_ht_cap wl18xx_siso40_ht_cap_5ghz = { |
1345 | .cap = IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40 | | 1511 | .cap = IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40 | |
1346 | IEEE80211_HT_CAP_SUP_WIDTH_20_40, | 1512 | IEEE80211_HT_CAP_SUP_WIDTH_20_40 | |
1513 | IEEE80211_HT_CAP_GRN_FLD, | ||
1347 | .ht_supported = true, | 1514 | .ht_supported = true, |
1348 | .ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K, | 1515 | .ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K, |
1349 | .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, | 1516 | .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, |
@@ -1356,7 +1523,8 @@ static struct ieee80211_sta_ht_cap wl18xx_siso40_ht_cap_5ghz = { | |||
1356 | 1523 | ||
1357 | /* HT cap appropriate for SISO 20 */ | 1524 | /* HT cap appropriate for SISO 20 */ |
1358 | static struct ieee80211_sta_ht_cap wl18xx_siso20_ht_cap = { | 1525 | static struct ieee80211_sta_ht_cap wl18xx_siso20_ht_cap = { |
1359 | .cap = IEEE80211_HT_CAP_SGI_20, | 1526 | .cap = IEEE80211_HT_CAP_SGI_20 | |
1527 | IEEE80211_HT_CAP_GRN_FLD, | ||
1360 | .ht_supported = true, | 1528 | .ht_supported = true, |
1361 | .ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K, | 1529 | .ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K, |
1362 | .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, | 1530 | .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, |
@@ -1369,7 +1537,8 @@ static struct ieee80211_sta_ht_cap wl18xx_siso20_ht_cap = { | |||
1369 | 1537 | ||
1370 | /* HT cap appropriate for MIMO rates in 20mhz channel */ | 1538 | /* HT cap appropriate for MIMO rates in 20mhz channel */ |
1371 | static struct ieee80211_sta_ht_cap wl18xx_mimo_ht_cap_2ghz = { | 1539 | static struct ieee80211_sta_ht_cap wl18xx_mimo_ht_cap_2ghz = { |
1372 | .cap = IEEE80211_HT_CAP_SGI_20, | 1540 | .cap = IEEE80211_HT_CAP_SGI_20 | |
1541 | IEEE80211_HT_CAP_GRN_FLD, | ||
1373 | .ht_supported = true, | 1542 | .ht_supported = true, |
1374 | .ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K, | 1543 | .ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K, |
1375 | .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, | 1544 | .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, |
@@ -1387,7 +1556,8 @@ static int wl18xx_setup(struct wl1271 *wl) | |||
1387 | 1556 | ||
1388 | wl->rtable = wl18xx_rtable; | 1557 | wl->rtable = wl18xx_rtable; |
1389 | wl->num_tx_desc = WL18XX_NUM_TX_DESCRIPTORS; | 1558 | wl->num_tx_desc = WL18XX_NUM_TX_DESCRIPTORS; |
1390 | wl->num_rx_desc = WL18XX_NUM_TX_DESCRIPTORS; | 1559 | wl->num_rx_desc = WL18XX_NUM_RX_DESCRIPTORS; |
1560 | wl->num_channels = 2; | ||
1391 | wl->num_mac_addr = WL18XX_NUM_MAC_ADDRESSES; | 1561 | wl->num_mac_addr = WL18XX_NUM_MAC_ADDRESSES; |
1392 | wl->band_rate_to_idx = wl18xx_band_rate_to_idx; | 1562 | wl->band_rate_to_idx = wl18xx_band_rate_to_idx; |
1393 | wl->hw_tx_rate_tbl_size = WL18XX_CONF_HW_RXTX_RATE_MAX; | 1563 | wl->hw_tx_rate_tbl_size = WL18XX_CONF_HW_RXTX_RATE_MAX; |
@@ -1506,7 +1676,8 @@ static int wl18xx_probe(struct platform_device *pdev) | |||
1506 | int ret; | 1676 | int ret; |
1507 | 1677 | ||
1508 | hw = wlcore_alloc_hw(sizeof(struct wl18xx_priv), | 1678 | hw = wlcore_alloc_hw(sizeof(struct wl18xx_priv), |
1509 | WL18XX_AGGR_BUFFER_SIZE); | 1679 | WL18XX_AGGR_BUFFER_SIZE, |
1680 | sizeof(struct wl18xx_event_mailbox)); | ||
1510 | if (IS_ERR(hw)) { | 1681 | if (IS_ERR(hw)) { |
1511 | wl1271_error("can't allocate hw"); | 1682 | wl1271_error("can't allocate hw"); |
1512 | ret = PTR_ERR(hw); | 1683 | ret = PTR_ERR(hw); |
diff --git a/drivers/net/wireless/ti/wl18xx/scan.c b/drivers/net/wireless/ti/wl18xx/scan.c new file mode 100644 index 000000000000..09d944505ac0 --- /dev/null +++ b/drivers/net/wireless/ti/wl18xx/scan.c | |||
@@ -0,0 +1,326 @@ | |||
1 | /* | ||
2 | * This file is part of wl18xx | ||
3 | * | ||
4 | * Copyright (C) 2012 Texas Instruments. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * version 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
18 | * 02110-1301 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include <linux/ieee80211.h> | ||
23 | #include "scan.h" | ||
24 | #include "../wlcore/debug.h" | ||
25 | |||
26 | static void wl18xx_adjust_channels(struct wl18xx_cmd_scan_params *cmd, | ||
27 | struct wlcore_scan_channels *cmd_channels) | ||
28 | { | ||
29 | memcpy(cmd->passive, cmd_channels->passive, sizeof(cmd->passive)); | ||
30 | memcpy(cmd->active, cmd_channels->active, sizeof(cmd->active)); | ||
31 | cmd->dfs = cmd_channels->dfs; | ||
32 | cmd->passive_active = cmd_channels->passive_active; | ||
33 | |||
34 | memcpy(cmd->channels_2, cmd_channels->channels_2, | ||
35 | sizeof(cmd->channels_2)); | ||
36 | memcpy(cmd->channels_5, cmd_channels->channels_5, | ||
37 | sizeof(cmd->channels_2)); | ||
38 | /* channels_4 are not supported, so no need to copy them */ | ||
39 | } | ||
40 | |||
41 | static int wl18xx_scan_send(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
42 | struct cfg80211_scan_request *req) | ||
43 | { | ||
44 | struct wl18xx_cmd_scan_params *cmd; | ||
45 | struct wlcore_scan_channels *cmd_channels = NULL; | ||
46 | int ret; | ||
47 | |||
48 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
49 | if (!cmd) { | ||
50 | ret = -ENOMEM; | ||
51 | goto out; | ||
52 | } | ||
53 | |||
54 | cmd->role_id = wlvif->role_id; | ||
55 | |||
56 | if (WARN_ON(cmd->role_id == WL12XX_INVALID_ROLE_ID)) { | ||
57 | ret = -EINVAL; | ||
58 | goto out; | ||
59 | } | ||
60 | |||
61 | cmd->scan_type = SCAN_TYPE_SEARCH; | ||
62 | cmd->rssi_threshold = -127; | ||
63 | cmd->snr_threshold = 0; | ||
64 | |||
65 | cmd->bss_type = SCAN_BSS_TYPE_ANY; | ||
66 | |||
67 | cmd->ssid_from_list = 0; | ||
68 | cmd->filter = 0; | ||
69 | cmd->add_broadcast = 0; | ||
70 | |||
71 | cmd->urgency = 0; | ||
72 | cmd->protect = 0; | ||
73 | |||
74 | cmd->n_probe_reqs = wl->conf.scan.num_probe_reqs; | ||
75 | cmd->terminate_after = 0; | ||
76 | |||
77 | /* configure channels */ | ||
78 | WARN_ON(req->n_ssids > 1); | ||
79 | |||
80 | cmd_channels = kzalloc(sizeof(*cmd_channels), GFP_KERNEL); | ||
81 | if (!cmd_channels) { | ||
82 | ret = -ENOMEM; | ||
83 | goto out; | ||
84 | } | ||
85 | |||
86 | wlcore_set_scan_chan_params(wl, cmd_channels, req->channels, | ||
87 | req->n_channels, req->n_ssids, | ||
88 | SCAN_TYPE_SEARCH); | ||
89 | wl18xx_adjust_channels(cmd, cmd_channels); | ||
90 | |||
91 | /* | ||
92 | * all the cycles params (except total cycles) should | ||
93 | * remain 0 for normal scan | ||
94 | */ | ||
95 | cmd->total_cycles = 1; | ||
96 | |||
97 | if (req->no_cck) | ||
98 | cmd->rate = WL18XX_SCAN_RATE_6; | ||
99 | |||
100 | cmd->tag = WL1271_SCAN_DEFAULT_TAG; | ||
101 | |||
102 | if (req->n_ssids) { | ||
103 | cmd->ssid_len = req->ssids[0].ssid_len; | ||
104 | memcpy(cmd->ssid, req->ssids[0].ssid, cmd->ssid_len); | ||
105 | } | ||
106 | |||
107 | /* TODO: per-band ies? */ | ||
108 | if (cmd->active[0]) { | ||
109 | u8 band = IEEE80211_BAND_2GHZ; | ||
110 | ret = wl12xx_cmd_build_probe_req(wl, wlvif, | ||
111 | cmd->role_id, band, | ||
112 | req->ssids ? req->ssids[0].ssid : NULL, | ||
113 | req->ssids ? req->ssids[0].ssid_len : 0, | ||
114 | req->ie, | ||
115 | req->ie_len, | ||
116 | false); | ||
117 | if (ret < 0) { | ||
118 | wl1271_error("2.4GHz PROBE request template failed"); | ||
119 | goto out; | ||
120 | } | ||
121 | } | ||
122 | |||
123 | if (cmd->active[1] || cmd->dfs) { | ||
124 | u8 band = IEEE80211_BAND_5GHZ; | ||
125 | ret = wl12xx_cmd_build_probe_req(wl, wlvif, | ||
126 | cmd->role_id, band, | ||
127 | req->ssids ? req->ssids[0].ssid : NULL, | ||
128 | req->ssids ? req->ssids[0].ssid_len : 0, | ||
129 | req->ie, | ||
130 | req->ie_len, | ||
131 | false); | ||
132 | if (ret < 0) { | ||
133 | wl1271_error("5GHz PROBE request template failed"); | ||
134 | goto out; | ||
135 | } | ||
136 | } | ||
137 | |||
138 | wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd)); | ||
139 | |||
140 | ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0); | ||
141 | if (ret < 0) { | ||
142 | wl1271_error("SCAN failed"); | ||
143 | goto out; | ||
144 | } | ||
145 | |||
146 | out: | ||
147 | kfree(cmd_channels); | ||
148 | kfree(cmd); | ||
149 | return ret; | ||
150 | } | ||
151 | |||
152 | void wl18xx_scan_completed(struct wl1271 *wl, struct wl12xx_vif *wlvif) | ||
153 | { | ||
154 | wl->scan.failed = false; | ||
155 | cancel_delayed_work(&wl->scan_complete_work); | ||
156 | ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, | ||
157 | msecs_to_jiffies(0)); | ||
158 | } | ||
159 | |||
160 | static | ||
161 | int wl18xx_scan_sched_scan_config(struct wl1271 *wl, | ||
162 | struct wl12xx_vif *wlvif, | ||
163 | struct cfg80211_sched_scan_request *req, | ||
164 | struct ieee80211_sched_scan_ies *ies) | ||
165 | { | ||
166 | struct wl18xx_cmd_scan_params *cmd; | ||
167 | struct wlcore_scan_channels *cmd_channels = NULL; | ||
168 | struct conf_sched_scan_settings *c = &wl->conf.sched_scan; | ||
169 | int ret; | ||
170 | int filter_type; | ||
171 | |||
172 | wl1271_debug(DEBUG_CMD, "cmd sched_scan scan config"); | ||
173 | |||
174 | filter_type = wlcore_scan_sched_scan_ssid_list(wl, wlvif, req); | ||
175 | if (filter_type < 0) | ||
176 | return filter_type; | ||
177 | |||
178 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
179 | if (!cmd) { | ||
180 | ret = -ENOMEM; | ||
181 | goto out; | ||
182 | } | ||
183 | |||
184 | cmd->role_id = wlvif->role_id; | ||
185 | |||
186 | if (WARN_ON(cmd->role_id == WL12XX_INVALID_ROLE_ID)) { | ||
187 | ret = -EINVAL; | ||
188 | goto out; | ||
189 | } | ||
190 | |||
191 | cmd->scan_type = SCAN_TYPE_PERIODIC; | ||
192 | cmd->rssi_threshold = c->rssi_threshold; | ||
193 | cmd->snr_threshold = c->snr_threshold; | ||
194 | |||
195 | /* don't filter on BSS type */ | ||
196 | cmd->bss_type = SCAN_BSS_TYPE_ANY; | ||
197 | |||
198 | cmd->ssid_from_list = 1; | ||
199 | if (filter_type == SCAN_SSID_FILTER_LIST) | ||
200 | cmd->filter = 1; | ||
201 | cmd->add_broadcast = 0; | ||
202 | |||
203 | cmd->urgency = 0; | ||
204 | cmd->protect = 0; | ||
205 | |||
206 | cmd->n_probe_reqs = c->num_probe_reqs; | ||
207 | /* don't stop scanning automatically when something is found */ | ||
208 | cmd->terminate_after = 0; | ||
209 | |||
210 | cmd_channels = kzalloc(sizeof(*cmd_channels), GFP_KERNEL); | ||
211 | if (!cmd_channels) { | ||
212 | ret = -ENOMEM; | ||
213 | goto out; | ||
214 | } | ||
215 | |||
216 | /* configure channels */ | ||
217 | wlcore_set_scan_chan_params(wl, cmd_channels, req->channels, | ||
218 | req->n_channels, req->n_ssids, | ||
219 | SCAN_TYPE_PERIODIC); | ||
220 | wl18xx_adjust_channels(cmd, cmd_channels); | ||
221 | |||
222 | cmd->short_cycles_sec = 0; | ||
223 | cmd->long_cycles_sec = cpu_to_le16(req->interval); | ||
224 | cmd->short_cycles_count = 0; | ||
225 | |||
226 | cmd->total_cycles = 0; | ||
227 | |||
228 | cmd->tag = WL1271_SCAN_DEFAULT_TAG; | ||
229 | |||
230 | /* create a PERIODIC_SCAN_REPORT_EVENT whenever we've got a match */ | ||
231 | cmd->report_threshold = 1; | ||
232 | cmd->terminate_on_report = 0; | ||
233 | |||
234 | if (cmd->active[0]) { | ||
235 | u8 band = IEEE80211_BAND_2GHZ; | ||
236 | ret = wl12xx_cmd_build_probe_req(wl, wlvif, | ||
237 | cmd->role_id, band, | ||
238 | req->ssids ? req->ssids[0].ssid : NULL, | ||
239 | req->ssids ? req->ssids[0].ssid_len : 0, | ||
240 | ies->ie[band], | ||
241 | ies->len[band], | ||
242 | true); | ||
243 | if (ret < 0) { | ||
244 | wl1271_error("2.4GHz PROBE request template failed"); | ||
245 | goto out; | ||
246 | } | ||
247 | } | ||
248 | |||
249 | if (cmd->active[1] || cmd->dfs) { | ||
250 | u8 band = IEEE80211_BAND_5GHZ; | ||
251 | ret = wl12xx_cmd_build_probe_req(wl, wlvif, | ||
252 | cmd->role_id, band, | ||
253 | req->ssids ? req->ssids[0].ssid : NULL, | ||
254 | req->ssids ? req->ssids[0].ssid_len : 0, | ||
255 | ies->ie[band], | ||
256 | ies->len[band], | ||
257 | true); | ||
258 | if (ret < 0) { | ||
259 | wl1271_error("5GHz PROBE request template failed"); | ||
260 | goto out; | ||
261 | } | ||
262 | } | ||
263 | |||
264 | wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd)); | ||
265 | |||
266 | ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0); | ||
267 | if (ret < 0) { | ||
268 | wl1271_error("SCAN failed"); | ||
269 | goto out; | ||
270 | } | ||
271 | |||
272 | out: | ||
273 | kfree(cmd_channels); | ||
274 | kfree(cmd); | ||
275 | return ret; | ||
276 | } | ||
277 | |||
278 | int wl18xx_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
279 | struct cfg80211_sched_scan_request *req, | ||
280 | struct ieee80211_sched_scan_ies *ies) | ||
281 | { | ||
282 | return wl18xx_scan_sched_scan_config(wl, wlvif, req, ies); | ||
283 | } | ||
284 | |||
285 | static int __wl18xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
286 | u8 scan_type) | ||
287 | { | ||
288 | struct wl18xx_cmd_scan_stop *stop; | ||
289 | int ret; | ||
290 | |||
291 | wl1271_debug(DEBUG_CMD, "cmd periodic scan stop"); | ||
292 | |||
293 | stop = kzalloc(sizeof(*stop), GFP_KERNEL); | ||
294 | if (!stop) { | ||
295 | wl1271_error("failed to alloc memory to send sched scan stop"); | ||
296 | return -ENOMEM; | ||
297 | } | ||
298 | |||
299 | stop->role_id = wlvif->role_id; | ||
300 | stop->scan_type = scan_type; | ||
301 | |||
302 | ret = wl1271_cmd_send(wl, CMD_STOP_SCAN, stop, sizeof(*stop), 0); | ||
303 | if (ret < 0) { | ||
304 | wl1271_error("failed to send sched scan stop command"); | ||
305 | goto out_free; | ||
306 | } | ||
307 | |||
308 | out_free: | ||
309 | kfree(stop); | ||
310 | return ret; | ||
311 | } | ||
312 | |||
313 | void wl18xx_scan_sched_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif) | ||
314 | { | ||
315 | __wl18xx_scan_stop(wl, wlvif, SCAN_TYPE_PERIODIC); | ||
316 | } | ||
317 | int wl18xx_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
318 | struct cfg80211_scan_request *req) | ||
319 | { | ||
320 | return wl18xx_scan_send(wl, wlvif, req); | ||
321 | } | ||
322 | |||
323 | int wl18xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif) | ||
324 | { | ||
325 | return __wl18xx_scan_stop(wl, wlvif, SCAN_TYPE_SEARCH); | ||
326 | } | ||
diff --git a/drivers/net/wireless/ti/wl18xx/scan.h b/drivers/net/wireless/ti/wl18xx/scan.h new file mode 100644 index 000000000000..eadee42689d1 --- /dev/null +++ b/drivers/net/wireless/ti/wl18xx/scan.h | |||
@@ -0,0 +1,127 @@ | |||
1 | /* | ||
2 | * This file is part of wl18xx | ||
3 | * | ||
4 | * Copyright (C) 2012 Texas Instruments. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * version 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
18 | * 02110-1301 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #ifndef __WL18XX_SCAN_H__ | ||
23 | #define __WL18XX_SCAN_H__ | ||
24 | |||
25 | #include "../wlcore/wlcore.h" | ||
26 | #include "../wlcore/cmd.h" | ||
27 | #include "../wlcore/scan.h" | ||
28 | |||
29 | struct tracking_ch_params { | ||
30 | struct conn_scan_ch_params channel; | ||
31 | |||
32 | __le32 bssid_lsb; | ||
33 | __le16 bssid_msb; | ||
34 | |||
35 | u8 padding[2]; | ||
36 | } __packed; | ||
37 | |||
38 | /* probe request rate */ | ||
39 | enum | ||
40 | { | ||
41 | WL18XX_SCAN_RATE_1 = 0, | ||
42 | WL18XX_SCAN_RATE_5_5 = 1, | ||
43 | WL18XX_SCAN_RATE_6 = 2, | ||
44 | }; | ||
45 | |||
46 | #define WL18XX_MAX_CHANNELS_5GHZ 32 | ||
47 | |||
48 | struct wl18xx_cmd_scan_params { | ||
49 | struct wl1271_cmd_header header; | ||
50 | |||
51 | u8 role_id; | ||
52 | u8 scan_type; | ||
53 | |||
54 | s8 rssi_threshold; /* for filtering (in dBm) */ | ||
55 | s8 snr_threshold; /* for filtering (in dB) */ | ||
56 | |||
57 | u8 bss_type; /* for filtering */ | ||
58 | u8 ssid_from_list; /* use ssid from configured ssid list */ | ||
59 | u8 filter; /* forward only results with matching ssids */ | ||
60 | |||
61 | /* | ||
62 | * add broadcast ssid in addition to the configured ssids. | ||
63 | * the driver should add dummy entry for it (?). | ||
64 | */ | ||
65 | u8 add_broadcast; | ||
66 | |||
67 | u8 urgency; | ||
68 | u8 protect; /* ??? */ | ||
69 | u8 n_probe_reqs; /* Number of probes requests per channel */ | ||
70 | u8 terminate_after; /* early terminate scan operation */ | ||
71 | |||
72 | u8 passive[SCAN_MAX_BANDS]; /* number of passive scan channels */ | ||
73 | u8 active[SCAN_MAX_BANDS]; /* number of active scan channels */ | ||
74 | u8 dfs; /* number of dfs channels in 5ghz */ | ||
75 | u8 passive_active; /* number of passive before active channels 2.4ghz */ | ||
76 | |||
77 | __le16 short_cycles_sec; | ||
78 | __le16 long_cycles_sec; | ||
79 | u8 short_cycles_count; | ||
80 | u8 total_cycles; /* 0 - infinite */ | ||
81 | u8 padding[2]; | ||
82 | |||
83 | union { | ||
84 | struct { | ||
85 | struct conn_scan_ch_params channels_2[MAX_CHANNELS_2GHZ]; | ||
86 | struct conn_scan_ch_params channels_5[WL18XX_MAX_CHANNELS_5GHZ]; | ||
87 | struct conn_scan_ch_params channels_4[MAX_CHANNELS_4GHZ]; | ||
88 | }; | ||
89 | struct tracking_ch_params channels_tracking[WL1271_SCAN_MAX_CHANNELS]; | ||
90 | } ; | ||
91 | |||
92 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | ||
93 | u8 ssid_len; /* For SCAN_SSID_FILTER_SPECIFIC */ | ||
94 | u8 tag; | ||
95 | u8 rate; | ||
96 | |||
97 | /* send SCAN_REPORT_EVENT in periodic scans after each cycle | ||
98 | * if number of results >= report_threshold. Must be 0 for | ||
99 | * non periodic scans | ||
100 | */ | ||
101 | u8 report_threshold; | ||
102 | |||
103 | /* Should periodic scan stop after a report event was created. | ||
104 | * Must be 0 for non periodic scans. | ||
105 | */ | ||
106 | u8 terminate_on_report; | ||
107 | |||
108 | u8 padding1[3]; | ||
109 | } __packed; | ||
110 | |||
111 | struct wl18xx_cmd_scan_stop { | ||
112 | struct wl1271_cmd_header header; | ||
113 | |||
114 | u8 role_id; | ||
115 | u8 scan_type; | ||
116 | u8 padding[2]; | ||
117 | } __packed; | ||
118 | |||
119 | int wl18xx_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
120 | struct cfg80211_scan_request *req); | ||
121 | int wl18xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif); | ||
122 | void wl18xx_scan_completed(struct wl1271 *wl, struct wl12xx_vif *wlvif); | ||
123 | int wl18xx_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
124 | struct cfg80211_sched_scan_request *req, | ||
125 | struct ieee80211_sched_scan_ies *ies); | ||
126 | void wl18xx_scan_sched_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif); | ||
127 | #endif | ||
diff --git a/drivers/net/wireless/ti/wl18xx/tx.c b/drivers/net/wireless/ti/wl18xx/tx.c index 5b1fb10d9fd7..57c694396647 100644 --- a/drivers/net/wireless/ti/wl18xx/tx.c +++ b/drivers/net/wireless/ti/wl18xx/tx.c | |||
@@ -28,6 +28,49 @@ | |||
28 | #include "wl18xx.h" | 28 | #include "wl18xx.h" |
29 | #include "tx.h" | 29 | #include "tx.h" |
30 | 30 | ||
31 | static | ||
32 | void wl18xx_get_last_tx_rate(struct wl1271 *wl, struct ieee80211_vif *vif, | ||
33 | struct ieee80211_tx_rate *rate) | ||
34 | { | ||
35 | u8 fw_rate = wl->fw_status_2->counters.tx_last_rate; | ||
36 | |||
37 | if (fw_rate > CONF_HW_RATE_INDEX_MAX) { | ||
38 | wl1271_error("last Tx rate invalid: %d", fw_rate); | ||
39 | rate->idx = 0; | ||
40 | rate->flags = 0; | ||
41 | return; | ||
42 | } | ||
43 | |||
44 | if (fw_rate <= CONF_HW_RATE_INDEX_54MBPS) { | ||
45 | rate->idx = fw_rate; | ||
46 | rate->flags = 0; | ||
47 | } else { | ||
48 | rate->flags = IEEE80211_TX_RC_MCS; | ||
49 | rate->idx = fw_rate - CONF_HW_RATE_INDEX_MCS0; | ||
50 | |||
51 | /* SGI modifier is counted as a separate rate */ | ||
52 | if (fw_rate >= CONF_HW_RATE_INDEX_MCS7_SGI) | ||
53 | (rate->idx)--; | ||
54 | if (fw_rate == CONF_HW_RATE_INDEX_MCS15_SGI) | ||
55 | (rate->idx)--; | ||
56 | |||
57 | /* this also covers the 40Mhz SGI case (= MCS15) */ | ||
58 | if (fw_rate == CONF_HW_RATE_INDEX_MCS7_SGI || | ||
59 | fw_rate == CONF_HW_RATE_INDEX_MCS15_SGI) | ||
60 | rate->flags |= IEEE80211_TX_RC_SHORT_GI; | ||
61 | |||
62 | if (fw_rate > CONF_HW_RATE_INDEX_MCS7_SGI && vif) { | ||
63 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | ||
64 | if (wlvif->channel_type == NL80211_CHAN_HT40MINUS || | ||
65 | wlvif->channel_type == NL80211_CHAN_HT40PLUS) { | ||
66 | /* adjustment needed for range 0-7 */ | ||
67 | rate->idx -= 8; | ||
68 | rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; | ||
69 | } | ||
70 | } | ||
71 | } | ||
72 | } | ||
73 | |||
31 | static void wl18xx_tx_complete_packet(struct wl1271 *wl, u8 tx_stat_byte) | 74 | static void wl18xx_tx_complete_packet(struct wl1271 *wl, u8 tx_stat_byte) |
32 | { | 75 | { |
33 | struct ieee80211_tx_info *info; | 76 | struct ieee80211_tx_info *info; |
@@ -44,7 +87,6 @@ static void wl18xx_tx_complete_packet(struct wl1271 *wl, u8 tx_stat_byte) | |||
44 | /* a zero bit indicates Tx success */ | 87 | /* a zero bit indicates Tx success */ |
45 | tx_success = !(tx_stat_byte & BIT(WL18XX_TX_STATUS_STAT_BIT_IDX)); | 88 | tx_success = !(tx_stat_byte & BIT(WL18XX_TX_STATUS_STAT_BIT_IDX)); |
46 | 89 | ||
47 | |||
48 | skb = wl->tx_frames[id]; | 90 | skb = wl->tx_frames[id]; |
49 | info = IEEE80211_SKB_CB(skb); | 91 | info = IEEE80211_SKB_CB(skb); |
50 | 92 | ||
@@ -56,11 +98,13 @@ static void wl18xx_tx_complete_packet(struct wl1271 *wl, u8 tx_stat_byte) | |||
56 | /* update the TX status info */ | 98 | /* update the TX status info */ |
57 | if (tx_success && !(info->flags & IEEE80211_TX_CTL_NO_ACK)) | 99 | if (tx_success && !(info->flags & IEEE80211_TX_CTL_NO_ACK)) |
58 | info->flags |= IEEE80211_TX_STAT_ACK; | 100 | info->flags |= IEEE80211_TX_STAT_ACK; |
101 | /* | ||
102 | * first pass info->control.vif while it's valid, and then fill out | ||
103 | * the info->status structures | ||
104 | */ | ||
105 | wl18xx_get_last_tx_rate(wl, info->control.vif, &info->status.rates[0]); | ||
59 | 106 | ||
60 | /* no real data about Tx completion */ | 107 | info->status.rates[0].count = 1; /* no data about retries */ |
61 | info->status.rates[0].idx = -1; | ||
62 | info->status.rates[0].count = 0; | ||
63 | info->status.rates[0].flags = 0; | ||
64 | info->status.ack_signal = -1; | 108 | info->status.ack_signal = -1; |
65 | 109 | ||
66 | if (!tx_success) | 110 | if (!tx_success) |
diff --git a/drivers/net/wireless/ti/wl18xx/wl18xx.h b/drivers/net/wireless/ti/wl18xx/wl18xx.h index 96a1e438d677..b6739e79efcf 100644 --- a/drivers/net/wireless/ti/wl18xx/wl18xx.h +++ b/drivers/net/wireless/ti/wl18xx/wl18xx.h | |||
@@ -26,10 +26,10 @@ | |||
26 | 26 | ||
27 | /* minimum FW required for driver */ | 27 | /* minimum FW required for driver */ |
28 | #define WL18XX_CHIP_VER 8 | 28 | #define WL18XX_CHIP_VER 8 |
29 | #define WL18XX_IFTYPE_VER 2 | 29 | #define WL18XX_IFTYPE_VER 5 |
30 | #define WL18XX_MAJOR_VER 0 | 30 | #define WL18XX_MAJOR_VER WLCORE_FW_VER_IGNORE |
31 | #define WL18XX_SUBTYPE_VER 0 | 31 | #define WL18XX_SUBTYPE_VER WLCORE_FW_VER_IGNORE |
32 | #define WL18XX_MINOR_VER 100 | 32 | #define WL18XX_MINOR_VER 28 |
33 | 33 | ||
34 | #define WL18XX_CMD_MAX_SIZE 740 | 34 | #define WL18XX_CMD_MAX_SIZE 740 |
35 | 35 | ||
@@ -49,8 +49,8 @@ struct wl18xx_priv { | |||
49 | /* Index of last released Tx desc in FW */ | 49 | /* Index of last released Tx desc in FW */ |
50 | u8 last_fw_rls_idx; | 50 | u8 last_fw_rls_idx; |
51 | 51 | ||
52 | /* number of VIFs requiring extra spare mem-blocks */ | 52 | /* number of keys requiring extra spare mem-blocks */ |
53 | int extra_spare_vif_count; | 53 | int extra_spare_key_count; |
54 | }; | 54 | }; |
55 | 55 | ||
56 | #define WL18XX_FW_MAX_TX_STATUS_DESC 33 | 56 | #define WL18XX_FW_MAX_TX_STATUS_DESC 33 |
@@ -68,7 +68,43 @@ struct wl18xx_fw_status_priv { | |||
68 | */ | 68 | */ |
69 | u8 released_tx_desc[WL18XX_FW_MAX_TX_STATUS_DESC]; | 69 | u8 released_tx_desc[WL18XX_FW_MAX_TX_STATUS_DESC]; |
70 | 70 | ||
71 | u8 padding[2]; | 71 | /* A bitmap representing the currently suspended links. The suspend |
72 | * is short lived, for multi-channel Tx requirements. | ||
73 | */ | ||
74 | __le32 link_suspend_bitmap; | ||
75 | |||
76 | /* packet threshold for an "almost empty" AC, | ||
77 | * for Tx schedulng purposes | ||
78 | */ | ||
79 | u8 tx_ac_threshold; | ||
80 | |||
81 | /* number of packets to queue up for a link in PS */ | ||
82 | u8 tx_ps_threshold; | ||
83 | |||
84 | /* number of packet to queue up for a suspended link */ | ||
85 | u8 tx_suspend_threshold; | ||
86 | |||
87 | /* Should have less than this number of packets in queue of a slow | ||
88 | * link to qualify as high priority link | ||
89 | */ | ||
90 | u8 tx_slow_link_prio_threshold; | ||
91 | |||
92 | /* Should have less than this number of packets in queue of a fast | ||
93 | * link to qualify as high priority link | ||
94 | */ | ||
95 | u8 tx_fast_link_prio_threshold; | ||
96 | |||
97 | /* Should have less than this number of packets in queue of a slow | ||
98 | * link before we stop queuing up packets for it. | ||
99 | */ | ||
100 | u8 tx_slow_stop_threshold; | ||
101 | |||
102 | /* Should have less than this number of packets in queue of a fast | ||
103 | * link before we stop queuing up packets for it. | ||
104 | */ | ||
105 | u8 tx_fast_stop_threshold; | ||
106 | |||
107 | u8 padding[3]; | ||
72 | }; | 108 | }; |
73 | 109 | ||
74 | #define WL18XX_PHY_VERSION_MAX_LEN 20 | 110 | #define WL18XX_PHY_VERSION_MAX_LEN 20 |
diff --git a/drivers/net/wireless/ti/wlcore/acx.c b/drivers/net/wireless/ti/wlcore/acx.c index ce108a736bd0..c79654323396 100644 --- a/drivers/net/wireless/ti/wlcore/acx.c +++ b/drivers/net/wireless/ti/wlcore/acx.c | |||
@@ -1340,6 +1340,8 @@ out: | |||
1340 | kfree(acx); | 1340 | kfree(acx); |
1341 | return ret; | 1341 | return ret; |
1342 | } | 1342 | } |
1343 | EXPORT_SYMBOL_GPL(wl1271_acx_set_ht_capabilities); | ||
1344 | |||
1343 | 1345 | ||
1344 | int wl1271_acx_set_ht_information(struct wl1271 *wl, | 1346 | int wl1271_acx_set_ht_information(struct wl1271 *wl, |
1345 | struct wl12xx_vif *wlvif, | 1347 | struct wl12xx_vif *wlvif, |
@@ -1433,13 +1435,22 @@ int wl12xx_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, | |||
1433 | acx->win_size = wl->conf.ht.rx_ba_win_size; | 1435 | acx->win_size = wl->conf.ht.rx_ba_win_size; |
1434 | acx->ssn = ssn; | 1436 | acx->ssn = ssn; |
1435 | 1437 | ||
1436 | ret = wl1271_cmd_configure(wl, ACX_BA_SESSION_RX_SETUP, acx, | 1438 | ret = wlcore_cmd_configure_failsafe(wl, ACX_BA_SESSION_RX_SETUP, acx, |
1437 | sizeof(*acx)); | 1439 | sizeof(*acx), |
1440 | BIT(CMD_STATUS_NO_RX_BA_SESSION)); | ||
1438 | if (ret < 0) { | 1441 | if (ret < 0) { |
1439 | wl1271_warning("acx ba receiver session failed: %d", ret); | 1442 | wl1271_warning("acx ba receiver session failed: %d", ret); |
1440 | goto out; | 1443 | goto out; |
1441 | } | 1444 | } |
1442 | 1445 | ||
1446 | /* sometimes we can't start the session */ | ||
1447 | if (ret == CMD_STATUS_NO_RX_BA_SESSION) { | ||
1448 | wl1271_warning("no fw rx ba on tid %d", tid_index); | ||
1449 | ret = -EBUSY; | ||
1450 | goto out; | ||
1451 | } | ||
1452 | |||
1453 | ret = 0; | ||
1443 | out: | 1454 | out: |
1444 | kfree(acx); | 1455 | kfree(acx); |
1445 | return ret; | 1456 | return ret; |
diff --git a/drivers/net/wireless/ti/wlcore/acx.h b/drivers/net/wireless/ti/wlcore/acx.h index d03215d6b3bd..126536c6a393 100644 --- a/drivers/net/wireless/ti/wlcore/acx.h +++ b/drivers/net/wireless/ti/wlcore/acx.h | |||
@@ -1025,7 +1025,6 @@ enum { | |||
1025 | ACX_CONFIG_HANGOVER = 0x0042, | 1025 | ACX_CONFIG_HANGOVER = 0x0042, |
1026 | ACX_FEATURE_CFG = 0x0043, | 1026 | ACX_FEATURE_CFG = 0x0043, |
1027 | ACX_PROTECTION_CFG = 0x0044, | 1027 | ACX_PROTECTION_CFG = 0x0044, |
1028 | ACX_CHECKSUM_CONFIG = 0x0045, | ||
1029 | }; | 1028 | }; |
1030 | 1029 | ||
1031 | 1030 | ||
diff --git a/drivers/net/wireless/ti/wlcore/boot.c b/drivers/net/wireless/ti/wlcore/boot.c index 375ea574eafb..b58ae5fc1487 100644 --- a/drivers/net/wireless/ti/wlcore/boot.c +++ b/drivers/net/wireless/ti/wlcore/boot.c | |||
@@ -84,47 +84,57 @@ out: | |||
84 | static int wlcore_validate_fw_ver(struct wl1271 *wl) | 84 | static int wlcore_validate_fw_ver(struct wl1271 *wl) |
85 | { | 85 | { |
86 | unsigned int *fw_ver = wl->chip.fw_ver; | 86 | unsigned int *fw_ver = wl->chip.fw_ver; |
87 | unsigned int *min_ver = wl->min_fw_ver; | 87 | unsigned int *min_ver = (wl->fw_type == WL12XX_FW_TYPE_NORMAL) ? |
88 | wl->min_sr_fw_ver : wl->min_mr_fw_ver; | ||
89 | char min_fw_str[32] = ""; | ||
90 | int i; | ||
88 | 91 | ||
89 | /* the chip must be exactly equal */ | 92 | /* the chip must be exactly equal */ |
90 | if (min_ver[FW_VER_CHIP] != fw_ver[FW_VER_CHIP]) | 93 | if ((min_ver[FW_VER_CHIP] != WLCORE_FW_VER_IGNORE) && |
94 | (min_ver[FW_VER_CHIP] != fw_ver[FW_VER_CHIP])) | ||
91 | goto fail; | 95 | goto fail; |
92 | 96 | ||
93 | /* always check the next digit if all previous ones are equal */ | 97 | /* the firmware type must be equal */ |
94 | 98 | if ((min_ver[FW_VER_IF_TYPE] != WLCORE_FW_VER_IGNORE) && | |
95 | if (min_ver[FW_VER_IF_TYPE] < fw_ver[FW_VER_IF_TYPE]) | 99 | (min_ver[FW_VER_IF_TYPE] != fw_ver[FW_VER_IF_TYPE])) |
96 | goto out; | ||
97 | else if (min_ver[FW_VER_IF_TYPE] > fw_ver[FW_VER_IF_TYPE]) | ||
98 | goto fail; | 100 | goto fail; |
99 | 101 | ||
100 | if (min_ver[FW_VER_MAJOR] < fw_ver[FW_VER_MAJOR]) | 102 | /* the project number must be equal */ |
101 | goto out; | 103 | if ((min_ver[FW_VER_SUBTYPE] != WLCORE_FW_VER_IGNORE) && |
102 | else if (min_ver[FW_VER_MAJOR] > fw_ver[FW_VER_MAJOR]) | 104 | (min_ver[FW_VER_SUBTYPE] != fw_ver[FW_VER_SUBTYPE])) |
103 | goto fail; | 105 | goto fail; |
104 | 106 | ||
105 | if (min_ver[FW_VER_SUBTYPE] < fw_ver[FW_VER_SUBTYPE]) | 107 | /* the API version must be greater or equal */ |
106 | goto out; | 108 | if ((min_ver[FW_VER_MAJOR] != WLCORE_FW_VER_IGNORE) && |
107 | else if (min_ver[FW_VER_SUBTYPE] > fw_ver[FW_VER_SUBTYPE]) | 109 | (min_ver[FW_VER_MAJOR] > fw_ver[FW_VER_MAJOR])) |
108 | goto fail; | 110 | goto fail; |
109 | 111 | ||
110 | if (min_ver[FW_VER_MINOR] < fw_ver[FW_VER_MINOR]) | 112 | /* if the API version is equal... */ |
111 | goto out; | 113 | if (((min_ver[FW_VER_MAJOR] == WLCORE_FW_VER_IGNORE) || |
112 | else if (min_ver[FW_VER_MINOR] > fw_ver[FW_VER_MINOR]) | 114 | (min_ver[FW_VER_MAJOR] == fw_ver[FW_VER_MAJOR])) && |
115 | /* ...the minor must be greater or equal */ | ||
116 | ((min_ver[FW_VER_MINOR] != WLCORE_FW_VER_IGNORE) && | ||
117 | (min_ver[FW_VER_MINOR] > fw_ver[FW_VER_MINOR]))) | ||
113 | goto fail; | 118 | goto fail; |
114 | 119 | ||
115 | out: | ||
116 | return 0; | 120 | return 0; |
117 | 121 | ||
118 | fail: | 122 | fail: |
119 | wl1271_error("Your WiFi FW version (%u.%u.%u.%u.%u) is outdated.\n" | 123 | for (i = 0; i < NUM_FW_VER; i++) |
120 | "Please use at least FW %u.%u.%u.%u.%u.\n" | 124 | if (min_ver[i] == WLCORE_FW_VER_IGNORE) |
121 | "You can get more information at:\n" | 125 | snprintf(min_fw_str, sizeof(min_fw_str), |
122 | "http://wireless.kernel.org/en/users/Drivers/wl12xx", | 126 | "%s*.", min_fw_str); |
127 | else | ||
128 | snprintf(min_fw_str, sizeof(min_fw_str), | ||
129 | "%s%u.", min_fw_str, min_ver[i]); | ||
130 | |||
131 | wl1271_error("Your WiFi FW version (%u.%u.%u.%u.%u) is invalid.\n" | ||
132 | "Please use at least FW %s\n" | ||
133 | "You can get the latest firmwares at:\n" | ||
134 | "git://github.com/TI-OpenLink/firmwares.git", | ||
123 | fw_ver[FW_VER_CHIP], fw_ver[FW_VER_IF_TYPE], | 135 | fw_ver[FW_VER_CHIP], fw_ver[FW_VER_IF_TYPE], |
124 | fw_ver[FW_VER_MAJOR], fw_ver[FW_VER_SUBTYPE], | 136 | fw_ver[FW_VER_MAJOR], fw_ver[FW_VER_SUBTYPE], |
125 | fw_ver[FW_VER_MINOR], min_ver[FW_VER_CHIP], | 137 | fw_ver[FW_VER_MINOR], min_fw_str); |
126 | min_ver[FW_VER_IF_TYPE], min_ver[FW_VER_MAJOR], | ||
127 | min_ver[FW_VER_SUBTYPE], min_ver[FW_VER_MINOR]); | ||
128 | return -EINVAL; | 138 | return -EINVAL; |
129 | } | 139 | } |
130 | 140 | ||
@@ -491,7 +501,7 @@ int wlcore_boot_run_firmware(struct wl1271 *wl) | |||
491 | if (ret < 0) | 501 | if (ret < 0) |
492 | return ret; | 502 | return ret; |
493 | 503 | ||
494 | wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox); | 504 | wl->mbox_ptr[1] = wl->mbox_ptr[0] + wl->mbox_size; |
495 | 505 | ||
496 | wl1271_debug(DEBUG_MAILBOX, "MBOX ptrs: 0x%x 0x%x", | 506 | wl1271_debug(DEBUG_MAILBOX, "MBOX ptrs: 0x%x 0x%x", |
497 | wl->mbox_ptr[0], wl->mbox_ptr[1]); | 507 | wl->mbox_ptr[0], wl->mbox_ptr[1]); |
@@ -508,23 +518,6 @@ int wlcore_boot_run_firmware(struct wl1271 *wl) | |||
508 | */ | 518 | */ |
509 | 519 | ||
510 | /* unmask required mbox events */ | 520 | /* unmask required mbox events */ |
511 | wl->event_mask = BSS_LOSE_EVENT_ID | | ||
512 | REGAINED_BSS_EVENT_ID | | ||
513 | SCAN_COMPLETE_EVENT_ID | | ||
514 | ROLE_STOP_COMPLETE_EVENT_ID | | ||
515 | RSSI_SNR_TRIGGER_0_EVENT_ID | | ||
516 | PSPOLL_DELIVERY_FAILURE_EVENT_ID | | ||
517 | SOFT_GEMINI_SENSE_EVENT_ID | | ||
518 | PERIODIC_SCAN_REPORT_EVENT_ID | | ||
519 | PERIODIC_SCAN_COMPLETE_EVENT_ID | | ||
520 | DUMMY_PACKET_EVENT_ID | | ||
521 | PEER_REMOVE_COMPLETE_EVENT_ID | | ||
522 | BA_SESSION_RX_CONSTRAINT_EVENT_ID | | ||
523 | REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID | | ||
524 | INACTIVE_STA_EVENT_ID | | ||
525 | MAX_TX_RETRY_EVENT_ID | | ||
526 | CHANNEL_SWITCH_COMPLETE_EVENT_ID; | ||
527 | |||
528 | ret = wl1271_event_unmask(wl); | 521 | ret = wl1271_event_unmask(wl); |
529 | if (ret < 0) { | 522 | if (ret < 0) { |
530 | wl1271_error("EVENT mask setting failed"); | 523 | wl1271_error("EVENT mask setting failed"); |
diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c index 27f83f72a93b..1201aca9c89a 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.c +++ b/drivers/net/wireless/ti/wlcore/cmd.c | |||
@@ -48,14 +48,15 @@ | |||
48 | * @id: command id | 48 | * @id: command id |
49 | * @buf: buffer containing the command, must work with dma | 49 | * @buf: buffer containing the command, must work with dma |
50 | * @len: length of the buffer | 50 | * @len: length of the buffer |
51 | * return the cmd status code on success. | ||
51 | */ | 52 | */ |
52 | int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, | 53 | static int __wlcore_cmd_send(struct wl1271 *wl, u16 id, void *buf, |
53 | size_t res_len) | 54 | size_t len, size_t res_len) |
54 | { | 55 | { |
55 | struct wl1271_cmd_header *cmd; | 56 | struct wl1271_cmd_header *cmd; |
56 | unsigned long timeout; | 57 | unsigned long timeout; |
57 | u32 intr; | 58 | u32 intr; |
58 | int ret = 0; | 59 | int ret; |
59 | u16 status; | 60 | u16 status; |
60 | u16 poll_count = 0; | 61 | u16 poll_count = 0; |
61 | 62 | ||
@@ -71,7 +72,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, | |||
71 | 72 | ||
72 | ret = wlcore_write(wl, wl->cmd_box_addr, buf, len, false); | 73 | ret = wlcore_write(wl, wl->cmd_box_addr, buf, len, false); |
73 | if (ret < 0) | 74 | if (ret < 0) |
74 | goto fail; | 75 | return ret; |
75 | 76 | ||
76 | /* | 77 | /* |
77 | * TODO: we just need this because one bit is in a different | 78 | * TODO: we just need this because one bit is in a different |
@@ -79,19 +80,18 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, | |||
79 | */ | 80 | */ |
80 | ret = wl->ops->trigger_cmd(wl, wl->cmd_box_addr, buf, len); | 81 | ret = wl->ops->trigger_cmd(wl, wl->cmd_box_addr, buf, len); |
81 | if (ret < 0) | 82 | if (ret < 0) |
82 | goto fail; | 83 | return ret; |
83 | 84 | ||
84 | timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT); | 85 | timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT); |
85 | 86 | ||
86 | ret = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR, &intr); | 87 | ret = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR, &intr); |
87 | if (ret < 0) | 88 | if (ret < 0) |
88 | goto fail; | 89 | return ret; |
89 | 90 | ||
90 | while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) { | 91 | while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) { |
91 | if (time_after(jiffies, timeout)) { | 92 | if (time_after(jiffies, timeout)) { |
92 | wl1271_error("command complete timeout"); | 93 | wl1271_error("command complete timeout"); |
93 | ret = -ETIMEDOUT; | 94 | return -ETIMEDOUT; |
94 | goto fail; | ||
95 | } | 95 | } |
96 | 96 | ||
97 | poll_count++; | 97 | poll_count++; |
@@ -102,7 +102,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, | |||
102 | 102 | ||
103 | ret = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR, &intr); | 103 | ret = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR, &intr); |
104 | if (ret < 0) | 104 | if (ret < 0) |
105 | goto fail; | 105 | return ret; |
106 | } | 106 | } |
107 | 107 | ||
108 | /* read back the status code of the command */ | 108 | /* read back the status code of the command */ |
@@ -111,33 +111,66 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, | |||
111 | 111 | ||
112 | ret = wlcore_read(wl, wl->cmd_box_addr, cmd, res_len, false); | 112 | ret = wlcore_read(wl, wl->cmd_box_addr, cmd, res_len, false); |
113 | if (ret < 0) | 113 | if (ret < 0) |
114 | goto fail; | 114 | return ret; |
115 | 115 | ||
116 | status = le16_to_cpu(cmd->status); | 116 | status = le16_to_cpu(cmd->status); |
117 | if (status != CMD_STATUS_SUCCESS) { | ||
118 | wl1271_error("command execute failure %d", status); | ||
119 | ret = -EIO; | ||
120 | goto fail; | ||
121 | } | ||
122 | 117 | ||
123 | ret = wlcore_write_reg(wl, REG_INTERRUPT_ACK, | 118 | ret = wlcore_write_reg(wl, REG_INTERRUPT_ACK, |
124 | WL1271_ACX_INTR_CMD_COMPLETE); | 119 | WL1271_ACX_INTR_CMD_COMPLETE); |
125 | if (ret < 0) | 120 | if (ret < 0) |
121 | return ret; | ||
122 | |||
123 | return status; | ||
124 | } | ||
125 | |||
126 | /* | ||
127 | * send command to fw and return cmd status on success | ||
128 | * valid_rets contains a bitmap of allowed error codes | ||
129 | */ | ||
130 | int wlcore_cmd_send_failsafe(struct wl1271 *wl, u16 id, void *buf, size_t len, | ||
131 | size_t res_len, unsigned long valid_rets) | ||
132 | { | ||
133 | int ret = __wlcore_cmd_send(wl, id, buf, len, res_len); | ||
134 | |||
135 | if (ret < 0) | ||
126 | goto fail; | 136 | goto fail; |
127 | 137 | ||
128 | return 0; | 138 | /* success is always a valid status */ |
139 | valid_rets |= BIT(CMD_STATUS_SUCCESS); | ||
129 | 140 | ||
141 | if (ret >= MAX_COMMAND_STATUS || | ||
142 | !test_bit(ret, &valid_rets)) { | ||
143 | wl1271_error("command execute failure %d", ret); | ||
144 | ret = -EIO; | ||
145 | goto fail; | ||
146 | } | ||
147 | return ret; | ||
130 | fail: | 148 | fail: |
131 | wl12xx_queue_recovery_work(wl); | 149 | wl12xx_queue_recovery_work(wl); |
132 | return ret; | 150 | return ret; |
133 | } | 151 | } |
152 | EXPORT_SYMBOL_GPL(wl1271_cmd_send); | ||
153 | |||
154 | /* | ||
155 | * wrapper for wlcore_cmd_send that accept only CMD_STATUS_SUCCESS | ||
156 | * return 0 on success. | ||
157 | */ | ||
158 | int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, | ||
159 | size_t res_len) | ||
160 | { | ||
161 | int ret = wlcore_cmd_send_failsafe(wl, id, buf, len, res_len, 0); | ||
162 | |||
163 | if (ret < 0) | ||
164 | return ret; | ||
165 | return 0; | ||
166 | } | ||
134 | 167 | ||
135 | /* | 168 | /* |
136 | * Poll the mailbox event field until any of the bits in the mask is set or a | 169 | * Poll the mailbox event field until any of the bits in the mask is set or a |
137 | * timeout occurs (WL1271_EVENT_TIMEOUT in msecs) | 170 | * timeout occurs (WL1271_EVENT_TIMEOUT in msecs) |
138 | */ | 171 | */ |
139 | static int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl, | 172 | int wlcore_cmd_wait_for_event_or_timeout(struct wl1271 *wl, |
140 | u32 mask, bool *timeout) | 173 | u32 mask, bool *timeout) |
141 | { | 174 | { |
142 | u32 *events_vector; | 175 | u32 *events_vector; |
143 | u32 event; | 176 | u32 event; |
@@ -187,20 +220,7 @@ out: | |||
187 | kfree(events_vector); | 220 | kfree(events_vector); |
188 | return ret; | 221 | return ret; |
189 | } | 222 | } |
190 | 223 | EXPORT_SYMBOL_GPL(wlcore_cmd_wait_for_event_or_timeout); | |
191 | static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask) | ||
192 | { | ||
193 | int ret; | ||
194 | bool timeout = false; | ||
195 | |||
196 | ret = wl1271_cmd_wait_for_event_or_timeout(wl, mask, &timeout); | ||
197 | if (ret != 0 || timeout) { | ||
198 | wl12xx_queue_recovery_work(wl); | ||
199 | return ret; | ||
200 | } | ||
201 | |||
202 | return 0; | ||
203 | } | ||
204 | 224 | ||
205 | int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 *addr, u8 role_type, | 225 | int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 *addr, u8 role_type, |
206 | u8 *role_id) | 226 | u8 *role_id) |
@@ -278,6 +298,16 @@ out: | |||
278 | return ret; | 298 | return ret; |
279 | } | 299 | } |
280 | 300 | ||
301 | static int wlcore_get_new_session_id(struct wl1271 *wl, u8 hlid) | ||
302 | { | ||
303 | if (wl->session_ids[hlid] >= SESSION_COUNTER_MAX) | ||
304 | wl->session_ids[hlid] = 0; | ||
305 | |||
306 | wl->session_ids[hlid]++; | ||
307 | |||
308 | return wl->session_ids[hlid]; | ||
309 | } | ||
310 | |||
281 | int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid) | 311 | int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid) |
282 | { | 312 | { |
283 | unsigned long flags; | 313 | unsigned long flags; |
@@ -285,12 +315,21 @@ int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid) | |||
285 | if (link >= WL12XX_MAX_LINKS) | 315 | if (link >= WL12XX_MAX_LINKS) |
286 | return -EBUSY; | 316 | return -EBUSY; |
287 | 317 | ||
318 | wl->session_ids[link] = wlcore_get_new_session_id(wl, link); | ||
319 | |||
288 | /* these bits are used by op_tx */ | 320 | /* these bits are used by op_tx */ |
289 | spin_lock_irqsave(&wl->wl_lock, flags); | 321 | spin_lock_irqsave(&wl->wl_lock, flags); |
290 | __set_bit(link, wl->links_map); | 322 | __set_bit(link, wl->links_map); |
291 | __set_bit(link, wlvif->links_map); | 323 | __set_bit(link, wlvif->links_map); |
292 | spin_unlock_irqrestore(&wl->wl_lock, flags); | 324 | spin_unlock_irqrestore(&wl->wl_lock, flags); |
325 | |||
326 | /* take the last "freed packets" value from the current FW status */ | ||
327 | wl->links[link].prev_freed_pkts = | ||
328 | wl->fw_status_2->counters.tx_lnk_free_pkts[link]; | ||
329 | wl->links[link].wlvif = wlvif; | ||
293 | *hlid = link; | 330 | *hlid = link; |
331 | |||
332 | wl->active_link_count++; | ||
294 | return 0; | 333 | return 0; |
295 | } | 334 | } |
296 | 335 | ||
@@ -307,24 +346,21 @@ void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid) | |||
307 | __clear_bit(*hlid, wlvif->links_map); | 346 | __clear_bit(*hlid, wlvif->links_map); |
308 | spin_unlock_irqrestore(&wl->wl_lock, flags); | 347 | spin_unlock_irqrestore(&wl->wl_lock, flags); |
309 | 348 | ||
349 | wl->links[*hlid].allocated_pkts = 0; | ||
350 | wl->links[*hlid].prev_freed_pkts = 0; | ||
351 | wl->links[*hlid].ba_bitmap = 0; | ||
352 | memset(wl->links[*hlid].addr, 0, ETH_ALEN); | ||
353 | |||
310 | /* | 354 | /* |
311 | * At this point op_tx() will not add more packets to the queues. We | 355 | * At this point op_tx() will not add more packets to the queues. We |
312 | * can purge them. | 356 | * can purge them. |
313 | */ | 357 | */ |
314 | wl1271_tx_reset_link_queues(wl, *hlid); | 358 | wl1271_tx_reset_link_queues(wl, *hlid); |
359 | wl->links[*hlid].wlvif = NULL; | ||
315 | 360 | ||
316 | *hlid = WL12XX_INVALID_LINK_ID; | 361 | *hlid = WL12XX_INVALID_LINK_ID; |
317 | } | 362 | wl->active_link_count--; |
318 | 363 | WARN_ON_ONCE(wl->active_link_count < 0); | |
319 | static int wl12xx_get_new_session_id(struct wl1271 *wl, | ||
320 | struct wl12xx_vif *wlvif) | ||
321 | { | ||
322 | if (wlvif->session_counter >= SESSION_COUNTER_MAX) | ||
323 | wlvif->session_counter = 0; | ||
324 | |||
325 | wlvif->session_counter++; | ||
326 | |||
327 | return wlvif->session_counter; | ||
328 | } | 364 | } |
329 | 365 | ||
330 | static u8 wlcore_get_native_channel_type(u8 nl_channel_type) | 366 | static u8 wlcore_get_native_channel_type(u8 nl_channel_type) |
@@ -345,7 +381,9 @@ static u8 wlcore_get_native_channel_type(u8 nl_channel_type) | |||
345 | } | 381 | } |
346 | 382 | ||
347 | static int wl12xx_cmd_role_start_dev(struct wl1271 *wl, | 383 | static int wl12xx_cmd_role_start_dev(struct wl1271 *wl, |
348 | struct wl12xx_vif *wlvif) | 384 | struct wl12xx_vif *wlvif, |
385 | enum ieee80211_band band, | ||
386 | int channel) | ||
349 | { | 387 | { |
350 | struct wl12xx_cmd_role_start *cmd; | 388 | struct wl12xx_cmd_role_start *cmd; |
351 | int ret; | 389 | int ret; |
@@ -359,9 +397,9 @@ static int wl12xx_cmd_role_start_dev(struct wl1271 *wl, | |||
359 | wl1271_debug(DEBUG_CMD, "cmd role start dev %d", wlvif->dev_role_id); | 397 | wl1271_debug(DEBUG_CMD, "cmd role start dev %d", wlvif->dev_role_id); |
360 | 398 | ||
361 | cmd->role_id = wlvif->dev_role_id; | 399 | cmd->role_id = wlvif->dev_role_id; |
362 | if (wlvif->band == IEEE80211_BAND_5GHZ) | 400 | if (band == IEEE80211_BAND_5GHZ) |
363 | cmd->band = WLCORE_BAND_5GHZ; | 401 | cmd->band = WLCORE_BAND_5GHZ; |
364 | cmd->channel = wlvif->channel; | 402 | cmd->channel = channel; |
365 | 403 | ||
366 | if (wlvif->dev_hlid == WL12XX_INVALID_LINK_ID) { | 404 | if (wlvif->dev_hlid == WL12XX_INVALID_LINK_ID) { |
367 | ret = wl12xx_allocate_link(wl, wlvif, &wlvif->dev_hlid); | 405 | ret = wl12xx_allocate_link(wl, wlvif, &wlvif->dev_hlid); |
@@ -369,7 +407,7 @@ static int wl12xx_cmd_role_start_dev(struct wl1271 *wl, | |||
369 | goto out_free; | 407 | goto out_free; |
370 | } | 408 | } |
371 | cmd->device.hlid = wlvif->dev_hlid; | 409 | cmd->device.hlid = wlvif->dev_hlid; |
372 | cmd->device.session = wl12xx_get_new_session_id(wl, wlvif); | 410 | cmd->device.session = wl->session_ids[wlvif->dev_hlid]; |
373 | 411 | ||
374 | wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d", | 412 | wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d", |
375 | cmd->role_id, cmd->device.hlid, cmd->device.session); | 413 | cmd->role_id, cmd->device.hlid, cmd->device.session); |
@@ -420,12 +458,6 @@ static int wl12xx_cmd_role_stop_dev(struct wl1271 *wl, | |||
420 | goto out_free; | 458 | goto out_free; |
421 | } | 459 | } |
422 | 460 | ||
423 | ret = wl1271_cmd_wait_for_event(wl, ROLE_STOP_COMPLETE_EVENT_ID); | ||
424 | if (ret < 0) { | ||
425 | wl1271_error("cmd role stop dev event completion error"); | ||
426 | goto out_free; | ||
427 | } | ||
428 | |||
429 | wl12xx_free_link(wl, wlvif, &wlvif->dev_hlid); | 461 | wl12xx_free_link(wl, wlvif, &wlvif->dev_hlid); |
430 | 462 | ||
431 | out_free: | 463 | out_free: |
@@ -439,6 +471,7 @@ int wl12xx_cmd_role_start_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif) | |||
439 | { | 471 | { |
440 | struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); | 472 | struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); |
441 | struct wl12xx_cmd_role_start *cmd; | 473 | struct wl12xx_cmd_role_start *cmd; |
474 | u32 supported_rates; | ||
442 | int ret; | 475 | int ret; |
443 | 476 | ||
444 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | 477 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); |
@@ -459,7 +492,14 @@ int wl12xx_cmd_role_start_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif) | |||
459 | cmd->sta.ssid_len = wlvif->ssid_len; | 492 | cmd->sta.ssid_len = wlvif->ssid_len; |
460 | memcpy(cmd->sta.ssid, wlvif->ssid, wlvif->ssid_len); | 493 | memcpy(cmd->sta.ssid, wlvif->ssid, wlvif->ssid_len); |
461 | memcpy(cmd->sta.bssid, vif->bss_conf.bssid, ETH_ALEN); | 494 | memcpy(cmd->sta.bssid, vif->bss_conf.bssid, ETH_ALEN); |
462 | cmd->sta.local_rates = cpu_to_le32(wlvif->rate_set); | 495 | |
496 | supported_rates = CONF_TX_ENABLED_RATES | CONF_TX_MCS_RATES | | ||
497 | wlcore_hw_sta_get_ap_rate_mask(wl, wlvif); | ||
498 | if (wlvif->p2p) | ||
499 | supported_rates &= ~CONF_TX_CCK_RATES; | ||
500 | |||
501 | cmd->sta.local_rates = cpu_to_le32(supported_rates); | ||
502 | |||
463 | cmd->channel_type = wlcore_get_native_channel_type(wlvif->channel_type); | 503 | cmd->channel_type = wlcore_get_native_channel_type(wlvif->channel_type); |
464 | 504 | ||
465 | if (wlvif->sta.hlid == WL12XX_INVALID_LINK_ID) { | 505 | if (wlvif->sta.hlid == WL12XX_INVALID_LINK_ID) { |
@@ -468,7 +508,11 @@ int wl12xx_cmd_role_start_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif) | |||
468 | goto out_free; | 508 | goto out_free; |
469 | } | 509 | } |
470 | cmd->sta.hlid = wlvif->sta.hlid; | 510 | cmd->sta.hlid = wlvif->sta.hlid; |
471 | cmd->sta.session = wl12xx_get_new_session_id(wl, wlvif); | 511 | cmd->sta.session = wl->session_ids[wlvif->sta.hlid]; |
512 | /* | ||
513 | * We don't have the correct remote rates in this stage. the rates | ||
514 | * will be reconfigured later, after authorization. | ||
515 | */ | ||
472 | cmd->sta.remote_rates = cpu_to_le32(wlvif->rate_set); | 516 | cmd->sta.remote_rates = cpu_to_le32(wlvif->rate_set); |
473 | 517 | ||
474 | wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d " | 518 | wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d " |
@@ -482,6 +526,7 @@ int wl12xx_cmd_role_start_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif) | |||
482 | goto err_hlid; | 526 | goto err_hlid; |
483 | } | 527 | } |
484 | 528 | ||
529 | wlvif->sta.role_chan_type = wlvif->channel_type; | ||
485 | goto out_free; | 530 | goto out_free; |
486 | 531 | ||
487 | err_hlid: | 532 | err_hlid: |
@@ -500,7 +545,6 @@ int wl12xx_cmd_role_stop_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif) | |||
500 | { | 545 | { |
501 | struct wl12xx_cmd_role_stop *cmd; | 546 | struct wl12xx_cmd_role_stop *cmd; |
502 | int ret; | 547 | int ret; |
503 | bool timeout = false; | ||
504 | 548 | ||
505 | if (WARN_ON(wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)) | 549 | if (WARN_ON(wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)) |
506 | return -EINVAL; | 550 | return -EINVAL; |
@@ -523,17 +567,6 @@ int wl12xx_cmd_role_stop_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif) | |||
523 | goto out_free; | 567 | goto out_free; |
524 | } | 568 | } |
525 | 569 | ||
526 | /* | ||
527 | * Sometimes the firmware doesn't send this event, so we just | ||
528 | * time out without failing. Queue recovery for other | ||
529 | * failures. | ||
530 | */ | ||
531 | ret = wl1271_cmd_wait_for_event_or_timeout(wl, | ||
532 | ROLE_STOP_COMPLETE_EVENT_ID, | ||
533 | &timeout); | ||
534 | if (ret) | ||
535 | wl12xx_queue_recovery_work(wl); | ||
536 | |||
537 | wl12xx_free_link(wl, wlvif, &wlvif->sta.hlid); | 570 | wl12xx_free_link(wl, wlvif, &wlvif->sta.hlid); |
538 | 571 | ||
539 | out_free: | 572 | out_free: |
@@ -579,12 +612,15 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif) | |||
579 | cmd->ap.bss_index = WL1271_AP_BSS_INDEX; | 612 | cmd->ap.bss_index = WL1271_AP_BSS_INDEX; |
580 | cmd->ap.global_hlid = wlvif->ap.global_hlid; | 613 | cmd->ap.global_hlid = wlvif->ap.global_hlid; |
581 | cmd->ap.broadcast_hlid = wlvif->ap.bcast_hlid; | 614 | cmd->ap.broadcast_hlid = wlvif->ap.bcast_hlid; |
615 | cmd->ap.global_session_id = wl->session_ids[wlvif->ap.global_hlid]; | ||
616 | cmd->ap.bcast_session_id = wl->session_ids[wlvif->ap.bcast_hlid]; | ||
582 | cmd->ap.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set); | 617 | cmd->ap.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set); |
583 | cmd->ap.beacon_interval = cpu_to_le16(wlvif->beacon_int); | 618 | cmd->ap.beacon_interval = cpu_to_le16(wlvif->beacon_int); |
584 | cmd->ap.dtim_interval = bss_conf->dtim_period; | 619 | cmd->ap.dtim_interval = bss_conf->dtim_period; |
585 | cmd->ap.beacon_expiry = WL1271_AP_DEF_BEACON_EXP; | 620 | cmd->ap.beacon_expiry = WL1271_AP_DEF_BEACON_EXP; |
586 | /* FIXME: Change when adding DFS */ | 621 | /* FIXME: Change when adding DFS */ |
587 | cmd->ap.reset_tsf = 1; /* By default reset AP TSF */ | 622 | cmd->ap.reset_tsf = 1; /* By default reset AP TSF */ |
623 | cmd->ap.wmm = wlvif->wmm_enabled; | ||
588 | cmd->channel = wlvif->channel; | 624 | cmd->channel = wlvif->channel; |
589 | cmd->channel_type = wlcore_get_native_channel_type(wlvif->channel_type); | 625 | cmd->channel_type = wlcore_get_native_channel_type(wlvif->channel_type); |
590 | 626 | ||
@@ -599,8 +635,10 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif) | |||
599 | memcpy(cmd->ap.ssid, bss_conf->ssid, bss_conf->ssid_len); | 635 | memcpy(cmd->ap.ssid, bss_conf->ssid, bss_conf->ssid_len); |
600 | } | 636 | } |
601 | 637 | ||
602 | supported_rates = CONF_TX_AP_ENABLED_RATES | CONF_TX_MCS_RATES | | 638 | supported_rates = CONF_TX_ENABLED_RATES | CONF_TX_MCS_RATES | |
603 | wlcore_hw_ap_get_mimo_wide_rate_mask(wl, wlvif); | 639 | wlcore_hw_ap_get_mimo_wide_rate_mask(wl, wlvif); |
640 | if (wlvif->p2p) | ||
641 | supported_rates &= ~CONF_TX_CCK_RATES; | ||
604 | 642 | ||
605 | wl1271_debug(DEBUG_CMD, "cmd role start ap with supported_rates 0x%08x", | 643 | wl1271_debug(DEBUG_CMD, "cmd role start ap with supported_rates 0x%08x", |
606 | supported_rates); | 644 | supported_rates); |
@@ -799,8 +837,11 @@ int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len) | |||
799 | * @id: acx id | 837 | * @id: acx id |
800 | * @buf: buffer containing acx, including all headers, must work with dma | 838 | * @buf: buffer containing acx, including all headers, must work with dma |
801 | * @len: length of buf | 839 | * @len: length of buf |
840 | * @valid_rets: bitmap of valid cmd status codes (i.e. return values). | ||
841 | * return the cmd status on success. | ||
802 | */ | 842 | */ |
803 | int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len) | 843 | int wlcore_cmd_configure_failsafe(struct wl1271 *wl, u16 id, void *buf, |
844 | size_t len, unsigned long valid_rets) | ||
804 | { | 845 | { |
805 | struct acx_header *acx = buf; | 846 | struct acx_header *acx = buf; |
806 | int ret; | 847 | int ret; |
@@ -812,12 +853,26 @@ int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len) | |||
812 | /* payload length, does not include any headers */ | 853 | /* payload length, does not include any headers */ |
813 | acx->len = cpu_to_le16(len - sizeof(*acx)); | 854 | acx->len = cpu_to_le16(len - sizeof(*acx)); |
814 | 855 | ||
815 | ret = wl1271_cmd_send(wl, CMD_CONFIGURE, acx, len, 0); | 856 | ret = wlcore_cmd_send_failsafe(wl, CMD_CONFIGURE, acx, len, 0, |
857 | valid_rets); | ||
816 | if (ret < 0) { | 858 | if (ret < 0) { |
817 | wl1271_warning("CONFIGURE command NOK"); | 859 | wl1271_warning("CONFIGURE command NOK"); |
818 | return ret; | 860 | return ret; |
819 | } | 861 | } |
820 | 862 | ||
863 | return ret; | ||
864 | } | ||
865 | |||
866 | /* | ||
867 | * wrapper for wlcore_cmd_configure that accepts only success status. | ||
868 | * return 0 on success | ||
869 | */ | ||
870 | int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len) | ||
871 | { | ||
872 | int ret = wlcore_cmd_configure_failsafe(wl, id, buf, len, 0); | ||
873 | |||
874 | if (ret < 0) | ||
875 | return ret; | ||
821 | return 0; | 876 | return 0; |
822 | } | 877 | } |
823 | EXPORT_SYMBOL_GPL(wl1271_cmd_configure); | 878 | EXPORT_SYMBOL_GPL(wl1271_cmd_configure); |
@@ -1034,8 +1089,8 @@ int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, | |||
1034 | struct sk_buff *skb; | 1089 | struct sk_buff *skb; |
1035 | int ret; | 1090 | int ret; |
1036 | u32 rate; | 1091 | u32 rate; |
1037 | u16 template_id_2_4 = CMD_TEMPL_CFG_PROBE_REQ_2_4; | 1092 | u16 template_id_2_4 = wl->scan_templ_id_2_4; |
1038 | u16 template_id_5 = CMD_TEMPL_CFG_PROBE_REQ_5; | 1093 | u16 template_id_5 = wl->scan_templ_id_5; |
1039 | 1094 | ||
1040 | skb = ieee80211_probereq_get(wl->hw, vif, ssid, ssid_len, | 1095 | skb = ieee80211_probereq_get(wl->hw, vif, ssid, ssid_len, |
1041 | ie_len); | 1096 | ie_len); |
@@ -1048,10 +1103,10 @@ int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, | |||
1048 | 1103 | ||
1049 | wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", skb->data, skb->len); | 1104 | wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", skb->data, skb->len); |
1050 | 1105 | ||
1051 | if (!sched_scan && | 1106 | if (sched_scan && |
1052 | (wl->quirks & WLCORE_QUIRK_DUAL_PROBE_TMPL)) { | 1107 | (wl->quirks & WLCORE_QUIRK_DUAL_PROBE_TMPL)) { |
1053 | template_id_2_4 = CMD_TEMPL_APP_PROBE_REQ_2_4; | 1108 | template_id_2_4 = wl->sched_scan_templ_id_2_4; |
1054 | template_id_5 = CMD_TEMPL_APP_PROBE_REQ_5; | 1109 | template_id_5 = wl->sched_scan_templ_id_5; |
1055 | } | 1110 | } |
1056 | 1111 | ||
1057 | rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]); | 1112 | rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]); |
@@ -1068,6 +1123,7 @@ out: | |||
1068 | dev_kfree_skb(skb); | 1123 | dev_kfree_skb(skb); |
1069 | return ret; | 1124 | return ret; |
1070 | } | 1125 | } |
1126 | EXPORT_SYMBOL_GPL(wl12xx_cmd_build_probe_req); | ||
1071 | 1127 | ||
1072 | struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl, | 1128 | struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl, |
1073 | struct wl12xx_vif *wlvif, | 1129 | struct wl12xx_vif *wlvif, |
@@ -1379,7 +1435,8 @@ out: | |||
1379 | return ret; | 1435 | return ret; |
1380 | } | 1436 | } |
1381 | 1437 | ||
1382 | int wl12xx_cmd_set_peer_state(struct wl1271 *wl, u8 hlid) | 1438 | int wl12xx_cmd_set_peer_state(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
1439 | u8 hlid) | ||
1383 | { | 1440 | { |
1384 | struct wl12xx_cmd_set_peer_state *cmd; | 1441 | struct wl12xx_cmd_set_peer_state *cmd; |
1385 | int ret = 0; | 1442 | int ret = 0; |
@@ -1395,6 +1452,10 @@ int wl12xx_cmd_set_peer_state(struct wl1271 *wl, u8 hlid) | |||
1395 | cmd->hlid = hlid; | 1452 | cmd->hlid = hlid; |
1396 | cmd->state = WL1271_CMD_STA_STATE_CONNECTED; | 1453 | cmd->state = WL1271_CMD_STA_STATE_CONNECTED; |
1397 | 1454 | ||
1455 | /* wmm param is valid only for station role */ | ||
1456 | if (wlvif->bss_type == BSS_TYPE_STA_BSS) | ||
1457 | cmd->wmm = wlvif->wmm_enabled; | ||
1458 | |||
1398 | ret = wl1271_cmd_send(wl, CMD_SET_PEER_STATE, cmd, sizeof(*cmd), 0); | 1459 | ret = wl1271_cmd_send(wl, CMD_SET_PEER_STATE, cmd, sizeof(*cmd), 0); |
1399 | if (ret < 0) { | 1460 | if (ret < 0) { |
1400 | wl1271_error("failed to send set peer state command"); | 1461 | wl1271_error("failed to send set peer state command"); |
@@ -1429,6 +1490,7 @@ int wl12xx_cmd_add_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif, | |||
1429 | cmd->hlid = hlid; | 1490 | cmd->hlid = hlid; |
1430 | cmd->sp_len = sta->max_sp; | 1491 | cmd->sp_len = sta->max_sp; |
1431 | cmd->wmm = sta->wme ? 1 : 0; | 1492 | cmd->wmm = sta->wme ? 1 : 0; |
1493 | cmd->session_id = wl->session_ids[hlid]; | ||
1432 | 1494 | ||
1433 | for (i = 0; i < NUM_ACCESS_CATEGORIES_COPY; i++) | 1495 | for (i = 0; i < NUM_ACCESS_CATEGORIES_COPY; i++) |
1434 | if (sta->wme && (sta->uapsd_queues & BIT(i))) | 1496 | if (sta->wme && (sta->uapsd_queues & BIT(i))) |
@@ -1490,9 +1552,10 @@ int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid) | |||
1490 | goto out_free; | 1552 | goto out_free; |
1491 | } | 1553 | } |
1492 | 1554 | ||
1493 | ret = wl1271_cmd_wait_for_event_or_timeout(wl, | 1555 | ret = wl->ops->wait_for_event(wl, |
1494 | PEER_REMOVE_COMPLETE_EVENT_ID, | 1556 | WLCORE_EVENT_PEER_REMOVE_COMPLETE, |
1495 | &timeout); | 1557 | &timeout); |
1558 | |||
1496 | /* | 1559 | /* |
1497 | * We are ok with a timeout here. The event is sometimes not sent | 1560 | * We are ok with a timeout here. The event is sometimes not sent |
1498 | * due to a firmware bug. In case of another error (like SDIO timeout) | 1561 | * due to a firmware bug. In case of another error (like SDIO timeout) |
@@ -1508,6 +1571,131 @@ out: | |||
1508 | return ret; | 1571 | return ret; |
1509 | } | 1572 | } |
1510 | 1573 | ||
1574 | static int wlcore_get_reg_conf_ch_idx(enum ieee80211_band band, u16 ch) | ||
1575 | { | ||
1576 | int idx = -1; | ||
1577 | |||
1578 | switch (band) { | ||
1579 | case IEEE80211_BAND_5GHZ: | ||
1580 | if (ch >= 8 && ch <= 16) | ||
1581 | idx = ((ch-8)/4 + 18); | ||
1582 | else if (ch >= 34 && ch <= 64) | ||
1583 | idx = ((ch-34)/2 + 3 + 18); | ||
1584 | else if (ch >= 100 && ch <= 140) | ||
1585 | idx = ((ch-100)/4 + 15 + 18); | ||
1586 | else if (ch >= 149 && ch <= 165) | ||
1587 | idx = ((ch-149)/4 + 26 + 18); | ||
1588 | else | ||
1589 | idx = -1; | ||
1590 | break; | ||
1591 | case IEEE80211_BAND_2GHZ: | ||
1592 | if (ch >= 1 && ch <= 14) | ||
1593 | idx = ch - 1; | ||
1594 | else | ||
1595 | idx = -1; | ||
1596 | break; | ||
1597 | default: | ||
1598 | wl1271_error("get reg conf ch idx - unknown band: %d", | ||
1599 | (int)band); | ||
1600 | } | ||
1601 | |||
1602 | return idx; | ||
1603 | } | ||
1604 | |||
1605 | void wlcore_set_pending_regdomain_ch(struct wl1271 *wl, u16 channel, | ||
1606 | enum ieee80211_band band) | ||
1607 | { | ||
1608 | int ch_bit_idx = 0; | ||
1609 | |||
1610 | if (!(wl->quirks & WLCORE_QUIRK_REGDOMAIN_CONF)) | ||
1611 | return; | ||
1612 | |||
1613 | ch_bit_idx = wlcore_get_reg_conf_ch_idx(band, channel); | ||
1614 | |||
1615 | if (ch_bit_idx > 0 && ch_bit_idx <= WL1271_MAX_CHANNELS) | ||
1616 | set_bit(ch_bit_idx, (long *)wl->reg_ch_conf_pending); | ||
1617 | } | ||
1618 | |||
1619 | int wlcore_cmd_regdomain_config_locked(struct wl1271 *wl) | ||
1620 | { | ||
1621 | struct wl12xx_cmd_regdomain_dfs_config *cmd = NULL; | ||
1622 | int ret = 0, i, b, ch_bit_idx; | ||
1623 | struct ieee80211_channel *channel; | ||
1624 | u32 tmp_ch_bitmap[2]; | ||
1625 | u16 ch; | ||
1626 | struct wiphy *wiphy = wl->hw->wiphy; | ||
1627 | struct ieee80211_supported_band *band; | ||
1628 | bool timeout = false; | ||
1629 | |||
1630 | if (!(wl->quirks & WLCORE_QUIRK_REGDOMAIN_CONF)) | ||
1631 | return 0; | ||
1632 | |||
1633 | wl1271_debug(DEBUG_CMD, "cmd reg domain config"); | ||
1634 | |||
1635 | memset(tmp_ch_bitmap, 0, sizeof(tmp_ch_bitmap)); | ||
1636 | |||
1637 | for (b = IEEE80211_BAND_2GHZ; b <= IEEE80211_BAND_5GHZ; b++) { | ||
1638 | band = wiphy->bands[b]; | ||
1639 | for (i = 0; i < band->n_channels; i++) { | ||
1640 | channel = &band->channels[i]; | ||
1641 | ch = channel->hw_value; | ||
1642 | |||
1643 | if (channel->flags & (IEEE80211_CHAN_DISABLED | | ||
1644 | IEEE80211_CHAN_RADAR | | ||
1645 | IEEE80211_CHAN_PASSIVE_SCAN)) | ||
1646 | continue; | ||
1647 | |||
1648 | ch_bit_idx = wlcore_get_reg_conf_ch_idx(b, ch); | ||
1649 | if (ch_bit_idx < 0) | ||
1650 | continue; | ||
1651 | |||
1652 | set_bit(ch_bit_idx, (long *)tmp_ch_bitmap); | ||
1653 | } | ||
1654 | } | ||
1655 | |||
1656 | tmp_ch_bitmap[0] |= wl->reg_ch_conf_pending[0]; | ||
1657 | tmp_ch_bitmap[1] |= wl->reg_ch_conf_pending[1]; | ||
1658 | |||
1659 | if (!memcmp(tmp_ch_bitmap, wl->reg_ch_conf_last, sizeof(tmp_ch_bitmap))) | ||
1660 | goto out; | ||
1661 | |||
1662 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
1663 | if (!cmd) { | ||
1664 | ret = -ENOMEM; | ||
1665 | goto out; | ||
1666 | } | ||
1667 | |||
1668 | cmd->ch_bit_map1 = cpu_to_le32(tmp_ch_bitmap[0]); | ||
1669 | cmd->ch_bit_map2 = cpu_to_le32(tmp_ch_bitmap[1]); | ||
1670 | |||
1671 | wl1271_debug(DEBUG_CMD, | ||
1672 | "cmd reg domain bitmap1: 0x%08x, bitmap2: 0x%08x", | ||
1673 | cmd->ch_bit_map1, cmd->ch_bit_map2); | ||
1674 | |||
1675 | ret = wl1271_cmd_send(wl, CMD_DFS_CHANNEL_CONFIG, cmd, sizeof(*cmd), 0); | ||
1676 | if (ret < 0) { | ||
1677 | wl1271_error("failed to send reg domain dfs config"); | ||
1678 | goto out; | ||
1679 | } | ||
1680 | |||
1681 | ret = wl->ops->wait_for_event(wl, | ||
1682 | WLCORE_EVENT_DFS_CONFIG_COMPLETE, | ||
1683 | &timeout); | ||
1684 | if (ret < 0 || timeout) { | ||
1685 | wl1271_error("reg domain conf %serror", | ||
1686 | timeout ? "completion " : ""); | ||
1687 | ret = timeout ? -ETIMEDOUT : ret; | ||
1688 | goto out; | ||
1689 | } | ||
1690 | |||
1691 | memcpy(wl->reg_ch_conf_last, tmp_ch_bitmap, sizeof(tmp_ch_bitmap)); | ||
1692 | memset(wl->reg_ch_conf_pending, 0, sizeof(wl->reg_ch_conf_pending)); | ||
1693 | |||
1694 | out: | ||
1695 | kfree(cmd); | ||
1696 | return ret; | ||
1697 | } | ||
1698 | |||
1511 | int wl12xx_cmd_config_fwlog(struct wl1271 *wl) | 1699 | int wl12xx_cmd_config_fwlog(struct wl1271 *wl) |
1512 | { | 1700 | { |
1513 | struct wl12xx_cmd_config_fwlog *cmd; | 1701 | struct wl12xx_cmd_config_fwlog *cmd; |
@@ -1593,12 +1781,12 @@ out: | |||
1593 | } | 1781 | } |
1594 | 1782 | ||
1595 | static int wl12xx_cmd_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, | 1783 | static int wl12xx_cmd_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
1596 | u8 role_id) | 1784 | u8 role_id, enum ieee80211_band band, u8 channel) |
1597 | { | 1785 | { |
1598 | struct wl12xx_cmd_roc *cmd; | 1786 | struct wl12xx_cmd_roc *cmd; |
1599 | int ret = 0; | 1787 | int ret = 0; |
1600 | 1788 | ||
1601 | wl1271_debug(DEBUG_CMD, "cmd roc %d (%d)", wlvif->channel, role_id); | 1789 | wl1271_debug(DEBUG_CMD, "cmd roc %d (%d)", channel, role_id); |
1602 | 1790 | ||
1603 | if (WARN_ON(role_id == WL12XX_INVALID_ROLE_ID)) | 1791 | if (WARN_ON(role_id == WL12XX_INVALID_ROLE_ID)) |
1604 | return -EINVAL; | 1792 | return -EINVAL; |
@@ -1610,8 +1798,8 @@ static int wl12xx_cmd_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, | |||
1610 | } | 1798 | } |
1611 | 1799 | ||
1612 | cmd->role_id = role_id; | 1800 | cmd->role_id = role_id; |
1613 | cmd->channel = wlvif->channel; | 1801 | cmd->channel = channel; |
1614 | switch (wlvif->band) { | 1802 | switch (band) { |
1615 | case IEEE80211_BAND_2GHZ: | 1803 | case IEEE80211_BAND_2GHZ: |
1616 | cmd->band = WLCORE_BAND_2_4GHZ; | 1804 | cmd->band = WLCORE_BAND_2_4GHZ; |
1617 | break; | 1805 | break; |
@@ -1666,30 +1854,18 @@ out: | |||
1666 | return ret; | 1854 | return ret; |
1667 | } | 1855 | } |
1668 | 1856 | ||
1669 | int wl12xx_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id) | 1857 | int wl12xx_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id, |
1858 | enum ieee80211_band band, u8 channel) | ||
1670 | { | 1859 | { |
1671 | int ret = 0; | 1860 | int ret = 0; |
1672 | bool is_first_roc; | ||
1673 | 1861 | ||
1674 | if (WARN_ON(test_bit(role_id, wl->roc_map))) | 1862 | if (WARN_ON(test_bit(role_id, wl->roc_map))) |
1675 | return 0; | 1863 | return 0; |
1676 | 1864 | ||
1677 | is_first_roc = (find_first_bit(wl->roc_map, WL12XX_MAX_ROLES) >= | 1865 | ret = wl12xx_cmd_roc(wl, wlvif, role_id, band, channel); |
1678 | WL12XX_MAX_ROLES); | ||
1679 | |||
1680 | ret = wl12xx_cmd_roc(wl, wlvif, role_id); | ||
1681 | if (ret < 0) | 1866 | if (ret < 0) |
1682 | goto out; | 1867 | goto out; |
1683 | 1868 | ||
1684 | if (is_first_roc) { | ||
1685 | ret = wl1271_cmd_wait_for_event(wl, | ||
1686 | REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID); | ||
1687 | if (ret < 0) { | ||
1688 | wl1271_error("cmd roc event completion error"); | ||
1689 | goto out; | ||
1690 | } | ||
1691 | } | ||
1692 | |||
1693 | __set_bit(role_id, wl->roc_map); | 1869 | __set_bit(role_id, wl->roc_map); |
1694 | out: | 1870 | out: |
1695 | return ret; | 1871 | return ret; |
@@ -1719,43 +1895,7 @@ out: | |||
1719 | return ret; | 1895 | return ret; |
1720 | } | 1896 | } |
1721 | 1897 | ||
1722 | int wl12xx_cmd_channel_switch(struct wl1271 *wl, | 1898 | int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl, struct wl12xx_vif *wlvif) |
1723 | struct wl12xx_vif *wlvif, | ||
1724 | struct ieee80211_channel_switch *ch_switch) | ||
1725 | { | ||
1726 | struct wl12xx_cmd_channel_switch *cmd; | ||
1727 | int ret; | ||
1728 | |||
1729 | wl1271_debug(DEBUG_ACX, "cmd channel switch"); | ||
1730 | |||
1731 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
1732 | if (!cmd) { | ||
1733 | ret = -ENOMEM; | ||
1734 | goto out; | ||
1735 | } | ||
1736 | |||
1737 | cmd->role_id = wlvif->role_id; | ||
1738 | cmd->channel = ch_switch->channel->hw_value; | ||
1739 | cmd->switch_time = ch_switch->count; | ||
1740 | cmd->stop_tx = ch_switch->block_tx; | ||
1741 | |||
1742 | /* FIXME: control from mac80211 in the future */ | ||
1743 | cmd->post_switch_tx_disable = 0; /* Enable TX on the target channel */ | ||
1744 | |||
1745 | ret = wl1271_cmd_send(wl, CMD_CHANNEL_SWITCH, cmd, sizeof(*cmd), 0); | ||
1746 | if (ret < 0) { | ||
1747 | wl1271_error("failed to send channel switch command"); | ||
1748 | goto out_free; | ||
1749 | } | ||
1750 | |||
1751 | out_free: | ||
1752 | kfree(cmd); | ||
1753 | |||
1754 | out: | ||
1755 | return ret; | ||
1756 | } | ||
1757 | |||
1758 | int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl) | ||
1759 | { | 1899 | { |
1760 | struct wl12xx_cmd_stop_channel_switch *cmd; | 1900 | struct wl12xx_cmd_stop_channel_switch *cmd; |
1761 | int ret; | 1901 | int ret; |
@@ -1768,6 +1908,8 @@ int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl) | |||
1768 | goto out; | 1908 | goto out; |
1769 | } | 1909 | } |
1770 | 1910 | ||
1911 | cmd->role_id = wlvif->role_id; | ||
1912 | |||
1771 | ret = wl1271_cmd_send(wl, CMD_STOP_CHANNEL_SWICTH, cmd, sizeof(*cmd), 0); | 1913 | ret = wl1271_cmd_send(wl, CMD_STOP_CHANNEL_SWICTH, cmd, sizeof(*cmd), 0); |
1772 | if (ret < 0) { | 1914 | if (ret < 0) { |
1773 | wl1271_error("failed to stop channel switch command"); | 1915 | wl1271_error("failed to stop channel switch command"); |
@@ -1782,7 +1924,8 @@ out: | |||
1782 | } | 1924 | } |
1783 | 1925 | ||
1784 | /* start dev role and roc on its channel */ | 1926 | /* start dev role and roc on its channel */ |
1785 | int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif) | 1927 | int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
1928 | enum ieee80211_band band, int channel) | ||
1786 | { | 1929 | { |
1787 | int ret; | 1930 | int ret; |
1788 | 1931 | ||
@@ -1797,11 +1940,11 @@ int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif) | |||
1797 | if (ret < 0) | 1940 | if (ret < 0) |
1798 | goto out; | 1941 | goto out; |
1799 | 1942 | ||
1800 | ret = wl12xx_cmd_role_start_dev(wl, wlvif); | 1943 | ret = wl12xx_cmd_role_start_dev(wl, wlvif, band, channel); |
1801 | if (ret < 0) | 1944 | if (ret < 0) |
1802 | goto out_disable; | 1945 | goto out_disable; |
1803 | 1946 | ||
1804 | ret = wl12xx_roc(wl, wlvif, wlvif->dev_role_id); | 1947 | ret = wl12xx_roc(wl, wlvif, wlvif->dev_role_id, band, channel); |
1805 | if (ret < 0) | 1948 | if (ret < 0) |
1806 | goto out_stop; | 1949 | goto out_stop; |
1807 | 1950 | ||
diff --git a/drivers/net/wireless/ti/wlcore/cmd.h b/drivers/net/wireless/ti/wlcore/cmd.h index 2409f3d71f63..fd34123047cd 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.h +++ b/drivers/net/wireless/ti/wlcore/cmd.h | |||
@@ -31,6 +31,8 @@ struct acx_header; | |||
31 | 31 | ||
32 | int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, | 32 | int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, |
33 | size_t res_len); | 33 | size_t res_len); |
34 | int wlcore_cmd_send_failsafe(struct wl1271 *wl, u16 id, void *buf, size_t len, | ||
35 | size_t res_len, unsigned long valid_rets); | ||
34 | int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 *addr, u8 role_type, | 36 | int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 *addr, u8 role_type, |
35 | u8 *role_id); | 37 | u8 *role_id); |
36 | int wl12xx_cmd_role_disable(struct wl1271 *wl, u8 *role_id); | 38 | int wl12xx_cmd_role_disable(struct wl1271 *wl, u8 *role_id); |
@@ -39,11 +41,14 @@ int wl12xx_cmd_role_stop_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif); | |||
39 | int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif); | 41 | int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif); |
40 | int wl12xx_cmd_role_stop_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif); | 42 | int wl12xx_cmd_role_stop_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif); |
41 | int wl12xx_cmd_role_start_ibss(struct wl1271 *wl, struct wl12xx_vif *wlvif); | 43 | int wl12xx_cmd_role_start_ibss(struct wl1271 *wl, struct wl12xx_vif *wlvif); |
42 | int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif); | 44 | int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
45 | enum ieee80211_band band, int channel); | ||
43 | int wl12xx_stop_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif); | 46 | int wl12xx_stop_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif); |
44 | int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer); | 47 | int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer); |
45 | int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len); | 48 | int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len); |
46 | int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len); | 49 | int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len); |
50 | int wlcore_cmd_configure_failsafe(struct wl1271 *wl, u16 id, void *buf, | ||
51 | size_t len, unsigned long valid_rets); | ||
47 | int wl1271_cmd_data_path(struct wl1271 *wl, bool enable); | 52 | int wl1271_cmd_data_path(struct wl1271 *wl, bool enable); |
48 | int wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, | 53 | int wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
49 | u8 ps_mode, u16 auto_ps_timeout); | 54 | u8 ps_mode, u16 auto_ps_timeout); |
@@ -75,22 +80,30 @@ int wl1271_cmd_set_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif, | |||
75 | u16 action, u8 id, u8 key_type, | 80 | u16 action, u8 id, u8 key_type, |
76 | u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32, | 81 | u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32, |
77 | u16 tx_seq_16); | 82 | u16 tx_seq_16); |
78 | int wl12xx_cmd_set_peer_state(struct wl1271 *wl, u8 hlid); | 83 | int wl12xx_cmd_set_peer_state(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
79 | int wl12xx_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id); | 84 | u8 hlid); |
85 | int wl12xx_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id, | ||
86 | enum ieee80211_band band, u8 channel); | ||
80 | int wl12xx_croc(struct wl1271 *wl, u8 role_id); | 87 | int wl12xx_croc(struct wl1271 *wl, u8 role_id); |
81 | int wl12xx_cmd_add_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif, | 88 | int wl12xx_cmd_add_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
82 | struct ieee80211_sta *sta, u8 hlid); | 89 | struct ieee80211_sta *sta, u8 hlid); |
83 | int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid); | 90 | int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid); |
91 | void wlcore_set_pending_regdomain_ch(struct wl1271 *wl, u16 channel, | ||
92 | enum ieee80211_band band); | ||
93 | int wlcore_cmd_regdomain_config_locked(struct wl1271 *wl); | ||
84 | int wl12xx_cmd_config_fwlog(struct wl1271 *wl); | 94 | int wl12xx_cmd_config_fwlog(struct wl1271 *wl); |
85 | int wl12xx_cmd_start_fwlog(struct wl1271 *wl); | 95 | int wl12xx_cmd_start_fwlog(struct wl1271 *wl); |
86 | int wl12xx_cmd_stop_fwlog(struct wl1271 *wl); | 96 | int wl12xx_cmd_stop_fwlog(struct wl1271 *wl); |
87 | int wl12xx_cmd_channel_switch(struct wl1271 *wl, | 97 | int wl12xx_cmd_channel_switch(struct wl1271 *wl, |
88 | struct wl12xx_vif *wlvif, | 98 | struct wl12xx_vif *wlvif, |
89 | struct ieee80211_channel_switch *ch_switch); | 99 | struct ieee80211_channel_switch *ch_switch); |
90 | int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl); | 100 | int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl, |
101 | struct wl12xx_vif *wlvif); | ||
91 | int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, | 102 | int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
92 | u8 *hlid); | 103 | u8 *hlid); |
93 | void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid); | 104 | void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid); |
105 | int wlcore_cmd_wait_for_event_or_timeout(struct wl1271 *wl, | ||
106 | u32 mask, bool *timeout); | ||
94 | 107 | ||
95 | enum wl1271_commands { | 108 | enum wl1271_commands { |
96 | CMD_INTERROGATE = 1, /* use this to read information elements */ | 109 | CMD_INTERROGATE = 1, /* use this to read information elements */ |
@@ -149,8 +162,11 @@ enum wl1271_commands { | |||
149 | CMD_WFD_START_DISCOVERY = 45, | 162 | CMD_WFD_START_DISCOVERY = 45, |
150 | CMD_WFD_STOP_DISCOVERY = 46, | 163 | CMD_WFD_STOP_DISCOVERY = 46, |
151 | CMD_WFD_ATTRIBUTE_CONFIG = 47, | 164 | CMD_WFD_ATTRIBUTE_CONFIG = 47, |
152 | CMD_NOP = 48, | 165 | CMD_GENERIC_CFG = 48, |
153 | CMD_LAST_COMMAND, | 166 | CMD_NOP = 49, |
167 | |||
168 | /* start of 18xx specific commands */ | ||
169 | CMD_DFS_CHANNEL_CONFIG = 60, | ||
154 | 170 | ||
155 | MAX_COMMAND_ID = 0xFFFF, | 171 | MAX_COMMAND_ID = 0xFFFF, |
156 | }; | 172 | }; |
@@ -167,8 +183,8 @@ enum cmd_templ { | |||
167 | CMD_TEMPL_PS_POLL, | 183 | CMD_TEMPL_PS_POLL, |
168 | CMD_TEMPL_KLV, | 184 | CMD_TEMPL_KLV, |
169 | CMD_TEMPL_DISCONNECT, | 185 | CMD_TEMPL_DISCONNECT, |
170 | CMD_TEMPL_APP_PROBE_REQ_2_4, | 186 | CMD_TEMPL_APP_PROBE_REQ_2_4_LEGACY, |
171 | CMD_TEMPL_APP_PROBE_REQ_5, | 187 | CMD_TEMPL_APP_PROBE_REQ_5_LEGACY, |
172 | CMD_TEMPL_BAR, /* for firmware internal use only */ | 188 | CMD_TEMPL_BAR, /* for firmware internal use only */ |
173 | CMD_TEMPL_CTS, /* | 189 | CMD_TEMPL_CTS, /* |
174 | * For CTS-to-self (FastCTS) mechanism | 190 | * For CTS-to-self (FastCTS) mechanism |
@@ -179,6 +195,8 @@ enum cmd_templ { | |||
179 | CMD_TEMPL_DEAUTH_AP, | 195 | CMD_TEMPL_DEAUTH_AP, |
180 | CMD_TEMPL_TEMPORARY, | 196 | CMD_TEMPL_TEMPORARY, |
181 | CMD_TEMPL_LINK_MEASUREMENT_REPORT, | 197 | CMD_TEMPL_LINK_MEASUREMENT_REPORT, |
198 | CMD_TEMPL_PROBE_REQ_2_4_PERIODIC, | ||
199 | CMD_TEMPL_PROBE_REQ_5_PERIODIC, | ||
182 | 200 | ||
183 | CMD_TEMPL_MAX = 0xff | 201 | CMD_TEMPL_MAX = 0xff |
184 | }; | 202 | }; |
@@ -220,7 +238,8 @@ enum { | |||
220 | CMD_STATUS_FW_RESET = 22, /* Driver internal use.*/ | 238 | CMD_STATUS_FW_RESET = 22, /* Driver internal use.*/ |
221 | CMD_STATUS_TEMPLATE_OOM = 23, | 239 | CMD_STATUS_TEMPLATE_OOM = 23, |
222 | CMD_STATUS_NO_RX_BA_SESSION = 24, | 240 | CMD_STATUS_NO_RX_BA_SESSION = 24, |
223 | MAX_COMMAND_STATUS = 0xff | 241 | |
242 | MAX_COMMAND_STATUS | ||
224 | }; | 243 | }; |
225 | 244 | ||
226 | #define CMDMBOX_HEADER_LEN 4 | 245 | #define CMDMBOX_HEADER_LEN 4 |
@@ -345,7 +364,15 @@ struct wl12xx_cmd_role_start { | |||
345 | 364 | ||
346 | u8 reset_tsf; | 365 | u8 reset_tsf; |
347 | 366 | ||
348 | u8 padding_1[4]; | 367 | /* |
368 | * ap supports wmm (note that there is additional | ||
369 | * per-sta wmm configuration) | ||
370 | */ | ||
371 | u8 wmm; | ||
372 | |||
373 | u8 bcast_session_id; | ||
374 | u8 global_session_id; | ||
375 | u8 padding_1[1]; | ||
349 | } __packed ap; | 376 | } __packed ap; |
350 | }; | 377 | }; |
351 | } __packed; | 378 | } __packed; |
@@ -515,7 +542,14 @@ struct wl12xx_cmd_set_peer_state { | |||
515 | 542 | ||
516 | u8 hlid; | 543 | u8 hlid; |
517 | u8 state; | 544 | u8 state; |
518 | u8 padding[2]; | 545 | |
546 | /* | ||
547 | * wmm is relevant for sta role only. | ||
548 | * ap role configures the per-sta wmm params in | ||
549 | * the add_peer command. | ||
550 | */ | ||
551 | u8 wmm; | ||
552 | u8 padding[1]; | ||
519 | } __packed; | 553 | } __packed; |
520 | 554 | ||
521 | struct wl12xx_cmd_roc { | 555 | struct wl12xx_cmd_roc { |
@@ -558,7 +592,7 @@ struct wl12xx_cmd_add_peer { | |||
558 | u8 bss_index; | 592 | u8 bss_index; |
559 | u8 sp_len; | 593 | u8 sp_len; |
560 | u8 wmm; | 594 | u8 wmm; |
561 | u8 padding1; | 595 | u8 session_id; |
562 | } __packed; | 596 | } __packed; |
563 | 597 | ||
564 | struct wl12xx_cmd_remove_peer { | 598 | struct wl12xx_cmd_remove_peer { |
@@ -597,6 +631,13 @@ enum wl12xx_fwlogger_output { | |||
597 | WL12XX_FWLOG_OUTPUT_HOST, | 631 | WL12XX_FWLOG_OUTPUT_HOST, |
598 | }; | 632 | }; |
599 | 633 | ||
634 | struct wl12xx_cmd_regdomain_dfs_config { | ||
635 | struct wl1271_cmd_header header; | ||
636 | |||
637 | __le32 ch_bit_map1; | ||
638 | __le32 ch_bit_map2; | ||
639 | } __packed; | ||
640 | |||
600 | struct wl12xx_cmd_config_fwlog { | 641 | struct wl12xx_cmd_config_fwlog { |
601 | struct wl1271_cmd_header header; | 642 | struct wl1271_cmd_header header; |
602 | 643 | ||
@@ -626,27 +667,13 @@ struct wl12xx_cmd_stop_fwlog { | |||
626 | struct wl1271_cmd_header header; | 667 | struct wl1271_cmd_header header; |
627 | } __packed; | 668 | } __packed; |
628 | 669 | ||
629 | struct wl12xx_cmd_channel_switch { | 670 | struct wl12xx_cmd_stop_channel_switch { |
630 | struct wl1271_cmd_header header; | 671 | struct wl1271_cmd_header header; |
631 | 672 | ||
632 | u8 role_id; | 673 | u8 role_id; |
633 | |||
634 | /* The new serving channel */ | ||
635 | u8 channel; | ||
636 | /* Relative time of the serving channel switch in TBTT units */ | ||
637 | u8 switch_time; | ||
638 | /* Stop the role TX, should expect it after radar detection */ | ||
639 | u8 stop_tx; | ||
640 | /* The target channel tx status 1-stopped 0-open*/ | ||
641 | u8 post_switch_tx_disable; | ||
642 | |||
643 | u8 padding[3]; | 674 | u8 padding[3]; |
644 | } __packed; | 675 | } __packed; |
645 | 676 | ||
646 | struct wl12xx_cmd_stop_channel_switch { | ||
647 | struct wl1271_cmd_header header; | ||
648 | } __packed; | ||
649 | |||
650 | /* Used to check radio status after calibration */ | 677 | /* Used to check radio status after calibration */ |
651 | #define MAX_TLV_LENGTH 500 | 678 | #define MAX_TLV_LENGTH 500 |
652 | #define TEST_CMD_P2G_CAL 2 /* TX BiP */ | 679 | #define TEST_CMD_P2G_CAL 2 /* TX BiP */ |
diff --git a/drivers/net/wireless/ti/wlcore/conf.h b/drivers/net/wireless/ti/wlcore/conf.h index 9e40760bafe1..2b96ff821341 100644 --- a/drivers/net/wireless/ti/wlcore/conf.h +++ b/drivers/net/wireless/ti/wlcore/conf.h | |||
@@ -57,20 +57,49 @@ enum { | |||
57 | }; | 57 | }; |
58 | 58 | ||
59 | enum { | 59 | enum { |
60 | CONF_HW_RATE_INDEX_1MBPS = 0, | 60 | CONF_HW_RATE_INDEX_1MBPS = 0, |
61 | CONF_HW_RATE_INDEX_2MBPS = 1, | 61 | CONF_HW_RATE_INDEX_2MBPS = 1, |
62 | CONF_HW_RATE_INDEX_5_5MBPS = 2, | 62 | CONF_HW_RATE_INDEX_5_5MBPS = 2, |
63 | CONF_HW_RATE_INDEX_6MBPS = 3, | 63 | CONF_HW_RATE_INDEX_11MBPS = 3, |
64 | CONF_HW_RATE_INDEX_9MBPS = 4, | 64 | CONF_HW_RATE_INDEX_6MBPS = 4, |
65 | CONF_HW_RATE_INDEX_11MBPS = 5, | 65 | CONF_HW_RATE_INDEX_9MBPS = 5, |
66 | CONF_HW_RATE_INDEX_12MBPS = 6, | 66 | CONF_HW_RATE_INDEX_12MBPS = 6, |
67 | CONF_HW_RATE_INDEX_18MBPS = 7, | 67 | CONF_HW_RATE_INDEX_18MBPS = 7, |
68 | CONF_HW_RATE_INDEX_22MBPS = 8, | 68 | CONF_HW_RATE_INDEX_24MBPS = 8, |
69 | CONF_HW_RATE_INDEX_24MBPS = 9, | 69 | CONF_HW_RATE_INDEX_36MBPS = 9, |
70 | CONF_HW_RATE_INDEX_36MBPS = 10, | 70 | CONF_HW_RATE_INDEX_48MBPS = 10, |
71 | CONF_HW_RATE_INDEX_48MBPS = 11, | 71 | CONF_HW_RATE_INDEX_54MBPS = 11, |
72 | CONF_HW_RATE_INDEX_54MBPS = 12, | 72 | CONF_HW_RATE_INDEX_MCS0 = 12, |
73 | CONF_HW_RATE_INDEX_MAX = CONF_HW_RATE_INDEX_54MBPS, | 73 | CONF_HW_RATE_INDEX_MCS1 = 13, |
74 | CONF_HW_RATE_INDEX_MCS2 = 14, | ||
75 | CONF_HW_RATE_INDEX_MCS3 = 15, | ||
76 | CONF_HW_RATE_INDEX_MCS4 = 16, | ||
77 | CONF_HW_RATE_INDEX_MCS5 = 17, | ||
78 | CONF_HW_RATE_INDEX_MCS6 = 18, | ||
79 | CONF_HW_RATE_INDEX_MCS7 = 19, | ||
80 | CONF_HW_RATE_INDEX_MCS7_SGI = 20, | ||
81 | CONF_HW_RATE_INDEX_MCS0_40MHZ = 21, | ||
82 | CONF_HW_RATE_INDEX_MCS1_40MHZ = 22, | ||
83 | CONF_HW_RATE_INDEX_MCS2_40MHZ = 23, | ||
84 | CONF_HW_RATE_INDEX_MCS3_40MHZ = 24, | ||
85 | CONF_HW_RATE_INDEX_MCS4_40MHZ = 25, | ||
86 | CONF_HW_RATE_INDEX_MCS5_40MHZ = 26, | ||
87 | CONF_HW_RATE_INDEX_MCS6_40MHZ = 27, | ||
88 | CONF_HW_RATE_INDEX_MCS7_40MHZ = 28, | ||
89 | CONF_HW_RATE_INDEX_MCS7_40MHZ_SGI = 29, | ||
90 | |||
91 | /* MCS8+ rates overlap with 40Mhz rates */ | ||
92 | CONF_HW_RATE_INDEX_MCS8 = 21, | ||
93 | CONF_HW_RATE_INDEX_MCS9 = 22, | ||
94 | CONF_HW_RATE_INDEX_MCS10 = 23, | ||
95 | CONF_HW_RATE_INDEX_MCS11 = 24, | ||
96 | CONF_HW_RATE_INDEX_MCS12 = 25, | ||
97 | CONF_HW_RATE_INDEX_MCS13 = 26, | ||
98 | CONF_HW_RATE_INDEX_MCS14 = 27, | ||
99 | CONF_HW_RATE_INDEX_MCS15 = 28, | ||
100 | CONF_HW_RATE_INDEX_MCS15_SGI = 29, | ||
101 | |||
102 | CONF_HW_RATE_INDEX_MAX = CONF_HW_RATE_INDEX_MCS7_40MHZ_SGI, | ||
74 | }; | 103 | }; |
75 | 104 | ||
76 | #define CONF_HW_RXTX_RATE_UNSUPPORTED 0xff | 105 | #define CONF_HW_RXTX_RATE_UNSUPPORTED 0xff |
@@ -415,11 +444,11 @@ struct conf_rx_settings { | |||
415 | #define CONF_TX_RATE_MASK_BASIC_P2P CONF_HW_BIT_RATE_6MBPS | 444 | #define CONF_TX_RATE_MASK_BASIC_P2P CONF_HW_BIT_RATE_6MBPS |
416 | 445 | ||
417 | /* | 446 | /* |
418 | * Rates supported for data packets when operating as AP. Note the absence | 447 | * Rates supported for data packets when operating as STA/AP. Note the absence |
419 | * of the 22Mbps rate. There is a FW limitation on 12 rates so we must drop | 448 | * of the 22Mbps rate. There is a FW limitation on 12 rates so we must drop |
420 | * one. The rate dropped is not mandatory under any operating mode. | 449 | * one. The rate dropped is not mandatory under any operating mode. |
421 | */ | 450 | */ |
422 | #define CONF_TX_AP_ENABLED_RATES (CONF_HW_BIT_RATE_1MBPS | \ | 451 | #define CONF_TX_ENABLED_RATES (CONF_HW_BIT_RATE_1MBPS | \ |
423 | CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS | \ | 452 | CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS | \ |
424 | CONF_HW_BIT_RATE_6MBPS | CONF_HW_BIT_RATE_9MBPS | \ | 453 | CONF_HW_BIT_RATE_6MBPS | CONF_HW_BIT_RATE_9MBPS | \ |
425 | CONF_HW_BIT_RATE_11MBPS | CONF_HW_BIT_RATE_12MBPS | \ | 454 | CONF_HW_BIT_RATE_11MBPS | CONF_HW_BIT_RATE_12MBPS | \ |
@@ -677,6 +706,18 @@ struct conf_tx_settings { | |||
677 | 706 | ||
678 | /* Time in ms for Tx watchdog timer to expire */ | 707 | /* Time in ms for Tx watchdog timer to expire */ |
679 | u32 tx_watchdog_timeout; | 708 | u32 tx_watchdog_timeout; |
709 | |||
710 | /* | ||
711 | * when a slow link has this much packets pending, it becomes a low | ||
712 | * priority link, scheduling-wise | ||
713 | */ | ||
714 | u8 slow_link_thold; | ||
715 | |||
716 | /* | ||
717 | * when a fast link has this much packets pending, it becomes a low | ||
718 | * priority link, scheduling-wise | ||
719 | */ | ||
720 | u8 fast_link_thold; | ||
680 | } __packed; | 721 | } __packed; |
681 | 722 | ||
682 | enum { | 723 | enum { |
@@ -1047,6 +1088,7 @@ struct conf_roam_trigger_settings { | |||
1047 | struct conf_scan_settings { | 1088 | struct conf_scan_settings { |
1048 | /* | 1089 | /* |
1049 | * The minimum time to wait on each channel for active scans | 1090 | * The minimum time to wait on each channel for active scans |
1091 | * This value will be used whenever there's a connected interface. | ||
1050 | * | 1092 | * |
1051 | * Range: u32 tu/1000 | 1093 | * Range: u32 tu/1000 |
1052 | */ | 1094 | */ |
@@ -1054,24 +1096,37 @@ struct conf_scan_settings { | |||
1054 | 1096 | ||
1055 | /* | 1097 | /* |
1056 | * The maximum time to wait on each channel for active scans | 1098 | * The maximum time to wait on each channel for active scans |
1099 | * This value will be currently used whenever there's a | ||
1100 | * connected interface. It shouldn't exceed 30000 (~30ms) to avoid | ||
1101 | * possible interference of voip traffic going on while scanning. | ||
1057 | * | 1102 | * |
1058 | * Range: u32 tu/1000 | 1103 | * Range: u32 tu/1000 |
1059 | */ | 1104 | */ |
1060 | u32 max_dwell_time_active; | 1105 | u32 max_dwell_time_active; |
1061 | 1106 | ||
1062 | /* | 1107 | /* The minimum time to wait on each channel for active scans |
1063 | * The minimum time to wait on each channel for passive scans | 1108 | * when it's possible to have longer scan dwell times. |
1109 | * Currently this is used whenever we're idle on all interfaces. | ||
1110 | * Longer dwell times improve detection of networks within a | ||
1111 | * single scan. | ||
1064 | * | 1112 | * |
1065 | * Range: u32 tu/1000 | 1113 | * Range: u32 tu/1000 |
1066 | */ | 1114 | */ |
1067 | u32 min_dwell_time_passive; | 1115 | u32 min_dwell_time_active_long; |
1068 | 1116 | ||
1069 | /* | 1117 | /* The maximum time to wait on each channel for active scans |
1070 | * The maximum time to wait on each channel for passive scans | 1118 | * when it's possible to have longer scan dwell times. |
1119 | * See min_dwell_time_active_long | ||
1071 | * | 1120 | * |
1072 | * Range: u32 tu/1000 | 1121 | * Range: u32 tu/1000 |
1073 | */ | 1122 | */ |
1074 | u32 max_dwell_time_passive; | 1123 | u32 max_dwell_time_active_long; |
1124 | |||
1125 | /* time to wait on the channel for passive scans (in TU/1000) */ | ||
1126 | u32 dwell_time_passive; | ||
1127 | |||
1128 | /* time to wait on the channel for DFS scans (in TU/1000) */ | ||
1129 | u32 dwell_time_dfs; | ||
1075 | 1130 | ||
1076 | /* | 1131 | /* |
1077 | * Number of probe requests to transmit on each active scan channel | 1132 | * Number of probe requests to transmit on each active scan channel |
@@ -1276,12 +1331,20 @@ struct conf_hangover_settings { | |||
1276 | u8 window_size; | 1331 | u8 window_size; |
1277 | } __packed; | 1332 | } __packed; |
1278 | 1333 | ||
1334 | struct conf_recovery_settings { | ||
1335 | /* BUG() on fw recovery */ | ||
1336 | u8 bug_on_recovery; | ||
1337 | |||
1338 | /* Prevent HW recovery. FW will remain stuck. */ | ||
1339 | u8 no_recovery; | ||
1340 | } __packed; | ||
1341 | |||
1279 | /* | 1342 | /* |
1280 | * The conf version consists of 4 bytes. The two MSB are the wlcore | 1343 | * The conf version consists of 4 bytes. The two MSB are the wlcore |
1281 | * version, the two LSB are the lower driver's private conf | 1344 | * version, the two LSB are the lower driver's private conf |
1282 | * version. | 1345 | * version. |
1283 | */ | 1346 | */ |
1284 | #define WLCORE_CONF_VERSION (0x0002 << 16) | 1347 | #define WLCORE_CONF_VERSION (0x0005 << 16) |
1285 | #define WLCORE_CONF_MASK 0xffff0000 | 1348 | #define WLCORE_CONF_MASK 0xffff0000 |
1286 | #define WLCORE_CONF_SIZE (sizeof(struct wlcore_conf_header) + \ | 1349 | #define WLCORE_CONF_SIZE (sizeof(struct wlcore_conf_header) + \ |
1287 | sizeof(struct wlcore_conf)) | 1350 | sizeof(struct wlcore_conf)) |
@@ -1309,6 +1372,7 @@ struct wlcore_conf { | |||
1309 | struct conf_fwlog fwlog; | 1372 | struct conf_fwlog fwlog; |
1310 | struct conf_rate_policy_settings rate; | 1373 | struct conf_rate_policy_settings rate; |
1311 | struct conf_hangover_settings hangover; | 1374 | struct conf_hangover_settings hangover; |
1375 | struct conf_recovery_settings recovery; | ||
1312 | } __packed; | 1376 | } __packed; |
1313 | 1377 | ||
1314 | struct wlcore_conf_file { | 1378 | struct wlcore_conf_file { |
diff --git a/drivers/net/wireless/ti/wlcore/debugfs.c b/drivers/net/wireless/ti/wlcore/debugfs.c index c86bb00c2488..e70a7c864865 100644 --- a/drivers/net/wireless/ti/wlcore/debugfs.c +++ b/drivers/net/wireless/ti/wlcore/debugfs.c | |||
@@ -490,7 +490,7 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf, | |||
490 | DRIVER_STATE_PRINT_HEX(chip.id); | 490 | DRIVER_STATE_PRINT_HEX(chip.id); |
491 | DRIVER_STATE_PRINT_STR(chip.fw_ver_str); | 491 | DRIVER_STATE_PRINT_STR(chip.fw_ver_str); |
492 | DRIVER_STATE_PRINT_STR(chip.phy_fw_ver_str); | 492 | DRIVER_STATE_PRINT_STR(chip.phy_fw_ver_str); |
493 | DRIVER_STATE_PRINT_INT(sched_scanning); | 493 | DRIVER_STATE_PRINT_INT(recovery_count); |
494 | 494 | ||
495 | #undef DRIVER_STATE_PRINT_INT | 495 | #undef DRIVER_STATE_PRINT_INT |
496 | #undef DRIVER_STATE_PRINT_LONG | 496 | #undef DRIVER_STATE_PRINT_LONG |
@@ -560,7 +560,6 @@ static ssize_t vifs_state_read(struct file *file, char __user *user_buf, | |||
560 | if (wlvif->bss_type == BSS_TYPE_STA_BSS || | 560 | if (wlvif->bss_type == BSS_TYPE_STA_BSS || |
561 | wlvif->bss_type == BSS_TYPE_IBSS) { | 561 | wlvif->bss_type == BSS_TYPE_IBSS) { |
562 | VIF_STATE_PRINT_INT(sta.hlid); | 562 | VIF_STATE_PRINT_INT(sta.hlid); |
563 | VIF_STATE_PRINT_INT(sta.ba_rx_bitmap); | ||
564 | VIF_STATE_PRINT_INT(sta.basic_rate_idx); | 563 | VIF_STATE_PRINT_INT(sta.basic_rate_idx); |
565 | VIF_STATE_PRINT_INT(sta.ap_rate_idx); | 564 | VIF_STATE_PRINT_INT(sta.ap_rate_idx); |
566 | VIF_STATE_PRINT_INT(sta.p2p_rate_idx); | 565 | VIF_STATE_PRINT_INT(sta.p2p_rate_idx); |
@@ -577,6 +576,10 @@ static ssize_t vifs_state_read(struct file *file, char __user *user_buf, | |||
577 | VIF_STATE_PRINT_INT(ap.ucast_rate_idx[3]); | 576 | VIF_STATE_PRINT_INT(ap.ucast_rate_idx[3]); |
578 | } | 577 | } |
579 | VIF_STATE_PRINT_INT(last_tx_hlid); | 578 | VIF_STATE_PRINT_INT(last_tx_hlid); |
579 | VIF_STATE_PRINT_INT(tx_queue_count[0]); | ||
580 | VIF_STATE_PRINT_INT(tx_queue_count[1]); | ||
581 | VIF_STATE_PRINT_INT(tx_queue_count[2]); | ||
582 | VIF_STATE_PRINT_INT(tx_queue_count[3]); | ||
580 | VIF_STATE_PRINT_LHEX(links_map[0]); | 583 | VIF_STATE_PRINT_LHEX(links_map[0]); |
581 | VIF_STATE_PRINT_NSTR(ssid, wlvif->ssid_len); | 584 | VIF_STATE_PRINT_NSTR(ssid, wlvif->ssid_len); |
582 | VIF_STATE_PRINT_INT(band); | 585 | VIF_STATE_PRINT_INT(band); |
@@ -589,7 +592,6 @@ static ssize_t vifs_state_read(struct file *file, char __user *user_buf, | |||
589 | VIF_STATE_PRINT_INT(beacon_int); | 592 | VIF_STATE_PRINT_INT(beacon_int); |
590 | VIF_STATE_PRINT_INT(default_key); | 593 | VIF_STATE_PRINT_INT(default_key); |
591 | VIF_STATE_PRINT_INT(aid); | 594 | VIF_STATE_PRINT_INT(aid); |
592 | VIF_STATE_PRINT_INT(session_counter); | ||
593 | VIF_STATE_PRINT_INT(psm_entry_retry); | 595 | VIF_STATE_PRINT_INT(psm_entry_retry); |
594 | VIF_STATE_PRINT_INT(power_level); | 596 | VIF_STATE_PRINT_INT(power_level); |
595 | VIF_STATE_PRINT_INT(rssi_thold); | 597 | VIF_STATE_PRINT_INT(rssi_thold); |
@@ -993,7 +995,7 @@ static ssize_t sleep_auth_write(struct file *file, | |||
993 | return -EINVAL; | 995 | return -EINVAL; |
994 | } | 996 | } |
995 | 997 | ||
996 | if (value < 0 || value > WL1271_PSM_MAX) { | 998 | if (value > WL1271_PSM_MAX) { |
997 | wl1271_warning("sleep_auth must be between 0 and %d", | 999 | wl1271_warning("sleep_auth must be between 0 and %d", |
998 | WL1271_PSM_MAX); | 1000 | WL1271_PSM_MAX); |
999 | return -ERANGE; | 1001 | return -ERANGE; |
diff --git a/drivers/net/wireless/ti/wlcore/event.c b/drivers/net/wireless/ti/wlcore/event.c index 48907054d493..70f289aa1bc6 100644 --- a/drivers/net/wireless/ti/wlcore/event.c +++ b/drivers/net/wireless/ti/wlcore/event.c | |||
@@ -29,34 +29,39 @@ | |||
29 | #include "scan.h" | 29 | #include "scan.h" |
30 | #include "wl12xx_80211.h" | 30 | #include "wl12xx_80211.h" |
31 | 31 | ||
32 | static void wl1271_event_rssi_trigger(struct wl1271 *wl, | 32 | void wlcore_event_rssi_trigger(struct wl1271 *wl, s8 *metric_arr) |
33 | struct wl12xx_vif *wlvif, | ||
34 | struct event_mailbox *mbox) | ||
35 | { | 33 | { |
36 | struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); | 34 | struct wl12xx_vif *wlvif; |
35 | struct ieee80211_vif *vif; | ||
37 | enum nl80211_cqm_rssi_threshold_event event; | 36 | enum nl80211_cqm_rssi_threshold_event event; |
38 | s8 metric = mbox->rssi_snr_trigger_metric[0]; | 37 | s8 metric = metric_arr[0]; |
39 | 38 | ||
40 | wl1271_debug(DEBUG_EVENT, "RSSI trigger metric: %d", metric); | 39 | wl1271_debug(DEBUG_EVENT, "RSSI trigger metric: %d", metric); |
41 | 40 | ||
42 | if (metric <= wlvif->rssi_thold) | 41 | /* TODO: check actual multi-role support */ |
43 | event = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW; | 42 | wl12xx_for_each_wlvif_sta(wl, wlvif) { |
44 | else | 43 | if (metric <= wlvif->rssi_thold) |
45 | event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH; | 44 | event = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW; |
46 | 45 | else | |
47 | if (event != wlvif->last_rssi_event) | 46 | event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH; |
48 | ieee80211_cqm_rssi_notify(vif, event, GFP_KERNEL); | 47 | |
49 | wlvif->last_rssi_event = event; | 48 | vif = wl12xx_wlvif_to_vif(wlvif); |
49 | if (event != wlvif->last_rssi_event) | ||
50 | ieee80211_cqm_rssi_notify(vif, event, GFP_KERNEL); | ||
51 | wlvif->last_rssi_event = event; | ||
52 | } | ||
50 | } | 53 | } |
54 | EXPORT_SYMBOL_GPL(wlcore_event_rssi_trigger); | ||
51 | 55 | ||
52 | static void wl1271_stop_ba_event(struct wl1271 *wl, struct wl12xx_vif *wlvif) | 56 | static void wl1271_stop_ba_event(struct wl1271 *wl, struct wl12xx_vif *wlvif) |
53 | { | 57 | { |
54 | struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); | 58 | struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); |
55 | 59 | ||
56 | if (wlvif->bss_type != BSS_TYPE_AP_BSS) { | 60 | if (wlvif->bss_type != BSS_TYPE_AP_BSS) { |
57 | if (!wlvif->sta.ba_rx_bitmap) | 61 | u8 hlid = wlvif->sta.hlid; |
62 | if (!wl->links[hlid].ba_bitmap) | ||
58 | return; | 63 | return; |
59 | ieee80211_stop_rx_ba_session(vif, wlvif->sta.ba_rx_bitmap, | 64 | ieee80211_stop_rx_ba_session(vif, wl->links[hlid].ba_bitmap, |
60 | vif->bss_conf.bssid); | 65 | vif->bss_conf.bssid); |
61 | } else { | 66 | } else { |
62 | u8 hlid; | 67 | u8 hlid; |
@@ -74,8 +79,7 @@ static void wl1271_stop_ba_event(struct wl1271 *wl, struct wl12xx_vif *wlvif) | |||
74 | } | 79 | } |
75 | } | 80 | } |
76 | 81 | ||
77 | static void wl12xx_event_soft_gemini_sense(struct wl1271 *wl, | 82 | void wlcore_event_soft_gemini_sense(struct wl1271 *wl, u8 enable) |
78 | u8 enable) | ||
79 | { | 83 | { |
80 | struct wl12xx_vif *wlvif; | 84 | struct wl12xx_vif *wlvif; |
81 | 85 | ||
@@ -87,201 +91,169 @@ static void wl12xx_event_soft_gemini_sense(struct wl1271 *wl, | |||
87 | wl1271_recalc_rx_streaming(wl, wlvif); | 91 | wl1271_recalc_rx_streaming(wl, wlvif); |
88 | } | 92 | } |
89 | } | 93 | } |
90 | |||
91 | } | 94 | } |
95 | EXPORT_SYMBOL_GPL(wlcore_event_soft_gemini_sense); | ||
92 | 96 | ||
93 | static void wl1271_event_mbox_dump(struct event_mailbox *mbox) | 97 | void wlcore_event_sched_scan_completed(struct wl1271 *wl, |
98 | u8 status) | ||
94 | { | 99 | { |
95 | wl1271_debug(DEBUG_EVENT, "MBOX DUMP:"); | 100 | wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_COMPLETE_EVENT (status 0x%0x)", |
96 | wl1271_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector); | 101 | status); |
97 | wl1271_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask); | 102 | |
103 | if (wl->sched_vif) { | ||
104 | ieee80211_sched_scan_stopped(wl->hw); | ||
105 | wl->sched_vif = NULL; | ||
106 | } | ||
98 | } | 107 | } |
108 | EXPORT_SYMBOL_GPL(wlcore_event_sched_scan_completed); | ||
99 | 109 | ||
100 | static int wl1271_event_process(struct wl1271 *wl) | 110 | void wlcore_event_ba_rx_constraint(struct wl1271 *wl, |
111 | unsigned long roles_bitmap, | ||
112 | unsigned long allowed_bitmap) | ||
101 | { | 113 | { |
102 | struct event_mailbox *mbox = wl->mbox; | ||
103 | struct ieee80211_vif *vif; | ||
104 | struct wl12xx_vif *wlvif; | 114 | struct wl12xx_vif *wlvif; |
105 | u32 vector; | ||
106 | bool disconnect_sta = false; | ||
107 | unsigned long sta_bitmap = 0; | ||
108 | int ret; | ||
109 | |||
110 | wl1271_event_mbox_dump(mbox); | ||
111 | |||
112 | vector = le32_to_cpu(mbox->events_vector); | ||
113 | vector &= ~(le32_to_cpu(mbox->events_mask)); | ||
114 | wl1271_debug(DEBUG_EVENT, "vector: 0x%x", vector); | ||
115 | 115 | ||
116 | if (vector & SCAN_COMPLETE_EVENT_ID) { | 116 | wl1271_debug(DEBUG_EVENT, "%s: roles=0x%lx allowed=0x%lx", |
117 | wl1271_debug(DEBUG_EVENT, "status: 0x%x", | 117 | __func__, roles_bitmap, allowed_bitmap); |
118 | mbox->scheduled_scan_status); | ||
119 | |||
120 | wl1271_scan_stm(wl, wl->scan_vif); | ||
121 | } | ||
122 | 118 | ||
123 | if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) { | 119 | wl12xx_for_each_wlvif(wl, wlvif) { |
124 | wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_REPORT_EVENT " | 120 | if (wlvif->role_id == WL12XX_INVALID_ROLE_ID || |
125 | "(status 0x%0x)", mbox->scheduled_scan_status); | 121 | !test_bit(wlvif->role_id , &roles_bitmap)) |
122 | continue; | ||
126 | 123 | ||
127 | wl1271_scan_sched_scan_results(wl); | 124 | wlvif->ba_allowed = !!test_bit(wlvif->role_id, |
125 | &allowed_bitmap); | ||
126 | if (!wlvif->ba_allowed) | ||
127 | wl1271_stop_ba_event(wl, wlvif); | ||
128 | } | 128 | } |
129 | } | ||
130 | EXPORT_SYMBOL_GPL(wlcore_event_ba_rx_constraint); | ||
129 | 131 | ||
130 | if (vector & PERIODIC_SCAN_COMPLETE_EVENT_ID) { | 132 | void wlcore_event_channel_switch(struct wl1271 *wl, |
131 | wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_COMPLETE_EVENT " | 133 | unsigned long roles_bitmap, |
132 | "(status 0x%0x)", mbox->scheduled_scan_status); | 134 | bool success) |
133 | if (wl->sched_scanning) { | 135 | { |
134 | ieee80211_sched_scan_stopped(wl->hw); | 136 | struct wl12xx_vif *wlvif; |
135 | wl->sched_scanning = false; | 137 | struct ieee80211_vif *vif; |
136 | } | ||
137 | } | ||
138 | 138 | ||
139 | if (vector & SOFT_GEMINI_SENSE_EVENT_ID) | 139 | wl1271_debug(DEBUG_EVENT, "%s: roles=0x%lx success=%d", |
140 | wl12xx_event_soft_gemini_sense(wl, | 140 | __func__, roles_bitmap, success); |
141 | mbox->soft_gemini_sense_info); | ||
142 | 141 | ||
143 | /* | 142 | wl12xx_for_each_wlvif_sta(wl, wlvif) { |
144 | * We are HW_MONITOR device. On beacon loss - queue | 143 | if (wlvif->role_id == WL12XX_INVALID_ROLE_ID || |
145 | * connection loss work. Cancel it on REGAINED event. | 144 | !test_bit(wlvif->role_id , &roles_bitmap)) |
146 | */ | 145 | continue; |
147 | if (vector & BSS_LOSE_EVENT_ID) { | ||
148 | /* TODO: check for multi-role */ | ||
149 | int delay = wl->conf.conn.synch_fail_thold * | ||
150 | wl->conf.conn.bss_lose_timeout; | ||
151 | wl1271_info("Beacon loss detected."); | ||
152 | 146 | ||
153 | /* | 147 | if (!test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, |
154 | * if the work is already queued, it should take place. We | 148 | &wlvif->flags)) |
155 | * don't want to delay the connection loss indication | 149 | continue; |
156 | * any more. | ||
157 | */ | ||
158 | ieee80211_queue_delayed_work(wl->hw, &wl->connection_loss_work, | ||
159 | msecs_to_jiffies(delay)); | ||
160 | 150 | ||
161 | wl12xx_for_each_wlvif_sta(wl, wlvif) { | 151 | vif = wl12xx_wlvif_to_vif(wlvif); |
162 | vif = wl12xx_wlvif_to_vif(wlvif); | ||
163 | 152 | ||
164 | ieee80211_cqm_rssi_notify( | 153 | ieee80211_chswitch_done(vif, success); |
165 | vif, | 154 | cancel_delayed_work(&wlvif->channel_switch_work); |
166 | NL80211_CQM_RSSI_BEACON_LOSS_EVENT, | ||
167 | GFP_KERNEL); | ||
168 | } | ||
169 | } | 155 | } |
156 | } | ||
157 | EXPORT_SYMBOL_GPL(wlcore_event_channel_switch); | ||
170 | 158 | ||
171 | if (vector & REGAINED_BSS_EVENT_ID) { | 159 | void wlcore_event_dummy_packet(struct wl1271 *wl) |
172 | /* TODO: check for multi-role */ | 160 | { |
173 | wl1271_info("Beacon regained."); | 161 | wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID"); |
174 | cancel_delayed_work(&wl->connection_loss_work); | 162 | wl1271_tx_dummy_packet(wl); |
175 | 163 | } | |
176 | /* sanity check - we can't lose and gain the beacon together */ | 164 | EXPORT_SYMBOL_GPL(wlcore_event_dummy_packet); |
177 | WARN(vector & BSS_LOSE_EVENT_ID, | ||
178 | "Concurrent beacon loss and gain from FW"); | ||
179 | } | ||
180 | 165 | ||
181 | if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) { | 166 | static void wlcore_disconnect_sta(struct wl1271 *wl, unsigned long sta_bitmap) |
182 | /* TODO: check actual multi-role support */ | 167 | { |
183 | wl1271_debug(DEBUG_EVENT, "RSSI_SNR_TRIGGER_0_EVENT"); | 168 | u32 num_packets = wl->conf.tx.max_tx_retries; |
184 | wl12xx_for_each_wlvif_sta(wl, wlvif) { | 169 | struct wl12xx_vif *wlvif; |
185 | wl1271_event_rssi_trigger(wl, wlvif, mbox); | 170 | struct ieee80211_vif *vif; |
171 | struct ieee80211_sta *sta; | ||
172 | const u8 *addr; | ||
173 | int h; | ||
174 | |||
175 | for_each_set_bit(h, &sta_bitmap, WL12XX_MAX_LINKS) { | ||
176 | bool found = false; | ||
177 | /* find the ap vif connected to this sta */ | ||
178 | wl12xx_for_each_wlvif_ap(wl, wlvif) { | ||
179 | if (!test_bit(h, wlvif->ap.sta_hlid_map)) | ||
180 | continue; | ||
181 | found = true; | ||
182 | break; | ||
186 | } | 183 | } |
187 | } | 184 | if (!found) |
185 | continue; | ||
188 | 186 | ||
189 | if (vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID) { | 187 | vif = wl12xx_wlvif_to_vif(wlvif); |
190 | u8 role_id = mbox->role_id; | 188 | addr = wl->links[h].addr; |
191 | wl1271_debug(DEBUG_EVENT, "BA_SESSION_RX_CONSTRAINT_EVENT_ID. " | ||
192 | "ba_allowed = 0x%x, role_id=%d", | ||
193 | mbox->rx_ba_allowed, role_id); | ||
194 | 189 | ||
195 | wl12xx_for_each_wlvif(wl, wlvif) { | 190 | rcu_read_lock(); |
196 | if (role_id != 0xff && role_id != wlvif->role_id) | 191 | sta = ieee80211_find_sta(vif, addr); |
197 | continue; | 192 | if (sta) { |
198 | 193 | wl1271_debug(DEBUG_EVENT, "remove sta %d", h); | |
199 | wlvif->ba_allowed = !!mbox->rx_ba_allowed; | 194 | ieee80211_report_low_ack(sta, num_packets); |
200 | if (!wlvif->ba_allowed) | ||
201 | wl1271_stop_ba_event(wl, wlvif); | ||
202 | } | 195 | } |
196 | rcu_read_unlock(); | ||
203 | } | 197 | } |
198 | } | ||
204 | 199 | ||
205 | if (vector & CHANNEL_SWITCH_COMPLETE_EVENT_ID) { | 200 | void wlcore_event_max_tx_failure(struct wl1271 *wl, unsigned long sta_bitmap) |
206 | wl1271_debug(DEBUG_EVENT, "CHANNEL_SWITCH_COMPLETE_EVENT_ID. " | 201 | { |
207 | "status = 0x%x", | 202 | wl1271_debug(DEBUG_EVENT, "MAX_TX_FAILURE_EVENT_ID"); |
208 | mbox->channel_switch_status); | 203 | wlcore_disconnect_sta(wl, sta_bitmap); |
209 | /* | 204 | } |
210 | * That event uses for two cases: | 205 | EXPORT_SYMBOL_GPL(wlcore_event_max_tx_failure); |
211 | * 1) channel switch complete with status=0 | ||
212 | * 2) channel switch failed status=1 | ||
213 | */ | ||
214 | |||
215 | /* TODO: configure only the relevant vif */ | ||
216 | wl12xx_for_each_wlvif_sta(wl, wlvif) { | ||
217 | bool success; | ||
218 | |||
219 | if (!test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, | ||
220 | &wlvif->flags)) | ||
221 | continue; | ||
222 | |||
223 | success = mbox->channel_switch_status ? false : true; | ||
224 | vif = wl12xx_wlvif_to_vif(wlvif); | ||
225 | 206 | ||
226 | ieee80211_chswitch_done(vif, success); | 207 | void wlcore_event_inactive_sta(struct wl1271 *wl, unsigned long sta_bitmap) |
227 | } | 208 | { |
228 | } | 209 | wl1271_debug(DEBUG_EVENT, "INACTIVE_STA_EVENT_ID"); |
210 | wlcore_disconnect_sta(wl, sta_bitmap); | ||
211 | } | ||
212 | EXPORT_SYMBOL_GPL(wlcore_event_inactive_sta); | ||
229 | 213 | ||
230 | if ((vector & DUMMY_PACKET_EVENT_ID)) { | 214 | void wlcore_event_roc_complete(struct wl1271 *wl) |
231 | wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID"); | 215 | { |
232 | ret = wl1271_tx_dummy_packet(wl); | 216 | wl1271_debug(DEBUG_EVENT, "REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID"); |
233 | if (ret < 0) | 217 | if (wl->roc_vif) |
234 | return ret; | 218 | ieee80211_ready_on_channel(wl->hw); |
235 | } | 219 | } |
220 | EXPORT_SYMBOL_GPL(wlcore_event_roc_complete); | ||
236 | 221 | ||
222 | void wlcore_event_beacon_loss(struct wl1271 *wl, unsigned long roles_bitmap) | ||
223 | { | ||
237 | /* | 224 | /* |
238 | * "TX retries exceeded" has a different meaning according to mode. | 225 | * We are HW_MONITOR device. On beacon loss - queue |
239 | * In AP mode the offending station is disconnected. | 226 | * connection loss work. Cancel it on REGAINED event. |
240 | */ | 227 | */ |
241 | if (vector & MAX_TX_RETRY_EVENT_ID) { | 228 | struct wl12xx_vif *wlvif; |
242 | wl1271_debug(DEBUG_EVENT, "MAX_TX_RETRY_EVENT_ID"); | 229 | struct ieee80211_vif *vif; |
243 | sta_bitmap |= le16_to_cpu(mbox->sta_tx_retry_exceeded); | 230 | int delay = wl->conf.conn.synch_fail_thold * |
244 | disconnect_sta = true; | 231 | wl->conf.conn.bss_lose_timeout; |
245 | } | ||
246 | 232 | ||
247 | if (vector & INACTIVE_STA_EVENT_ID) { | 233 | wl1271_info("Beacon loss detected. roles:0x%lx", roles_bitmap); |
248 | wl1271_debug(DEBUG_EVENT, "INACTIVE_STA_EVENT_ID"); | ||
249 | sta_bitmap |= le16_to_cpu(mbox->sta_aging_status); | ||
250 | disconnect_sta = true; | ||
251 | } | ||
252 | 234 | ||
253 | if (disconnect_sta) { | 235 | wl12xx_for_each_wlvif_sta(wl, wlvif) { |
254 | u32 num_packets = wl->conf.tx.max_tx_retries; | 236 | if (wlvif->role_id == WL12XX_INVALID_ROLE_ID || |
255 | struct ieee80211_sta *sta; | 237 | !test_bit(wlvif->role_id , &roles_bitmap)) |
256 | const u8 *addr; | 238 | continue; |
257 | int h; | ||
258 | |||
259 | for_each_set_bit(h, &sta_bitmap, WL12XX_MAX_LINKS) { | ||
260 | bool found = false; | ||
261 | /* find the ap vif connected to this sta */ | ||
262 | wl12xx_for_each_wlvif_ap(wl, wlvif) { | ||
263 | if (!test_bit(h, wlvif->ap.sta_hlid_map)) | ||
264 | continue; | ||
265 | found = true; | ||
266 | break; | ||
267 | } | ||
268 | if (!found) | ||
269 | continue; | ||
270 | 239 | ||
271 | vif = wl12xx_wlvif_to_vif(wlvif); | 240 | /* |
272 | addr = wl->links[h].addr; | 241 | * if the work is already queued, it should take place. |
242 | * We don't want to delay the connection loss | ||
243 | * indication any more. | ||
244 | */ | ||
245 | ieee80211_queue_delayed_work(wl->hw, | ||
246 | &wlvif->connection_loss_work, | ||
247 | msecs_to_jiffies(delay)); | ||
273 | 248 | ||
274 | rcu_read_lock(); | 249 | vif = wl12xx_wlvif_to_vif(wlvif); |
275 | sta = ieee80211_find_sta(vif, addr); | 250 | ieee80211_cqm_rssi_notify( |
276 | if (sta) { | 251 | vif, |
277 | wl1271_debug(DEBUG_EVENT, "remove sta %d", h); | 252 | NL80211_CQM_RSSI_BEACON_LOSS_EVENT, |
278 | ieee80211_report_low_ack(sta, num_packets); | 253 | GFP_KERNEL); |
279 | } | ||
280 | rcu_read_unlock(); | ||
281 | } | ||
282 | } | 254 | } |
283 | return 0; | ||
284 | } | 255 | } |
256 | EXPORT_SYMBOL_GPL(wlcore_event_beacon_loss); | ||
285 | 257 | ||
286 | int wl1271_event_unmask(struct wl1271 *wl) | 258 | int wl1271_event_unmask(struct wl1271 *wl) |
287 | { | 259 | { |
@@ -305,12 +277,12 @@ int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num) | |||
305 | 277 | ||
306 | /* first we read the mbox descriptor */ | 278 | /* first we read the mbox descriptor */ |
307 | ret = wlcore_read(wl, wl->mbox_ptr[mbox_num], wl->mbox, | 279 | ret = wlcore_read(wl, wl->mbox_ptr[mbox_num], wl->mbox, |
308 | sizeof(*wl->mbox), false); | 280 | wl->mbox_size, false); |
309 | if (ret < 0) | 281 | if (ret < 0) |
310 | return ret; | 282 | return ret; |
311 | 283 | ||
312 | /* process the descriptor */ | 284 | /* process the descriptor */ |
313 | ret = wl1271_event_process(wl); | 285 | ret = wl->ops->process_mailbox_events(wl); |
314 | if (ret < 0) | 286 | if (ret < 0) |
315 | return ret; | 287 | return ret; |
316 | 288 | ||
diff --git a/drivers/net/wireless/ti/wlcore/event.h b/drivers/net/wireless/ti/wlcore/event.h index 8adf18d6c58f..acc7a59d3828 100644 --- a/drivers/net/wireless/ti/wlcore/event.h +++ b/drivers/net/wireless/ti/wlcore/event.h | |||
@@ -46,33 +46,17 @@ enum { | |||
46 | RSSI_SNR_TRIGGER_5_EVENT_ID = BIT(5), | 46 | RSSI_SNR_TRIGGER_5_EVENT_ID = BIT(5), |
47 | RSSI_SNR_TRIGGER_6_EVENT_ID = BIT(6), | 47 | RSSI_SNR_TRIGGER_6_EVENT_ID = BIT(6), |
48 | RSSI_SNR_TRIGGER_7_EVENT_ID = BIT(7), | 48 | RSSI_SNR_TRIGGER_7_EVENT_ID = BIT(7), |
49 | MEASUREMENT_START_EVENT_ID = BIT(8), | 49 | |
50 | MEASUREMENT_COMPLETE_EVENT_ID = BIT(9), | ||
51 | SCAN_COMPLETE_EVENT_ID = BIT(10), | ||
52 | WFD_DISCOVERY_COMPLETE_EVENT_ID = BIT(11), | ||
53 | AP_DISCOVERY_COMPLETE_EVENT_ID = BIT(12), | ||
54 | RESERVED1 = BIT(13), | ||
55 | PSPOLL_DELIVERY_FAILURE_EVENT_ID = BIT(14), | ||
56 | ROLE_STOP_COMPLETE_EVENT_ID = BIT(15), | ||
57 | RADAR_DETECTED_EVENT_ID = BIT(16), | ||
58 | CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(17), | ||
59 | BSS_LOSE_EVENT_ID = BIT(18), | ||
60 | REGAINED_BSS_EVENT_ID = BIT(19), | ||
61 | MAX_TX_RETRY_EVENT_ID = BIT(20), | ||
62 | DUMMY_PACKET_EVENT_ID = BIT(21), | ||
63 | SOFT_GEMINI_SENSE_EVENT_ID = BIT(22), | ||
64 | CHANGE_AUTO_MODE_TIMEOUT_EVENT_ID = BIT(23), | ||
65 | SOFT_GEMINI_AVALANCHE_EVENT_ID = BIT(24), | ||
66 | PLT_RX_CALIBRATION_COMPLETE_EVENT_ID = BIT(25), | ||
67 | INACTIVE_STA_EVENT_ID = BIT(26), | ||
68 | PEER_REMOVE_COMPLETE_EVENT_ID = BIT(27), | ||
69 | PERIODIC_SCAN_COMPLETE_EVENT_ID = BIT(28), | ||
70 | PERIODIC_SCAN_REPORT_EVENT_ID = BIT(29), | ||
71 | BA_SESSION_RX_CONSTRAINT_EVENT_ID = BIT(30), | ||
72 | REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID = BIT(31), | ||
73 | EVENT_MBOX_ALL_EVENT_ID = 0x7fffffff, | 50 | EVENT_MBOX_ALL_EVENT_ID = 0x7fffffff, |
74 | }; | 51 | }; |
75 | 52 | ||
53 | /* events the driver might want to wait for */ | ||
54 | enum wlcore_wait_event { | ||
55 | WLCORE_EVENT_ROLE_STOP_COMPLETE, | ||
56 | WLCORE_EVENT_PEER_REMOVE_COMPLETE, | ||
57 | WLCORE_EVENT_DFS_CONFIG_COMPLETE | ||
58 | }; | ||
59 | |||
76 | enum { | 60 | enum { |
77 | EVENT_ENTER_POWER_SAVE_FAIL = 0, | 61 | EVENT_ENTER_POWER_SAVE_FAIL = 0, |
78 | EVENT_ENTER_POWER_SAVE_SUCCESS, | 62 | EVENT_ENTER_POWER_SAVE_SUCCESS, |
@@ -80,61 +64,24 @@ enum { | |||
80 | 64 | ||
81 | #define NUM_OF_RSSI_SNR_TRIGGERS 8 | 65 | #define NUM_OF_RSSI_SNR_TRIGGERS 8 |
82 | 66 | ||
83 | struct event_mailbox { | ||
84 | __le32 events_vector; | ||
85 | __le32 events_mask; | ||
86 | __le32 reserved_1; | ||
87 | __le32 reserved_2; | ||
88 | |||
89 | u8 number_of_scan_results; | ||
90 | u8 scan_tag; | ||
91 | u8 completed_scan_status; | ||
92 | u8 reserved_3; | ||
93 | |||
94 | u8 soft_gemini_sense_info; | ||
95 | u8 soft_gemini_protective_info; | ||
96 | s8 rssi_snr_trigger_metric[NUM_OF_RSSI_SNR_TRIGGERS]; | ||
97 | u8 change_auto_mode_timeout; | ||
98 | u8 scheduled_scan_status; | ||
99 | u8 reserved4; | ||
100 | /* tuned channel (roc) */ | ||
101 | u8 roc_channel; | ||
102 | |||
103 | __le16 hlid_removed_bitmap; | ||
104 | |||
105 | /* bitmap of aged stations (by HLID) */ | ||
106 | __le16 sta_aging_status; | ||
107 | |||
108 | /* bitmap of stations (by HLID) which exceeded max tx retries */ | ||
109 | __le16 sta_tx_retry_exceeded; | ||
110 | |||
111 | /* discovery completed results */ | ||
112 | u8 discovery_tag; | ||
113 | u8 number_of_preq_results; | ||
114 | u8 number_of_prsp_results; | ||
115 | u8 reserved_5; | ||
116 | |||
117 | /* rx ba constraint */ | ||
118 | u8 role_id; /* 0xFF means any role. */ | ||
119 | u8 rx_ba_allowed; | ||
120 | u8 reserved_6[2]; | ||
121 | |||
122 | /* Channel switch results */ | ||
123 | |||
124 | u8 channel_switch_role_id; | ||
125 | u8 channel_switch_status; | ||
126 | u8 reserved_7[2]; | ||
127 | |||
128 | u8 ps_poll_delivery_failure_role_ids; | ||
129 | u8 stopped_role_ids; | ||
130 | u8 started_role_ids; | ||
131 | |||
132 | u8 reserved_8[9]; | ||
133 | } __packed; | ||
134 | |||
135 | struct wl1271; | 67 | struct wl1271; |
136 | 68 | ||
137 | int wl1271_event_unmask(struct wl1271 *wl); | 69 | int wl1271_event_unmask(struct wl1271 *wl); |
138 | int wl1271_event_handle(struct wl1271 *wl, u8 mbox); | 70 | int wl1271_event_handle(struct wl1271 *wl, u8 mbox); |
139 | 71 | ||
72 | void wlcore_event_soft_gemini_sense(struct wl1271 *wl, u8 enable); | ||
73 | void wlcore_event_sched_scan_completed(struct wl1271 *wl, | ||
74 | u8 status); | ||
75 | void wlcore_event_ba_rx_constraint(struct wl1271 *wl, | ||
76 | unsigned long roles_bitmap, | ||
77 | unsigned long allowed_bitmap); | ||
78 | void wlcore_event_channel_switch(struct wl1271 *wl, | ||
79 | unsigned long roles_bitmap, | ||
80 | bool success); | ||
81 | void wlcore_event_beacon_loss(struct wl1271 *wl, unsigned long roles_bitmap); | ||
82 | void wlcore_event_dummy_packet(struct wl1271 *wl); | ||
83 | void wlcore_event_max_tx_failure(struct wl1271 *wl, unsigned long sta_bitmap); | ||
84 | void wlcore_event_inactive_sta(struct wl1271 *wl, unsigned long sta_bitmap); | ||
85 | void wlcore_event_roc_complete(struct wl1271 *wl); | ||
86 | void wlcore_event_rssi_trigger(struct wl1271 *wl, s8 *metric_arr); | ||
140 | #endif | 87 | #endif |
diff --git a/drivers/net/wireless/ti/wlcore/hw_ops.h b/drivers/net/wireless/ti/wlcore/hw_ops.h index 2673d783ec1e..7fd260c02a0a 100644 --- a/drivers/net/wireless/ti/wlcore/hw_ops.h +++ b/drivers/net/wireless/ti/wlcore/hw_ops.h | |||
@@ -201,4 +201,45 @@ wlcore_hw_pre_pkt_send(struct wl1271 *wl, u32 buf_offset, u32 last_len) | |||
201 | return buf_offset; | 201 | return buf_offset; |
202 | } | 202 | } |
203 | 203 | ||
204 | static inline void | ||
205 | wlcore_hw_sta_rc_update(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
206 | struct ieee80211_sta *sta, u32 changed) | ||
207 | { | ||
208 | if (wl->ops->sta_rc_update) | ||
209 | wl->ops->sta_rc_update(wl, wlvif, sta, changed); | ||
210 | } | ||
211 | |||
212 | static inline int | ||
213 | wlcore_hw_set_peer_cap(struct wl1271 *wl, | ||
214 | struct ieee80211_sta_ht_cap *ht_cap, | ||
215 | bool allow_ht_operation, | ||
216 | u32 rate_set, u8 hlid) | ||
217 | { | ||
218 | if (wl->ops->set_peer_cap) | ||
219 | return wl->ops->set_peer_cap(wl, ht_cap, allow_ht_operation, | ||
220 | rate_set, hlid); | ||
221 | |||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | static inline bool | ||
226 | wlcore_hw_lnk_high_prio(struct wl1271 *wl, u8 hlid, | ||
227 | struct wl1271_link *lnk) | ||
228 | { | ||
229 | if (!wl->ops->lnk_high_prio) | ||
230 | BUG_ON(1); | ||
231 | |||
232 | return wl->ops->lnk_high_prio(wl, hlid, lnk); | ||
233 | } | ||
234 | |||
235 | static inline bool | ||
236 | wlcore_hw_lnk_low_prio(struct wl1271 *wl, u8 hlid, | ||
237 | struct wl1271_link *lnk) | ||
238 | { | ||
239 | if (!wl->ops->lnk_low_prio) | ||
240 | BUG_ON(1); | ||
241 | |||
242 | return wl->ops->lnk_low_prio(wl, hlid, lnk); | ||
243 | } | ||
244 | |||
204 | #endif | 245 | #endif |
diff --git a/drivers/net/wireless/ti/wlcore/init.c b/drivers/net/wireless/ti/wlcore/init.c index 32d157f62f31..5c6f11e157d9 100644 --- a/drivers/net/wireless/ti/wlcore/init.c +++ b/drivers/net/wireless/ti/wlcore/init.c | |||
@@ -41,14 +41,14 @@ int wl1271_init_templates_config(struct wl1271 *wl) | |||
41 | 41 | ||
42 | /* send empty templates for fw memory reservation */ | 42 | /* send empty templates for fw memory reservation */ |
43 | ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, | 43 | ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, |
44 | CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL, | 44 | wl->scan_templ_id_2_4, NULL, |
45 | WL1271_CMD_TEMPL_MAX_SIZE, | 45 | WL1271_CMD_TEMPL_MAX_SIZE, |
46 | 0, WL1271_RATE_AUTOMATIC); | 46 | 0, WL1271_RATE_AUTOMATIC); |
47 | if (ret < 0) | 47 | if (ret < 0) |
48 | return ret; | 48 | return ret; |
49 | 49 | ||
50 | ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, | 50 | ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, |
51 | CMD_TEMPL_CFG_PROBE_REQ_5, | 51 | wl->scan_templ_id_5, |
52 | NULL, WL1271_CMD_TEMPL_MAX_SIZE, 0, | 52 | NULL, WL1271_CMD_TEMPL_MAX_SIZE, 0, |
53 | WL1271_RATE_AUTOMATIC); | 53 | WL1271_RATE_AUTOMATIC); |
54 | if (ret < 0) | 54 | if (ret < 0) |
@@ -56,14 +56,16 @@ int wl1271_init_templates_config(struct wl1271 *wl) | |||
56 | 56 | ||
57 | if (wl->quirks & WLCORE_QUIRK_DUAL_PROBE_TMPL) { | 57 | if (wl->quirks & WLCORE_QUIRK_DUAL_PROBE_TMPL) { |
58 | ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, | 58 | ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, |
59 | CMD_TEMPL_APP_PROBE_REQ_2_4, NULL, | 59 | wl->sched_scan_templ_id_2_4, |
60 | NULL, | ||
60 | WL1271_CMD_TEMPL_MAX_SIZE, | 61 | WL1271_CMD_TEMPL_MAX_SIZE, |
61 | 0, WL1271_RATE_AUTOMATIC); | 62 | 0, WL1271_RATE_AUTOMATIC); |
62 | if (ret < 0) | 63 | if (ret < 0) |
63 | return ret; | 64 | return ret; |
64 | 65 | ||
65 | ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, | 66 | ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, |
66 | CMD_TEMPL_APP_PROBE_REQ_5, NULL, | 67 | wl->sched_scan_templ_id_5, |
68 | NULL, | ||
67 | WL1271_CMD_TEMPL_MAX_SIZE, | 69 | WL1271_CMD_TEMPL_MAX_SIZE, |
68 | 0, WL1271_RATE_AUTOMATIC); | 70 | 0, WL1271_RATE_AUTOMATIC); |
69 | if (ret < 0) | 71 | if (ret < 0) |
@@ -463,7 +465,7 @@ int wl1271_init_ap_rates(struct wl1271 *wl, struct wl12xx_vif *wlvif) | |||
463 | if ((wlvif->basic_rate_set & CONF_TX_OFDM_RATES)) | 465 | if ((wlvif->basic_rate_set & CONF_TX_OFDM_RATES)) |
464 | supported_rates = CONF_TX_OFDM_RATES; | 466 | supported_rates = CONF_TX_OFDM_RATES; |
465 | else | 467 | else |
466 | supported_rates = CONF_TX_AP_ENABLED_RATES; | 468 | supported_rates = CONF_TX_ENABLED_RATES; |
467 | 469 | ||
468 | /* unconditionally enable HT rates */ | 470 | /* unconditionally enable HT rates */ |
469 | supported_rates |= CONF_TX_MCS_RATES; | 471 | supported_rates |= CONF_TX_MCS_RATES; |
@@ -575,9 +577,6 @@ int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif) | |||
575 | /* Configure for power according to debugfs */ | 577 | /* Configure for power according to debugfs */ |
576 | if (sta_auth != WL1271_PSM_ILLEGAL) | 578 | if (sta_auth != WL1271_PSM_ILLEGAL) |
577 | ret = wl1271_acx_sleep_auth(wl, sta_auth); | 579 | ret = wl1271_acx_sleep_auth(wl, sta_auth); |
578 | /* Configure for power always on */ | ||
579 | else if (wl->quirks & WLCORE_QUIRK_NO_ELP) | ||
580 | ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM); | ||
581 | /* Configure for ELP power saving */ | 580 | /* Configure for ELP power saving */ |
582 | else | 581 | else |
583 | ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP); | 582 | ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP); |
@@ -679,6 +678,10 @@ int wl1271_hw_init(struct wl1271 *wl) | |||
679 | if (ret < 0) | 678 | if (ret < 0) |
680 | return ret; | 679 | return ret; |
681 | 680 | ||
681 | ret = wlcore_cmd_regdomain_config_locked(wl); | ||
682 | if (ret < 0) | ||
683 | return ret; | ||
684 | |||
682 | /* Bluetooth WLAN coexistence */ | 685 | /* Bluetooth WLAN coexistence */ |
683 | ret = wl1271_init_pta(wl); | 686 | ret = wl1271_init_pta(wl); |
684 | if (ret < 0) | 687 | if (ret < 0) |
diff --git a/drivers/net/wireless/ti/wlcore/io.h b/drivers/net/wireless/ti/wlcore/io.h index f48530fec14f..af7d9f9b3b4d 100644 --- a/drivers/net/wireless/ti/wlcore/io.h +++ b/drivers/net/wireless/ti/wlcore/io.h | |||
@@ -105,13 +105,13 @@ static inline int __must_check wlcore_raw_read32(struct wl1271 *wl, int addr, | |||
105 | { | 105 | { |
106 | int ret; | 106 | int ret; |
107 | 107 | ||
108 | ret = wlcore_raw_read(wl, addr, &wl->buffer_32, | 108 | ret = wlcore_raw_read(wl, addr, wl->buffer_32, |
109 | sizeof(wl->buffer_32), false); | 109 | sizeof(*wl->buffer_32), false); |
110 | if (ret < 0) | 110 | if (ret < 0) |
111 | return ret; | 111 | return ret; |
112 | 112 | ||
113 | if (val) | 113 | if (val) |
114 | *val = le32_to_cpu(wl->buffer_32); | 114 | *val = le32_to_cpu(*wl->buffer_32); |
115 | 115 | ||
116 | return 0; | 116 | return 0; |
117 | } | 117 | } |
@@ -119,9 +119,9 @@ static inline int __must_check wlcore_raw_read32(struct wl1271 *wl, int addr, | |||
119 | static inline int __must_check wlcore_raw_write32(struct wl1271 *wl, int addr, | 119 | static inline int __must_check wlcore_raw_write32(struct wl1271 *wl, int addr, |
120 | u32 val) | 120 | u32 val) |
121 | { | 121 | { |
122 | wl->buffer_32 = cpu_to_le32(val); | 122 | *wl->buffer_32 = cpu_to_le32(val); |
123 | return wlcore_raw_write(wl, addr, &wl->buffer_32, | 123 | return wlcore_raw_write(wl, addr, wl->buffer_32, |
124 | sizeof(wl->buffer_32), false); | 124 | sizeof(*wl->buffer_32), false); |
125 | } | 125 | } |
126 | 126 | ||
127 | static inline int __must_check wlcore_read(struct wl1271 *wl, int addr, | 127 | static inline int __must_check wlcore_read(struct wl1271 *wl, int addr, |
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index ce6e62a37e14..e1dfdf94d0f7 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c | |||
@@ -56,8 +56,8 @@ | |||
56 | #define WL1271_BOOT_RETRIES 3 | 56 | #define WL1271_BOOT_RETRIES 3 |
57 | 57 | ||
58 | static char *fwlog_param; | 58 | static char *fwlog_param; |
59 | static bool bug_on_recovery; | 59 | static int bug_on_recovery = -1; |
60 | static bool no_recovery; | 60 | static int no_recovery = -1; |
61 | 61 | ||
62 | static void __wl1271_op_remove_interface(struct wl1271 *wl, | 62 | static void __wl1271_op_remove_interface(struct wl1271 *wl, |
63 | struct ieee80211_vif *vif, | 63 | struct ieee80211_vif *vif, |
@@ -79,12 +79,10 @@ static int wl12xx_set_authorized(struct wl1271 *wl, | |||
79 | if (test_and_set_bit(WLVIF_FLAG_STA_STATE_SENT, &wlvif->flags)) | 79 | if (test_and_set_bit(WLVIF_FLAG_STA_STATE_SENT, &wlvif->flags)) |
80 | return 0; | 80 | return 0; |
81 | 81 | ||
82 | ret = wl12xx_cmd_set_peer_state(wl, wlvif->sta.hlid); | 82 | ret = wl12xx_cmd_set_peer_state(wl, wlvif, wlvif->sta.hlid); |
83 | if (ret < 0) | 83 | if (ret < 0) |
84 | return ret; | 84 | return ret; |
85 | 85 | ||
86 | wl12xx_croc(wl, wlvif->role_id); | ||
87 | |||
88 | wl1271_info("Association completed."); | 86 | wl1271_info("Association completed."); |
89 | return 0; | 87 | return 0; |
90 | } | 88 | } |
@@ -95,6 +93,8 @@ static void wl1271_reg_notify(struct wiphy *wiphy, | |||
95 | struct ieee80211_supported_band *band; | 93 | struct ieee80211_supported_band *band; |
96 | struct ieee80211_channel *ch; | 94 | struct ieee80211_channel *ch; |
97 | int i; | 95 | int i; |
96 | struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); | ||
97 | struct wl1271 *wl = hw->priv; | ||
98 | 98 | ||
99 | band = wiphy->bands[IEEE80211_BAND_5GHZ]; | 99 | band = wiphy->bands[IEEE80211_BAND_5GHZ]; |
100 | for (i = 0; i < band->n_channels; i++) { | 100 | for (i = 0; i < band->n_channels; i++) { |
@@ -107,6 +107,9 @@ static void wl1271_reg_notify(struct wiphy *wiphy, | |||
107 | IEEE80211_CHAN_PASSIVE_SCAN; | 107 | IEEE80211_CHAN_PASSIVE_SCAN; |
108 | 108 | ||
109 | } | 109 | } |
110 | |||
111 | if (likely(wl->state == WLCORE_STATE_ON)) | ||
112 | wlcore_regdomain_config(wl); | ||
110 | } | 113 | } |
111 | 114 | ||
112 | static int wl1271_set_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif, | 115 | static int wl1271_set_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
@@ -301,6 +304,7 @@ out: | |||
301 | static void wlcore_adjust_conf(struct wl1271 *wl) | 304 | static void wlcore_adjust_conf(struct wl1271 *wl) |
302 | { | 305 | { |
303 | /* Adjust settings according to optional module parameters */ | 306 | /* Adjust settings according to optional module parameters */ |
307 | |||
304 | if (fwlog_param) { | 308 | if (fwlog_param) { |
305 | if (!strcmp(fwlog_param, "continuous")) { | 309 | if (!strcmp(fwlog_param, "continuous")) { |
306 | wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS; | 310 | wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS; |
@@ -316,16 +320,22 @@ static void wlcore_adjust_conf(struct wl1271 *wl) | |||
316 | wl1271_error("Unknown fwlog parameter %s", fwlog_param); | 320 | wl1271_error("Unknown fwlog parameter %s", fwlog_param); |
317 | } | 321 | } |
318 | } | 322 | } |
323 | |||
324 | if (bug_on_recovery != -1) | ||
325 | wl->conf.recovery.bug_on_recovery = (u8) bug_on_recovery; | ||
326 | |||
327 | if (no_recovery != -1) | ||
328 | wl->conf.recovery.no_recovery = (u8) no_recovery; | ||
319 | } | 329 | } |
320 | 330 | ||
321 | static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl, | 331 | static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl, |
322 | struct wl12xx_vif *wlvif, | 332 | struct wl12xx_vif *wlvif, |
323 | u8 hlid, u8 tx_pkts) | 333 | u8 hlid, u8 tx_pkts) |
324 | { | 334 | { |
325 | bool fw_ps, single_sta; | 335 | bool fw_ps, single_link; |
326 | 336 | ||
327 | fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); | 337 | fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); |
328 | single_sta = (wl->active_sta_count == 1); | 338 | single_link = (wl->active_link_count == 1); |
329 | 339 | ||
330 | /* | 340 | /* |
331 | * Wake up from high level PS if the STA is asleep with too little | 341 | * Wake up from high level PS if the STA is asleep with too little |
@@ -336,10 +346,10 @@ static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl, | |||
336 | 346 | ||
337 | /* | 347 | /* |
338 | * Start high-level PS if the STA is asleep with enough blocks in FW. | 348 | * Start high-level PS if the STA is asleep with enough blocks in FW. |
339 | * Make an exception if this is the only connected station. In this | 349 | * Make an exception if this is the only connected link. In this |
340 | * case FW-memory congestion is not a problem. | 350 | * case FW-memory congestion is less of a problem. |
341 | */ | 351 | */ |
342 | else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS) | 352 | else if (!single_link && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS) |
343 | wl12xx_ps_link_start(wl, wlvif, hlid, true); | 353 | wl12xx_ps_link_start(wl, wlvif, hlid, true); |
344 | } | 354 | } |
345 | 355 | ||
@@ -347,11 +357,8 @@ static void wl12xx_irq_update_links_status(struct wl1271 *wl, | |||
347 | struct wl12xx_vif *wlvif, | 357 | struct wl12xx_vif *wlvif, |
348 | struct wl_fw_status_2 *status) | 358 | struct wl_fw_status_2 *status) |
349 | { | 359 | { |
350 | struct wl1271_link *lnk; | ||
351 | u32 cur_fw_ps_map; | 360 | u32 cur_fw_ps_map; |
352 | u8 hlid, cnt; | 361 | u8 hlid; |
353 | |||
354 | /* TODO: also use link_fast_bitmap here */ | ||
355 | 362 | ||
356 | cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap); | 363 | cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap); |
357 | if (wl->ap_fw_ps_map != cur_fw_ps_map) { | 364 | if (wl->ap_fw_ps_map != cur_fw_ps_map) { |
@@ -363,17 +370,9 @@ static void wl12xx_irq_update_links_status(struct wl1271 *wl, | |||
363 | wl->ap_fw_ps_map = cur_fw_ps_map; | 370 | wl->ap_fw_ps_map = cur_fw_ps_map; |
364 | } | 371 | } |
365 | 372 | ||
366 | for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, WL12XX_MAX_LINKS) { | 373 | for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, WL12XX_MAX_LINKS) |
367 | lnk = &wl->links[hlid]; | ||
368 | cnt = status->counters.tx_lnk_free_pkts[hlid] - | ||
369 | lnk->prev_freed_pkts; | ||
370 | |||
371 | lnk->prev_freed_pkts = status->counters.tx_lnk_free_pkts[hlid]; | ||
372 | lnk->allocated_pkts -= cnt; | ||
373 | |||
374 | wl12xx_irq_ps_regulate_link(wl, wlvif, hlid, | 374 | wl12xx_irq_ps_regulate_link(wl, wlvif, hlid, |
375 | lnk->allocated_pkts); | 375 | wl->links[hlid].allocated_pkts); |
376 | } | ||
377 | } | 376 | } |
378 | 377 | ||
379 | static int wlcore_fw_status(struct wl1271 *wl, | 378 | static int wlcore_fw_status(struct wl1271 *wl, |
@@ -387,6 +386,7 @@ static int wlcore_fw_status(struct wl1271 *wl, | |||
387 | int i; | 386 | int i; |
388 | size_t status_len; | 387 | size_t status_len; |
389 | int ret; | 388 | int ret; |
389 | struct wl1271_link *lnk; | ||
390 | 390 | ||
391 | status_len = WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc) + | 391 | status_len = WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc) + |
392 | sizeof(*status_2) + wl->fw_status_priv_len; | 392 | sizeof(*status_2) + wl->fw_status_priv_len; |
@@ -412,6 +412,17 @@ static int wlcore_fw_status(struct wl1271 *wl, | |||
412 | wl->tx_pkts_freed[i] = status_2->counters.tx_released_pkts[i]; | 412 | wl->tx_pkts_freed[i] = status_2->counters.tx_released_pkts[i]; |
413 | } | 413 | } |
414 | 414 | ||
415 | |||
416 | for_each_set_bit(i, wl->links_map, WL12XX_MAX_LINKS) { | ||
417 | lnk = &wl->links[i]; | ||
418 | /* prevent wrap-around in freed-packets counter */ | ||
419 | lnk->allocated_pkts -= | ||
420 | (status_2->counters.tx_lnk_free_pkts[i] - | ||
421 | lnk->prev_freed_pkts) & 0xff; | ||
422 | |||
423 | lnk->prev_freed_pkts = status_2->counters.tx_lnk_free_pkts[i]; | ||
424 | } | ||
425 | |||
415 | /* prevent wrap-around in total blocks counter */ | 426 | /* prevent wrap-around in total blocks counter */ |
416 | if (likely(wl->tx_blocks_freed <= | 427 | if (likely(wl->tx_blocks_freed <= |
417 | le32_to_cpu(status_2->total_released_blks))) | 428 | le32_to_cpu(status_2->total_released_blks))) |
@@ -464,6 +475,8 @@ static int wlcore_fw_status(struct wl1271 *wl, | |||
464 | wl->time_offset = (timespec_to_ns(&ts) >> 10) - | 475 | wl->time_offset = (timespec_to_ns(&ts) >> 10) - |
465 | (s64)le32_to_cpu(status_2->fw_localtime); | 476 | (s64)le32_to_cpu(status_2->fw_localtime); |
466 | 477 | ||
478 | wl->fw_fast_lnk_map = le32_to_cpu(status_2->link_fast_bitmap); | ||
479 | |||
467 | return 0; | 480 | return 0; |
468 | } | 481 | } |
469 | 482 | ||
@@ -800,11 +813,13 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl) | |||
800 | 813 | ||
801 | /* | 814 | /* |
802 | * Make sure the chip is awake and the logger isn't active. | 815 | * Make sure the chip is awake and the logger isn't active. |
803 | * Do not send a stop fwlog command if the fw is hanged. | 816 | * Do not send a stop fwlog command if the fw is hanged or if |
817 | * dbgpins are used (due to some fw bug). | ||
804 | */ | 818 | */ |
805 | if (wl1271_ps_elp_wakeup(wl)) | 819 | if (wl1271_ps_elp_wakeup(wl)) |
806 | goto out; | 820 | goto out; |
807 | if (!wl->watchdog_recovery) | 821 | if (!wl->watchdog_recovery && |
822 | wl->conf.fwlog.output != WL12XX_FWLOG_OUTPUT_DBG_PINS) | ||
808 | wl12xx_cmd_stop_fwlog(wl); | 823 | wl12xx_cmd_stop_fwlog(wl); |
809 | 824 | ||
810 | /* Read the first memory block address */ | 825 | /* Read the first memory block address */ |
@@ -872,7 +887,8 @@ static void wlcore_print_recovery(struct wl1271 *wl) | |||
872 | if (ret < 0) | 887 | if (ret < 0) |
873 | return; | 888 | return; |
874 | 889 | ||
875 | wl1271_info("pc: 0x%x, hint_sts: 0x%08x", pc, hint_sts); | 890 | wl1271_info("pc: 0x%x, hint_sts: 0x%08x count: %d", |
891 | pc, hint_sts, ++wl->recovery_count); | ||
876 | 892 | ||
877 | wlcore_set_partition(wl, &wl->ptable[PART_WORK]); | 893 | wlcore_set_partition(wl, &wl->ptable[PART_WORK]); |
878 | } | 894 | } |
@@ -895,10 +911,10 @@ static void wl1271_recovery_work(struct work_struct *work) | |||
895 | wlcore_print_recovery(wl); | 911 | wlcore_print_recovery(wl); |
896 | } | 912 | } |
897 | 913 | ||
898 | BUG_ON(bug_on_recovery && | 914 | BUG_ON(wl->conf.recovery.bug_on_recovery && |
899 | !test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags)); | 915 | !test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags)); |
900 | 916 | ||
901 | if (no_recovery) { | 917 | if (wl->conf.recovery.no_recovery) { |
902 | wl1271_info("No recovery (chosen on module load). Fw will remain stuck."); | 918 | wl1271_info("No recovery (chosen on module load). Fw will remain stuck."); |
903 | goto out_unlock; | 919 | goto out_unlock; |
904 | } | 920 | } |
@@ -918,11 +934,6 @@ static void wl1271_recovery_work(struct work_struct *work) | |||
918 | /* Prevent spurious TX during FW restart */ | 934 | /* Prevent spurious TX during FW restart */ |
919 | wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_FW_RESTART); | 935 | wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_FW_RESTART); |
920 | 936 | ||
921 | if (wl->sched_scanning) { | ||
922 | ieee80211_sched_scan_stopped(wl->hw); | ||
923 | wl->sched_scanning = false; | ||
924 | } | ||
925 | |||
926 | /* reboot the chipset */ | 937 | /* reboot the chipset */ |
927 | while (!list_empty(&wl->wlvif_list)) { | 938 | while (!list_empty(&wl->wlvif_list)) { |
928 | wlvif = list_first_entry(&wl->wlvif_list, | 939 | wlvif = list_first_entry(&wl->wlvif_list, |
@@ -1139,7 +1150,6 @@ int wl1271_plt_stop(struct wl1271 *wl) | |||
1139 | cancel_work_sync(&wl->recovery_work); | 1150 | cancel_work_sync(&wl->recovery_work); |
1140 | cancel_delayed_work_sync(&wl->elp_work); | 1151 | cancel_delayed_work_sync(&wl->elp_work); |
1141 | cancel_delayed_work_sync(&wl->tx_watchdog_work); | 1152 | cancel_delayed_work_sync(&wl->tx_watchdog_work); |
1142 | cancel_delayed_work_sync(&wl->connection_loss_work); | ||
1143 | 1153 | ||
1144 | mutex_lock(&wl->mutex); | 1154 | mutex_lock(&wl->mutex); |
1145 | wl1271_power_off(wl); | 1155 | wl1271_power_off(wl); |
@@ -1167,9 +1177,13 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, | |||
1167 | int q, mapping; | 1177 | int q, mapping; |
1168 | u8 hlid; | 1178 | u8 hlid; |
1169 | 1179 | ||
1170 | if (vif) | 1180 | if (!vif) { |
1171 | wlvif = wl12xx_vif_to_data(vif); | 1181 | wl1271_debug(DEBUG_TX, "DROP skb with no vif"); |
1182 | ieee80211_free_txskb(hw, skb); | ||
1183 | return; | ||
1184 | } | ||
1172 | 1185 | ||
1186 | wlvif = wl12xx_vif_to_data(vif); | ||
1173 | mapping = skb_get_queue_mapping(skb); | 1187 | mapping = skb_get_queue_mapping(skb); |
1174 | q = wl1271_tx_get_queue(mapping); | 1188 | q = wl1271_tx_get_queue(mapping); |
1175 | 1189 | ||
@@ -1183,9 +1197,9 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, | |||
1183 | * allow these packets through. | 1197 | * allow these packets through. |
1184 | */ | 1198 | */ |
1185 | if (hlid == WL12XX_INVALID_LINK_ID || | 1199 | if (hlid == WL12XX_INVALID_LINK_ID || |
1186 | (wlvif && !test_bit(hlid, wlvif->links_map)) || | 1200 | (!test_bit(hlid, wlvif->links_map)) || |
1187 | (wlcore_is_queue_stopped(wl, q) && | 1201 | (wlcore_is_queue_stopped_locked(wl, wlvif, q) && |
1188 | !wlcore_is_queue_stopped_by_reason(wl, q, | 1202 | !wlcore_is_queue_stopped_by_reason_locked(wl, wlvif, q, |
1189 | WLCORE_QUEUE_STOP_REASON_WATERMARK))) { | 1203 | WLCORE_QUEUE_STOP_REASON_WATERMARK))) { |
1190 | wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q); | 1204 | wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q); |
1191 | ieee80211_free_txskb(hw, skb); | 1205 | ieee80211_free_txskb(hw, skb); |
@@ -1197,16 +1211,17 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, | |||
1197 | skb_queue_tail(&wl->links[hlid].tx_queue[q], skb); | 1211 | skb_queue_tail(&wl->links[hlid].tx_queue[q], skb); |
1198 | 1212 | ||
1199 | wl->tx_queue_count[q]++; | 1213 | wl->tx_queue_count[q]++; |
1214 | wlvif->tx_queue_count[q]++; | ||
1200 | 1215 | ||
1201 | /* | 1216 | /* |
1202 | * The workqueue is slow to process the tx_queue and we need stop | 1217 | * The workqueue is slow to process the tx_queue and we need stop |
1203 | * the queue here, otherwise the queue will get too long. | 1218 | * the queue here, otherwise the queue will get too long. |
1204 | */ | 1219 | */ |
1205 | if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK && | 1220 | if (wlvif->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK && |
1206 | !wlcore_is_queue_stopped_by_reason(wl, q, | 1221 | !wlcore_is_queue_stopped_by_reason_locked(wl, wlvif, q, |
1207 | WLCORE_QUEUE_STOP_REASON_WATERMARK)) { | 1222 | WLCORE_QUEUE_STOP_REASON_WATERMARK)) { |
1208 | wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q); | 1223 | wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q); |
1209 | wlcore_stop_queue_locked(wl, q, | 1224 | wlcore_stop_queue_locked(wl, wlvif, q, |
1210 | WLCORE_QUEUE_STOP_REASON_WATERMARK); | 1225 | WLCORE_QUEUE_STOP_REASON_WATERMARK); |
1211 | } | 1226 | } |
1212 | 1227 | ||
@@ -1841,11 +1856,10 @@ static void wlcore_op_stop_locked(struct wl1271 *wl) | |||
1841 | cancel_work_sync(&wl->tx_work); | 1856 | cancel_work_sync(&wl->tx_work); |
1842 | cancel_delayed_work_sync(&wl->elp_work); | 1857 | cancel_delayed_work_sync(&wl->elp_work); |
1843 | cancel_delayed_work_sync(&wl->tx_watchdog_work); | 1858 | cancel_delayed_work_sync(&wl->tx_watchdog_work); |
1844 | cancel_delayed_work_sync(&wl->connection_loss_work); | ||
1845 | 1859 | ||
1846 | /* let's notify MAC80211 about the remaining pending TX frames */ | 1860 | /* let's notify MAC80211 about the remaining pending TX frames */ |
1847 | wl12xx_tx_reset(wl); | ||
1848 | mutex_lock(&wl->mutex); | 1861 | mutex_lock(&wl->mutex); |
1862 | wl12xx_tx_reset(wl); | ||
1849 | 1863 | ||
1850 | wl1271_power_off(wl); | 1864 | wl1271_power_off(wl); |
1851 | /* | 1865 | /* |
@@ -1868,14 +1882,17 @@ static void wlcore_op_stop_locked(struct wl1271 *wl) | |||
1868 | wl->time_offset = 0; | 1882 | wl->time_offset = 0; |
1869 | wl->ap_fw_ps_map = 0; | 1883 | wl->ap_fw_ps_map = 0; |
1870 | wl->ap_ps_map = 0; | 1884 | wl->ap_ps_map = 0; |
1871 | wl->sched_scanning = false; | ||
1872 | wl->sleep_auth = WL1271_PSM_ILLEGAL; | 1885 | wl->sleep_auth = WL1271_PSM_ILLEGAL; |
1873 | memset(wl->roles_map, 0, sizeof(wl->roles_map)); | 1886 | memset(wl->roles_map, 0, sizeof(wl->roles_map)); |
1874 | memset(wl->links_map, 0, sizeof(wl->links_map)); | 1887 | memset(wl->links_map, 0, sizeof(wl->links_map)); |
1875 | memset(wl->roc_map, 0, sizeof(wl->roc_map)); | 1888 | memset(wl->roc_map, 0, sizeof(wl->roc_map)); |
1889 | memset(wl->session_ids, 0, sizeof(wl->session_ids)); | ||
1876 | wl->active_sta_count = 0; | 1890 | wl->active_sta_count = 0; |
1891 | wl->active_link_count = 0; | ||
1877 | 1892 | ||
1878 | /* The system link is always allocated */ | 1893 | /* The system link is always allocated */ |
1894 | wl->links[WL12XX_SYSTEM_HLID].allocated_pkts = 0; | ||
1895 | wl->links[WL12XX_SYSTEM_HLID].prev_freed_pkts = 0; | ||
1879 | __set_bit(WL12XX_SYSTEM_HLID, wl->links_map); | 1896 | __set_bit(WL12XX_SYSTEM_HLID, wl->links_map); |
1880 | 1897 | ||
1881 | /* | 1898 | /* |
@@ -1901,6 +1918,12 @@ static void wlcore_op_stop_locked(struct wl1271 *wl) | |||
1901 | wl->tx_res_if = NULL; | 1918 | wl->tx_res_if = NULL; |
1902 | kfree(wl->target_mem_map); | 1919 | kfree(wl->target_mem_map); |
1903 | wl->target_mem_map = NULL; | 1920 | wl->target_mem_map = NULL; |
1921 | |||
1922 | /* | ||
1923 | * FW channels must be re-calibrated after recovery, | ||
1924 | * clear the last Reg-Domain channel configuration. | ||
1925 | */ | ||
1926 | memset(wl->reg_ch_conf_last, 0, sizeof(wl->reg_ch_conf_last)); | ||
1904 | } | 1927 | } |
1905 | 1928 | ||
1906 | static void wlcore_op_stop(struct ieee80211_hw *hw) | 1929 | static void wlcore_op_stop(struct ieee80211_hw *hw) |
@@ -1916,6 +1939,71 @@ static void wlcore_op_stop(struct ieee80211_hw *hw) | |||
1916 | mutex_unlock(&wl->mutex); | 1939 | mutex_unlock(&wl->mutex); |
1917 | } | 1940 | } |
1918 | 1941 | ||
1942 | static void wlcore_channel_switch_work(struct work_struct *work) | ||
1943 | { | ||
1944 | struct delayed_work *dwork; | ||
1945 | struct wl1271 *wl; | ||
1946 | struct ieee80211_vif *vif; | ||
1947 | struct wl12xx_vif *wlvif; | ||
1948 | int ret; | ||
1949 | |||
1950 | dwork = container_of(work, struct delayed_work, work); | ||
1951 | wlvif = container_of(dwork, struct wl12xx_vif, channel_switch_work); | ||
1952 | wl = wlvif->wl; | ||
1953 | |||
1954 | wl1271_info("channel switch failed (role_id: %d).", wlvif->role_id); | ||
1955 | |||
1956 | mutex_lock(&wl->mutex); | ||
1957 | |||
1958 | if (unlikely(wl->state != WLCORE_STATE_ON)) | ||
1959 | goto out; | ||
1960 | |||
1961 | /* check the channel switch is still ongoing */ | ||
1962 | if (!test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) | ||
1963 | goto out; | ||
1964 | |||
1965 | vif = wl12xx_wlvif_to_vif(wlvif); | ||
1966 | ieee80211_chswitch_done(vif, false); | ||
1967 | |||
1968 | ret = wl1271_ps_elp_wakeup(wl); | ||
1969 | if (ret < 0) | ||
1970 | goto out; | ||
1971 | |||
1972 | wl12xx_cmd_stop_channel_switch(wl, wlvif); | ||
1973 | |||
1974 | wl1271_ps_elp_sleep(wl); | ||
1975 | out: | ||
1976 | mutex_unlock(&wl->mutex); | ||
1977 | } | ||
1978 | |||
1979 | static void wlcore_connection_loss_work(struct work_struct *work) | ||
1980 | { | ||
1981 | struct delayed_work *dwork; | ||
1982 | struct wl1271 *wl; | ||
1983 | struct ieee80211_vif *vif; | ||
1984 | struct wl12xx_vif *wlvif; | ||
1985 | |||
1986 | dwork = container_of(work, struct delayed_work, work); | ||
1987 | wlvif = container_of(dwork, struct wl12xx_vif, connection_loss_work); | ||
1988 | wl = wlvif->wl; | ||
1989 | |||
1990 | wl1271_info("Connection loss work (role_id: %d).", wlvif->role_id); | ||
1991 | |||
1992 | mutex_lock(&wl->mutex); | ||
1993 | |||
1994 | if (unlikely(wl->state != WLCORE_STATE_ON)) | ||
1995 | goto out; | ||
1996 | |||
1997 | /* Call mac80211 connection loss */ | ||
1998 | if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) | ||
1999 | goto out; | ||
2000 | |||
2001 | vif = wl12xx_wlvif_to_vif(wlvif); | ||
2002 | ieee80211_connection_loss(vif); | ||
2003 | out: | ||
2004 | mutex_unlock(&wl->mutex); | ||
2005 | } | ||
2006 | |||
1919 | static int wl12xx_allocate_rate_policy(struct wl1271 *wl, u8 *idx) | 2007 | static int wl12xx_allocate_rate_policy(struct wl1271 *wl, u8 *idx) |
1920 | { | 2008 | { |
1921 | u8 policy = find_first_zero_bit(wl->rate_policies_map, | 2009 | u8 policy = find_first_zero_bit(wl->rate_policies_map, |
@@ -2035,15 +2123,15 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif) | |||
2035 | for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++) | 2123 | for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++) |
2036 | wl12xx_allocate_rate_policy(wl, | 2124 | wl12xx_allocate_rate_policy(wl, |
2037 | &wlvif->ap.ucast_rate_idx[i]); | 2125 | &wlvif->ap.ucast_rate_idx[i]); |
2038 | wlvif->basic_rate_set = CONF_TX_AP_ENABLED_RATES; | 2126 | wlvif->basic_rate_set = CONF_TX_ENABLED_RATES; |
2039 | /* | 2127 | /* |
2040 | * TODO: check if basic_rate shouldn't be | 2128 | * TODO: check if basic_rate shouldn't be |
2041 | * wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); | 2129 | * wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); |
2042 | * instead (the same thing for STA above). | 2130 | * instead (the same thing for STA above). |
2043 | */ | 2131 | */ |
2044 | wlvif->basic_rate = CONF_TX_AP_ENABLED_RATES; | 2132 | wlvif->basic_rate = CONF_TX_ENABLED_RATES; |
2045 | /* TODO: this seems to be used only for STA, check it */ | 2133 | /* TODO: this seems to be used only for STA, check it */ |
2046 | wlvif->rate_set = CONF_TX_AP_ENABLED_RATES; | 2134 | wlvif->rate_set = CONF_TX_ENABLED_RATES; |
2047 | } | 2135 | } |
2048 | 2136 | ||
2049 | wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate; | 2137 | wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate; |
@@ -2063,6 +2151,10 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif) | |||
2063 | wl1271_rx_streaming_enable_work); | 2151 | wl1271_rx_streaming_enable_work); |
2064 | INIT_WORK(&wlvif->rx_streaming_disable_work, | 2152 | INIT_WORK(&wlvif->rx_streaming_disable_work, |
2065 | wl1271_rx_streaming_disable_work); | 2153 | wl1271_rx_streaming_disable_work); |
2154 | INIT_DELAYED_WORK(&wlvif->channel_switch_work, | ||
2155 | wlcore_channel_switch_work); | ||
2156 | INIT_DELAYED_WORK(&wlvif->connection_loss_work, | ||
2157 | wlcore_connection_loss_work); | ||
2066 | INIT_LIST_HEAD(&wlvif->list); | 2158 | INIT_LIST_HEAD(&wlvif->list); |
2067 | 2159 | ||
2068 | setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer, | 2160 | setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer, |
@@ -2196,6 +2288,81 @@ static void wl12xx_force_active_psm(struct wl1271 *wl) | |||
2196 | } | 2288 | } |
2197 | } | 2289 | } |
2198 | 2290 | ||
2291 | struct wlcore_hw_queue_iter_data { | ||
2292 | unsigned long hw_queue_map[BITS_TO_LONGS(WLCORE_NUM_MAC_ADDRESSES)]; | ||
2293 | /* current vif */ | ||
2294 | struct ieee80211_vif *vif; | ||
2295 | /* is the current vif among those iterated */ | ||
2296 | bool cur_running; | ||
2297 | }; | ||
2298 | |||
2299 | static void wlcore_hw_queue_iter(void *data, u8 *mac, | ||
2300 | struct ieee80211_vif *vif) | ||
2301 | { | ||
2302 | struct wlcore_hw_queue_iter_data *iter_data = data; | ||
2303 | |||
2304 | if (WARN_ON_ONCE(vif->hw_queue[0] == IEEE80211_INVAL_HW_QUEUE)) | ||
2305 | return; | ||
2306 | |||
2307 | if (iter_data->cur_running || vif == iter_data->vif) { | ||
2308 | iter_data->cur_running = true; | ||
2309 | return; | ||
2310 | } | ||
2311 | |||
2312 | __set_bit(vif->hw_queue[0] / NUM_TX_QUEUES, iter_data->hw_queue_map); | ||
2313 | } | ||
2314 | |||
2315 | static int wlcore_allocate_hw_queue_base(struct wl1271 *wl, | ||
2316 | struct wl12xx_vif *wlvif) | ||
2317 | { | ||
2318 | struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); | ||
2319 | struct wlcore_hw_queue_iter_data iter_data = {}; | ||
2320 | int i, q_base; | ||
2321 | |||
2322 | iter_data.vif = vif; | ||
2323 | |||
2324 | /* mark all bits taken by active interfaces */ | ||
2325 | ieee80211_iterate_active_interfaces_atomic(wl->hw, | ||
2326 | IEEE80211_IFACE_ITER_RESUME_ALL, | ||
2327 | wlcore_hw_queue_iter, &iter_data); | ||
2328 | |||
2329 | /* the current vif is already running in mac80211 (resume/recovery) */ | ||
2330 | if (iter_data.cur_running) { | ||
2331 | wlvif->hw_queue_base = vif->hw_queue[0]; | ||
2332 | wl1271_debug(DEBUG_MAC80211, | ||
2333 | "using pre-allocated hw queue base %d", | ||
2334 | wlvif->hw_queue_base); | ||
2335 | |||
2336 | /* interface type might have changed type */ | ||
2337 | goto adjust_cab_queue; | ||
2338 | } | ||
2339 | |||
2340 | q_base = find_first_zero_bit(iter_data.hw_queue_map, | ||
2341 | WLCORE_NUM_MAC_ADDRESSES); | ||
2342 | if (q_base >= WLCORE_NUM_MAC_ADDRESSES) | ||
2343 | return -EBUSY; | ||
2344 | |||
2345 | wlvif->hw_queue_base = q_base * NUM_TX_QUEUES; | ||
2346 | wl1271_debug(DEBUG_MAC80211, "allocating hw queue base: %d", | ||
2347 | wlvif->hw_queue_base); | ||
2348 | |||
2349 | for (i = 0; i < NUM_TX_QUEUES; i++) { | ||
2350 | wl->queue_stop_reasons[wlvif->hw_queue_base + i] = 0; | ||
2351 | /* register hw queues in mac80211 */ | ||
2352 | vif->hw_queue[i] = wlvif->hw_queue_base + i; | ||
2353 | } | ||
2354 | |||
2355 | adjust_cab_queue: | ||
2356 | /* the last places are reserved for cab queues per interface */ | ||
2357 | if (wlvif->bss_type == BSS_TYPE_AP_BSS) | ||
2358 | vif->cab_queue = NUM_TX_QUEUES * WLCORE_NUM_MAC_ADDRESSES + | ||
2359 | wlvif->hw_queue_base / NUM_TX_QUEUES; | ||
2360 | else | ||
2361 | vif->cab_queue = IEEE80211_INVAL_HW_QUEUE; | ||
2362 | |||
2363 | return 0; | ||
2364 | } | ||
2365 | |||
2199 | static int wl1271_op_add_interface(struct ieee80211_hw *hw, | 2366 | static int wl1271_op_add_interface(struct ieee80211_hw *hw, |
2200 | struct ieee80211_vif *vif) | 2367 | struct ieee80211_vif *vif) |
2201 | { | 2368 | { |
@@ -2242,6 +2409,10 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, | |||
2242 | goto out; | 2409 | goto out; |
2243 | } | 2410 | } |
2244 | 2411 | ||
2412 | ret = wlcore_allocate_hw_queue_base(wl, wlvif); | ||
2413 | if (ret < 0) | ||
2414 | goto out; | ||
2415 | |||
2245 | if (wl12xx_need_fw_change(wl, vif_count, true)) { | 2416 | if (wl12xx_need_fw_change(wl, vif_count, true)) { |
2246 | wl12xx_force_active_psm(wl); | 2417 | wl12xx_force_active_psm(wl); |
2247 | set_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags); | 2418 | set_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags); |
@@ -2312,7 +2483,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, | |||
2312 | wl1271_info("down"); | 2483 | wl1271_info("down"); |
2313 | 2484 | ||
2314 | if (wl->scan.state != WL1271_SCAN_STATE_IDLE && | 2485 | if (wl->scan.state != WL1271_SCAN_STATE_IDLE && |
2315 | wl->scan_vif == vif) { | 2486 | wl->scan_wlvif == wlvif) { |
2316 | /* | 2487 | /* |
2317 | * Rearm the tx watchdog just before idling scan. This | 2488 | * Rearm the tx watchdog just before idling scan. This |
2318 | * prevents just-finished scans from triggering the watchdog | 2489 | * prevents just-finished scans from triggering the watchdog |
@@ -2321,11 +2492,21 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, | |||
2321 | 2492 | ||
2322 | wl->scan.state = WL1271_SCAN_STATE_IDLE; | 2493 | wl->scan.state = WL1271_SCAN_STATE_IDLE; |
2323 | memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); | 2494 | memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); |
2324 | wl->scan_vif = NULL; | 2495 | wl->scan_wlvif = NULL; |
2325 | wl->scan.req = NULL; | 2496 | wl->scan.req = NULL; |
2326 | ieee80211_scan_completed(wl->hw, true); | 2497 | ieee80211_scan_completed(wl->hw, true); |
2327 | } | 2498 | } |
2328 | 2499 | ||
2500 | if (wl->sched_vif == wlvif) { | ||
2501 | ieee80211_sched_scan_stopped(wl->hw); | ||
2502 | wl->sched_vif = NULL; | ||
2503 | } | ||
2504 | |||
2505 | if (wl->roc_vif == vif) { | ||
2506 | wl->roc_vif = NULL; | ||
2507 | ieee80211_remain_on_channel_expired(wl->hw); | ||
2508 | } | ||
2509 | |||
2329 | if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) { | 2510 | if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) { |
2330 | /* disable active roles */ | 2511 | /* disable active roles */ |
2331 | ret = wl1271_ps_elp_wakeup(wl); | 2512 | ret = wl1271_ps_elp_wakeup(wl); |
@@ -2394,9 +2575,6 @@ deinit: | |||
2394 | /* Configure for power according to debugfs */ | 2575 | /* Configure for power according to debugfs */ |
2395 | if (sta_auth != WL1271_PSM_ILLEGAL) | 2576 | if (sta_auth != WL1271_PSM_ILLEGAL) |
2396 | wl1271_acx_sleep_auth(wl, sta_auth); | 2577 | wl1271_acx_sleep_auth(wl, sta_auth); |
2397 | /* Configure for power always on */ | ||
2398 | else if (wl->quirks & WLCORE_QUIRK_NO_ELP) | ||
2399 | wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM); | ||
2400 | /* Configure for ELP power saving */ | 2578 | /* Configure for ELP power saving */ |
2401 | else | 2579 | else |
2402 | wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP); | 2580 | wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP); |
@@ -2408,6 +2586,7 @@ unlock: | |||
2408 | del_timer_sync(&wlvif->rx_streaming_timer); | 2586 | del_timer_sync(&wlvif->rx_streaming_timer); |
2409 | cancel_work_sync(&wlvif->rx_streaming_enable_work); | 2587 | cancel_work_sync(&wlvif->rx_streaming_enable_work); |
2410 | cancel_work_sync(&wlvif->rx_streaming_disable_work); | 2588 | cancel_work_sync(&wlvif->rx_streaming_disable_work); |
2589 | cancel_delayed_work_sync(&wlvif->connection_loss_work); | ||
2411 | 2590 | ||
2412 | mutex_lock(&wl->mutex); | 2591 | mutex_lock(&wl->mutex); |
2413 | } | 2592 | } |
@@ -2466,8 +2645,7 @@ static int wl12xx_op_change_interface(struct ieee80211_hw *hw, | |||
2466 | return ret; | 2645 | return ret; |
2467 | } | 2646 | } |
2468 | 2647 | ||
2469 | static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif, | 2648 | static int wlcore_join(struct wl1271 *wl, struct wl12xx_vif *wlvif) |
2470 | bool set_assoc) | ||
2471 | { | 2649 | { |
2472 | int ret; | 2650 | int ret; |
2473 | bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS); | 2651 | bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS); |
@@ -2487,18 +2665,111 @@ static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif, | |||
2487 | /* clear encryption type */ | 2665 | /* clear encryption type */ |
2488 | wlvif->encryption_type = KEY_NONE; | 2666 | wlvif->encryption_type = KEY_NONE; |
2489 | 2667 | ||
2490 | if (set_assoc) | ||
2491 | set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags); | ||
2492 | |||
2493 | if (is_ibss) | 2668 | if (is_ibss) |
2494 | ret = wl12xx_cmd_role_start_ibss(wl, wlvif); | 2669 | ret = wl12xx_cmd_role_start_ibss(wl, wlvif); |
2495 | else | 2670 | else { |
2671 | if (wl->quirks & WLCORE_QUIRK_START_STA_FAILS) { | ||
2672 | /* | ||
2673 | * TODO: this is an ugly workaround for wl12xx fw | ||
2674 | * bug - we are not able to tx/rx after the first | ||
2675 | * start_sta, so make dummy start+stop calls, | ||
2676 | * and then call start_sta again. | ||
2677 | * this should be fixed in the fw. | ||
2678 | */ | ||
2679 | wl12xx_cmd_role_start_sta(wl, wlvif); | ||
2680 | wl12xx_cmd_role_stop_sta(wl, wlvif); | ||
2681 | } | ||
2682 | |||
2496 | ret = wl12xx_cmd_role_start_sta(wl, wlvif); | 2683 | ret = wl12xx_cmd_role_start_sta(wl, wlvif); |
2684 | } | ||
2685 | |||
2686 | return ret; | ||
2687 | } | ||
2688 | |||
2689 | static int wl1271_ssid_set(struct wl12xx_vif *wlvif, struct sk_buff *skb, | ||
2690 | int offset) | ||
2691 | { | ||
2692 | u8 ssid_len; | ||
2693 | const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset, | ||
2694 | skb->len - offset); | ||
2695 | |||
2696 | if (!ptr) { | ||
2697 | wl1271_error("No SSID in IEs!"); | ||
2698 | return -ENOENT; | ||
2699 | } | ||
2700 | |||
2701 | ssid_len = ptr[1]; | ||
2702 | if (ssid_len > IEEE80211_MAX_SSID_LEN) { | ||
2703 | wl1271_error("SSID is too long!"); | ||
2704 | return -EINVAL; | ||
2705 | } | ||
2706 | |||
2707 | wlvif->ssid_len = ssid_len; | ||
2708 | memcpy(wlvif->ssid, ptr+2, ssid_len); | ||
2709 | return 0; | ||
2710 | } | ||
2711 | |||
2712 | static int wlcore_set_ssid(struct wl1271 *wl, struct wl12xx_vif *wlvif) | ||
2713 | { | ||
2714 | struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); | ||
2715 | struct sk_buff *skb; | ||
2716 | int ieoffset; | ||
2717 | |||
2718 | /* we currently only support setting the ssid from the ap probe req */ | ||
2719 | if (wlvif->bss_type != BSS_TYPE_STA_BSS) | ||
2720 | return -EINVAL; | ||
2721 | |||
2722 | skb = ieee80211_ap_probereq_get(wl->hw, vif); | ||
2723 | if (!skb) | ||
2724 | return -EINVAL; | ||
2725 | |||
2726 | ieoffset = offsetof(struct ieee80211_mgmt, | ||
2727 | u.probe_req.variable); | ||
2728 | wl1271_ssid_set(wlvif, skb, ieoffset); | ||
2729 | dev_kfree_skb(skb); | ||
2730 | |||
2731 | return 0; | ||
2732 | } | ||
2733 | |||
2734 | static int wlcore_set_assoc(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
2735 | struct ieee80211_bss_conf *bss_conf, | ||
2736 | u32 sta_rate_set) | ||
2737 | { | ||
2738 | int ieoffset; | ||
2739 | int ret; | ||
2740 | |||
2741 | wlvif->aid = bss_conf->aid; | ||
2742 | wlvif->channel_type = cfg80211_get_chandef_type(&bss_conf->chandef); | ||
2743 | wlvif->beacon_int = bss_conf->beacon_int; | ||
2744 | wlvif->wmm_enabled = bss_conf->qos; | ||
2745 | |||
2746 | set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags); | ||
2747 | |||
2748 | /* | ||
2749 | * with wl1271, we don't need to update the | ||
2750 | * beacon_int and dtim_period, because the firmware | ||
2751 | * updates it by itself when the first beacon is | ||
2752 | * received after a join. | ||
2753 | */ | ||
2754 | ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid); | ||
2497 | if (ret < 0) | 2755 | if (ret < 0) |
2498 | goto out; | 2756 | return ret; |
2499 | 2757 | ||
2500 | if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) | 2758 | /* |
2501 | goto out; | 2759 | * Get a template for hardware connection maintenance |
2760 | */ | ||
2761 | dev_kfree_skb(wlvif->probereq); | ||
2762 | wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl, | ||
2763 | wlvif, | ||
2764 | NULL); | ||
2765 | ieoffset = offsetof(struct ieee80211_mgmt, | ||
2766 | u.probe_req.variable); | ||
2767 | wl1271_ssid_set(wlvif, wlvif->probereq, ieoffset); | ||
2768 | |||
2769 | /* enable the connection monitoring feature */ | ||
2770 | ret = wl1271_acx_conn_monit_params(wl, wlvif, true); | ||
2771 | if (ret < 0) | ||
2772 | return ret; | ||
2502 | 2773 | ||
2503 | /* | 2774 | /* |
2504 | * The join command disable the keep-alive mode, shut down its process, | 2775 | * The join command disable the keep-alive mode, shut down its process, |
@@ -2508,35 +2779,83 @@ static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif, | |||
2508 | */ | 2779 | */ |
2509 | ret = wl1271_acx_keep_alive_mode(wl, wlvif, true); | 2780 | ret = wl1271_acx_keep_alive_mode(wl, wlvif, true); |
2510 | if (ret < 0) | 2781 | if (ret < 0) |
2511 | goto out; | 2782 | return ret; |
2512 | 2783 | ||
2513 | ret = wl1271_acx_aid(wl, wlvif, wlvif->aid); | 2784 | ret = wl1271_acx_aid(wl, wlvif, wlvif->aid); |
2514 | if (ret < 0) | 2785 | if (ret < 0) |
2515 | goto out; | 2786 | return ret; |
2516 | 2787 | ||
2517 | ret = wl12xx_cmd_build_klv_null_data(wl, wlvif); | 2788 | ret = wl12xx_cmd_build_klv_null_data(wl, wlvif); |
2518 | if (ret < 0) | 2789 | if (ret < 0) |
2519 | goto out; | 2790 | return ret; |
2520 | 2791 | ||
2521 | ret = wl1271_acx_keep_alive_config(wl, wlvif, | 2792 | ret = wl1271_acx_keep_alive_config(wl, wlvif, |
2522 | wlvif->sta.klv_template_id, | 2793 | wlvif->sta.klv_template_id, |
2523 | ACX_KEEP_ALIVE_TPL_VALID); | 2794 | ACX_KEEP_ALIVE_TPL_VALID); |
2524 | if (ret < 0) | 2795 | if (ret < 0) |
2525 | goto out; | 2796 | return ret; |
2797 | |||
2798 | /* | ||
2799 | * The default fw psm configuration is AUTO, while mac80211 default | ||
2800 | * setting is off (ACTIVE), so sync the fw with the correct value. | ||
2801 | */ | ||
2802 | ret = wl1271_ps_set_mode(wl, wlvif, STATION_ACTIVE_MODE); | ||
2803 | if (ret < 0) | ||
2804 | return ret; | ||
2805 | |||
2806 | if (sta_rate_set) { | ||
2807 | wlvif->rate_set = | ||
2808 | wl1271_tx_enabled_rates_get(wl, | ||
2809 | sta_rate_set, | ||
2810 | wlvif->band); | ||
2811 | ret = wl1271_acx_sta_rate_policies(wl, wlvif); | ||
2812 | if (ret < 0) | ||
2813 | return ret; | ||
2814 | } | ||
2526 | 2815 | ||
2527 | out: | ||
2528 | return ret; | 2816 | return ret; |
2529 | } | 2817 | } |
2530 | 2818 | ||
2531 | static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif) | 2819 | static int wlcore_unset_assoc(struct wl1271 *wl, struct wl12xx_vif *wlvif) |
2532 | { | 2820 | { |
2533 | int ret; | 2821 | int ret; |
2822 | bool sta = wlvif->bss_type == BSS_TYPE_STA_BSS; | ||
2823 | |||
2824 | /* make sure we are connected (sta) joined */ | ||
2825 | if (sta && | ||
2826 | !test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) | ||
2827 | return false; | ||
2828 | |||
2829 | /* make sure we are joined (ibss) */ | ||
2830 | if (!sta && | ||
2831 | test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags)) | ||
2832 | return false; | ||
2833 | |||
2834 | if (sta) { | ||
2835 | /* use defaults when not associated */ | ||
2836 | wlvif->aid = 0; | ||
2837 | |||
2838 | /* free probe-request template */ | ||
2839 | dev_kfree_skb(wlvif->probereq); | ||
2840 | wlvif->probereq = NULL; | ||
2841 | |||
2842 | /* disable connection monitor features */ | ||
2843 | ret = wl1271_acx_conn_monit_params(wl, wlvif, false); | ||
2844 | if (ret < 0) | ||
2845 | return ret; | ||
2846 | |||
2847 | /* Disable the keep-alive feature */ | ||
2848 | ret = wl1271_acx_keep_alive_mode(wl, wlvif, false); | ||
2849 | if (ret < 0) | ||
2850 | return ret; | ||
2851 | } | ||
2534 | 2852 | ||
2535 | if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) { | 2853 | if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) { |
2536 | struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); | 2854 | struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); |
2537 | 2855 | ||
2538 | wl12xx_cmd_stop_channel_switch(wl); | 2856 | wl12xx_cmd_stop_channel_switch(wl, wlvif); |
2539 | ieee80211_chswitch_done(vif, false); | 2857 | ieee80211_chswitch_done(vif, false); |
2858 | cancel_delayed_work(&wlvif->channel_switch_work); | ||
2540 | } | 2859 | } |
2541 | 2860 | ||
2542 | /* invalidate keep-alive template */ | 2861 | /* invalidate keep-alive template */ |
@@ -2544,17 +2863,11 @@ static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif) | |||
2544 | wlvif->sta.klv_template_id, | 2863 | wlvif->sta.klv_template_id, |
2545 | ACX_KEEP_ALIVE_TPL_INVALID); | 2864 | ACX_KEEP_ALIVE_TPL_INVALID); |
2546 | 2865 | ||
2547 | /* to stop listening to a channel, we disconnect */ | ||
2548 | ret = wl12xx_cmd_role_stop_sta(wl, wlvif); | ||
2549 | if (ret < 0) | ||
2550 | goto out; | ||
2551 | |||
2552 | /* reset TX security counters on a clean disconnect */ | 2866 | /* reset TX security counters on a clean disconnect */ |
2553 | wlvif->tx_security_last_seq_lsb = 0; | 2867 | wlvif->tx_security_last_seq_lsb = 0; |
2554 | wlvif->tx_security_seq = 0; | 2868 | wlvif->tx_security_seq = 0; |
2555 | 2869 | ||
2556 | out: | 2870 | return 0; |
2557 | return ret; | ||
2558 | } | 2871 | } |
2559 | 2872 | ||
2560 | static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif) | 2873 | static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif) |
@@ -2563,147 +2876,10 @@ static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif) | |||
2563 | wlvif->rate_set = wlvif->basic_rate_set; | 2876 | wlvif->rate_set = wlvif->basic_rate_set; |
2564 | } | 2877 | } |
2565 | 2878 | ||
2566 | static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
2567 | bool idle) | ||
2568 | { | ||
2569 | int ret; | ||
2570 | bool cur_idle = !test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags); | ||
2571 | |||
2572 | if (idle == cur_idle) | ||
2573 | return 0; | ||
2574 | |||
2575 | if (idle) { | ||
2576 | /* no need to croc if we weren't busy (e.g. during boot) */ | ||
2577 | if (wl12xx_dev_role_started(wlvif)) { | ||
2578 | ret = wl12xx_stop_dev(wl, wlvif); | ||
2579 | if (ret < 0) | ||
2580 | goto out; | ||
2581 | } | ||
2582 | wlvif->rate_set = | ||
2583 | wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); | ||
2584 | ret = wl1271_acx_sta_rate_policies(wl, wlvif); | ||
2585 | if (ret < 0) | ||
2586 | goto out; | ||
2587 | clear_bit(WLVIF_FLAG_IN_USE, &wlvif->flags); | ||
2588 | } else { | ||
2589 | /* The current firmware only supports sched_scan in idle */ | ||
2590 | if (wl->sched_scanning) { | ||
2591 | wl1271_scan_sched_scan_stop(wl, wlvif); | ||
2592 | ieee80211_sched_scan_stopped(wl->hw); | ||
2593 | } | ||
2594 | |||
2595 | ret = wl12xx_start_dev(wl, wlvif); | ||
2596 | if (ret < 0) | ||
2597 | goto out; | ||
2598 | set_bit(WLVIF_FLAG_IN_USE, &wlvif->flags); | ||
2599 | } | ||
2600 | |||
2601 | out: | ||
2602 | return ret; | ||
2603 | } | ||
2604 | |||
2605 | static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif, | 2879 | static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
2606 | struct ieee80211_conf *conf, u32 changed) | 2880 | struct ieee80211_conf *conf, u32 changed) |
2607 | { | 2881 | { |
2608 | bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); | 2882 | int ret; |
2609 | int channel, ret; | ||
2610 | |||
2611 | channel = ieee80211_frequency_to_channel(conf->channel->center_freq); | ||
2612 | |||
2613 | /* if the channel changes while joined, join again */ | ||
2614 | if (changed & IEEE80211_CONF_CHANGE_CHANNEL && | ||
2615 | ((wlvif->band != conf->channel->band) || | ||
2616 | (wlvif->channel != channel) || | ||
2617 | (wlvif->channel_type != conf->channel_type))) { | ||
2618 | /* send all pending packets */ | ||
2619 | ret = wlcore_tx_work_locked(wl); | ||
2620 | if (ret < 0) | ||
2621 | return ret; | ||
2622 | |||
2623 | wlvif->band = conf->channel->band; | ||
2624 | wlvif->channel = channel; | ||
2625 | wlvif->channel_type = conf->channel_type; | ||
2626 | |||
2627 | if (is_ap) { | ||
2628 | wl1271_set_band_rate(wl, wlvif); | ||
2629 | ret = wl1271_init_ap_rates(wl, wlvif); | ||
2630 | if (ret < 0) | ||
2631 | wl1271_error("AP rate policy change failed %d", | ||
2632 | ret); | ||
2633 | } else { | ||
2634 | /* | ||
2635 | * FIXME: the mac80211 should really provide a fixed | ||
2636 | * rate to use here. for now, just use the smallest | ||
2637 | * possible rate for the band as a fixed rate for | ||
2638 | * association frames and other control messages. | ||
2639 | */ | ||
2640 | if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) | ||
2641 | wl1271_set_band_rate(wl, wlvif); | ||
2642 | |||
2643 | wlvif->basic_rate = | ||
2644 | wl1271_tx_min_rate_get(wl, | ||
2645 | wlvif->basic_rate_set); | ||
2646 | ret = wl1271_acx_sta_rate_policies(wl, wlvif); | ||
2647 | if (ret < 0) | ||
2648 | wl1271_warning("rate policy for channel " | ||
2649 | "failed %d", ret); | ||
2650 | |||
2651 | /* | ||
2652 | * change the ROC channel. do it only if we are | ||
2653 | * not idle. otherwise, CROC will be called | ||
2654 | * anyway. | ||
2655 | */ | ||
2656 | if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, | ||
2657 | &wlvif->flags) && | ||
2658 | wl12xx_dev_role_started(wlvif) && | ||
2659 | !(conf->flags & IEEE80211_CONF_IDLE)) { | ||
2660 | ret = wl12xx_stop_dev(wl, wlvif); | ||
2661 | if (ret < 0) | ||
2662 | return ret; | ||
2663 | |||
2664 | ret = wl12xx_start_dev(wl, wlvif); | ||
2665 | if (ret < 0) | ||
2666 | return ret; | ||
2667 | } | ||
2668 | } | ||
2669 | } | ||
2670 | |||
2671 | if ((changed & IEEE80211_CONF_CHANGE_PS) && !is_ap) { | ||
2672 | |||
2673 | if ((conf->flags & IEEE80211_CONF_PS) && | ||
2674 | test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) && | ||
2675 | !test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) { | ||
2676 | |||
2677 | int ps_mode; | ||
2678 | char *ps_mode_str; | ||
2679 | |||
2680 | if (wl->conf.conn.forced_ps) { | ||
2681 | ps_mode = STATION_POWER_SAVE_MODE; | ||
2682 | ps_mode_str = "forced"; | ||
2683 | } else { | ||
2684 | ps_mode = STATION_AUTO_PS_MODE; | ||
2685 | ps_mode_str = "auto"; | ||
2686 | } | ||
2687 | |||
2688 | wl1271_debug(DEBUG_PSM, "%s ps enabled", ps_mode_str); | ||
2689 | |||
2690 | ret = wl1271_ps_set_mode(wl, wlvif, ps_mode); | ||
2691 | |||
2692 | if (ret < 0) | ||
2693 | wl1271_warning("enter %s ps failed %d", | ||
2694 | ps_mode_str, ret); | ||
2695 | |||
2696 | } else if (!(conf->flags & IEEE80211_CONF_PS) && | ||
2697 | test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) { | ||
2698 | |||
2699 | wl1271_debug(DEBUG_PSM, "auto ps disabled"); | ||
2700 | |||
2701 | ret = wl1271_ps_set_mode(wl, wlvif, | ||
2702 | STATION_ACTIVE_MODE); | ||
2703 | if (ret < 0) | ||
2704 | wl1271_warning("exit auto ps failed %d", ret); | ||
2705 | } | ||
2706 | } | ||
2707 | 2883 | ||
2708 | if (conf->power_level != wlvif->power_level) { | 2884 | if (conf->power_level != wlvif->power_level) { |
2709 | ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level); | 2885 | ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level); |
@@ -2721,37 +2897,17 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) | |||
2721 | struct wl1271 *wl = hw->priv; | 2897 | struct wl1271 *wl = hw->priv; |
2722 | struct wl12xx_vif *wlvif; | 2898 | struct wl12xx_vif *wlvif; |
2723 | struct ieee80211_conf *conf = &hw->conf; | 2899 | struct ieee80211_conf *conf = &hw->conf; |
2724 | int channel, ret = 0; | 2900 | int ret = 0; |
2725 | |||
2726 | channel = ieee80211_frequency_to_channel(conf->channel->center_freq); | ||
2727 | 2901 | ||
2728 | wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s" | 2902 | wl1271_debug(DEBUG_MAC80211, "mac80211 config psm %s power %d %s" |
2729 | " changed 0x%x", | 2903 | " changed 0x%x", |
2730 | channel, | ||
2731 | conf->flags & IEEE80211_CONF_PS ? "on" : "off", | 2904 | conf->flags & IEEE80211_CONF_PS ? "on" : "off", |
2732 | conf->power_level, | 2905 | conf->power_level, |
2733 | conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use", | 2906 | conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use", |
2734 | changed); | 2907 | changed); |
2735 | 2908 | ||
2736 | /* | ||
2737 | * mac80211 will go to idle nearly immediately after transmitting some | ||
2738 | * frames, such as the deauth. To make sure those frames reach the air, | ||
2739 | * wait here until the TX queue is fully flushed. | ||
2740 | */ | ||
2741 | if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) || | ||
2742 | ((changed & IEEE80211_CONF_CHANGE_IDLE) && | ||
2743 | (conf->flags & IEEE80211_CONF_IDLE))) | ||
2744 | wl1271_tx_flush(wl); | ||
2745 | |||
2746 | mutex_lock(&wl->mutex); | 2909 | mutex_lock(&wl->mutex); |
2747 | 2910 | ||
2748 | /* we support configuring the channel and band even while off */ | ||
2749 | if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { | ||
2750 | wl->band = conf->channel->band; | ||
2751 | wl->channel = channel; | ||
2752 | wl->channel_type = conf->channel_type; | ||
2753 | } | ||
2754 | |||
2755 | if (changed & IEEE80211_CONF_CHANGE_POWER) | 2911 | if (changed & IEEE80211_CONF_CHANGE_POWER) |
2756 | wl->power_level = conf->power_level; | 2912 | wl->power_level = conf->power_level; |
2757 | 2913 | ||
@@ -3071,10 +3227,7 @@ static int wlcore_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | |||
3071 | * stop the queues and flush to ensure the next packets are | 3227 | * stop the queues and flush to ensure the next packets are |
3072 | * in sync with FW spare block accounting | 3228 | * in sync with FW spare block accounting |
3073 | */ | 3229 | */ |
3074 | mutex_lock(&wl->mutex); | ||
3075 | wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_SPARE_BLK); | 3230 | wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_SPARE_BLK); |
3076 | mutex_unlock(&wl->mutex); | ||
3077 | |||
3078 | wl1271_tx_flush(wl); | 3231 | wl1271_tx_flush(wl); |
3079 | } | 3232 | } |
3080 | 3233 | ||
@@ -3200,6 +3353,29 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd, | |||
3200 | } | 3353 | } |
3201 | EXPORT_SYMBOL_GPL(wlcore_set_key); | 3354 | EXPORT_SYMBOL_GPL(wlcore_set_key); |
3202 | 3355 | ||
3356 | void wlcore_regdomain_config(struct wl1271 *wl) | ||
3357 | { | ||
3358 | int ret; | ||
3359 | |||
3360 | if (!(wl->quirks & WLCORE_QUIRK_REGDOMAIN_CONF)) | ||
3361 | return; | ||
3362 | |||
3363 | mutex_lock(&wl->mutex); | ||
3364 | ret = wl1271_ps_elp_wakeup(wl); | ||
3365 | if (ret < 0) | ||
3366 | goto out; | ||
3367 | |||
3368 | ret = wlcore_cmd_regdomain_config_locked(wl); | ||
3369 | if (ret < 0) { | ||
3370 | wl12xx_queue_recovery_work(wl); | ||
3371 | goto out; | ||
3372 | } | ||
3373 | |||
3374 | wl1271_ps_elp_sleep(wl); | ||
3375 | out: | ||
3376 | mutex_unlock(&wl->mutex); | ||
3377 | } | ||
3378 | |||
3203 | static int wl1271_op_hw_scan(struct ieee80211_hw *hw, | 3379 | static int wl1271_op_hw_scan(struct ieee80211_hw *hw, |
3204 | struct ieee80211_vif *vif, | 3380 | struct ieee80211_vif *vif, |
3205 | struct cfg80211_scan_request *req) | 3381 | struct cfg80211_scan_request *req) |
@@ -3239,7 +3415,7 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw, | |||
3239 | goto out_sleep; | 3415 | goto out_sleep; |
3240 | } | 3416 | } |
3241 | 3417 | ||
3242 | ret = wl1271_scan(hw->priv, vif, ssid, len, req); | 3418 | ret = wlcore_scan(hw->priv, vif, ssid, len, req); |
3243 | out_sleep: | 3419 | out_sleep: |
3244 | wl1271_ps_elp_sleep(wl); | 3420 | wl1271_ps_elp_sleep(wl); |
3245 | out: | 3421 | out: |
@@ -3252,6 +3428,7 @@ static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw, | |||
3252 | struct ieee80211_vif *vif) | 3428 | struct ieee80211_vif *vif) |
3253 | { | 3429 | { |
3254 | struct wl1271 *wl = hw->priv; | 3430 | struct wl1271 *wl = hw->priv; |
3431 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | ||
3255 | int ret; | 3432 | int ret; |
3256 | 3433 | ||
3257 | wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan"); | 3434 | wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan"); |
@@ -3269,7 +3446,7 @@ static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw, | |||
3269 | goto out; | 3446 | goto out; |
3270 | 3447 | ||
3271 | if (wl->scan.state != WL1271_SCAN_STATE_DONE) { | 3448 | if (wl->scan.state != WL1271_SCAN_STATE_DONE) { |
3272 | ret = wl1271_scan_stop(wl); | 3449 | ret = wl->ops->scan_stop(wl, wlvif); |
3273 | if (ret < 0) | 3450 | if (ret < 0) |
3274 | goto out_sleep; | 3451 | goto out_sleep; |
3275 | } | 3452 | } |
@@ -3282,7 +3459,7 @@ static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw, | |||
3282 | 3459 | ||
3283 | wl->scan.state = WL1271_SCAN_STATE_IDLE; | 3460 | wl->scan.state = WL1271_SCAN_STATE_IDLE; |
3284 | memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); | 3461 | memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); |
3285 | wl->scan_vif = NULL; | 3462 | wl->scan_wlvif = NULL; |
3286 | wl->scan.req = NULL; | 3463 | wl->scan.req = NULL; |
3287 | ieee80211_scan_completed(wl->hw, true); | 3464 | ieee80211_scan_completed(wl->hw, true); |
3288 | 3465 | ||
@@ -3316,15 +3493,11 @@ static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw, | |||
3316 | if (ret < 0) | 3493 | if (ret < 0) |
3317 | goto out; | 3494 | goto out; |
3318 | 3495 | ||
3319 | ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies); | 3496 | ret = wl->ops->sched_scan_start(wl, wlvif, req, ies); |
3320 | if (ret < 0) | 3497 | if (ret < 0) |
3321 | goto out_sleep; | 3498 | goto out_sleep; |
3322 | 3499 | ||
3323 | ret = wl1271_scan_sched_scan_start(wl, wlvif); | 3500 | wl->sched_vif = wlvif; |
3324 | if (ret < 0) | ||
3325 | goto out_sleep; | ||
3326 | |||
3327 | wl->sched_scanning = true; | ||
3328 | 3501 | ||
3329 | out_sleep: | 3502 | out_sleep: |
3330 | wl1271_ps_elp_sleep(wl); | 3503 | wl1271_ps_elp_sleep(wl); |
@@ -3351,7 +3524,7 @@ static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw, | |||
3351 | if (ret < 0) | 3524 | if (ret < 0) |
3352 | goto out; | 3525 | goto out; |
3353 | 3526 | ||
3354 | wl1271_scan_sched_scan_stop(wl, wlvif); | 3527 | wl->ops->sched_scan_stop(wl, wlvif); |
3355 | 3528 | ||
3356 | wl1271_ps_elp_sleep(wl); | 3529 | wl1271_ps_elp_sleep(wl); |
3357 | out: | 3530 | out: |
@@ -3416,30 +3589,6 @@ out: | |||
3416 | return ret; | 3589 | return ret; |
3417 | } | 3590 | } |
3418 | 3591 | ||
3419 | static int wl1271_ssid_set(struct ieee80211_vif *vif, struct sk_buff *skb, | ||
3420 | int offset) | ||
3421 | { | ||
3422 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | ||
3423 | u8 ssid_len; | ||
3424 | const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset, | ||
3425 | skb->len - offset); | ||
3426 | |||
3427 | if (!ptr) { | ||
3428 | wl1271_error("No SSID in IEs!"); | ||
3429 | return -ENOENT; | ||
3430 | } | ||
3431 | |||
3432 | ssid_len = ptr[1]; | ||
3433 | if (ssid_len > IEEE80211_MAX_SSID_LEN) { | ||
3434 | wl1271_error("SSID is too long!"); | ||
3435 | return -EINVAL; | ||
3436 | } | ||
3437 | |||
3438 | wlvif->ssid_len = ssid_len; | ||
3439 | memcpy(wlvif->ssid, ptr+2, ssid_len); | ||
3440 | return 0; | ||
3441 | } | ||
3442 | |||
3443 | static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset) | 3592 | static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset) |
3444 | { | 3593 | { |
3445 | int len; | 3594 | int len; |
@@ -3620,7 +3769,7 @@ static int wlcore_set_beacon_template(struct wl1271 *wl, | |||
3620 | 3769 | ||
3621 | wl1271_debug(DEBUG_MASTER, "beacon updated"); | 3770 | wl1271_debug(DEBUG_MASTER, "beacon updated"); |
3622 | 3771 | ||
3623 | ret = wl1271_ssid_set(vif, beacon, ieoffset); | 3772 | ret = wl1271_ssid_set(wlvif, beacon, ieoffset); |
3624 | if (ret < 0) { | 3773 | if (ret < 0) { |
3625 | dev_kfree_skb(beacon); | 3774 | dev_kfree_skb(beacon); |
3626 | goto out; | 3775 | goto out; |
@@ -3637,6 +3786,12 @@ static int wlcore_set_beacon_template(struct wl1271 *wl, | |||
3637 | goto out; | 3786 | goto out; |
3638 | } | 3787 | } |
3639 | 3788 | ||
3789 | wlvif->wmm_enabled = | ||
3790 | cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, | ||
3791 | WLAN_OUI_TYPE_MICROSOFT_WMM, | ||
3792 | beacon->data + ieoffset, | ||
3793 | beacon->len - ieoffset); | ||
3794 | |||
3640 | /* | 3795 | /* |
3641 | * In case we already have a probe-resp beacon set explicitly | 3796 | * In case we already have a probe-resp beacon set explicitly |
3642 | * by usermode, don't use the beacon data. | 3797 | * by usermode, don't use the beacon data. |
@@ -3690,7 +3845,7 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl, | |||
3690 | bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); | 3845 | bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); |
3691 | int ret = 0; | 3846 | int ret = 0; |
3692 | 3847 | ||
3693 | if ((changed & BSS_CHANGED_BEACON_INT)) { | 3848 | if (changed & BSS_CHANGED_BEACON_INT) { |
3694 | wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d", | 3849 | wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d", |
3695 | bss_conf->beacon_int); | 3850 | bss_conf->beacon_int); |
3696 | 3851 | ||
@@ -3703,7 +3858,7 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl, | |||
3703 | wl1271_ap_set_probe_resp_tmpl(wl, rate, vif); | 3858 | wl1271_ap_set_probe_resp_tmpl(wl, rate, vif); |
3704 | } | 3859 | } |
3705 | 3860 | ||
3706 | if ((changed & BSS_CHANGED_BEACON)) { | 3861 | if (changed & BSS_CHANGED_BEACON) { |
3707 | ret = wlcore_set_beacon_template(wl, vif, is_ap); | 3862 | ret = wlcore_set_beacon_template(wl, vif, is_ap); |
3708 | if (ret < 0) | 3863 | if (ret < 0) |
3709 | goto out; | 3864 | goto out; |
@@ -3724,7 +3879,7 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl, | |||
3724 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | 3879 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); |
3725 | int ret = 0; | 3880 | int ret = 0; |
3726 | 3881 | ||
3727 | if ((changed & BSS_CHANGED_BASIC_RATES)) { | 3882 | if (changed & BSS_CHANGED_BASIC_RATES) { |
3728 | u32 rates = bss_conf->basic_rates; | 3883 | u32 rates = bss_conf->basic_rates; |
3729 | 3884 | ||
3730 | wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates, | 3885 | wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates, |
@@ -3755,7 +3910,7 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl, | |||
3755 | if (ret < 0) | 3910 | if (ret < 0) |
3756 | goto out; | 3911 | goto out; |
3757 | 3912 | ||
3758 | if ((changed & BSS_CHANGED_BEACON_ENABLED)) { | 3913 | if (changed & BSS_CHANGED_BEACON_ENABLED) { |
3759 | if (bss_conf->enable_beacon) { | 3914 | if (bss_conf->enable_beacon) { |
3760 | if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) { | 3915 | if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) { |
3761 | ret = wl12xx_cmd_role_start_ap(wl, wlvif); | 3916 | ret = wl12xx_cmd_role_start_ap(wl, wlvif); |
@@ -3802,6 +3957,79 @@ out: | |||
3802 | return; | 3957 | return; |
3803 | } | 3958 | } |
3804 | 3959 | ||
3960 | static int wlcore_set_bssid(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
3961 | struct ieee80211_bss_conf *bss_conf, | ||
3962 | u32 sta_rate_set) | ||
3963 | { | ||
3964 | u32 rates; | ||
3965 | int ret; | ||
3966 | |||
3967 | wl1271_debug(DEBUG_MAC80211, | ||
3968 | "changed_bssid: %pM, aid: %d, bcn_int: %d, brates: 0x%x sta_rate_set: 0x%x", | ||
3969 | bss_conf->bssid, bss_conf->aid, | ||
3970 | bss_conf->beacon_int, | ||
3971 | bss_conf->basic_rates, sta_rate_set); | ||
3972 | |||
3973 | wlvif->beacon_int = bss_conf->beacon_int; | ||
3974 | rates = bss_conf->basic_rates; | ||
3975 | wlvif->basic_rate_set = | ||
3976 | wl1271_tx_enabled_rates_get(wl, rates, | ||
3977 | wlvif->band); | ||
3978 | wlvif->basic_rate = | ||
3979 | wl1271_tx_min_rate_get(wl, | ||
3980 | wlvif->basic_rate_set); | ||
3981 | |||
3982 | if (sta_rate_set) | ||
3983 | wlvif->rate_set = | ||
3984 | wl1271_tx_enabled_rates_get(wl, | ||
3985 | sta_rate_set, | ||
3986 | wlvif->band); | ||
3987 | |||
3988 | /* we only support sched_scan while not connected */ | ||
3989 | if (wl->sched_vif == wlvif) | ||
3990 | wl->ops->sched_scan_stop(wl, wlvif); | ||
3991 | |||
3992 | ret = wl1271_acx_sta_rate_policies(wl, wlvif); | ||
3993 | if (ret < 0) | ||
3994 | return ret; | ||
3995 | |||
3996 | ret = wl12xx_cmd_build_null_data(wl, wlvif); | ||
3997 | if (ret < 0) | ||
3998 | return ret; | ||
3999 | |||
4000 | ret = wl1271_build_qos_null_data(wl, wl12xx_wlvif_to_vif(wlvif)); | ||
4001 | if (ret < 0) | ||
4002 | return ret; | ||
4003 | |||
4004 | wlcore_set_ssid(wl, wlvif); | ||
4005 | |||
4006 | set_bit(WLVIF_FLAG_IN_USE, &wlvif->flags); | ||
4007 | |||
4008 | return 0; | ||
4009 | } | ||
4010 | |||
4011 | static int wlcore_clear_bssid(struct wl1271 *wl, struct wl12xx_vif *wlvif) | ||
4012 | { | ||
4013 | int ret; | ||
4014 | |||
4015 | /* revert back to minimum rates for the current band */ | ||
4016 | wl1271_set_band_rate(wl, wlvif); | ||
4017 | wlvif->basic_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); | ||
4018 | |||
4019 | ret = wl1271_acx_sta_rate_policies(wl, wlvif); | ||
4020 | if (ret < 0) | ||
4021 | return ret; | ||
4022 | |||
4023 | if (wlvif->bss_type == BSS_TYPE_STA_BSS && | ||
4024 | test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags)) { | ||
4025 | ret = wl12xx_cmd_role_stop_sta(wl, wlvif); | ||
4026 | if (ret < 0) | ||
4027 | return ret; | ||
4028 | } | ||
4029 | |||
4030 | clear_bit(WLVIF_FLAG_IN_USE, &wlvif->flags); | ||
4031 | return 0; | ||
4032 | } | ||
3805 | /* STA/IBSS mode changes */ | 4033 | /* STA/IBSS mode changes */ |
3806 | static void wl1271_bss_info_changed_sta(struct wl1271 *wl, | 4034 | static void wl1271_bss_info_changed_sta(struct wl1271 *wl, |
3807 | struct ieee80211_vif *vif, | 4035 | struct ieee80211_vif *vif, |
@@ -3809,7 +4037,7 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, | |||
3809 | u32 changed) | 4037 | u32 changed) |
3810 | { | 4038 | { |
3811 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | 4039 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); |
3812 | bool do_join = false, set_assoc = false; | 4040 | bool do_join = false; |
3813 | bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS); | 4041 | bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS); |
3814 | bool ibss_joined = false; | 4042 | bool ibss_joined = false; |
3815 | u32 sta_rate_set = 0; | 4043 | u32 sta_rate_set = 0; |
@@ -3830,9 +4058,8 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, | |||
3830 | set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags); | 4058 | set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags); |
3831 | ibss_joined = true; | 4059 | ibss_joined = true; |
3832 | } else { | 4060 | } else { |
3833 | if (test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED, | 4061 | wlcore_unset_assoc(wl, wlvif); |
3834 | &wlvif->flags)) | 4062 | wl12xx_cmd_role_stop_sta(wl, wlvif); |
3835 | wl1271_unjoin(wl, wlvif); | ||
3836 | } | 4063 | } |
3837 | } | 4064 | } |
3838 | 4065 | ||
@@ -3850,13 +4077,7 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, | |||
3850 | do_join = true; | 4077 | do_join = true; |
3851 | } | 4078 | } |
3852 | 4079 | ||
3853 | if (changed & BSS_CHANGED_IDLE && !is_ibss) { | 4080 | if (changed & BSS_CHANGED_CQM) { |
3854 | ret = wl1271_sta_handle_idle(wl, wlvif, bss_conf->idle); | ||
3855 | if (ret < 0) | ||
3856 | wl1271_warning("idle mode change failed %d", ret); | ||
3857 | } | ||
3858 | |||
3859 | if ((changed & BSS_CHANGED_CQM)) { | ||
3860 | bool enable = false; | 4081 | bool enable = false; |
3861 | if (bss_conf->cqm_rssi_thold) | 4082 | if (bss_conf->cqm_rssi_thold) |
3862 | enable = true; | 4083 | enable = true; |
@@ -3868,150 +4089,39 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, | |||
3868 | wlvif->rssi_thold = bss_conf->cqm_rssi_thold; | 4089 | wlvif->rssi_thold = bss_conf->cqm_rssi_thold; |
3869 | } | 4090 | } |
3870 | 4091 | ||
3871 | if (changed & BSS_CHANGED_BSSID) | 4092 | if (changed & (BSS_CHANGED_BSSID | BSS_CHANGED_HT | |
3872 | if (!is_zero_ether_addr(bss_conf->bssid)) { | 4093 | BSS_CHANGED_ASSOC)) { |
3873 | ret = wl12xx_cmd_build_null_data(wl, wlvif); | ||
3874 | if (ret < 0) | ||
3875 | goto out; | ||
3876 | |||
3877 | ret = wl1271_build_qos_null_data(wl, vif); | ||
3878 | if (ret < 0) | ||
3879 | goto out; | ||
3880 | } | ||
3881 | |||
3882 | if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) { | ||
3883 | rcu_read_lock(); | 4094 | rcu_read_lock(); |
3884 | sta = ieee80211_find_sta(vif, bss_conf->bssid); | 4095 | sta = ieee80211_find_sta(vif, bss_conf->bssid); |
3885 | if (!sta) | 4096 | if (sta) { |
3886 | goto sta_not_found; | 4097 | u8 *rx_mask = sta->ht_cap.mcs.rx_mask; |
3887 | 4098 | ||
3888 | /* save the supp_rates of the ap */ | 4099 | /* save the supp_rates of the ap */ |
3889 | sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band]; | 4100 | sta_rate_set = sta->supp_rates[wlvif->band]; |
3890 | if (sta->ht_cap.ht_supported) | 4101 | if (sta->ht_cap.ht_supported) |
3891 | sta_rate_set |= | 4102 | sta_rate_set |= |
3892 | (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET) | | 4103 | (rx_mask[0] << HW_HT_RATES_OFFSET) | |
3893 | (sta->ht_cap.mcs.rx_mask[1] << HW_MIMO_RATES_OFFSET); | 4104 | (rx_mask[1] << HW_MIMO_RATES_OFFSET); |
3894 | sta_ht_cap = sta->ht_cap; | 4105 | sta_ht_cap = sta->ht_cap; |
3895 | sta_exists = true; | 4106 | sta_exists = true; |
3896 | 4107 | } | |
3897 | sta_not_found: | 4108 | |
3898 | rcu_read_unlock(); | 4109 | rcu_read_unlock(); |
3899 | } | 4110 | } |
3900 | 4111 | ||
3901 | if ((changed & BSS_CHANGED_ASSOC)) { | 4112 | if (changed & BSS_CHANGED_BSSID) { |
3902 | if (bss_conf->assoc) { | 4113 | if (!is_zero_ether_addr(bss_conf->bssid)) { |
3903 | u32 rates; | 4114 | ret = wlcore_set_bssid(wl, wlvif, bss_conf, |
3904 | int ieoffset; | 4115 | sta_rate_set); |
3905 | wlvif->aid = bss_conf->aid; | ||
3906 | wlvif->channel_type = | ||
3907 | cfg80211_get_chandef_type(&bss_conf->chandef); | ||
3908 | wlvif->beacon_int = bss_conf->beacon_int; | ||
3909 | do_join = true; | ||
3910 | set_assoc = true; | ||
3911 | |||
3912 | /* | ||
3913 | * use basic rates from AP, and determine lowest rate | ||
3914 | * to use with control frames. | ||
3915 | */ | ||
3916 | rates = bss_conf->basic_rates; | ||
3917 | wlvif->basic_rate_set = | ||
3918 | wl1271_tx_enabled_rates_get(wl, rates, | ||
3919 | wlvif->band); | ||
3920 | wlvif->basic_rate = | ||
3921 | wl1271_tx_min_rate_get(wl, | ||
3922 | wlvif->basic_rate_set); | ||
3923 | if (sta_rate_set) | ||
3924 | wlvif->rate_set = | ||
3925 | wl1271_tx_enabled_rates_get(wl, | ||
3926 | sta_rate_set, | ||
3927 | wlvif->band); | ||
3928 | ret = wl1271_acx_sta_rate_policies(wl, wlvif); | ||
3929 | if (ret < 0) | ||
3930 | goto out; | ||
3931 | |||
3932 | /* | ||
3933 | * with wl1271, we don't need to update the | ||
3934 | * beacon_int and dtim_period, because the firmware | ||
3935 | * updates it by itself when the first beacon is | ||
3936 | * received after a join. | ||
3937 | */ | ||
3938 | ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid); | ||
3939 | if (ret < 0) | 4116 | if (ret < 0) |
3940 | goto out; | 4117 | goto out; |
3941 | 4118 | ||
3942 | /* | 4119 | /* Need to update the BSSID (for filtering etc) */ |
3943 | * Get a template for hardware connection maintenance | 4120 | do_join = true; |
3944 | */ | ||
3945 | dev_kfree_skb(wlvif->probereq); | ||
3946 | wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl, | ||
3947 | wlvif, | ||
3948 | NULL); | ||
3949 | ieoffset = offsetof(struct ieee80211_mgmt, | ||
3950 | u.probe_req.variable); | ||
3951 | wl1271_ssid_set(vif, wlvif->probereq, ieoffset); | ||
3952 | |||
3953 | /* enable the connection monitoring feature */ | ||
3954 | ret = wl1271_acx_conn_monit_params(wl, wlvif, true); | ||
3955 | if (ret < 0) | ||
3956 | goto out; | ||
3957 | } else { | 4121 | } else { |
3958 | /* use defaults when not associated */ | 4122 | ret = wlcore_clear_bssid(wl, wlvif); |
3959 | bool was_assoc = | ||
3960 | !!test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED, | ||
3961 | &wlvif->flags); | ||
3962 | bool was_ifup = | ||
3963 | !!test_and_clear_bit(WLVIF_FLAG_STA_STATE_SENT, | ||
3964 | &wlvif->flags); | ||
3965 | wlvif->aid = 0; | ||
3966 | |||
3967 | /* free probe-request template */ | ||
3968 | dev_kfree_skb(wlvif->probereq); | ||
3969 | wlvif->probereq = NULL; | ||
3970 | |||
3971 | /* revert back to minimum rates for the current band */ | ||
3972 | wl1271_set_band_rate(wl, wlvif); | ||
3973 | wlvif->basic_rate = | ||
3974 | wl1271_tx_min_rate_get(wl, | ||
3975 | wlvif->basic_rate_set); | ||
3976 | ret = wl1271_acx_sta_rate_policies(wl, wlvif); | ||
3977 | if (ret < 0) | ||
3978 | goto out; | ||
3979 | |||
3980 | /* disable connection monitor features */ | ||
3981 | ret = wl1271_acx_conn_monit_params(wl, wlvif, false); | ||
3982 | |||
3983 | /* Disable the keep-alive feature */ | ||
3984 | ret = wl1271_acx_keep_alive_mode(wl, wlvif, false); | ||
3985 | if (ret < 0) | 4123 | if (ret < 0) |
3986 | goto out; | 4124 | goto out; |
3987 | |||
3988 | /* restore the bssid filter and go to dummy bssid */ | ||
3989 | if (was_assoc) { | ||
3990 | /* | ||
3991 | * we might have to disable roc, if there was | ||
3992 | * no IF_OPER_UP notification. | ||
3993 | */ | ||
3994 | if (!was_ifup) { | ||
3995 | ret = wl12xx_croc(wl, wlvif->role_id); | ||
3996 | if (ret < 0) | ||
3997 | goto out; | ||
3998 | } | ||
3999 | /* | ||
4000 | * (we also need to disable roc in case of | ||
4001 | * roaming on the same channel. until we will | ||
4002 | * have a better flow...) | ||
4003 | */ | ||
4004 | if (test_bit(wlvif->dev_role_id, wl->roc_map)) { | ||
4005 | ret = wl12xx_croc(wl, | ||
4006 | wlvif->dev_role_id); | ||
4007 | if (ret < 0) | ||
4008 | goto out; | ||
4009 | } | ||
4010 | |||
4011 | wl1271_unjoin(wl, wlvif); | ||
4012 | if (!bss_conf->idle) | ||
4013 | wl12xx_start_dev(wl, wlvif); | ||
4014 | } | ||
4015 | } | 4125 | } |
4016 | } | 4126 | } |
4017 | 4127 | ||
@@ -4041,71 +4151,87 @@ sta_not_found: | |||
4041 | goto out; | 4151 | goto out; |
4042 | 4152 | ||
4043 | if (do_join) { | 4153 | if (do_join) { |
4044 | ret = wl1271_join(wl, wlvif, set_assoc); | 4154 | ret = wlcore_join(wl, wlvif); |
4045 | if (ret < 0) { | 4155 | if (ret < 0) { |
4046 | wl1271_warning("cmd join failed %d", ret); | 4156 | wl1271_warning("cmd join failed %d", ret); |
4047 | goto out; | 4157 | goto out; |
4048 | } | 4158 | } |
4159 | } | ||
4049 | 4160 | ||
4050 | /* ROC until connected (after EAPOL exchange) */ | 4161 | if (changed & BSS_CHANGED_ASSOC) { |
4051 | if (!is_ibss) { | 4162 | if (bss_conf->assoc) { |
4052 | ret = wl12xx_roc(wl, wlvif, wlvif->role_id); | 4163 | ret = wlcore_set_assoc(wl, wlvif, bss_conf, |
4164 | sta_rate_set); | ||
4053 | if (ret < 0) | 4165 | if (ret < 0) |
4054 | goto out; | 4166 | goto out; |
4055 | 4167 | ||
4056 | if (test_bit(WLVIF_FLAG_STA_AUTHORIZED, &wlvif->flags)) | 4168 | if (test_bit(WLVIF_FLAG_STA_AUTHORIZED, &wlvif->flags)) |
4057 | wl12xx_set_authorized(wl, wlvif); | 4169 | wl12xx_set_authorized(wl, wlvif); |
4170 | } else { | ||
4171 | wlcore_unset_assoc(wl, wlvif); | ||
4058 | } | 4172 | } |
4059 | /* | 4173 | } |
4060 | * stop device role if started (we might already be in | 4174 | |
4061 | * STA/IBSS role). | 4175 | if (changed & BSS_CHANGED_PS) { |
4062 | */ | 4176 | if ((bss_conf->ps) && |
4063 | if (wl12xx_dev_role_started(wlvif)) { | 4177 | test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) && |
4064 | ret = wl12xx_stop_dev(wl, wlvif); | 4178 | !test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) { |
4179 | int ps_mode; | ||
4180 | char *ps_mode_str; | ||
4181 | |||
4182 | if (wl->conf.conn.forced_ps) { | ||
4183 | ps_mode = STATION_POWER_SAVE_MODE; | ||
4184 | ps_mode_str = "forced"; | ||
4185 | } else { | ||
4186 | ps_mode = STATION_AUTO_PS_MODE; | ||
4187 | ps_mode_str = "auto"; | ||
4188 | } | ||
4189 | |||
4190 | wl1271_debug(DEBUG_PSM, "%s ps enabled", ps_mode_str); | ||
4191 | |||
4192 | ret = wl1271_ps_set_mode(wl, wlvif, ps_mode); | ||
4065 | if (ret < 0) | 4193 | if (ret < 0) |
4066 | goto out; | 4194 | wl1271_warning("enter %s ps failed %d", |
4195 | ps_mode_str, ret); | ||
4196 | } else if (!bss_conf->ps && | ||
4197 | test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) { | ||
4198 | wl1271_debug(DEBUG_PSM, "auto ps disabled"); | ||
4199 | |||
4200 | ret = wl1271_ps_set_mode(wl, wlvif, | ||
4201 | STATION_ACTIVE_MODE); | ||
4202 | if (ret < 0) | ||
4203 | wl1271_warning("exit auto ps failed %d", ret); | ||
4067 | } | 4204 | } |
4068 | } | 4205 | } |
4069 | 4206 | ||
4070 | /* Handle new association with HT. Do this after join. */ | 4207 | /* Handle new association with HT. Do this after join. */ |
4071 | if (sta_exists) { | 4208 | if (sta_exists && |
4072 | if ((changed & BSS_CHANGED_HT) && | 4209 | (changed & BSS_CHANGED_HT)) { |
4073 | (bss_conf->chandef.width != NL80211_CHAN_WIDTH_20_NOHT)) { | 4210 | bool enabled = |
4074 | ret = wl1271_acx_set_ht_capabilities(wl, | 4211 | bss_conf->chandef.width != NL80211_CHAN_WIDTH_20_NOHT; |
4075 | &sta_ht_cap, | 4212 | |
4076 | true, | 4213 | ret = wlcore_hw_set_peer_cap(wl, |
4077 | wlvif->sta.hlid); | 4214 | &sta_ht_cap, |
4078 | if (ret < 0) { | 4215 | enabled, |
4079 | wl1271_warning("Set ht cap true failed %d", | 4216 | wlvif->rate_set, |
4080 | ret); | 4217 | wlvif->sta.hlid); |
4081 | goto out; | 4218 | if (ret < 0) { |
4082 | } | 4219 | wl1271_warning("Set ht cap failed %d", ret); |
4220 | goto out; | ||
4221 | |||
4083 | } | 4222 | } |
4084 | /* handle new association without HT and disassociation */ | 4223 | |
4085 | else if (changed & BSS_CHANGED_ASSOC) { | 4224 | if (enabled) { |
4086 | ret = wl1271_acx_set_ht_capabilities(wl, | 4225 | ret = wl1271_acx_set_ht_information(wl, wlvif, |
4087 | &sta_ht_cap, | 4226 | bss_conf->ht_operation_mode); |
4088 | false, | ||
4089 | wlvif->sta.hlid); | ||
4090 | if (ret < 0) { | 4227 | if (ret < 0) { |
4091 | wl1271_warning("Set ht cap false failed %d", | 4228 | wl1271_warning("Set ht information failed %d", |
4092 | ret); | 4229 | ret); |
4093 | goto out; | 4230 | goto out; |
4094 | } | 4231 | } |
4095 | } | 4232 | } |
4096 | } | 4233 | } |
4097 | 4234 | ||
4098 | /* Handle HT information change. Done after join. */ | ||
4099 | if ((changed & BSS_CHANGED_HT) && | ||
4100 | (bss_conf->chandef.width != NL80211_CHAN_WIDTH_20_NOHT)) { | ||
4101 | ret = wl1271_acx_set_ht_information(wl, wlvif, | ||
4102 | bss_conf->ht_operation_mode); | ||
4103 | if (ret < 0) { | ||
4104 | wl1271_warning("Set ht information failed %d", ret); | ||
4105 | goto out; | ||
4106 | } | ||
4107 | } | ||
4108 | |||
4109 | /* Handle arp filtering. Done after join. */ | 4235 | /* Handle arp filtering. Done after join. */ |
4110 | if ((changed & BSS_CHANGED_ARP_FILTER) || | 4236 | if ((changed & BSS_CHANGED_ARP_FILTER) || |
4111 | (!is_ibss && (changed & BSS_CHANGED_QOS))) { | 4237 | (!is_ibss && (changed & BSS_CHANGED_QOS))) { |
@@ -4113,8 +4239,7 @@ sta_not_found: | |||
4113 | wlvif->sta.qos = bss_conf->qos; | 4239 | wlvif->sta.qos = bss_conf->qos; |
4114 | WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS); | 4240 | WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS); |
4115 | 4241 | ||
4116 | if (bss_conf->arp_addr_cnt == 1 && | 4242 | if (bss_conf->arp_addr_cnt == 1 && bss_conf->assoc) { |
4117 | bss_conf->arp_filter_enabled) { | ||
4118 | wlvif->ip_addr = addr; | 4243 | wlvif->ip_addr = addr; |
4119 | /* | 4244 | /* |
4120 | * The template should have been configured only upon | 4245 | * The template should have been configured only upon |
@@ -4155,15 +4280,15 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, | |||
4155 | bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); | 4280 | bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); |
4156 | int ret; | 4281 | int ret; |
4157 | 4282 | ||
4158 | wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x", | 4283 | wl1271_debug(DEBUG_MAC80211, "mac80211 bss info role %d changed 0x%x", |
4159 | (int)changed); | 4284 | wlvif->role_id, (int)changed); |
4160 | 4285 | ||
4161 | /* | 4286 | /* |
4162 | * make sure to cancel pending disconnections if our association | 4287 | * make sure to cancel pending disconnections if our association |
4163 | * state changed | 4288 | * state changed |
4164 | */ | 4289 | */ |
4165 | if (!is_ap && (changed & BSS_CHANGED_ASSOC)) | 4290 | if (!is_ap && (changed & BSS_CHANGED_ASSOC)) |
4166 | cancel_delayed_work_sync(&wl->connection_loss_work); | 4291 | cancel_delayed_work_sync(&wlvif->connection_loss_work); |
4167 | 4292 | ||
4168 | if (is_ap && (changed & BSS_CHANGED_BEACON_ENABLED) && | 4293 | if (is_ap && (changed & BSS_CHANGED_BEACON_ENABLED) && |
4169 | !bss_conf->enable_beacon) | 4294 | !bss_conf->enable_beacon) |
@@ -4192,6 +4317,76 @@ out: | |||
4192 | mutex_unlock(&wl->mutex); | 4317 | mutex_unlock(&wl->mutex); |
4193 | } | 4318 | } |
4194 | 4319 | ||
4320 | static int wlcore_op_add_chanctx(struct ieee80211_hw *hw, | ||
4321 | struct ieee80211_chanctx_conf *ctx) | ||
4322 | { | ||
4323 | wl1271_debug(DEBUG_MAC80211, "mac80211 add chanctx %d (type %d)", | ||
4324 | ieee80211_frequency_to_channel(ctx->def.chan->center_freq), | ||
4325 | cfg80211_get_chandef_type(&ctx->def)); | ||
4326 | return 0; | ||
4327 | } | ||
4328 | |||
4329 | static void wlcore_op_remove_chanctx(struct ieee80211_hw *hw, | ||
4330 | struct ieee80211_chanctx_conf *ctx) | ||
4331 | { | ||
4332 | wl1271_debug(DEBUG_MAC80211, "mac80211 remove chanctx %d (type %d)", | ||
4333 | ieee80211_frequency_to_channel(ctx->def.chan->center_freq), | ||
4334 | cfg80211_get_chandef_type(&ctx->def)); | ||
4335 | } | ||
4336 | |||
4337 | static void wlcore_op_change_chanctx(struct ieee80211_hw *hw, | ||
4338 | struct ieee80211_chanctx_conf *ctx, | ||
4339 | u32 changed) | ||
4340 | { | ||
4341 | wl1271_debug(DEBUG_MAC80211, | ||
4342 | "mac80211 change chanctx %d (type %d) changed 0x%x", | ||
4343 | ieee80211_frequency_to_channel(ctx->def.chan->center_freq), | ||
4344 | cfg80211_get_chandef_type(&ctx->def), changed); | ||
4345 | } | ||
4346 | |||
4347 | static int wlcore_op_assign_vif_chanctx(struct ieee80211_hw *hw, | ||
4348 | struct ieee80211_vif *vif, | ||
4349 | struct ieee80211_chanctx_conf *ctx) | ||
4350 | { | ||
4351 | struct wl1271 *wl = hw->priv; | ||
4352 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | ||
4353 | int channel = ieee80211_frequency_to_channel( | ||
4354 | ctx->def.chan->center_freq); | ||
4355 | |||
4356 | wl1271_debug(DEBUG_MAC80211, | ||
4357 | "mac80211 assign chanctx (role %d) %d (type %d)", | ||
4358 | wlvif->role_id, channel, cfg80211_get_chandef_type(&ctx->def)); | ||
4359 | |||
4360 | mutex_lock(&wl->mutex); | ||
4361 | |||
4362 | wlvif->band = ctx->def.chan->band; | ||
4363 | wlvif->channel = channel; | ||
4364 | wlvif->channel_type = cfg80211_get_chandef_type(&ctx->def); | ||
4365 | |||
4366 | /* update default rates according to the band */ | ||
4367 | wl1271_set_band_rate(wl, wlvif); | ||
4368 | |||
4369 | mutex_unlock(&wl->mutex); | ||
4370 | |||
4371 | return 0; | ||
4372 | } | ||
4373 | |||
4374 | static void wlcore_op_unassign_vif_chanctx(struct ieee80211_hw *hw, | ||
4375 | struct ieee80211_vif *vif, | ||
4376 | struct ieee80211_chanctx_conf *ctx) | ||
4377 | { | ||
4378 | struct wl1271 *wl = hw->priv; | ||
4379 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | ||
4380 | |||
4381 | wl1271_debug(DEBUG_MAC80211, | ||
4382 | "mac80211 unassign chanctx (role %d) %d (type %d)", | ||
4383 | wlvif->role_id, | ||
4384 | ieee80211_frequency_to_channel(ctx->def.chan->center_freq), | ||
4385 | cfg80211_get_chandef_type(&ctx->def)); | ||
4386 | |||
4387 | wl1271_tx_flush(wl); | ||
4388 | } | ||
4389 | |||
4195 | static int wl1271_op_conf_tx(struct ieee80211_hw *hw, | 4390 | static int wl1271_op_conf_tx(struct ieee80211_hw *hw, |
4196 | struct ieee80211_vif *vif, u16 queue, | 4391 | struct ieee80211_vif *vif, u16 queue, |
4197 | const struct ieee80211_tx_queue_params *params) | 4392 | const struct ieee80211_tx_queue_params *params) |
@@ -4319,8 +4514,6 @@ void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid) | |||
4319 | return; | 4514 | return; |
4320 | 4515 | ||
4321 | clear_bit(hlid, wlvif->ap.sta_hlid_map); | 4516 | clear_bit(hlid, wlvif->ap.sta_hlid_map); |
4322 | memset(wl->links[hlid].addr, 0, ETH_ALEN); | ||
4323 | wl->links[hlid].ba_bitmap = 0; | ||
4324 | __clear_bit(hlid, &wl->ap_ps_map); | 4517 | __clear_bit(hlid, &wl->ap_ps_map); |
4325 | __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); | 4518 | __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); |
4326 | wl12xx_free_link(wl, wlvif, &hlid); | 4519 | wl12xx_free_link(wl, wlvif, &hlid); |
@@ -4380,6 +4573,45 @@ static int wl12xx_sta_remove(struct wl1271 *wl, | |||
4380 | return ret; | 4573 | return ret; |
4381 | } | 4574 | } |
4382 | 4575 | ||
4576 | static void wlcore_roc_if_possible(struct wl1271 *wl, | ||
4577 | struct wl12xx_vif *wlvif) | ||
4578 | { | ||
4579 | if (find_first_bit(wl->roc_map, | ||
4580 | WL12XX_MAX_ROLES) < WL12XX_MAX_ROLES) | ||
4581 | return; | ||
4582 | |||
4583 | if (WARN_ON(wlvif->role_id == WL12XX_INVALID_ROLE_ID)) | ||
4584 | return; | ||
4585 | |||
4586 | wl12xx_roc(wl, wlvif, wlvif->role_id, wlvif->band, wlvif->channel); | ||
4587 | } | ||
4588 | |||
4589 | static void wlcore_update_inconn_sta(struct wl1271 *wl, | ||
4590 | struct wl12xx_vif *wlvif, | ||
4591 | struct wl1271_station *wl_sta, | ||
4592 | bool in_connection) | ||
4593 | { | ||
4594 | if (in_connection) { | ||
4595 | if (WARN_ON(wl_sta->in_connection)) | ||
4596 | return; | ||
4597 | wl_sta->in_connection = true; | ||
4598 | if (!wlvif->inconn_count++) | ||
4599 | wlcore_roc_if_possible(wl, wlvif); | ||
4600 | } else { | ||
4601 | if (!wl_sta->in_connection) | ||
4602 | return; | ||
4603 | |||
4604 | wl_sta->in_connection = false; | ||
4605 | wlvif->inconn_count--; | ||
4606 | if (WARN_ON(wlvif->inconn_count < 0)) | ||
4607 | return; | ||
4608 | |||
4609 | if (!wlvif->inconn_count) | ||
4610 | if (test_bit(wlvif->role_id, wl->roc_map)) | ||
4611 | wl12xx_croc(wl, wlvif->role_id); | ||
4612 | } | ||
4613 | } | ||
4614 | |||
4383 | static int wl12xx_update_sta_state(struct wl1271 *wl, | 4615 | static int wl12xx_update_sta_state(struct wl1271 *wl, |
4384 | struct wl12xx_vif *wlvif, | 4616 | struct wl12xx_vif *wlvif, |
4385 | struct ieee80211_sta *sta, | 4617 | struct ieee80211_sta *sta, |
@@ -4398,8 +4630,13 @@ static int wl12xx_update_sta_state(struct wl1271 *wl, | |||
4398 | /* Add station (AP mode) */ | 4630 | /* Add station (AP mode) */ |
4399 | if (is_ap && | 4631 | if (is_ap && |
4400 | old_state == IEEE80211_STA_NOTEXIST && | 4632 | old_state == IEEE80211_STA_NOTEXIST && |
4401 | new_state == IEEE80211_STA_NONE) | 4633 | new_state == IEEE80211_STA_NONE) { |
4402 | return wl12xx_sta_add(wl, wlvif, sta); | 4634 | ret = wl12xx_sta_add(wl, wlvif, sta); |
4635 | if (ret) | ||
4636 | return ret; | ||
4637 | |||
4638 | wlcore_update_inconn_sta(wl, wlvif, wl_sta, true); | ||
4639 | } | ||
4403 | 4640 | ||
4404 | /* Remove station (AP mode) */ | 4641 | /* Remove station (AP mode) */ |
4405 | if (is_ap && | 4642 | if (is_ap && |
@@ -4407,35 +4644,59 @@ static int wl12xx_update_sta_state(struct wl1271 *wl, | |||
4407 | new_state == IEEE80211_STA_NOTEXIST) { | 4644 | new_state == IEEE80211_STA_NOTEXIST) { |
4408 | /* must not fail */ | 4645 | /* must not fail */ |
4409 | wl12xx_sta_remove(wl, wlvif, sta); | 4646 | wl12xx_sta_remove(wl, wlvif, sta); |
4410 | return 0; | 4647 | |
4648 | wlcore_update_inconn_sta(wl, wlvif, wl_sta, false); | ||
4411 | } | 4649 | } |
4412 | 4650 | ||
4413 | /* Authorize station (AP mode) */ | 4651 | /* Authorize station (AP mode) */ |
4414 | if (is_ap && | 4652 | if (is_ap && |
4415 | new_state == IEEE80211_STA_AUTHORIZED) { | 4653 | new_state == IEEE80211_STA_AUTHORIZED) { |
4416 | ret = wl12xx_cmd_set_peer_state(wl, hlid); | 4654 | ret = wl12xx_cmd_set_peer_state(wl, wlvif, hlid); |
4417 | if (ret < 0) | 4655 | if (ret < 0) |
4418 | return ret; | 4656 | return ret; |
4419 | 4657 | ||
4420 | ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, | 4658 | ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, |
4421 | hlid); | 4659 | hlid); |
4422 | return ret; | 4660 | if (ret) |
4661 | return ret; | ||
4662 | |||
4663 | wlcore_update_inconn_sta(wl, wlvif, wl_sta, false); | ||
4423 | } | 4664 | } |
4424 | 4665 | ||
4425 | /* Authorize station */ | 4666 | /* Authorize station */ |
4426 | if (is_sta && | 4667 | if (is_sta && |
4427 | new_state == IEEE80211_STA_AUTHORIZED) { | 4668 | new_state == IEEE80211_STA_AUTHORIZED) { |
4428 | set_bit(WLVIF_FLAG_STA_AUTHORIZED, &wlvif->flags); | 4669 | set_bit(WLVIF_FLAG_STA_AUTHORIZED, &wlvif->flags); |
4429 | return wl12xx_set_authorized(wl, wlvif); | 4670 | ret = wl12xx_set_authorized(wl, wlvif); |
4671 | if (ret) | ||
4672 | return ret; | ||
4430 | } | 4673 | } |
4431 | 4674 | ||
4432 | if (is_sta && | 4675 | if (is_sta && |
4433 | old_state == IEEE80211_STA_AUTHORIZED && | 4676 | old_state == IEEE80211_STA_AUTHORIZED && |
4434 | new_state == IEEE80211_STA_ASSOC) { | 4677 | new_state == IEEE80211_STA_ASSOC) { |
4435 | clear_bit(WLVIF_FLAG_STA_AUTHORIZED, &wlvif->flags); | 4678 | clear_bit(WLVIF_FLAG_STA_AUTHORIZED, &wlvif->flags); |
4436 | return 0; | 4679 | clear_bit(WLVIF_FLAG_STA_STATE_SENT, &wlvif->flags); |
4437 | } | 4680 | } |
4438 | 4681 | ||
4682 | /* clear ROCs on failure or authorization */ | ||
4683 | if (is_sta && | ||
4684 | (new_state == IEEE80211_STA_AUTHORIZED || | ||
4685 | new_state == IEEE80211_STA_NOTEXIST)) { | ||
4686 | if (test_bit(wlvif->role_id, wl->roc_map)) | ||
4687 | wl12xx_croc(wl, wlvif->role_id); | ||
4688 | } | ||
4689 | |||
4690 | if (is_sta && | ||
4691 | old_state == IEEE80211_STA_NOTEXIST && | ||
4692 | new_state == IEEE80211_STA_NONE) { | ||
4693 | if (find_first_bit(wl->roc_map, | ||
4694 | WL12XX_MAX_ROLES) >= WL12XX_MAX_ROLES) { | ||
4695 | WARN_ON(wlvif->role_id == WL12XX_INVALID_ROLE_ID); | ||
4696 | wl12xx_roc(wl, wlvif, wlvif->role_id, | ||
4697 | wlvif->band, wlvif->channel); | ||
4698 | } | ||
4699 | } | ||
4439 | return 0; | 4700 | return 0; |
4440 | } | 4701 | } |
4441 | 4702 | ||
@@ -4500,18 +4761,18 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw, | |||
4500 | 4761 | ||
4501 | if (wlvif->bss_type == BSS_TYPE_STA_BSS) { | 4762 | if (wlvif->bss_type == BSS_TYPE_STA_BSS) { |
4502 | hlid = wlvif->sta.hlid; | 4763 | hlid = wlvif->sta.hlid; |
4503 | ba_bitmap = &wlvif->sta.ba_rx_bitmap; | ||
4504 | } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) { | 4764 | } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) { |
4505 | struct wl1271_station *wl_sta; | 4765 | struct wl1271_station *wl_sta; |
4506 | 4766 | ||
4507 | wl_sta = (struct wl1271_station *)sta->drv_priv; | 4767 | wl_sta = (struct wl1271_station *)sta->drv_priv; |
4508 | hlid = wl_sta->hlid; | 4768 | hlid = wl_sta->hlid; |
4509 | ba_bitmap = &wl->links[hlid].ba_bitmap; | ||
4510 | } else { | 4769 | } else { |
4511 | ret = -EINVAL; | 4770 | ret = -EINVAL; |
4512 | goto out; | 4771 | goto out; |
4513 | } | 4772 | } |
4514 | 4773 | ||
4774 | ba_bitmap = &wl->links[hlid].ba_bitmap; | ||
4775 | |||
4515 | ret = wl1271_ps_elp_wakeup(wl); | 4776 | ret = wl1271_ps_elp_wakeup(wl); |
4516 | if (ret < 0) | 4777 | if (ret < 0) |
4517 | goto out; | 4778 | goto out; |
@@ -4665,12 +4926,23 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw, | |||
4665 | 4926 | ||
4666 | /* TODO: change mac80211 to pass vif as param */ | 4927 | /* TODO: change mac80211 to pass vif as param */ |
4667 | wl12xx_for_each_wlvif_sta(wl, wlvif) { | 4928 | wl12xx_for_each_wlvif_sta(wl, wlvif) { |
4668 | ret = wl12xx_cmd_channel_switch(wl, wlvif, ch_switch); | 4929 | unsigned long delay_usec; |
4930 | |||
4931 | ret = wl->ops->channel_switch(wl, wlvif, ch_switch); | ||
4932 | if (ret) | ||
4933 | goto out_sleep; | ||
4934 | |||
4935 | set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags); | ||
4669 | 4936 | ||
4670 | if (!ret) | 4937 | /* indicate failure 5 seconds after channel switch time */ |
4671 | set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags); | 4938 | delay_usec = ieee80211_tu_to_usec(wlvif->beacon_int) * |
4939 | ch_switch->count; | ||
4940 | ieee80211_queue_delayed_work(hw, &wlvif->channel_switch_work, | ||
4941 | usecs_to_jiffies(delay_usec) + | ||
4942 | msecs_to_jiffies(5000)); | ||
4672 | } | 4943 | } |
4673 | 4944 | ||
4945 | out_sleep: | ||
4674 | wl1271_ps_elp_sleep(wl); | 4946 | wl1271_ps_elp_sleep(wl); |
4675 | 4947 | ||
4676 | out: | 4948 | out: |
@@ -4684,6 +4956,144 @@ static void wlcore_op_flush(struct ieee80211_hw *hw, bool drop) | |||
4684 | wl1271_tx_flush(wl); | 4956 | wl1271_tx_flush(wl); |
4685 | } | 4957 | } |
4686 | 4958 | ||
4959 | static int wlcore_op_remain_on_channel(struct ieee80211_hw *hw, | ||
4960 | struct ieee80211_vif *vif, | ||
4961 | struct ieee80211_channel *chan, | ||
4962 | int duration) | ||
4963 | { | ||
4964 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | ||
4965 | struct wl1271 *wl = hw->priv; | ||
4966 | int channel, ret = 0; | ||
4967 | |||
4968 | channel = ieee80211_frequency_to_channel(chan->center_freq); | ||
4969 | |||
4970 | wl1271_debug(DEBUG_MAC80211, "mac80211 roc %d (%d)", | ||
4971 | channel, wlvif->role_id); | ||
4972 | |||
4973 | mutex_lock(&wl->mutex); | ||
4974 | |||
4975 | if (unlikely(wl->state != WLCORE_STATE_ON)) | ||
4976 | goto out; | ||
4977 | |||
4978 | /* return EBUSY if we can't ROC right now */ | ||
4979 | if (WARN_ON(wl->roc_vif || | ||
4980 | find_first_bit(wl->roc_map, | ||
4981 | WL12XX_MAX_ROLES) < WL12XX_MAX_ROLES)) { | ||
4982 | ret = -EBUSY; | ||
4983 | goto out; | ||
4984 | } | ||
4985 | |||
4986 | ret = wl1271_ps_elp_wakeup(wl); | ||
4987 | if (ret < 0) | ||
4988 | goto out; | ||
4989 | |||
4990 | ret = wl12xx_start_dev(wl, wlvif, chan->band, channel); | ||
4991 | if (ret < 0) | ||
4992 | goto out_sleep; | ||
4993 | |||
4994 | wl->roc_vif = vif; | ||
4995 | ieee80211_queue_delayed_work(hw, &wl->roc_complete_work, | ||
4996 | msecs_to_jiffies(duration)); | ||
4997 | out_sleep: | ||
4998 | wl1271_ps_elp_sleep(wl); | ||
4999 | out: | ||
5000 | mutex_unlock(&wl->mutex); | ||
5001 | return ret; | ||
5002 | } | ||
5003 | |||
5004 | static int __wlcore_roc_completed(struct wl1271 *wl) | ||
5005 | { | ||
5006 | struct wl12xx_vif *wlvif; | ||
5007 | int ret; | ||
5008 | |||
5009 | /* already completed */ | ||
5010 | if (unlikely(!wl->roc_vif)) | ||
5011 | return 0; | ||
5012 | |||
5013 | wlvif = wl12xx_vif_to_data(wl->roc_vif); | ||
5014 | |||
5015 | if (!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) | ||
5016 | return -EBUSY; | ||
5017 | |||
5018 | ret = wl12xx_stop_dev(wl, wlvif); | ||
5019 | if (ret < 0) | ||
5020 | return ret; | ||
5021 | |||
5022 | wl->roc_vif = NULL; | ||
5023 | |||
5024 | return 0; | ||
5025 | } | ||
5026 | |||
5027 | static int wlcore_roc_completed(struct wl1271 *wl) | ||
5028 | { | ||
5029 | int ret; | ||
5030 | |||
5031 | wl1271_debug(DEBUG_MAC80211, "roc complete"); | ||
5032 | |||
5033 | mutex_lock(&wl->mutex); | ||
5034 | |||
5035 | if (unlikely(wl->state != WLCORE_STATE_ON)) { | ||
5036 | ret = -EBUSY; | ||
5037 | goto out; | ||
5038 | } | ||
5039 | |||
5040 | ret = wl1271_ps_elp_wakeup(wl); | ||
5041 | if (ret < 0) | ||
5042 | goto out; | ||
5043 | |||
5044 | ret = __wlcore_roc_completed(wl); | ||
5045 | |||
5046 | wl1271_ps_elp_sleep(wl); | ||
5047 | out: | ||
5048 | mutex_unlock(&wl->mutex); | ||
5049 | |||
5050 | return ret; | ||
5051 | } | ||
5052 | |||
5053 | static void wlcore_roc_complete_work(struct work_struct *work) | ||
5054 | { | ||
5055 | struct delayed_work *dwork; | ||
5056 | struct wl1271 *wl; | ||
5057 | int ret; | ||
5058 | |||
5059 | dwork = container_of(work, struct delayed_work, work); | ||
5060 | wl = container_of(dwork, struct wl1271, roc_complete_work); | ||
5061 | |||
5062 | ret = wlcore_roc_completed(wl); | ||
5063 | if (!ret) | ||
5064 | ieee80211_remain_on_channel_expired(wl->hw); | ||
5065 | } | ||
5066 | |||
5067 | static int wlcore_op_cancel_remain_on_channel(struct ieee80211_hw *hw) | ||
5068 | { | ||
5069 | struct wl1271 *wl = hw->priv; | ||
5070 | |||
5071 | wl1271_debug(DEBUG_MAC80211, "mac80211 croc"); | ||
5072 | |||
5073 | /* TODO: per-vif */ | ||
5074 | wl1271_tx_flush(wl); | ||
5075 | |||
5076 | /* | ||
5077 | * we can't just flush_work here, because it might deadlock | ||
5078 | * (as we might get called from the same workqueue) | ||
5079 | */ | ||
5080 | cancel_delayed_work_sync(&wl->roc_complete_work); | ||
5081 | wlcore_roc_completed(wl); | ||
5082 | |||
5083 | return 0; | ||
5084 | } | ||
5085 | |||
5086 | static void wlcore_op_sta_rc_update(struct ieee80211_hw *hw, | ||
5087 | struct ieee80211_vif *vif, | ||
5088 | struct ieee80211_sta *sta, | ||
5089 | u32 changed) | ||
5090 | { | ||
5091 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | ||
5092 | struct wl1271 *wl = hw->priv; | ||
5093 | |||
5094 | wlcore_hw_sta_rc_update(wl, wlvif, sta, changed); | ||
5095 | } | ||
5096 | |||
4687 | static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw) | 5097 | static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw) |
4688 | { | 5098 | { |
4689 | struct wl1271 *wl = hw->priv; | 5099 | struct wl1271 *wl = hw->priv; |
@@ -4747,20 +5157,20 @@ static struct ieee80211_rate wl1271_rates[] = { | |||
4747 | 5157 | ||
4748 | /* can't be const, mac80211 writes to this */ | 5158 | /* can't be const, mac80211 writes to this */ |
4749 | static struct ieee80211_channel wl1271_channels[] = { | 5159 | static struct ieee80211_channel wl1271_channels[] = { |
4750 | { .hw_value = 1, .center_freq = 2412, .max_power = 25 }, | 5160 | { .hw_value = 1, .center_freq = 2412, .max_power = WLCORE_MAX_TXPWR }, |
4751 | { .hw_value = 2, .center_freq = 2417, .max_power = 25 }, | 5161 | { .hw_value = 2, .center_freq = 2417, .max_power = WLCORE_MAX_TXPWR }, |
4752 | { .hw_value = 3, .center_freq = 2422, .max_power = 25 }, | 5162 | { .hw_value = 3, .center_freq = 2422, .max_power = WLCORE_MAX_TXPWR }, |
4753 | { .hw_value = 4, .center_freq = 2427, .max_power = 25 }, | 5163 | { .hw_value = 4, .center_freq = 2427, .max_power = WLCORE_MAX_TXPWR }, |
4754 | { .hw_value = 5, .center_freq = 2432, .max_power = 25 }, | 5164 | { .hw_value = 5, .center_freq = 2432, .max_power = WLCORE_MAX_TXPWR }, |
4755 | { .hw_value = 6, .center_freq = 2437, .max_power = 25 }, | 5165 | { .hw_value = 6, .center_freq = 2437, .max_power = WLCORE_MAX_TXPWR }, |
4756 | { .hw_value = 7, .center_freq = 2442, .max_power = 25 }, | 5166 | { .hw_value = 7, .center_freq = 2442, .max_power = WLCORE_MAX_TXPWR }, |
4757 | { .hw_value = 8, .center_freq = 2447, .max_power = 25 }, | 5167 | { .hw_value = 8, .center_freq = 2447, .max_power = WLCORE_MAX_TXPWR }, |
4758 | { .hw_value = 9, .center_freq = 2452, .max_power = 25 }, | 5168 | { .hw_value = 9, .center_freq = 2452, .max_power = WLCORE_MAX_TXPWR }, |
4759 | { .hw_value = 10, .center_freq = 2457, .max_power = 25 }, | 5169 | { .hw_value = 10, .center_freq = 2457, .max_power = WLCORE_MAX_TXPWR }, |
4760 | { .hw_value = 11, .center_freq = 2462, .max_power = 25 }, | 5170 | { .hw_value = 11, .center_freq = 2462, .max_power = WLCORE_MAX_TXPWR }, |
4761 | { .hw_value = 12, .center_freq = 2467, .max_power = 25 }, | 5171 | { .hw_value = 12, .center_freq = 2467, .max_power = WLCORE_MAX_TXPWR }, |
4762 | { .hw_value = 13, .center_freq = 2472, .max_power = 25 }, | 5172 | { .hw_value = 13, .center_freq = 2472, .max_power = WLCORE_MAX_TXPWR }, |
4763 | { .hw_value = 14, .center_freq = 2484, .max_power = 25 }, | 5173 | { .hw_value = 14, .center_freq = 2484, .max_power = WLCORE_MAX_TXPWR }, |
4764 | }; | 5174 | }; |
4765 | 5175 | ||
4766 | /* can't be const, mac80211 writes to this */ | 5176 | /* can't be const, mac80211 writes to this */ |
@@ -4801,40 +5211,40 @@ static struct ieee80211_rate wl1271_rates_5ghz[] = { | |||
4801 | 5211 | ||
4802 | /* 5 GHz band channels for WL1273 */ | 5212 | /* 5 GHz band channels for WL1273 */ |
4803 | static struct ieee80211_channel wl1271_channels_5ghz[] = { | 5213 | static struct ieee80211_channel wl1271_channels_5ghz[] = { |
4804 | { .hw_value = 7, .center_freq = 5035, .max_power = 25 }, | 5214 | { .hw_value = 7, .center_freq = 5035, .max_power = WLCORE_MAX_TXPWR }, |
4805 | { .hw_value = 8, .center_freq = 5040, .max_power = 25 }, | 5215 | { .hw_value = 8, .center_freq = 5040, .max_power = WLCORE_MAX_TXPWR }, |
4806 | { .hw_value = 9, .center_freq = 5045, .max_power = 25 }, | 5216 | { .hw_value = 9, .center_freq = 5045, .max_power = WLCORE_MAX_TXPWR }, |
4807 | { .hw_value = 11, .center_freq = 5055, .max_power = 25 }, | 5217 | { .hw_value = 11, .center_freq = 5055, .max_power = WLCORE_MAX_TXPWR }, |
4808 | { .hw_value = 12, .center_freq = 5060, .max_power = 25 }, | 5218 | { .hw_value = 12, .center_freq = 5060, .max_power = WLCORE_MAX_TXPWR }, |
4809 | { .hw_value = 16, .center_freq = 5080, .max_power = 25 }, | 5219 | { .hw_value = 16, .center_freq = 5080, .max_power = WLCORE_MAX_TXPWR }, |
4810 | { .hw_value = 34, .center_freq = 5170, .max_power = 25 }, | 5220 | { .hw_value = 34, .center_freq = 5170, .max_power = WLCORE_MAX_TXPWR }, |
4811 | { .hw_value = 36, .center_freq = 5180, .max_power = 25 }, | 5221 | { .hw_value = 36, .center_freq = 5180, .max_power = WLCORE_MAX_TXPWR }, |
4812 | { .hw_value = 38, .center_freq = 5190, .max_power = 25 }, | 5222 | { .hw_value = 38, .center_freq = 5190, .max_power = WLCORE_MAX_TXPWR }, |
4813 | { .hw_value = 40, .center_freq = 5200, .max_power = 25 }, | 5223 | { .hw_value = 40, .center_freq = 5200, .max_power = WLCORE_MAX_TXPWR }, |
4814 | { .hw_value = 42, .center_freq = 5210, .max_power = 25 }, | 5224 | { .hw_value = 42, .center_freq = 5210, .max_power = WLCORE_MAX_TXPWR }, |
4815 | { .hw_value = 44, .center_freq = 5220, .max_power = 25 }, | 5225 | { .hw_value = 44, .center_freq = 5220, .max_power = WLCORE_MAX_TXPWR }, |
4816 | { .hw_value = 46, .center_freq = 5230, .max_power = 25 }, | 5226 | { .hw_value = 46, .center_freq = 5230, .max_power = WLCORE_MAX_TXPWR }, |
4817 | { .hw_value = 48, .center_freq = 5240, .max_power = 25 }, | 5227 | { .hw_value = 48, .center_freq = 5240, .max_power = WLCORE_MAX_TXPWR }, |
4818 | { .hw_value = 52, .center_freq = 5260, .max_power = 25 }, | 5228 | { .hw_value = 52, .center_freq = 5260, .max_power = WLCORE_MAX_TXPWR }, |
4819 | { .hw_value = 56, .center_freq = 5280, .max_power = 25 }, | 5229 | { .hw_value = 56, .center_freq = 5280, .max_power = WLCORE_MAX_TXPWR }, |
4820 | { .hw_value = 60, .center_freq = 5300, .max_power = 25 }, | 5230 | { .hw_value = 60, .center_freq = 5300, .max_power = WLCORE_MAX_TXPWR }, |
4821 | { .hw_value = 64, .center_freq = 5320, .max_power = 25 }, | 5231 | { .hw_value = 64, .center_freq = 5320, .max_power = WLCORE_MAX_TXPWR }, |
4822 | { .hw_value = 100, .center_freq = 5500, .max_power = 25 }, | 5232 | { .hw_value = 100, .center_freq = 5500, .max_power = WLCORE_MAX_TXPWR }, |
4823 | { .hw_value = 104, .center_freq = 5520, .max_power = 25 }, | 5233 | { .hw_value = 104, .center_freq = 5520, .max_power = WLCORE_MAX_TXPWR }, |
4824 | { .hw_value = 108, .center_freq = 5540, .max_power = 25 }, | 5234 | { .hw_value = 108, .center_freq = 5540, .max_power = WLCORE_MAX_TXPWR }, |
4825 | { .hw_value = 112, .center_freq = 5560, .max_power = 25 }, | 5235 | { .hw_value = 112, .center_freq = 5560, .max_power = WLCORE_MAX_TXPWR }, |
4826 | { .hw_value = 116, .center_freq = 5580, .max_power = 25 }, | 5236 | { .hw_value = 116, .center_freq = 5580, .max_power = WLCORE_MAX_TXPWR }, |
4827 | { .hw_value = 120, .center_freq = 5600, .max_power = 25 }, | 5237 | { .hw_value = 120, .center_freq = 5600, .max_power = WLCORE_MAX_TXPWR }, |
4828 | { .hw_value = 124, .center_freq = 5620, .max_power = 25 }, | 5238 | { .hw_value = 124, .center_freq = 5620, .max_power = WLCORE_MAX_TXPWR }, |
4829 | { .hw_value = 128, .center_freq = 5640, .max_power = 25 }, | 5239 | { .hw_value = 128, .center_freq = 5640, .max_power = WLCORE_MAX_TXPWR }, |
4830 | { .hw_value = 132, .center_freq = 5660, .max_power = 25 }, | 5240 | { .hw_value = 132, .center_freq = 5660, .max_power = WLCORE_MAX_TXPWR }, |
4831 | { .hw_value = 136, .center_freq = 5680, .max_power = 25 }, | 5241 | { .hw_value = 136, .center_freq = 5680, .max_power = WLCORE_MAX_TXPWR }, |
4832 | { .hw_value = 140, .center_freq = 5700, .max_power = 25 }, | 5242 | { .hw_value = 140, .center_freq = 5700, .max_power = WLCORE_MAX_TXPWR }, |
4833 | { .hw_value = 149, .center_freq = 5745, .max_power = 25 }, | 5243 | { .hw_value = 149, .center_freq = 5745, .max_power = WLCORE_MAX_TXPWR }, |
4834 | { .hw_value = 153, .center_freq = 5765, .max_power = 25 }, | 5244 | { .hw_value = 153, .center_freq = 5765, .max_power = WLCORE_MAX_TXPWR }, |
4835 | { .hw_value = 157, .center_freq = 5785, .max_power = 25 }, | 5245 | { .hw_value = 157, .center_freq = 5785, .max_power = WLCORE_MAX_TXPWR }, |
4836 | { .hw_value = 161, .center_freq = 5805, .max_power = 25 }, | 5246 | { .hw_value = 161, .center_freq = 5805, .max_power = WLCORE_MAX_TXPWR }, |
4837 | { .hw_value = 165, .center_freq = 5825, .max_power = 25 }, | 5247 | { .hw_value = 165, .center_freq = 5825, .max_power = WLCORE_MAX_TXPWR }, |
4838 | }; | 5248 | }; |
4839 | 5249 | ||
4840 | static struct ieee80211_supported_band wl1271_band_5ghz = { | 5250 | static struct ieee80211_supported_band wl1271_band_5ghz = { |
@@ -4875,6 +5285,14 @@ static const struct ieee80211_ops wl1271_ops = { | |||
4875 | .set_bitrate_mask = wl12xx_set_bitrate_mask, | 5285 | .set_bitrate_mask = wl12xx_set_bitrate_mask, |
4876 | .channel_switch = wl12xx_op_channel_switch, | 5286 | .channel_switch = wl12xx_op_channel_switch, |
4877 | .flush = wlcore_op_flush, | 5287 | .flush = wlcore_op_flush, |
5288 | .remain_on_channel = wlcore_op_remain_on_channel, | ||
5289 | .cancel_remain_on_channel = wlcore_op_cancel_remain_on_channel, | ||
5290 | .add_chanctx = wlcore_op_add_chanctx, | ||
5291 | .remove_chanctx = wlcore_op_remove_chanctx, | ||
5292 | .change_chanctx = wlcore_op_change_chanctx, | ||
5293 | .assign_vif_chanctx = wlcore_op_assign_vif_chanctx, | ||
5294 | .unassign_vif_chanctx = wlcore_op_unassign_vif_chanctx, | ||
5295 | .sta_rc_update = wlcore_op_sta_rc_update, | ||
4878 | CFG80211_TESTMODE_CMD(wl1271_tm_cmd) | 5296 | CFG80211_TESTMODE_CMD(wl1271_tm_cmd) |
4879 | }; | 5297 | }; |
4880 | 5298 | ||
@@ -5044,34 +5462,6 @@ static struct bin_attribute fwlog_attr = { | |||
5044 | .read = wl1271_sysfs_read_fwlog, | 5462 | .read = wl1271_sysfs_read_fwlog, |
5045 | }; | 5463 | }; |
5046 | 5464 | ||
5047 | static void wl1271_connection_loss_work(struct work_struct *work) | ||
5048 | { | ||
5049 | struct delayed_work *dwork; | ||
5050 | struct wl1271 *wl; | ||
5051 | struct ieee80211_vif *vif; | ||
5052 | struct wl12xx_vif *wlvif; | ||
5053 | |||
5054 | dwork = container_of(work, struct delayed_work, work); | ||
5055 | wl = container_of(dwork, struct wl1271, connection_loss_work); | ||
5056 | |||
5057 | wl1271_info("Connection loss work."); | ||
5058 | |||
5059 | mutex_lock(&wl->mutex); | ||
5060 | |||
5061 | if (unlikely(wl->state != WLCORE_STATE_ON)) | ||
5062 | goto out; | ||
5063 | |||
5064 | /* Call mac80211 connection loss */ | ||
5065 | wl12xx_for_each_wlvif_sta(wl, wlvif) { | ||
5066 | if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) | ||
5067 | goto out; | ||
5068 | vif = wl12xx_wlvif_to_vif(wlvif); | ||
5069 | ieee80211_connection_loss(vif); | ||
5070 | } | ||
5071 | out: | ||
5072 | mutex_unlock(&wl->mutex); | ||
5073 | } | ||
5074 | |||
5075 | static void wl12xx_derive_mac_addresses(struct wl1271 *wl, u32 oui, u32 nic) | 5465 | static void wl12xx_derive_mac_addresses(struct wl1271 *wl, u32 oui, u32 nic) |
5076 | { | 5466 | { |
5077 | int i; | 5467 | int i; |
@@ -5117,7 +5507,7 @@ static int wl12xx_get_hw_info(struct wl1271 *wl) | |||
5117 | 5507 | ||
5118 | ret = wl12xx_set_power_on(wl); | 5508 | ret = wl12xx_set_power_on(wl); |
5119 | if (ret < 0) | 5509 | if (ret < 0) |
5120 | goto out; | 5510 | return ret; |
5121 | 5511 | ||
5122 | ret = wlcore_read_reg(wl, REG_CHIP_ID_B, &wl->chip.id); | 5512 | ret = wlcore_read_reg(wl, REG_CHIP_ID_B, &wl->chip.id); |
5123 | if (ret < 0) | 5513 | if (ret < 0) |
@@ -5207,10 +5597,9 @@ static const struct ieee80211_iface_limit wlcore_iface_limits[] = { | |||
5207 | }, | 5597 | }, |
5208 | }; | 5598 | }; |
5209 | 5599 | ||
5210 | static const struct ieee80211_iface_combination | 5600 | static struct ieee80211_iface_combination |
5211 | wlcore_iface_combinations[] = { | 5601 | wlcore_iface_combinations[] = { |
5212 | { | 5602 | { |
5213 | .num_different_channels = 1, | ||
5214 | .max_interfaces = 3, | 5603 | .max_interfaces = 3, |
5215 | .limits = wlcore_iface_limits, | 5604 | .limits = wlcore_iface_limits, |
5216 | .n_limits = ARRAY_SIZE(wlcore_iface_limits), | 5605 | .n_limits = ARRAY_SIZE(wlcore_iface_limits), |
@@ -5219,6 +5608,7 @@ wlcore_iface_combinations[] = { | |||
5219 | 5608 | ||
5220 | static int wl1271_init_ieee80211(struct wl1271 *wl) | 5609 | static int wl1271_init_ieee80211(struct wl1271 *wl) |
5221 | { | 5610 | { |
5611 | int i; | ||
5222 | static const u32 cipher_suites[] = { | 5612 | static const u32 cipher_suites[] = { |
5223 | WLAN_CIPHER_SUITE_WEP40, | 5613 | WLAN_CIPHER_SUITE_WEP40, |
5224 | WLAN_CIPHER_SUITE_WEP104, | 5614 | WLAN_CIPHER_SUITE_WEP104, |
@@ -5249,7 +5639,8 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) | |||
5249 | IEEE80211_HW_AP_LINK_PS | | 5639 | IEEE80211_HW_AP_LINK_PS | |
5250 | IEEE80211_HW_AMPDU_AGGREGATION | | 5640 | IEEE80211_HW_AMPDU_AGGREGATION | |
5251 | IEEE80211_HW_TX_AMPDU_SETUP_IN_HW | | 5641 | IEEE80211_HW_TX_AMPDU_SETUP_IN_HW | |
5252 | IEEE80211_HW_SCAN_WHILE_IDLE; | 5642 | IEEE80211_HW_SCAN_WHILE_IDLE | |
5643 | IEEE80211_HW_QUEUE_CONTROL; | ||
5253 | 5644 | ||
5254 | wl->hw->wiphy->cipher_suites = cipher_suites; | 5645 | wl->hw->wiphy->cipher_suites = cipher_suites; |
5255 | wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); | 5646 | wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); |
@@ -5271,6 +5662,8 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) | |||
5271 | wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE - | 5662 | wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE - |
5272 | sizeof(struct ieee80211_header); | 5663 | sizeof(struct ieee80211_header); |
5273 | 5664 | ||
5665 | wl->hw->wiphy->max_remain_on_channel_duration = 5000; | ||
5666 | |||
5274 | wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD | | 5667 | wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD | |
5275 | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; | 5668 | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; |
5276 | 5669 | ||
@@ -5279,6 +5672,22 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) | |||
5279 | ARRAY_SIZE(wl1271_channels_5ghz) > | 5672 | ARRAY_SIZE(wl1271_channels_5ghz) > |
5280 | WL1271_MAX_CHANNELS); | 5673 | WL1271_MAX_CHANNELS); |
5281 | /* | 5674 | /* |
5675 | * clear channel flags from the previous usage | ||
5676 | * and restore max_power & max_antenna_gain values. | ||
5677 | */ | ||
5678 | for (i = 0; i < ARRAY_SIZE(wl1271_channels); i++) { | ||
5679 | wl1271_band_2ghz.channels[i].flags = 0; | ||
5680 | wl1271_band_2ghz.channels[i].max_power = WLCORE_MAX_TXPWR; | ||
5681 | wl1271_band_2ghz.channels[i].max_antenna_gain = 0; | ||
5682 | } | ||
5683 | |||
5684 | for (i = 0; i < ARRAY_SIZE(wl1271_channels_5ghz); i++) { | ||
5685 | wl1271_band_5ghz.channels[i].flags = 0; | ||
5686 | wl1271_band_5ghz.channels[i].max_power = WLCORE_MAX_TXPWR; | ||
5687 | wl1271_band_5ghz.channels[i].max_antenna_gain = 0; | ||
5688 | } | ||
5689 | |||
5690 | /* | ||
5282 | * We keep local copies of the band structs because we need to | 5691 | * We keep local copies of the band structs because we need to |
5283 | * modify them on a per-device basis. | 5692 | * modify them on a per-device basis. |
5284 | */ | 5693 | */ |
@@ -5298,7 +5707,14 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) | |||
5298 | wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = | 5707 | wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = |
5299 | &wl->bands[IEEE80211_BAND_5GHZ]; | 5708 | &wl->bands[IEEE80211_BAND_5GHZ]; |
5300 | 5709 | ||
5301 | wl->hw->queues = 4; | 5710 | /* |
5711 | * allow 4 queues per mac address we support + | ||
5712 | * 1 cab queue per mac + one global offchannel Tx queue | ||
5713 | */ | ||
5714 | wl->hw->queues = (NUM_TX_QUEUES + 1) * WLCORE_NUM_MAC_ADDRESSES + 1; | ||
5715 | |||
5716 | /* the last queue is the offchannel queue */ | ||
5717 | wl->hw->offchannel_tx_hw_queue = wl->hw->queues - 1; | ||
5302 | wl->hw->max_rates = 1; | 5718 | wl->hw->max_rates = 1; |
5303 | 5719 | ||
5304 | wl->hw->wiphy->reg_notifier = wl1271_reg_notify; | 5720 | wl->hw->wiphy->reg_notifier = wl1271_reg_notify; |
@@ -5311,6 +5727,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) | |||
5311 | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P; | 5727 | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P; |
5312 | 5728 | ||
5313 | /* allowed interface combinations */ | 5729 | /* allowed interface combinations */ |
5730 | wlcore_iface_combinations[0].num_different_channels = wl->num_channels; | ||
5314 | wl->hw->wiphy->iface_combinations = wlcore_iface_combinations; | 5731 | wl->hw->wiphy->iface_combinations = wlcore_iface_combinations; |
5315 | wl->hw->wiphy->n_iface_combinations = | 5732 | wl->hw->wiphy->n_iface_combinations = |
5316 | ARRAY_SIZE(wlcore_iface_combinations); | 5733 | ARRAY_SIZE(wlcore_iface_combinations); |
@@ -5327,7 +5744,8 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) | |||
5327 | 5744 | ||
5328 | #define WL1271_DEFAULT_CHANNEL 0 | 5745 | #define WL1271_DEFAULT_CHANNEL 0 |
5329 | 5746 | ||
5330 | struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size) | 5747 | struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size, |
5748 | u32 mbox_size) | ||
5331 | { | 5749 | { |
5332 | struct ieee80211_hw *hw; | 5750 | struct ieee80211_hw *hw; |
5333 | struct wl1271 *wl; | 5751 | struct wl1271 *wl; |
@@ -5369,9 +5787,8 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size) | |||
5369 | INIT_WORK(&wl->tx_work, wl1271_tx_work); | 5787 | INIT_WORK(&wl->tx_work, wl1271_tx_work); |
5370 | INIT_WORK(&wl->recovery_work, wl1271_recovery_work); | 5788 | INIT_WORK(&wl->recovery_work, wl1271_recovery_work); |
5371 | INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work); | 5789 | INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work); |
5790 | INIT_DELAYED_WORK(&wl->roc_complete_work, wlcore_roc_complete_work); | ||
5372 | INIT_DELAYED_WORK(&wl->tx_watchdog_work, wl12xx_tx_watchdog_work); | 5791 | INIT_DELAYED_WORK(&wl->tx_watchdog_work, wl12xx_tx_watchdog_work); |
5373 | INIT_DELAYED_WORK(&wl->connection_loss_work, | ||
5374 | wl1271_connection_loss_work); | ||
5375 | 5792 | ||
5376 | wl->freezable_wq = create_freezable_workqueue("wl12xx_wq"); | 5793 | wl->freezable_wq = create_freezable_workqueue("wl12xx_wq"); |
5377 | if (!wl->freezable_wq) { | 5794 | if (!wl->freezable_wq) { |
@@ -5387,14 +5804,15 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size) | |||
5387 | wl->flags = 0; | 5804 | wl->flags = 0; |
5388 | wl->sg_enabled = true; | 5805 | wl->sg_enabled = true; |
5389 | wl->sleep_auth = WL1271_PSM_ILLEGAL; | 5806 | wl->sleep_auth = WL1271_PSM_ILLEGAL; |
5807 | wl->recovery_count = 0; | ||
5390 | wl->hw_pg_ver = -1; | 5808 | wl->hw_pg_ver = -1; |
5391 | wl->ap_ps_map = 0; | 5809 | wl->ap_ps_map = 0; |
5392 | wl->ap_fw_ps_map = 0; | 5810 | wl->ap_fw_ps_map = 0; |
5393 | wl->quirks = 0; | 5811 | wl->quirks = 0; |
5394 | wl->platform_quirks = 0; | 5812 | wl->platform_quirks = 0; |
5395 | wl->sched_scanning = false; | ||
5396 | wl->system_hlid = WL12XX_SYSTEM_HLID; | 5813 | wl->system_hlid = WL12XX_SYSTEM_HLID; |
5397 | wl->active_sta_count = 0; | 5814 | wl->active_sta_count = 0; |
5815 | wl->active_link_count = 0; | ||
5398 | wl->fwlog_size = 0; | 5816 | wl->fwlog_size = 0; |
5399 | init_waitqueue_head(&wl->fwlog_waitq); | 5817 | init_waitqueue_head(&wl->fwlog_waitq); |
5400 | 5818 | ||
@@ -5434,14 +5852,24 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size) | |||
5434 | goto err_dummy_packet; | 5852 | goto err_dummy_packet; |
5435 | } | 5853 | } |
5436 | 5854 | ||
5437 | wl->mbox = kmalloc(sizeof(*wl->mbox), GFP_KERNEL | GFP_DMA); | 5855 | wl->mbox_size = mbox_size; |
5856 | wl->mbox = kmalloc(wl->mbox_size, GFP_KERNEL | GFP_DMA); | ||
5438 | if (!wl->mbox) { | 5857 | if (!wl->mbox) { |
5439 | ret = -ENOMEM; | 5858 | ret = -ENOMEM; |
5440 | goto err_fwlog; | 5859 | goto err_fwlog; |
5441 | } | 5860 | } |
5442 | 5861 | ||
5862 | wl->buffer_32 = kmalloc(sizeof(*wl->buffer_32), GFP_KERNEL); | ||
5863 | if (!wl->buffer_32) { | ||
5864 | ret = -ENOMEM; | ||
5865 | goto err_mbox; | ||
5866 | } | ||
5867 | |||
5443 | return hw; | 5868 | return hw; |
5444 | 5869 | ||
5870 | err_mbox: | ||
5871 | kfree(wl->mbox); | ||
5872 | |||
5445 | err_fwlog: | 5873 | err_fwlog: |
5446 | free_page((unsigned long)wl->fwlog); | 5874 | free_page((unsigned long)wl->fwlog); |
5447 | 5875 | ||
@@ -5480,6 +5908,8 @@ int wlcore_free_hw(struct wl1271 *wl) | |||
5480 | device_remove_file(wl->dev, &dev_attr_hw_pg_ver); | 5908 | device_remove_file(wl->dev, &dev_attr_hw_pg_ver); |
5481 | 5909 | ||
5482 | device_remove_file(wl->dev, &dev_attr_bt_coex_state); | 5910 | device_remove_file(wl->dev, &dev_attr_bt_coex_state); |
5911 | kfree(wl->buffer_32); | ||
5912 | kfree(wl->mbox); | ||
5483 | free_page((unsigned long)wl->fwlog); | 5913 | free_page((unsigned long)wl->fwlog); |
5484 | dev_kfree_skb(wl->dummy_packet); | 5914 | dev_kfree_skb(wl->dummy_packet); |
5485 | free_pages((unsigned long)wl->aggr_buf, get_order(wl->aggr_buf_size)); | 5915 | free_pages((unsigned long)wl->aggr_buf, get_order(wl->aggr_buf_size)); |
@@ -5712,10 +6142,10 @@ module_param_named(fwlog, fwlog_param, charp, 0); | |||
5712 | MODULE_PARM_DESC(fwlog, | 6142 | MODULE_PARM_DESC(fwlog, |
5713 | "FW logger options: continuous, ondemand, dbgpins or disable"); | 6143 | "FW logger options: continuous, ondemand, dbgpins or disable"); |
5714 | 6144 | ||
5715 | module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR); | 6145 | module_param(bug_on_recovery, int, S_IRUSR | S_IWUSR); |
5716 | MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery"); | 6146 | MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery"); |
5717 | 6147 | ||
5718 | module_param(no_recovery, bool, S_IRUSR | S_IWUSR); | 6148 | module_param(no_recovery, int, S_IRUSR | S_IWUSR); |
5719 | MODULE_PARM_DESC(no_recovery, "Prevent HW recovery. FW will remain stuck."); | 6149 | MODULE_PARM_DESC(no_recovery, "Prevent HW recovery. FW will remain stuck."); |
5720 | 6150 | ||
5721 | MODULE_LICENSE("GPL"); | 6151 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/net/wireless/ti/wlcore/ps.c b/drivers/net/wireless/ti/wlcore/ps.c index 4d1414a673fb..9b7b6e2e4fbc 100644 --- a/drivers/net/wireless/ti/wlcore/ps.c +++ b/drivers/net/wireless/ti/wlcore/ps.c | |||
@@ -151,9 +151,6 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl) | |||
151 | wl12xx_queue_recovery_work(wl); | 151 | wl12xx_queue_recovery_work(wl); |
152 | ret = -ETIMEDOUT; | 152 | ret = -ETIMEDOUT; |
153 | goto err; | 153 | goto err; |
154 | } else if (ret < 0) { | ||
155 | wl1271_error("ELP wakeup completion error."); | ||
156 | goto err; | ||
157 | } | 154 | } |
158 | } | 155 | } |
159 | 156 | ||
@@ -242,11 +239,12 @@ static void wl1271_ps_filter_frames(struct wl1271 *wl, u8 hlid) | |||
242 | struct ieee80211_tx_info *info; | 239 | struct ieee80211_tx_info *info; |
243 | unsigned long flags; | 240 | unsigned long flags; |
244 | int filtered[NUM_TX_QUEUES]; | 241 | int filtered[NUM_TX_QUEUES]; |
242 | struct wl1271_link *lnk = &wl->links[hlid]; | ||
245 | 243 | ||
246 | /* filter all frames currently in the low level queues for this hlid */ | 244 | /* filter all frames currently in the low level queues for this hlid */ |
247 | for (i = 0; i < NUM_TX_QUEUES; i++) { | 245 | for (i = 0; i < NUM_TX_QUEUES; i++) { |
248 | filtered[i] = 0; | 246 | filtered[i] = 0; |
249 | while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) { | 247 | while ((skb = skb_dequeue(&lnk->tx_queue[i]))) { |
250 | filtered[i]++; | 248 | filtered[i]++; |
251 | 249 | ||
252 | if (WARN_ON(wl12xx_is_dummy_packet(wl, skb))) | 250 | if (WARN_ON(wl12xx_is_dummy_packet(wl, skb))) |
@@ -260,8 +258,11 @@ static void wl1271_ps_filter_frames(struct wl1271 *wl, u8 hlid) | |||
260 | } | 258 | } |
261 | 259 | ||
262 | spin_lock_irqsave(&wl->wl_lock, flags); | 260 | spin_lock_irqsave(&wl->wl_lock, flags); |
263 | for (i = 0; i < NUM_TX_QUEUES; i++) | 261 | for (i = 0; i < NUM_TX_QUEUES; i++) { |
264 | wl->tx_queue_count[i] -= filtered[i]; | 262 | wl->tx_queue_count[i] -= filtered[i]; |
263 | if (lnk->wlvif) | ||
264 | lnk->wlvif->tx_queue_count[i] -= filtered[i]; | ||
265 | } | ||
265 | spin_unlock_irqrestore(&wl->wl_lock, flags); | 266 | spin_unlock_irqrestore(&wl->wl_lock, flags); |
266 | 267 | ||
267 | wl1271_handle_tx_low_watermark(wl); | 268 | wl1271_handle_tx_low_watermark(wl); |
diff --git a/drivers/net/wireless/ti/wlcore/rx.c b/drivers/net/wireless/ti/wlcore/rx.c index 9ee0ec6fd1db..6791a1a6afba 100644 --- a/drivers/net/wireless/ti/wlcore/rx.c +++ b/drivers/net/wireless/ti/wlcore/rx.c | |||
@@ -92,11 +92,16 @@ static void wl1271_rx_status(struct wl1271 *wl, | |||
92 | status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED | | 92 | status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED | |
93 | RX_FLAG_DECRYPTED; | 93 | RX_FLAG_DECRYPTED; |
94 | 94 | ||
95 | if (unlikely(desc_err_code == WL1271_RX_DESC_MIC_FAIL)) { | 95 | if (unlikely(desc_err_code & WL1271_RX_DESC_MIC_FAIL)) { |
96 | status->flag |= RX_FLAG_MMIC_ERROR; | 96 | status->flag |= RX_FLAG_MMIC_ERROR; |
97 | wl1271_warning("Michael MIC error"); | 97 | wl1271_warning("Michael MIC error. Desc: 0x%x", |
98 | desc_err_code); | ||
98 | } | 99 | } |
99 | } | 100 | } |
101 | |||
102 | if (beacon) | ||
103 | wlcore_set_pending_regdomain_ch(wl, (u16)desc->channel, | ||
104 | status->band); | ||
100 | } | 105 | } |
101 | 106 | ||
102 | static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, | 107 | static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, |
@@ -108,7 +113,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, | |||
108 | u8 *buf; | 113 | u8 *buf; |
109 | u8 beacon = 0; | 114 | u8 beacon = 0; |
110 | u8 is_data = 0; | 115 | u8 is_data = 0; |
111 | u8 reserved = 0; | 116 | u8 reserved = 0, offset_to_data = 0; |
112 | u16 seq_num; | 117 | u16 seq_num; |
113 | u32 pkt_data_len; | 118 | u32 pkt_data_len; |
114 | 119 | ||
@@ -128,6 +133,8 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, | |||
128 | 133 | ||
129 | if (rx_align == WLCORE_RX_BUF_UNALIGNED) | 134 | if (rx_align == WLCORE_RX_BUF_UNALIGNED) |
130 | reserved = RX_BUF_ALIGN; | 135 | reserved = RX_BUF_ALIGN; |
136 | else if (rx_align == WLCORE_RX_BUF_PADDED) | ||
137 | offset_to_data = RX_BUF_ALIGN; | ||
131 | 138 | ||
132 | /* the data read starts with the descriptor */ | 139 | /* the data read starts with the descriptor */ |
133 | desc = (struct wl1271_rx_descriptor *) data; | 140 | desc = (struct wl1271_rx_descriptor *) data; |
@@ -139,19 +146,15 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, | |||
139 | return 0; | 146 | return 0; |
140 | } | 147 | } |
141 | 148 | ||
142 | switch (desc->status & WL1271_RX_DESC_STATUS_MASK) { | ||
143 | /* discard corrupted packets */ | 149 | /* discard corrupted packets */ |
144 | case WL1271_RX_DESC_DRIVER_RX_Q_FAIL: | 150 | if (desc->status & WL1271_RX_DESC_DECRYPT_FAIL) { |
145 | case WL1271_RX_DESC_DECRYPT_FAIL: | 151 | hdr = (void *)(data + sizeof(*desc) + offset_to_data); |
146 | wl1271_warning("corrupted packet in RX with status: 0x%x", | 152 | wl1271_warning("corrupted packet in RX: status: 0x%x len: %d", |
147 | desc->status & WL1271_RX_DESC_STATUS_MASK); | 153 | desc->status & WL1271_RX_DESC_STATUS_MASK, |
148 | return -EINVAL; | 154 | pkt_data_len); |
149 | case WL1271_RX_DESC_SUCCESS: | 155 | wl1271_dump((DEBUG_RX|DEBUG_CMD), "PKT: ", data + sizeof(*desc), |
150 | case WL1271_RX_DESC_MIC_FAIL: | 156 | min(pkt_data_len, |
151 | break; | 157 | ieee80211_hdrlen(hdr->frame_control))); |
152 | default: | ||
153 | wl1271_error("invalid RX descriptor status: 0x%x", | ||
154 | desc->status & WL1271_RX_DESC_STATUS_MASK); | ||
155 | return -EINVAL; | 158 | return -EINVAL; |
156 | } | 159 | } |
157 | 160 | ||
diff --git a/drivers/net/wireless/ti/wlcore/rx.h b/drivers/net/wireless/ti/wlcore/rx.h index 71eba1899915..3363f60fb7da 100644 --- a/drivers/net/wireless/ti/wlcore/rx.h +++ b/drivers/net/wireless/ti/wlcore/rx.h | |||
@@ -84,12 +84,11 @@ | |||
84 | * Bits 3-5 - process_id tag (AP mode FW) | 84 | * Bits 3-5 - process_id tag (AP mode FW) |
85 | * Bits 6-7 - reserved | 85 | * Bits 6-7 - reserved |
86 | */ | 86 | */ |
87 | #define WL1271_RX_DESC_STATUS_MASK 0x03 | 87 | #define WL1271_RX_DESC_STATUS_MASK 0x07 |
88 | 88 | ||
89 | #define WL1271_RX_DESC_SUCCESS 0x00 | 89 | #define WL1271_RX_DESC_SUCCESS 0x00 |
90 | #define WL1271_RX_DESC_DECRYPT_FAIL 0x01 | 90 | #define WL1271_RX_DESC_DECRYPT_FAIL 0x01 |
91 | #define WL1271_RX_DESC_MIC_FAIL 0x02 | 91 | #define WL1271_RX_DESC_MIC_FAIL 0x02 |
92 | #define WL1271_RX_DESC_DRIVER_RX_Q_FAIL 0x03 | ||
93 | 92 | ||
94 | #define RX_MEM_BLOCK_MASK 0xFF | 93 | #define RX_MEM_BLOCK_MASK 0xFF |
95 | #define RX_BUF_SIZE_MASK 0xFFF00 | 94 | #define RX_BUF_SIZE_MASK 0xFFF00 |
diff --git a/drivers/net/wireless/ti/wlcore/scan.c b/drivers/net/wireless/ti/wlcore/scan.c index d00501493dfe..f407101e525b 100644 --- a/drivers/net/wireless/ti/wlcore/scan.c +++ b/drivers/net/wireless/ti/wlcore/scan.c | |||
@@ -35,7 +35,6 @@ void wl1271_scan_complete_work(struct work_struct *work) | |||
35 | { | 35 | { |
36 | struct delayed_work *dwork; | 36 | struct delayed_work *dwork; |
37 | struct wl1271 *wl; | 37 | struct wl1271 *wl; |
38 | struct ieee80211_vif *vif; | ||
39 | struct wl12xx_vif *wlvif; | 38 | struct wl12xx_vif *wlvif; |
40 | int ret; | 39 | int ret; |
41 | 40 | ||
@@ -52,8 +51,7 @@ void wl1271_scan_complete_work(struct work_struct *work) | |||
52 | if (wl->scan.state == WL1271_SCAN_STATE_IDLE) | 51 | if (wl->scan.state == WL1271_SCAN_STATE_IDLE) |
53 | goto out; | 52 | goto out; |
54 | 53 | ||
55 | vif = wl->scan_vif; | 54 | wlvif = wl->scan_wlvif; |
56 | wlvif = wl12xx_vif_to_data(vif); | ||
57 | 55 | ||
58 | /* | 56 | /* |
59 | * Rearm the tx watchdog just before idling scan. This | 57 | * Rearm the tx watchdog just before idling scan. This |
@@ -64,7 +62,7 @@ void wl1271_scan_complete_work(struct work_struct *work) | |||
64 | wl->scan.state = WL1271_SCAN_STATE_IDLE; | 62 | wl->scan.state = WL1271_SCAN_STATE_IDLE; |
65 | memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); | 63 | memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); |
66 | wl->scan.req = NULL; | 64 | wl->scan.req = NULL; |
67 | wl->scan_vif = NULL; | 65 | wl->scan_wlvif = NULL; |
68 | 66 | ||
69 | ret = wl1271_ps_elp_wakeup(wl); | 67 | ret = wl1271_ps_elp_wakeup(wl); |
70 | if (ret < 0) | 68 | if (ret < 0) |
@@ -82,6 +80,8 @@ void wl1271_scan_complete_work(struct work_struct *work) | |||
82 | wl12xx_queue_recovery_work(wl); | 80 | wl12xx_queue_recovery_work(wl); |
83 | } | 81 | } |
84 | 82 | ||
83 | wlcore_cmd_regdomain_config_locked(wl); | ||
84 | |||
85 | ieee80211_scan_completed(wl->hw, false); | 85 | ieee80211_scan_completed(wl->hw, false); |
86 | 86 | ||
87 | out: | 87 | out: |
@@ -89,371 +89,99 @@ out: | |||
89 | 89 | ||
90 | } | 90 | } |
91 | 91 | ||
92 | 92 | static void wlcore_started_vifs_iter(void *data, u8 *mac, | |
93 | static int wl1271_get_scan_channels(struct wl1271 *wl, | 93 | struct ieee80211_vif *vif) |
94 | struct cfg80211_scan_request *req, | ||
95 | struct basic_scan_channel_params *channels, | ||
96 | enum ieee80211_band band, bool passive) | ||
97 | { | ||
98 | struct conf_scan_settings *c = &wl->conf.scan; | ||
99 | int i, j; | ||
100 | u32 flags; | ||
101 | |||
102 | for (i = 0, j = 0; | ||
103 | i < req->n_channels && j < WL1271_SCAN_MAX_CHANNELS; | ||
104 | i++) { | ||
105 | flags = req->channels[i]->flags; | ||
106 | |||
107 | if (!test_bit(i, wl->scan.scanned_ch) && | ||
108 | !(flags & IEEE80211_CHAN_DISABLED) && | ||
109 | (req->channels[i]->band == band) && | ||
110 | /* | ||
111 | * In passive scans, we scan all remaining | ||
112 | * channels, even if not marked as such. | ||
113 | * In active scans, we only scan channels not | ||
114 | * marked as passive. | ||
115 | */ | ||
116 | (passive || !(flags & IEEE80211_CHAN_PASSIVE_SCAN))) { | ||
117 | wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ", | ||
118 | req->channels[i]->band, | ||
119 | req->channels[i]->center_freq); | ||
120 | wl1271_debug(DEBUG_SCAN, "hw_value %d, flags %X", | ||
121 | req->channels[i]->hw_value, | ||
122 | req->channels[i]->flags); | ||
123 | wl1271_debug(DEBUG_SCAN, | ||
124 | "max_antenna_gain %d, max_power %d", | ||
125 | req->channels[i]->max_antenna_gain, | ||
126 | req->channels[i]->max_power); | ||
127 | wl1271_debug(DEBUG_SCAN, "beacon_found %d", | ||
128 | req->channels[i]->beacon_found); | ||
129 | |||
130 | if (!passive) { | ||
131 | channels[j].min_duration = | ||
132 | cpu_to_le32(c->min_dwell_time_active); | ||
133 | channels[j].max_duration = | ||
134 | cpu_to_le32(c->max_dwell_time_active); | ||
135 | } else { | ||
136 | channels[j].min_duration = | ||
137 | cpu_to_le32(c->min_dwell_time_passive); | ||
138 | channels[j].max_duration = | ||
139 | cpu_to_le32(c->max_dwell_time_passive); | ||
140 | } | ||
141 | channels[j].early_termination = 0; | ||
142 | channels[j].tx_power_att = req->channels[i]->max_power; | ||
143 | channels[j].channel = req->channels[i]->hw_value; | ||
144 | |||
145 | memset(&channels[j].bssid_lsb, 0xff, 4); | ||
146 | memset(&channels[j].bssid_msb, 0xff, 2); | ||
147 | |||
148 | /* Mark the channels we already used */ | ||
149 | set_bit(i, wl->scan.scanned_ch); | ||
150 | |||
151 | j++; | ||
152 | } | ||
153 | } | ||
154 | |||
155 | return j; | ||
156 | } | ||
157 | |||
158 | #define WL1271_NOTHING_TO_SCAN 1 | ||
159 | |||
160 | static int wl1271_scan_send(struct wl1271 *wl, struct ieee80211_vif *vif, | ||
161 | enum ieee80211_band band, | ||
162 | bool passive, u32 basic_rate) | ||
163 | { | 94 | { |
164 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | 95 | int *count = (int *)data; |
165 | struct wl1271_cmd_scan *cmd; | ||
166 | struct wl1271_cmd_trigger_scan_to *trigger; | ||
167 | int ret; | ||
168 | u16 scan_options = 0; | ||
169 | |||
170 | /* skip active scans if we don't have SSIDs */ | ||
171 | if (!passive && wl->scan.req->n_ssids == 0) | ||
172 | return WL1271_NOTHING_TO_SCAN; | ||
173 | |||
174 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
175 | trigger = kzalloc(sizeof(*trigger), GFP_KERNEL); | ||
176 | if (!cmd || !trigger) { | ||
177 | ret = -ENOMEM; | ||
178 | goto out; | ||
179 | } | ||
180 | |||
181 | if (wl->conf.scan.split_scan_timeout) | ||
182 | scan_options |= WL1271_SCAN_OPT_SPLIT_SCAN; | ||
183 | |||
184 | if (passive) | ||
185 | scan_options |= WL1271_SCAN_OPT_PASSIVE; | ||
186 | |||
187 | cmd->params.role_id = wlvif->role_id; | ||
188 | |||
189 | if (WARN_ON(cmd->params.role_id == WL12XX_INVALID_ROLE_ID)) { | ||
190 | ret = -EINVAL; | ||
191 | goto out; | ||
192 | } | ||
193 | |||
194 | cmd->params.scan_options = cpu_to_le16(scan_options); | ||
195 | |||
196 | cmd->params.n_ch = wl1271_get_scan_channels(wl, wl->scan.req, | ||
197 | cmd->channels, | ||
198 | band, passive); | ||
199 | if (cmd->params.n_ch == 0) { | ||
200 | ret = WL1271_NOTHING_TO_SCAN; | ||
201 | goto out; | ||
202 | } | ||
203 | |||
204 | cmd->params.tx_rate = cpu_to_le32(basic_rate); | ||
205 | cmd->params.n_probe_reqs = wl->conf.scan.num_probe_reqs; | ||
206 | cmd->params.tid_trigger = CONF_TX_AC_ANY_TID; | ||
207 | cmd->params.scan_tag = WL1271_SCAN_DEFAULT_TAG; | ||
208 | |||
209 | if (band == IEEE80211_BAND_2GHZ) | ||
210 | cmd->params.band = WL1271_SCAN_BAND_2_4_GHZ; | ||
211 | else | ||
212 | cmd->params.band = WL1271_SCAN_BAND_5_GHZ; | ||
213 | |||
214 | if (wl->scan.ssid_len && wl->scan.ssid) { | ||
215 | cmd->params.ssid_len = wl->scan.ssid_len; | ||
216 | memcpy(cmd->params.ssid, wl->scan.ssid, wl->scan.ssid_len); | ||
217 | } | ||
218 | |||
219 | memcpy(cmd->addr, vif->addr, ETH_ALEN); | ||
220 | |||
221 | ret = wl12xx_cmd_build_probe_req(wl, wlvif, | ||
222 | cmd->params.role_id, band, | ||
223 | wl->scan.ssid, wl->scan.ssid_len, | ||
224 | wl->scan.req->ie, | ||
225 | wl->scan.req->ie_len, false); | ||
226 | if (ret < 0) { | ||
227 | wl1271_error("PROBE request template failed"); | ||
228 | goto out; | ||
229 | } | ||
230 | |||
231 | trigger->timeout = cpu_to_le32(wl->conf.scan.split_scan_timeout); | ||
232 | ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger, | ||
233 | sizeof(*trigger), 0); | ||
234 | if (ret < 0) { | ||
235 | wl1271_error("trigger scan to failed for hw scan"); | ||
236 | goto out; | ||
237 | } | ||
238 | |||
239 | wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd)); | ||
240 | 96 | ||
241 | ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0); | 97 | if (!vif->bss_conf.idle) |
242 | if (ret < 0) { | 98 | (*count)++; |
243 | wl1271_error("SCAN failed"); | ||
244 | goto out; | ||
245 | } | ||
246 | |||
247 | out: | ||
248 | kfree(cmd); | ||
249 | kfree(trigger); | ||
250 | return ret; | ||
251 | } | 99 | } |
252 | 100 | ||
253 | void wl1271_scan_stm(struct wl1271 *wl, struct ieee80211_vif *vif) | 101 | static int wlcore_count_started_vifs(struct wl1271 *wl) |
254 | { | 102 | { |
255 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | 103 | int count = 0; |
256 | int ret = 0; | ||
257 | enum ieee80211_band band; | ||
258 | u32 rate, mask; | ||
259 | |||
260 | switch (wl->scan.state) { | ||
261 | case WL1271_SCAN_STATE_IDLE: | ||
262 | break; | ||
263 | |||
264 | case WL1271_SCAN_STATE_2GHZ_ACTIVE: | ||
265 | band = IEEE80211_BAND_2GHZ; | ||
266 | mask = wlvif->bitrate_masks[band]; | ||
267 | if (wl->scan.req->no_cck) { | ||
268 | mask &= ~CONF_TX_CCK_RATES; | ||
269 | if (!mask) | ||
270 | mask = CONF_TX_RATE_MASK_BASIC_P2P; | ||
271 | } | ||
272 | rate = wl1271_tx_min_rate_get(wl, mask); | ||
273 | ret = wl1271_scan_send(wl, vif, band, false, rate); | ||
274 | if (ret == WL1271_NOTHING_TO_SCAN) { | ||
275 | wl->scan.state = WL1271_SCAN_STATE_2GHZ_PASSIVE; | ||
276 | wl1271_scan_stm(wl, vif); | ||
277 | } | ||
278 | |||
279 | break; | ||
280 | |||
281 | case WL1271_SCAN_STATE_2GHZ_PASSIVE: | ||
282 | band = IEEE80211_BAND_2GHZ; | ||
283 | mask = wlvif->bitrate_masks[band]; | ||
284 | if (wl->scan.req->no_cck) { | ||
285 | mask &= ~CONF_TX_CCK_RATES; | ||
286 | if (!mask) | ||
287 | mask = CONF_TX_RATE_MASK_BASIC_P2P; | ||
288 | } | ||
289 | rate = wl1271_tx_min_rate_get(wl, mask); | ||
290 | ret = wl1271_scan_send(wl, vif, band, true, rate); | ||
291 | if (ret == WL1271_NOTHING_TO_SCAN) { | ||
292 | if (wl->enable_11a) | ||
293 | wl->scan.state = WL1271_SCAN_STATE_5GHZ_ACTIVE; | ||
294 | else | ||
295 | wl->scan.state = WL1271_SCAN_STATE_DONE; | ||
296 | wl1271_scan_stm(wl, vif); | ||
297 | } | ||
298 | |||
299 | break; | ||
300 | 104 | ||
301 | case WL1271_SCAN_STATE_5GHZ_ACTIVE: | 105 | ieee80211_iterate_active_interfaces_atomic(wl->hw, |
302 | band = IEEE80211_BAND_5GHZ; | 106 | IEEE80211_IFACE_ITER_RESUME_ALL, |
303 | rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]); | 107 | wlcore_started_vifs_iter, &count); |
304 | ret = wl1271_scan_send(wl, vif, band, false, rate); | 108 | return count; |
305 | if (ret == WL1271_NOTHING_TO_SCAN) { | ||
306 | wl->scan.state = WL1271_SCAN_STATE_5GHZ_PASSIVE; | ||
307 | wl1271_scan_stm(wl, vif); | ||
308 | } | ||
309 | |||
310 | break; | ||
311 | |||
312 | case WL1271_SCAN_STATE_5GHZ_PASSIVE: | ||
313 | band = IEEE80211_BAND_5GHZ; | ||
314 | rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]); | ||
315 | ret = wl1271_scan_send(wl, vif, band, true, rate); | ||
316 | if (ret == WL1271_NOTHING_TO_SCAN) { | ||
317 | wl->scan.state = WL1271_SCAN_STATE_DONE; | ||
318 | wl1271_scan_stm(wl, vif); | ||
319 | } | ||
320 | |||
321 | break; | ||
322 | |||
323 | case WL1271_SCAN_STATE_DONE: | ||
324 | wl->scan.failed = false; | ||
325 | cancel_delayed_work(&wl->scan_complete_work); | ||
326 | ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, | ||
327 | msecs_to_jiffies(0)); | ||
328 | break; | ||
329 | |||
330 | default: | ||
331 | wl1271_error("invalid scan state"); | ||
332 | break; | ||
333 | } | ||
334 | |||
335 | if (ret < 0) { | ||
336 | cancel_delayed_work(&wl->scan_complete_work); | ||
337 | ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, | ||
338 | msecs_to_jiffies(0)); | ||
339 | } | ||
340 | } | ||
341 | |||
342 | int wl1271_scan(struct wl1271 *wl, struct ieee80211_vif *vif, | ||
343 | const u8 *ssid, size_t ssid_len, | ||
344 | struct cfg80211_scan_request *req) | ||
345 | { | ||
346 | /* | ||
347 | * cfg80211 should guarantee that we don't get more channels | ||
348 | * than what we have registered. | ||
349 | */ | ||
350 | BUG_ON(req->n_channels > WL1271_MAX_CHANNELS); | ||
351 | |||
352 | if (wl->scan.state != WL1271_SCAN_STATE_IDLE) | ||
353 | return -EBUSY; | ||
354 | |||
355 | wl->scan.state = WL1271_SCAN_STATE_2GHZ_ACTIVE; | ||
356 | |||
357 | if (ssid_len && ssid) { | ||
358 | wl->scan.ssid_len = ssid_len; | ||
359 | memcpy(wl->scan.ssid, ssid, ssid_len); | ||
360 | } else { | ||
361 | wl->scan.ssid_len = 0; | ||
362 | } | ||
363 | |||
364 | wl->scan_vif = vif; | ||
365 | wl->scan.req = req; | ||
366 | memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); | ||
367 | |||
368 | /* we assume failure so that timeout scenarios are handled correctly */ | ||
369 | wl->scan.failed = true; | ||
370 | ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, | ||
371 | msecs_to_jiffies(WL1271_SCAN_TIMEOUT)); | ||
372 | |||
373 | wl1271_scan_stm(wl, vif); | ||
374 | |||
375 | return 0; | ||
376 | } | ||
377 | |||
378 | int wl1271_scan_stop(struct wl1271 *wl) | ||
379 | { | ||
380 | struct wl1271_cmd_header *cmd = NULL; | ||
381 | int ret = 0; | ||
382 | |||
383 | if (WARN_ON(wl->scan.state == WL1271_SCAN_STATE_IDLE)) | ||
384 | return -EINVAL; | ||
385 | |||
386 | wl1271_debug(DEBUG_CMD, "cmd scan stop"); | ||
387 | |||
388 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
389 | if (!cmd) { | ||
390 | ret = -ENOMEM; | ||
391 | goto out; | ||
392 | } | ||
393 | |||
394 | ret = wl1271_cmd_send(wl, CMD_STOP_SCAN, cmd, | ||
395 | sizeof(*cmd), 0); | ||
396 | if (ret < 0) { | ||
397 | wl1271_error("cmd stop_scan failed"); | ||
398 | goto out; | ||
399 | } | ||
400 | out: | ||
401 | kfree(cmd); | ||
402 | return ret; | ||
403 | } | 109 | } |
404 | 110 | ||
405 | static int | 111 | static int |
406 | wl1271_scan_get_sched_scan_channels(struct wl1271 *wl, | 112 | wlcore_scan_get_channels(struct wl1271 *wl, |
407 | struct cfg80211_sched_scan_request *req, | 113 | struct ieee80211_channel *req_channels[], |
408 | struct conn_scan_ch_params *channels, | 114 | u32 n_channels, |
409 | u32 band, bool radar, bool passive, | 115 | u32 n_ssids, |
410 | int start, int max_channels, | 116 | struct conn_scan_ch_params *channels, |
411 | u8 *n_pactive_ch) | 117 | u32 band, bool radar, bool passive, |
118 | int start, int max_channels, | ||
119 | u8 *n_pactive_ch, | ||
120 | int scan_type) | ||
412 | { | 121 | { |
413 | struct conf_sched_scan_settings *c = &wl->conf.sched_scan; | ||
414 | int i, j; | 122 | int i, j; |
415 | u32 flags; | 123 | u32 flags; |
416 | bool force_passive = !req->n_ssids; | 124 | bool force_passive = !n_ssids; |
417 | u32 min_dwell_time_active, max_dwell_time_active, delta_per_probe; | 125 | u32 min_dwell_time_active, max_dwell_time_active; |
418 | u32 dwell_time_passive, dwell_time_dfs; | 126 | u32 dwell_time_passive, dwell_time_dfs; |
419 | 127 | ||
420 | if (band == IEEE80211_BAND_5GHZ) | 128 | /* configure dwell times according to scan type */ |
421 | delta_per_probe = c->dwell_time_delta_per_probe_5; | 129 | if (scan_type == SCAN_TYPE_SEARCH) { |
422 | else | 130 | struct conf_scan_settings *c = &wl->conf.scan; |
423 | delta_per_probe = c->dwell_time_delta_per_probe; | 131 | bool active_vif_exists = !!wlcore_count_started_vifs(wl); |
132 | |||
133 | min_dwell_time_active = active_vif_exists ? | ||
134 | c->min_dwell_time_active : | ||
135 | c->min_dwell_time_active_long; | ||
136 | max_dwell_time_active = active_vif_exists ? | ||
137 | c->max_dwell_time_active : | ||
138 | c->max_dwell_time_active_long; | ||
139 | dwell_time_passive = c->dwell_time_passive; | ||
140 | dwell_time_dfs = c->dwell_time_dfs; | ||
141 | } else { | ||
142 | struct conf_sched_scan_settings *c = &wl->conf.sched_scan; | ||
143 | u32 delta_per_probe; | ||
424 | 144 | ||
425 | min_dwell_time_active = c->base_dwell_time + | 145 | if (band == IEEE80211_BAND_5GHZ) |
426 | req->n_ssids * c->num_probe_reqs * delta_per_probe; | 146 | delta_per_probe = c->dwell_time_delta_per_probe_5; |
147 | else | ||
148 | delta_per_probe = c->dwell_time_delta_per_probe; | ||
427 | 149 | ||
428 | max_dwell_time_active = min_dwell_time_active + c->max_dwell_time_delta; | 150 | min_dwell_time_active = c->base_dwell_time + |
151 | n_ssids * c->num_probe_reqs * delta_per_probe; | ||
429 | 152 | ||
153 | max_dwell_time_active = min_dwell_time_active + | ||
154 | c->max_dwell_time_delta; | ||
155 | dwell_time_passive = c->dwell_time_passive; | ||
156 | dwell_time_dfs = c->dwell_time_dfs; | ||
157 | } | ||
430 | min_dwell_time_active = DIV_ROUND_UP(min_dwell_time_active, 1000); | 158 | min_dwell_time_active = DIV_ROUND_UP(min_dwell_time_active, 1000); |
431 | max_dwell_time_active = DIV_ROUND_UP(max_dwell_time_active, 1000); | 159 | max_dwell_time_active = DIV_ROUND_UP(max_dwell_time_active, 1000); |
432 | dwell_time_passive = DIV_ROUND_UP(c->dwell_time_passive, 1000); | 160 | dwell_time_passive = DIV_ROUND_UP(dwell_time_passive, 1000); |
433 | dwell_time_dfs = DIV_ROUND_UP(c->dwell_time_dfs, 1000); | 161 | dwell_time_dfs = DIV_ROUND_UP(dwell_time_dfs, 1000); |
434 | 162 | ||
435 | for (i = 0, j = start; | 163 | for (i = 0, j = start; |
436 | i < req->n_channels && j < max_channels; | 164 | i < n_channels && j < max_channels; |
437 | i++) { | 165 | i++) { |
438 | flags = req->channels[i]->flags; | 166 | flags = req_channels[i]->flags; |
439 | 167 | ||
440 | if (force_passive) | 168 | if (force_passive) |
441 | flags |= IEEE80211_CHAN_PASSIVE_SCAN; | 169 | flags |= IEEE80211_CHAN_PASSIVE_SCAN; |
442 | 170 | ||
443 | if ((req->channels[i]->band == band) && | 171 | if ((req_channels[i]->band == band) && |
444 | !(flags & IEEE80211_CHAN_DISABLED) && | 172 | !(flags & IEEE80211_CHAN_DISABLED) && |
445 | (!!(flags & IEEE80211_CHAN_RADAR) == radar) && | 173 | (!!(flags & IEEE80211_CHAN_RADAR) == radar) && |
446 | /* if radar is set, we ignore the passive flag */ | 174 | /* if radar is set, we ignore the passive flag */ |
447 | (radar || | 175 | (radar || |
448 | !!(flags & IEEE80211_CHAN_PASSIVE_SCAN) == passive)) { | 176 | !!(flags & IEEE80211_CHAN_PASSIVE_SCAN) == passive)) { |
449 | wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ", | 177 | wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ", |
450 | req->channels[i]->band, | 178 | req_channels[i]->band, |
451 | req->channels[i]->center_freq); | 179 | req_channels[i]->center_freq); |
452 | wl1271_debug(DEBUG_SCAN, "hw_value %d, flags %X", | 180 | wl1271_debug(DEBUG_SCAN, "hw_value %d, flags %X", |
453 | req->channels[i]->hw_value, | 181 | req_channels[i]->hw_value, |
454 | req->channels[i]->flags); | 182 | req_channels[i]->flags); |
455 | wl1271_debug(DEBUG_SCAN, "max_power %d", | 183 | wl1271_debug(DEBUG_SCAN, "max_power %d", |
456 | req->channels[i]->max_power); | 184 | req_channels[i]->max_power); |
457 | wl1271_debug(DEBUG_SCAN, "min_dwell_time %d max dwell time %d", | 185 | wl1271_debug(DEBUG_SCAN, "min_dwell_time %d max dwell time %d", |
458 | min_dwell_time_active, | 186 | min_dwell_time_active, |
459 | max_dwell_time_active); | 187 | max_dwell_time_active); |
@@ -473,10 +201,11 @@ wl1271_scan_get_sched_scan_channels(struct wl1271 *wl, | |||
473 | channels[j].max_duration = | 201 | channels[j].max_duration = |
474 | cpu_to_le16(max_dwell_time_active); | 202 | cpu_to_le16(max_dwell_time_active); |
475 | 203 | ||
476 | channels[j].tx_power_att = req->channels[i]->max_power; | 204 | channels[j].tx_power_att = req_channels[i]->max_power; |
477 | channels[j].channel = req->channels[i]->hw_value; | 205 | channels[j].channel = req_channels[i]->hw_value; |
478 | 206 | ||
479 | if ((band == IEEE80211_BAND_2GHZ) && | 207 | if (n_pactive_ch && |
208 | (band == IEEE80211_BAND_2GHZ) && | ||
480 | (channels[j].channel >= 12) && | 209 | (channels[j].channel >= 12) && |
481 | (channels[j].channel <= 14) && | 210 | (channels[j].channel <= 14) && |
482 | (flags & IEEE80211_CHAN_PASSIVE_SCAN) && | 211 | (flags & IEEE80211_CHAN_PASSIVE_SCAN) && |
@@ -500,51 +229,80 @@ wl1271_scan_get_sched_scan_channels(struct wl1271 *wl, | |||
500 | return j - start; | 229 | return j - start; |
501 | } | 230 | } |
502 | 231 | ||
503 | static bool | 232 | bool |
504 | wl1271_scan_sched_scan_channels(struct wl1271 *wl, | 233 | wlcore_set_scan_chan_params(struct wl1271 *wl, |
505 | struct cfg80211_sched_scan_request *req, | 234 | struct wlcore_scan_channels *cfg, |
506 | struct wl1271_cmd_sched_scan_config *cfg) | 235 | struct ieee80211_channel *channels[], |
236 | u32 n_channels, | ||
237 | u32 n_ssids, | ||
238 | int scan_type) | ||
507 | { | 239 | { |
508 | u8 n_pactive_ch = 0; | 240 | u8 n_pactive_ch = 0; |
509 | 241 | ||
510 | cfg->passive[0] = | 242 | cfg->passive[0] = |
511 | wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_2, | 243 | wlcore_scan_get_channels(wl, |
512 | IEEE80211_BAND_2GHZ, | 244 | channels, |
513 | false, true, 0, | 245 | n_channels, |
514 | MAX_CHANNELS_2GHZ, | 246 | n_ssids, |
515 | &n_pactive_ch); | 247 | cfg->channels_2, |
248 | IEEE80211_BAND_2GHZ, | ||
249 | false, true, 0, | ||
250 | MAX_CHANNELS_2GHZ, | ||
251 | &n_pactive_ch, | ||
252 | scan_type); | ||
516 | cfg->active[0] = | 253 | cfg->active[0] = |
517 | wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_2, | 254 | wlcore_scan_get_channels(wl, |
518 | IEEE80211_BAND_2GHZ, | 255 | channels, |
519 | false, false, | 256 | n_channels, |
520 | cfg->passive[0], | 257 | n_ssids, |
521 | MAX_CHANNELS_2GHZ, | 258 | cfg->channels_2, |
522 | &n_pactive_ch); | 259 | IEEE80211_BAND_2GHZ, |
260 | false, false, | ||
261 | cfg->passive[0], | ||
262 | MAX_CHANNELS_2GHZ, | ||
263 | &n_pactive_ch, | ||
264 | scan_type); | ||
523 | cfg->passive[1] = | 265 | cfg->passive[1] = |
524 | wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_5, | 266 | wlcore_scan_get_channels(wl, |
525 | IEEE80211_BAND_5GHZ, | 267 | channels, |
526 | false, true, 0, | 268 | n_channels, |
527 | MAX_CHANNELS_5GHZ, | 269 | n_ssids, |
528 | &n_pactive_ch); | 270 | cfg->channels_5, |
271 | IEEE80211_BAND_5GHZ, | ||
272 | false, true, 0, | ||
273 | wl->max_channels_5, | ||
274 | &n_pactive_ch, | ||
275 | scan_type); | ||
529 | cfg->dfs = | 276 | cfg->dfs = |
530 | wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_5, | 277 | wlcore_scan_get_channels(wl, |
531 | IEEE80211_BAND_5GHZ, | 278 | channels, |
532 | true, true, | 279 | n_channels, |
533 | cfg->passive[1], | 280 | n_ssids, |
534 | MAX_CHANNELS_5GHZ, | 281 | cfg->channels_5, |
535 | &n_pactive_ch); | 282 | IEEE80211_BAND_5GHZ, |
283 | true, true, | ||
284 | cfg->passive[1], | ||
285 | wl->max_channels_5, | ||
286 | &n_pactive_ch, | ||
287 | scan_type); | ||
536 | cfg->active[1] = | 288 | cfg->active[1] = |
537 | wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_5, | 289 | wlcore_scan_get_channels(wl, |
538 | IEEE80211_BAND_5GHZ, | 290 | channels, |
539 | false, false, | 291 | n_channels, |
540 | cfg->passive[1] + cfg->dfs, | 292 | n_ssids, |
541 | MAX_CHANNELS_5GHZ, | 293 | cfg->channels_5, |
542 | &n_pactive_ch); | 294 | IEEE80211_BAND_5GHZ, |
295 | false, false, | ||
296 | cfg->passive[1] + cfg->dfs, | ||
297 | wl->max_channels_5, | ||
298 | &n_pactive_ch, | ||
299 | scan_type); | ||
300 | |||
543 | /* 802.11j channels are not supported yet */ | 301 | /* 802.11j channels are not supported yet */ |
544 | cfg->passive[2] = 0; | 302 | cfg->passive[2] = 0; |
545 | cfg->active[2] = 0; | 303 | cfg->active[2] = 0; |
546 | 304 | ||
547 | cfg->n_pactive_ch = n_pactive_ch; | 305 | cfg->passive_active = n_pactive_ch; |
548 | 306 | ||
549 | wl1271_debug(DEBUG_SCAN, " 2.4GHz: active %d passive %d", | 307 | wl1271_debug(DEBUG_SCAN, " 2.4GHz: active %d passive %d", |
550 | cfg->active[0], cfg->passive[0]); | 308 | cfg->active[0], cfg->passive[0]); |
@@ -556,10 +314,48 @@ wl1271_scan_sched_scan_channels(struct wl1271 *wl, | |||
556 | cfg->passive[1] || cfg->active[1] || cfg->dfs || | 314 | cfg->passive[1] || cfg->active[1] || cfg->dfs || |
557 | cfg->passive[2] || cfg->active[2]; | 315 | cfg->passive[2] || cfg->active[2]; |
558 | } | 316 | } |
317 | EXPORT_SYMBOL_GPL(wlcore_set_scan_chan_params); | ||
318 | |||
319 | int wlcore_scan(struct wl1271 *wl, struct ieee80211_vif *vif, | ||
320 | const u8 *ssid, size_t ssid_len, | ||
321 | struct cfg80211_scan_request *req) | ||
322 | { | ||
323 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | ||
324 | |||
325 | /* | ||
326 | * cfg80211 should guarantee that we don't get more channels | ||
327 | * than what we have registered. | ||
328 | */ | ||
329 | BUG_ON(req->n_channels > WL1271_MAX_CHANNELS); | ||
330 | |||
331 | if (wl->scan.state != WL1271_SCAN_STATE_IDLE) | ||
332 | return -EBUSY; | ||
333 | |||
334 | wl->scan.state = WL1271_SCAN_STATE_2GHZ_ACTIVE; | ||
335 | |||
336 | if (ssid_len && ssid) { | ||
337 | wl->scan.ssid_len = ssid_len; | ||
338 | memcpy(wl->scan.ssid, ssid, ssid_len); | ||
339 | } else { | ||
340 | wl->scan.ssid_len = 0; | ||
341 | } | ||
342 | |||
343 | wl->scan_wlvif = wlvif; | ||
344 | wl->scan.req = req; | ||
345 | memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); | ||
346 | |||
347 | /* we assume failure so that timeout scenarios are handled correctly */ | ||
348 | wl->scan.failed = true; | ||
349 | ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, | ||
350 | msecs_to_jiffies(WL1271_SCAN_TIMEOUT)); | ||
559 | 351 | ||
352 | wl->ops->scan_start(wl, wlvif, req); | ||
353 | |||
354 | return 0; | ||
355 | } | ||
560 | /* Returns the scan type to be used or a negative value on error */ | 356 | /* Returns the scan type to be used or a negative value on error */ |
561 | static int | 357 | int |
562 | wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl, | 358 | wlcore_scan_sched_scan_ssid_list(struct wl1271 *wl, |
563 | struct wl12xx_vif *wlvif, | 359 | struct wl12xx_vif *wlvif, |
564 | struct cfg80211_sched_scan_request *req) | 360 | struct cfg80211_sched_scan_request *req) |
565 | { | 361 | { |
@@ -662,160 +458,12 @@ out: | |||
662 | return ret; | 458 | return ret; |
663 | return type; | 459 | return type; |
664 | } | 460 | } |
461 | EXPORT_SYMBOL_GPL(wlcore_scan_sched_scan_ssid_list); | ||
665 | 462 | ||
666 | int wl1271_scan_sched_scan_config(struct wl1271 *wl, | 463 | void wlcore_scan_sched_scan_results(struct wl1271 *wl) |
667 | struct wl12xx_vif *wlvif, | ||
668 | struct cfg80211_sched_scan_request *req, | ||
669 | struct ieee80211_sched_scan_ies *ies) | ||
670 | { | ||
671 | struct wl1271_cmd_sched_scan_config *cfg = NULL; | ||
672 | struct conf_sched_scan_settings *c = &wl->conf.sched_scan; | ||
673 | int i, ret; | ||
674 | bool force_passive = !req->n_ssids; | ||
675 | |||
676 | wl1271_debug(DEBUG_CMD, "cmd sched_scan scan config"); | ||
677 | |||
678 | cfg = kzalloc(sizeof(*cfg), GFP_KERNEL); | ||
679 | if (!cfg) | ||
680 | return -ENOMEM; | ||
681 | |||
682 | cfg->role_id = wlvif->role_id; | ||
683 | cfg->rssi_threshold = c->rssi_threshold; | ||
684 | cfg->snr_threshold = c->snr_threshold; | ||
685 | cfg->n_probe_reqs = c->num_probe_reqs; | ||
686 | /* cycles set to 0 it means infinite (until manually stopped) */ | ||
687 | cfg->cycles = 0; | ||
688 | /* report APs when at least 1 is found */ | ||
689 | cfg->report_after = 1; | ||
690 | /* don't stop scanning automatically when something is found */ | ||
691 | cfg->terminate = 0; | ||
692 | cfg->tag = WL1271_SCAN_DEFAULT_TAG; | ||
693 | /* don't filter on BSS type */ | ||
694 | cfg->bss_type = SCAN_BSS_TYPE_ANY; | ||
695 | /* currently NL80211 supports only a single interval */ | ||
696 | for (i = 0; i < SCAN_MAX_CYCLE_INTERVALS; i++) | ||
697 | cfg->intervals[i] = cpu_to_le32(req->interval); | ||
698 | |||
699 | cfg->ssid_len = 0; | ||
700 | ret = wl12xx_scan_sched_scan_ssid_list(wl, wlvif, req); | ||
701 | if (ret < 0) | ||
702 | goto out; | ||
703 | |||
704 | cfg->filter_type = ret; | ||
705 | |||
706 | wl1271_debug(DEBUG_SCAN, "filter_type = %d", cfg->filter_type); | ||
707 | |||
708 | if (!wl1271_scan_sched_scan_channels(wl, req, cfg)) { | ||
709 | wl1271_error("scan channel list is empty"); | ||
710 | ret = -EINVAL; | ||
711 | goto out; | ||
712 | } | ||
713 | |||
714 | if (!force_passive && cfg->active[0]) { | ||
715 | u8 band = IEEE80211_BAND_2GHZ; | ||
716 | ret = wl12xx_cmd_build_probe_req(wl, wlvif, | ||
717 | wlvif->role_id, band, | ||
718 | req->ssids[0].ssid, | ||
719 | req->ssids[0].ssid_len, | ||
720 | ies->ie[band], | ||
721 | ies->len[band], true); | ||
722 | if (ret < 0) { | ||
723 | wl1271_error("2.4GHz PROBE request template failed"); | ||
724 | goto out; | ||
725 | } | ||
726 | } | ||
727 | |||
728 | if (!force_passive && cfg->active[1]) { | ||
729 | u8 band = IEEE80211_BAND_5GHZ; | ||
730 | ret = wl12xx_cmd_build_probe_req(wl, wlvif, | ||
731 | wlvif->role_id, band, | ||
732 | req->ssids[0].ssid, | ||
733 | req->ssids[0].ssid_len, | ||
734 | ies->ie[band], | ||
735 | ies->len[band], true); | ||
736 | if (ret < 0) { | ||
737 | wl1271_error("5GHz PROBE request template failed"); | ||
738 | goto out; | ||
739 | } | ||
740 | } | ||
741 | |||
742 | wl1271_dump(DEBUG_SCAN, "SCAN_CFG: ", cfg, sizeof(*cfg)); | ||
743 | |||
744 | ret = wl1271_cmd_send(wl, CMD_CONNECTION_SCAN_CFG, cfg, | ||
745 | sizeof(*cfg), 0); | ||
746 | if (ret < 0) { | ||
747 | wl1271_error("SCAN configuration failed"); | ||
748 | goto out; | ||
749 | } | ||
750 | out: | ||
751 | kfree(cfg); | ||
752 | return ret; | ||
753 | } | ||
754 | |||
755 | int wl1271_scan_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif) | ||
756 | { | ||
757 | struct wl1271_cmd_sched_scan_start *start; | ||
758 | int ret = 0; | ||
759 | |||
760 | wl1271_debug(DEBUG_CMD, "cmd periodic scan start"); | ||
761 | |||
762 | if (wlvif->bss_type != BSS_TYPE_STA_BSS) | ||
763 | return -EOPNOTSUPP; | ||
764 | |||
765 | if ((wl->quirks & WLCORE_QUIRK_NO_SCHED_SCAN_WHILE_CONN) && | ||
766 | test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags)) | ||
767 | return -EBUSY; | ||
768 | |||
769 | start = kzalloc(sizeof(*start), GFP_KERNEL); | ||
770 | if (!start) | ||
771 | return -ENOMEM; | ||
772 | |||
773 | start->role_id = wlvif->role_id; | ||
774 | start->tag = WL1271_SCAN_DEFAULT_TAG; | ||
775 | |||
776 | ret = wl1271_cmd_send(wl, CMD_START_PERIODIC_SCAN, start, | ||
777 | sizeof(*start), 0); | ||
778 | if (ret < 0) { | ||
779 | wl1271_error("failed to send scan start command"); | ||
780 | goto out_free; | ||
781 | } | ||
782 | |||
783 | out_free: | ||
784 | kfree(start); | ||
785 | return ret; | ||
786 | } | ||
787 | |||
788 | void wl1271_scan_sched_scan_results(struct wl1271 *wl) | ||
789 | { | 464 | { |
790 | wl1271_debug(DEBUG_SCAN, "got periodic scan results"); | 465 | wl1271_debug(DEBUG_SCAN, "got periodic scan results"); |
791 | 466 | ||
792 | ieee80211_sched_scan_results(wl->hw); | 467 | ieee80211_sched_scan_results(wl->hw); |
793 | } | 468 | } |
794 | 469 | EXPORT_SYMBOL_GPL(wlcore_scan_sched_scan_results); | |
795 | void wl1271_scan_sched_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif) | ||
796 | { | ||
797 | struct wl1271_cmd_sched_scan_stop *stop; | ||
798 | int ret = 0; | ||
799 | |||
800 | wl1271_debug(DEBUG_CMD, "cmd periodic scan stop"); | ||
801 | |||
802 | /* FIXME: what to do if alloc'ing to stop fails? */ | ||
803 | stop = kzalloc(sizeof(*stop), GFP_KERNEL); | ||
804 | if (!stop) { | ||
805 | wl1271_error("failed to alloc memory to send sched scan stop"); | ||
806 | return; | ||
807 | } | ||
808 | |||
809 | stop->role_id = wlvif->role_id; | ||
810 | stop->tag = WL1271_SCAN_DEFAULT_TAG; | ||
811 | |||
812 | ret = wl1271_cmd_send(wl, CMD_STOP_PERIODIC_SCAN, stop, | ||
813 | sizeof(*stop), 0); | ||
814 | if (ret < 0) { | ||
815 | wl1271_error("failed to send sched scan stop command"); | ||
816 | goto out_free; | ||
817 | } | ||
818 | |||
819 | out_free: | ||
820 | kfree(stop); | ||
821 | } | ||
diff --git a/drivers/net/wireless/ti/wlcore/scan.h b/drivers/net/wireless/ti/wlcore/scan.h index 29f3c8d6b046..a6ab24b5c0f9 100644 --- a/drivers/net/wireless/ti/wlcore/scan.h +++ b/drivers/net/wireless/ti/wlcore/scan.h | |||
@@ -26,22 +26,20 @@ | |||
26 | 26 | ||
27 | #include "wlcore.h" | 27 | #include "wlcore.h" |
28 | 28 | ||
29 | int wl1271_scan(struct wl1271 *wl, struct ieee80211_vif *vif, | 29 | int wlcore_scan(struct wl1271 *wl, struct ieee80211_vif *vif, |
30 | const u8 *ssid, size_t ssid_len, | 30 | const u8 *ssid, size_t ssid_len, |
31 | struct cfg80211_scan_request *req); | 31 | struct cfg80211_scan_request *req); |
32 | int wl1271_scan_stop(struct wl1271 *wl); | ||
33 | int wl1271_scan_build_probe_req(struct wl1271 *wl, | 32 | int wl1271_scan_build_probe_req(struct wl1271 *wl, |
34 | const u8 *ssid, size_t ssid_len, | 33 | const u8 *ssid, size_t ssid_len, |
35 | const u8 *ie, size_t ie_len, u8 band); | 34 | const u8 *ie, size_t ie_len, u8 band); |
36 | void wl1271_scan_stm(struct wl1271 *wl, struct ieee80211_vif *vif); | 35 | void wl1271_scan_stm(struct wl1271 *wl, struct wl12xx_vif *wlvif); |
37 | void wl1271_scan_complete_work(struct work_struct *work); | 36 | void wl1271_scan_complete_work(struct work_struct *work); |
38 | int wl1271_scan_sched_scan_config(struct wl1271 *wl, | 37 | int wl1271_scan_sched_scan_config(struct wl1271 *wl, |
39 | struct wl12xx_vif *wlvif, | 38 | struct wl12xx_vif *wlvif, |
40 | struct cfg80211_sched_scan_request *req, | 39 | struct cfg80211_sched_scan_request *req, |
41 | struct ieee80211_sched_scan_ies *ies); | 40 | struct ieee80211_sched_scan_ies *ies); |
42 | int wl1271_scan_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif); | 41 | int wl1271_scan_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif); |
43 | void wl1271_scan_sched_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif); | 42 | void wlcore_scan_sched_scan_results(struct wl1271 *wl); |
44 | void wl1271_scan_sched_scan_results(struct wl1271 *wl); | ||
45 | 43 | ||
46 | #define WL1271_SCAN_MAX_CHANNELS 24 | 44 | #define WL1271_SCAN_MAX_CHANNELS 24 |
47 | #define WL1271_SCAN_DEFAULT_TAG 1 | 45 | #define WL1271_SCAN_DEFAULT_TAG 1 |
@@ -66,56 +64,6 @@ enum { | |||
66 | WL1271_SCAN_STATE_DONE | 64 | WL1271_SCAN_STATE_DONE |
67 | }; | 65 | }; |
68 | 66 | ||
69 | struct basic_scan_params { | ||
70 | /* Scan option flags (WL1271_SCAN_OPT_*) */ | ||
71 | __le16 scan_options; | ||
72 | u8 role_id; | ||
73 | /* Number of scan channels in the list (maximum 30) */ | ||
74 | u8 n_ch; | ||
75 | /* This field indicates the number of probe requests to send | ||
76 | per channel for an active scan */ | ||
77 | u8 n_probe_reqs; | ||
78 | u8 tid_trigger; | ||
79 | u8 ssid_len; | ||
80 | u8 use_ssid_list; | ||
81 | |||
82 | /* Rate bit field for sending the probes */ | ||
83 | __le32 tx_rate; | ||
84 | |||
85 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | ||
86 | /* Band to scan */ | ||
87 | u8 band; | ||
88 | |||
89 | u8 scan_tag; | ||
90 | u8 padding2[2]; | ||
91 | } __packed; | ||
92 | |||
93 | struct basic_scan_channel_params { | ||
94 | /* Duration in TU to wait for frames on a channel for active scan */ | ||
95 | __le32 min_duration; | ||
96 | __le32 max_duration; | ||
97 | __le32 bssid_lsb; | ||
98 | __le16 bssid_msb; | ||
99 | u8 early_termination; | ||
100 | u8 tx_power_att; | ||
101 | u8 channel; | ||
102 | /* FW internal use only! */ | ||
103 | u8 dfs_candidate; | ||
104 | u8 activity_detected; | ||
105 | u8 pad; | ||
106 | } __packed; | ||
107 | |||
108 | struct wl1271_cmd_scan { | ||
109 | struct wl1271_cmd_header header; | ||
110 | |||
111 | struct basic_scan_params params; | ||
112 | struct basic_scan_channel_params channels[WL1271_SCAN_MAX_CHANNELS]; | ||
113 | |||
114 | /* src mac address */ | ||
115 | u8 addr[ETH_ALEN]; | ||
116 | u8 padding[2]; | ||
117 | } __packed; | ||
118 | |||
119 | struct wl1271_cmd_trigger_scan_to { | 67 | struct wl1271_cmd_trigger_scan_to { |
120 | struct wl1271_cmd_header header; | 68 | struct wl1271_cmd_header header; |
121 | 69 | ||
@@ -123,9 +71,17 @@ struct wl1271_cmd_trigger_scan_to { | |||
123 | } __packed; | 71 | } __packed; |
124 | 72 | ||
125 | #define MAX_CHANNELS_2GHZ 14 | 73 | #define MAX_CHANNELS_2GHZ 14 |
126 | #define MAX_CHANNELS_5GHZ 23 | ||
127 | #define MAX_CHANNELS_4GHZ 4 | 74 | #define MAX_CHANNELS_4GHZ 4 |
128 | 75 | ||
76 | /* | ||
77 | * This max value here is used only for the struct definition of | ||
78 | * wlcore_scan_channels. This struct is used by both 12xx | ||
79 | * and 18xx (which have different max 5ghz channels value). | ||
80 | * In order to make sure this is large enough, just use the | ||
81 | * max possible 5ghz channels. | ||
82 | */ | ||
83 | #define MAX_CHANNELS_5GHZ 42 | ||
84 | |||
129 | #define SCAN_MAX_CYCLE_INTERVALS 16 | 85 | #define SCAN_MAX_CYCLE_INTERVALS 16 |
130 | #define SCAN_MAX_BANDS 3 | 86 | #define SCAN_MAX_BANDS 3 |
131 | 87 | ||
@@ -160,43 +116,6 @@ struct conn_scan_ch_params { | |||
160 | u8 padding[3]; | 116 | u8 padding[3]; |
161 | } __packed; | 117 | } __packed; |
162 | 118 | ||
163 | struct wl1271_cmd_sched_scan_config { | ||
164 | struct wl1271_cmd_header header; | ||
165 | |||
166 | __le32 intervals[SCAN_MAX_CYCLE_INTERVALS]; | ||
167 | |||
168 | s8 rssi_threshold; /* for filtering (in dBm) */ | ||
169 | s8 snr_threshold; /* for filtering (in dB) */ | ||
170 | |||
171 | u8 cycles; /* maximum number of scan cycles */ | ||
172 | u8 report_after; /* report when this number of results are received */ | ||
173 | u8 terminate; /* stop scanning after reporting */ | ||
174 | |||
175 | u8 tag; | ||
176 | u8 bss_type; /* for filtering */ | ||
177 | u8 filter_type; | ||
178 | |||
179 | u8 ssid_len; /* For SCAN_SSID_FILTER_SPECIFIC */ | ||
180 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | ||
181 | |||
182 | u8 n_probe_reqs; /* Number of probes requests per channel */ | ||
183 | |||
184 | u8 passive[SCAN_MAX_BANDS]; | ||
185 | u8 active[SCAN_MAX_BANDS]; | ||
186 | |||
187 | u8 dfs; | ||
188 | |||
189 | u8 n_pactive_ch; /* number of pactive (passive until fw detects energy) | ||
190 | channels in BG band */ | ||
191 | u8 role_id; | ||
192 | u8 padding[1]; | ||
193 | |||
194 | struct conn_scan_ch_params channels_2[MAX_CHANNELS_2GHZ]; | ||
195 | struct conn_scan_ch_params channels_5[MAX_CHANNELS_5GHZ]; | ||
196 | struct conn_scan_ch_params channels_4[MAX_CHANNELS_4GHZ]; | ||
197 | } __packed; | ||
198 | |||
199 | |||
200 | #define SCHED_SCAN_MAX_SSIDS 16 | 119 | #define SCHED_SCAN_MAX_SSIDS 16 |
201 | 120 | ||
202 | enum { | 121 | enum { |
@@ -220,21 +139,34 @@ struct wl1271_cmd_sched_scan_ssid_list { | |||
220 | u8 padding[2]; | 139 | u8 padding[2]; |
221 | } __packed; | 140 | } __packed; |
222 | 141 | ||
223 | struct wl1271_cmd_sched_scan_start { | 142 | struct wlcore_scan_channels { |
224 | struct wl1271_cmd_header header; | 143 | u8 passive[SCAN_MAX_BANDS]; /* number of passive scan channels */ |
144 | u8 active[SCAN_MAX_BANDS]; /* number of active scan channels */ | ||
145 | u8 dfs; /* number of dfs channels in 5ghz */ | ||
146 | u8 passive_active; /* number of passive before active channels 2.4ghz */ | ||
225 | 147 | ||
226 | u8 tag; | 148 | struct conn_scan_ch_params channels_2[MAX_CHANNELS_2GHZ]; |
227 | u8 role_id; | 149 | struct conn_scan_ch_params channels_5[MAX_CHANNELS_5GHZ]; |
228 | u8 padding[2]; | 150 | struct conn_scan_ch_params channels_4[MAX_CHANNELS_4GHZ]; |
229 | } __packed; | 151 | }; |
230 | |||
231 | struct wl1271_cmd_sched_scan_stop { | ||
232 | struct wl1271_cmd_header header; | ||
233 | 152 | ||
234 | u8 tag; | 153 | enum { |
235 | u8 role_id; | 154 | SCAN_TYPE_SEARCH = 0, |
236 | u8 padding[2]; | 155 | SCAN_TYPE_PERIODIC = 1, |
237 | } __packed; | 156 | SCAN_TYPE_TRACKING = 2, |
157 | }; | ||
238 | 158 | ||
159 | bool | ||
160 | wlcore_set_scan_chan_params(struct wl1271 *wl, | ||
161 | struct wlcore_scan_channels *cfg, | ||
162 | struct ieee80211_channel *channels[], | ||
163 | u32 n_channels, | ||
164 | u32 n_ssids, | ||
165 | int scan_type); | ||
166 | |||
167 | int | ||
168 | wlcore_scan_sched_scan_ssid_list(struct wl1271 *wl, | ||
169 | struct wl12xx_vif *wlvif, | ||
170 | struct cfg80211_sched_scan_request *req); | ||
239 | 171 | ||
240 | #endif /* __WL1271_SCAN_H__ */ | 172 | #endif /* __WL1271_SCAN_H__ */ |
diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c index a3a20be2036f..75622f6f3e6c 100644 --- a/drivers/net/wireless/ti/wlcore/sdio.c +++ b/drivers/net/wireless/ti/wlcore/sdio.c | |||
@@ -324,8 +324,7 @@ static void wl1271_remove(struct sdio_func *func) | |||
324 | /* Undo decrement done above in wl1271_probe */ | 324 | /* Undo decrement done above in wl1271_probe */ |
325 | pm_runtime_get_noresume(&func->dev); | 325 | pm_runtime_get_noresume(&func->dev); |
326 | 326 | ||
327 | platform_device_del(glue->core); | 327 | platform_device_unregister(glue->core); |
328 | platform_device_put(glue->core); | ||
329 | kfree(glue); | 328 | kfree(glue); |
330 | } | 329 | } |
331 | 330 | ||
diff --git a/drivers/net/wireless/ti/wlcore/spi.c b/drivers/net/wireless/ti/wlcore/spi.c index 18cadc07b754..53790d1d0d27 100644 --- a/drivers/net/wireless/ti/wlcore/spi.c +++ b/drivers/net/wireless/ti/wlcore/spi.c | |||
@@ -264,7 +264,7 @@ static int __must_check wl12xx_spi_raw_write(struct device *child, int addr, | |||
264 | void *buf, size_t len, bool fixed) | 264 | void *buf, size_t len, bool fixed) |
265 | { | 265 | { |
266 | struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent); | 266 | struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent); |
267 | struct spi_transfer t[2 * WSPI_MAX_NUM_OF_CHUNKS]; | 267 | struct spi_transfer t[2 * (WSPI_MAX_NUM_OF_CHUNKS + 1)]; |
268 | struct spi_message m; | 268 | struct spi_message m; |
269 | u32 commands[WSPI_MAX_NUM_OF_CHUNKS]; | 269 | u32 commands[WSPI_MAX_NUM_OF_CHUNKS]; |
270 | u32 *cmd; | 270 | u32 *cmd; |
@@ -399,8 +399,7 @@ static int wl1271_remove(struct spi_device *spi) | |||
399 | { | 399 | { |
400 | struct wl12xx_spi_glue *glue = spi_get_drvdata(spi); | 400 | struct wl12xx_spi_glue *glue = spi_get_drvdata(spi); |
401 | 401 | ||
402 | platform_device_del(glue->core); | 402 | platform_device_unregister(glue->core); |
403 | platform_device_put(glue->core); | ||
404 | kfree(glue); | 403 | kfree(glue); |
405 | 404 | ||
406 | return 0; | 405 | return 0; |
diff --git a/drivers/net/wireless/ti/wlcore/tx.c b/drivers/net/wireless/ti/wlcore/tx.c index a90d3cd09408..ece392c54d9c 100644 --- a/drivers/net/wireless/ti/wlcore/tx.c +++ b/drivers/net/wireless/ti/wlcore/tx.c | |||
@@ -104,7 +104,7 @@ static void wl1271_tx_regulate_link(struct wl1271 *wl, | |||
104 | struct wl12xx_vif *wlvif, | 104 | struct wl12xx_vif *wlvif, |
105 | u8 hlid) | 105 | u8 hlid) |
106 | { | 106 | { |
107 | bool fw_ps, single_sta; | 107 | bool fw_ps, single_link; |
108 | u8 tx_pkts; | 108 | u8 tx_pkts; |
109 | 109 | ||
110 | if (WARN_ON(!test_bit(hlid, wlvif->links_map))) | 110 | if (WARN_ON(!test_bit(hlid, wlvif->links_map))) |
@@ -112,15 +112,15 @@ static void wl1271_tx_regulate_link(struct wl1271 *wl, | |||
112 | 112 | ||
113 | fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); | 113 | fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); |
114 | tx_pkts = wl->links[hlid].allocated_pkts; | 114 | tx_pkts = wl->links[hlid].allocated_pkts; |
115 | single_sta = (wl->active_sta_count == 1); | 115 | single_link = (wl->active_link_count == 1); |
116 | 116 | ||
117 | /* | 117 | /* |
118 | * if in FW PS and there is enough data in FW we can put the link | 118 | * if in FW PS and there is enough data in FW we can put the link |
119 | * into high-level PS and clean out its TX queues. | 119 | * into high-level PS and clean out its TX queues. |
120 | * Make an exception if this is the only connected station. In this | 120 | * Make an exception if this is the only connected link. In this |
121 | * case FW-memory congestion is not a problem. | 121 | * case FW-memory congestion is less of a problem. |
122 | */ | 122 | */ |
123 | if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS) | 123 | if (!single_link && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS) |
124 | wl12xx_ps_link_start(wl, wlvif, hlid, true); | 124 | wl12xx_ps_link_start(wl, wlvif, hlid, true); |
125 | } | 125 | } |
126 | 126 | ||
@@ -155,21 +155,18 @@ static u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif, | |||
155 | u8 wl12xx_tx_get_hlid(struct wl1271 *wl, struct wl12xx_vif *wlvif, | 155 | u8 wl12xx_tx_get_hlid(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
156 | struct sk_buff *skb, struct ieee80211_sta *sta) | 156 | struct sk_buff *skb, struct ieee80211_sta *sta) |
157 | { | 157 | { |
158 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 158 | struct ieee80211_tx_info *control; |
159 | |||
160 | if (!wlvif || wl12xx_is_dummy_packet(wl, skb)) | ||
161 | return wl->system_hlid; | ||
162 | 159 | ||
163 | if (wlvif->bss_type == BSS_TYPE_AP_BSS) | 160 | if (wlvif->bss_type == BSS_TYPE_AP_BSS) |
164 | return wl12xx_tx_get_hlid_ap(wl, wlvif, skb, sta); | 161 | return wl12xx_tx_get_hlid_ap(wl, wlvif, skb, sta); |
165 | 162 | ||
166 | if ((test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) || | 163 | control = IEEE80211_SKB_CB(skb); |
167 | test_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags)) && | 164 | if (control->flags & IEEE80211_TX_CTL_TX_OFFCHAN) { |
168 | !ieee80211_is_auth(hdr->frame_control) && | 165 | wl1271_debug(DEBUG_TX, "tx offchannel"); |
169 | !ieee80211_is_assoc_req(hdr->frame_control)) | ||
170 | return wlvif->sta.hlid; | ||
171 | else | ||
172 | return wlvif->dev_hlid; | 166 | return wlvif->dev_hlid; |
167 | } | ||
168 | |||
169 | return wlvif->sta.hlid; | ||
173 | } | 170 | } |
174 | 171 | ||
175 | unsigned int wlcore_calc_packet_alignment(struct wl1271 *wl, | 172 | unsigned int wlcore_calc_packet_alignment(struct wl1271 *wl, |
@@ -224,9 +221,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif, | |||
224 | ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); | 221 | ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); |
225 | wl->tx_allocated_pkts[ac]++; | 222 | wl->tx_allocated_pkts[ac]++; |
226 | 223 | ||
227 | if (!wl12xx_is_dummy_packet(wl, skb) && wlvif && | 224 | if (test_bit(hlid, wl->links_map)) |
228 | wlvif->bss_type == BSS_TYPE_AP_BSS && | ||
229 | test_bit(hlid, wlvif->ap.sta_hlid_map)) | ||
230 | wl->links[hlid].allocated_pkts++; | 225 | wl->links[hlid].allocated_pkts++; |
231 | 226 | ||
232 | ret = 0; | 227 | ret = 0; |
@@ -293,9 +288,14 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif, | |||
293 | 288 | ||
294 | tx_attr |= TX_HW_ATTR_TX_DUMMY_REQ; | 289 | tx_attr |= TX_HW_ATTR_TX_DUMMY_REQ; |
295 | } else if (wlvif) { | 290 | } else if (wlvif) { |
291 | u8 session_id = wl->session_ids[hlid]; | ||
292 | |||
293 | if ((wl->quirks & WLCORE_QUIRK_AP_ZERO_SESSION_ID) && | ||
294 | (wlvif->bss_type == BSS_TYPE_AP_BSS)) | ||
295 | session_id = 0; | ||
296 | |||
296 | /* configure the tx attributes */ | 297 | /* configure the tx attributes */ |
297 | tx_attr = wlvif->session_counter << | 298 | tx_attr = session_id << TX_HW_ATTR_OFST_SESSION_COUNTER; |
298 | TX_HW_ATTR_OFST_SESSION_COUNTER; | ||
299 | } | 299 | } |
300 | 300 | ||
301 | desc->hlid = hlid; | 301 | desc->hlid = hlid; |
@@ -452,20 +452,22 @@ u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set, | |||
452 | void wl1271_handle_tx_low_watermark(struct wl1271 *wl) | 452 | void wl1271_handle_tx_low_watermark(struct wl1271 *wl) |
453 | { | 453 | { |
454 | int i; | 454 | int i; |
455 | struct wl12xx_vif *wlvif; | ||
455 | 456 | ||
456 | for (i = 0; i < NUM_TX_QUEUES; i++) { | 457 | wl12xx_for_each_wlvif(wl, wlvif) { |
457 | if (wlcore_is_queue_stopped_by_reason(wl, i, | 458 | for (i = 0; i < NUM_TX_QUEUES; i++) { |
458 | WLCORE_QUEUE_STOP_REASON_WATERMARK) && | 459 | if (wlcore_is_queue_stopped_by_reason(wl, wlvif, i, |
459 | wl->tx_queue_count[i] <= WL1271_TX_QUEUE_LOW_WATERMARK) { | 460 | WLCORE_QUEUE_STOP_REASON_WATERMARK) && |
460 | /* firmware buffer has space, restart queues */ | 461 | wlvif->tx_queue_count[i] <= |
461 | wlcore_wake_queue(wl, i, | 462 | WL1271_TX_QUEUE_LOW_WATERMARK) |
462 | WLCORE_QUEUE_STOP_REASON_WATERMARK); | 463 | /* firmware buffer has space, restart queues */ |
464 | wlcore_wake_queue(wl, wlvif, i, | ||
465 | WLCORE_QUEUE_STOP_REASON_WATERMARK); | ||
463 | } | 466 | } |
464 | } | 467 | } |
465 | } | 468 | } |
466 | 469 | ||
467 | static struct sk_buff_head *wl1271_select_queue(struct wl1271 *wl, | 470 | static int wlcore_select_ac(struct wl1271 *wl) |
468 | struct sk_buff_head *queues) | ||
469 | { | 471 | { |
470 | int i, q = -1, ac; | 472 | int i, q = -1, ac; |
471 | u32 min_pkts = 0xffffffff; | 473 | u32 min_pkts = 0xffffffff; |
@@ -479,45 +481,60 @@ static struct sk_buff_head *wl1271_select_queue(struct wl1271 *wl, | |||
479 | */ | 481 | */ |
480 | for (i = 0; i < NUM_TX_QUEUES; i++) { | 482 | for (i = 0; i < NUM_TX_QUEUES; i++) { |
481 | ac = wl1271_tx_get_queue(i); | 483 | ac = wl1271_tx_get_queue(i); |
482 | if (!skb_queue_empty(&queues[ac]) && | 484 | if (wl->tx_queue_count[ac] && |
483 | (wl->tx_allocated_pkts[ac] < min_pkts)) { | 485 | wl->tx_allocated_pkts[ac] < min_pkts) { |
484 | q = ac; | 486 | q = ac; |
485 | min_pkts = wl->tx_allocated_pkts[q]; | 487 | min_pkts = wl->tx_allocated_pkts[q]; |
486 | } | 488 | } |
487 | } | 489 | } |
488 | 490 | ||
489 | if (q == -1) | 491 | return q; |
490 | return NULL; | ||
491 | |||
492 | return &queues[q]; | ||
493 | } | 492 | } |
494 | 493 | ||
495 | static struct sk_buff *wl12xx_lnk_skb_dequeue(struct wl1271 *wl, | 494 | static struct sk_buff *wlcore_lnk_dequeue(struct wl1271 *wl, |
496 | struct wl1271_link *lnk) | 495 | struct wl1271_link *lnk, u8 q) |
497 | { | 496 | { |
498 | struct sk_buff *skb; | 497 | struct sk_buff *skb; |
499 | unsigned long flags; | 498 | unsigned long flags; |
500 | struct sk_buff_head *queue; | ||
501 | 499 | ||
502 | queue = wl1271_select_queue(wl, lnk->tx_queue); | 500 | skb = skb_dequeue(&lnk->tx_queue[q]); |
503 | if (!queue) | ||
504 | return NULL; | ||
505 | |||
506 | skb = skb_dequeue(queue); | ||
507 | if (skb) { | 501 | if (skb) { |
508 | int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); | ||
509 | spin_lock_irqsave(&wl->wl_lock, flags); | 502 | spin_lock_irqsave(&wl->wl_lock, flags); |
510 | WARN_ON_ONCE(wl->tx_queue_count[q] <= 0); | 503 | WARN_ON_ONCE(wl->tx_queue_count[q] <= 0); |
511 | wl->tx_queue_count[q]--; | 504 | wl->tx_queue_count[q]--; |
505 | if (lnk->wlvif) { | ||
506 | WARN_ON_ONCE(lnk->wlvif->tx_queue_count[q] <= 0); | ||
507 | lnk->wlvif->tx_queue_count[q]--; | ||
508 | } | ||
512 | spin_unlock_irqrestore(&wl->wl_lock, flags); | 509 | spin_unlock_irqrestore(&wl->wl_lock, flags); |
513 | } | 510 | } |
514 | 511 | ||
515 | return skb; | 512 | return skb; |
516 | } | 513 | } |
517 | 514 | ||
518 | static struct sk_buff *wl12xx_vif_skb_dequeue(struct wl1271 *wl, | 515 | static struct sk_buff *wlcore_lnk_dequeue_high_prio(struct wl1271 *wl, |
519 | struct wl12xx_vif *wlvif, | 516 | u8 hlid, u8 ac, |
520 | u8 *hlid) | 517 | u8 *low_prio_hlid) |
518 | { | ||
519 | struct wl1271_link *lnk = &wl->links[hlid]; | ||
520 | |||
521 | if (!wlcore_hw_lnk_high_prio(wl, hlid, lnk)) { | ||
522 | if (*low_prio_hlid == WL12XX_INVALID_LINK_ID && | ||
523 | !skb_queue_empty(&lnk->tx_queue[ac]) && | ||
524 | wlcore_hw_lnk_low_prio(wl, hlid, lnk)) | ||
525 | /* we found the first non-empty low priority queue */ | ||
526 | *low_prio_hlid = hlid; | ||
527 | |||
528 | return NULL; | ||
529 | } | ||
530 | |||
531 | return wlcore_lnk_dequeue(wl, lnk, ac); | ||
532 | } | ||
533 | |||
534 | static struct sk_buff *wlcore_vif_dequeue_high_prio(struct wl1271 *wl, | ||
535 | struct wl12xx_vif *wlvif, | ||
536 | u8 ac, u8 *hlid, | ||
537 | u8 *low_prio_hlid) | ||
521 | { | 538 | { |
522 | struct sk_buff *skb = NULL; | 539 | struct sk_buff *skb = NULL; |
523 | int i, h, start_hlid; | 540 | int i, h, start_hlid; |
@@ -533,7 +550,8 @@ static struct sk_buff *wl12xx_vif_skb_dequeue(struct wl1271 *wl, | |||
533 | if (!test_bit(h, wlvif->links_map)) | 550 | if (!test_bit(h, wlvif->links_map)) |
534 | continue; | 551 | continue; |
535 | 552 | ||
536 | skb = wl12xx_lnk_skb_dequeue(wl, &wl->links[h]); | 553 | skb = wlcore_lnk_dequeue_high_prio(wl, h, ac, |
554 | low_prio_hlid); | ||
537 | if (!skb) | 555 | if (!skb) |
538 | continue; | 556 | continue; |
539 | 557 | ||
@@ -553,42 +571,74 @@ static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl, u8 *hlid) | |||
553 | unsigned long flags; | 571 | unsigned long flags; |
554 | struct wl12xx_vif *wlvif = wl->last_wlvif; | 572 | struct wl12xx_vif *wlvif = wl->last_wlvif; |
555 | struct sk_buff *skb = NULL; | 573 | struct sk_buff *skb = NULL; |
574 | int ac; | ||
575 | u8 low_prio_hlid = WL12XX_INVALID_LINK_ID; | ||
576 | |||
577 | ac = wlcore_select_ac(wl); | ||
578 | if (ac < 0) | ||
579 | goto out; | ||
556 | 580 | ||
557 | /* continue from last wlvif (round robin) */ | 581 | /* continue from last wlvif (round robin) */ |
558 | if (wlvif) { | 582 | if (wlvif) { |
559 | wl12xx_for_each_wlvif_continue(wl, wlvif) { | 583 | wl12xx_for_each_wlvif_continue(wl, wlvif) { |
560 | skb = wl12xx_vif_skb_dequeue(wl, wlvif, hlid); | 584 | if (!wlvif->tx_queue_count[ac]) |
561 | if (skb) { | 585 | continue; |
562 | wl->last_wlvif = wlvif; | 586 | |
563 | break; | 587 | skb = wlcore_vif_dequeue_high_prio(wl, wlvif, ac, hlid, |
564 | } | 588 | &low_prio_hlid); |
589 | if (!skb) | ||
590 | continue; | ||
591 | |||
592 | wl->last_wlvif = wlvif; | ||
593 | break; | ||
565 | } | 594 | } |
566 | } | 595 | } |
567 | 596 | ||
568 | /* dequeue from the system HLID before the restarting wlvif list */ | 597 | /* dequeue from the system HLID before the restarting wlvif list */ |
569 | if (!skb) { | 598 | if (!skb) { |
570 | skb = wl12xx_lnk_skb_dequeue(wl, &wl->links[wl->system_hlid]); | 599 | skb = wlcore_lnk_dequeue_high_prio(wl, wl->system_hlid, |
571 | *hlid = wl->system_hlid; | 600 | ac, &low_prio_hlid); |
601 | if (skb) { | ||
602 | *hlid = wl->system_hlid; | ||
603 | wl->last_wlvif = NULL; | ||
604 | } | ||
572 | } | 605 | } |
573 | 606 | ||
574 | /* do a new pass over the wlvif list */ | 607 | /* Do a new pass over the wlvif list. But no need to continue |
608 | * after last_wlvif. The previous pass should have found it. */ | ||
575 | if (!skb) { | 609 | if (!skb) { |
576 | wl12xx_for_each_wlvif(wl, wlvif) { | 610 | wl12xx_for_each_wlvif(wl, wlvif) { |
577 | skb = wl12xx_vif_skb_dequeue(wl, wlvif, hlid); | 611 | if (!wlvif->tx_queue_count[ac]) |
612 | goto next; | ||
613 | |||
614 | skb = wlcore_vif_dequeue_high_prio(wl, wlvif, ac, hlid, | ||
615 | &low_prio_hlid); | ||
578 | if (skb) { | 616 | if (skb) { |
579 | wl->last_wlvif = wlvif; | 617 | wl->last_wlvif = wlvif; |
580 | break; | 618 | break; |
581 | } | 619 | } |
582 | 620 | ||
583 | /* | 621 | next: |
584 | * No need to continue after last_wlvif. The previous | ||
585 | * pass should have found it. | ||
586 | */ | ||
587 | if (wlvif == wl->last_wlvif) | 622 | if (wlvif == wl->last_wlvif) |
588 | break; | 623 | break; |
589 | } | 624 | } |
590 | } | 625 | } |
591 | 626 | ||
627 | /* no high priority skbs found - but maybe a low priority one? */ | ||
628 | if (!skb && low_prio_hlid != WL12XX_INVALID_LINK_ID) { | ||
629 | struct wl1271_link *lnk = &wl->links[low_prio_hlid]; | ||
630 | skb = wlcore_lnk_dequeue(wl, lnk, ac); | ||
631 | |||
632 | WARN_ON(!skb); /* we checked this before */ | ||
633 | *hlid = low_prio_hlid; | ||
634 | |||
635 | /* ensure proper round robin in the vif/link levels */ | ||
636 | wl->last_wlvif = lnk->wlvif; | ||
637 | if (lnk->wlvif) | ||
638 | lnk->wlvif->last_tx_hlid = low_prio_hlid; | ||
639 | |||
640 | } | ||
641 | |||
592 | if (!skb && | 642 | if (!skb && |
593 | test_and_clear_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) { | 643 | test_and_clear_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) { |
594 | int q; | 644 | int q; |
@@ -602,6 +652,7 @@ static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl, u8 *hlid) | |||
602 | spin_unlock_irqrestore(&wl->wl_lock, flags); | 652 | spin_unlock_irqrestore(&wl->wl_lock, flags); |
603 | } | 653 | } |
604 | 654 | ||
655 | out: | ||
605 | return skb; | 656 | return skb; |
606 | } | 657 | } |
607 | 658 | ||
@@ -623,6 +674,8 @@ static void wl1271_skb_queue_head(struct wl1271 *wl, struct wl12xx_vif *wlvif, | |||
623 | 674 | ||
624 | spin_lock_irqsave(&wl->wl_lock, flags); | 675 | spin_lock_irqsave(&wl->wl_lock, flags); |
625 | wl->tx_queue_count[q]++; | 676 | wl->tx_queue_count[q]++; |
677 | if (wlvif) | ||
678 | wlvif->tx_queue_count[q]++; | ||
626 | spin_unlock_irqrestore(&wl->wl_lock, flags); | 679 | spin_unlock_irqrestore(&wl->wl_lock, flags); |
627 | } | 680 | } |
628 | 681 | ||
@@ -699,7 +752,7 @@ int wlcore_tx_work_locked(struct wl1271 *wl) | |||
699 | bool has_data = false; | 752 | bool has_data = false; |
700 | 753 | ||
701 | wlvif = NULL; | 754 | wlvif = NULL; |
702 | if (!wl12xx_is_dummy_packet(wl, skb) && info->control.vif) | 755 | if (!wl12xx_is_dummy_packet(wl, skb)) |
703 | wlvif = wl12xx_vif_to_data(info->control.vif); | 756 | wlvif = wl12xx_vif_to_data(info->control.vif); |
704 | else | 757 | else |
705 | hlid = wl->system_hlid; | 758 | hlid = wl->system_hlid; |
@@ -972,10 +1025,11 @@ void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid) | |||
972 | unsigned long flags; | 1025 | unsigned long flags; |
973 | struct ieee80211_tx_info *info; | 1026 | struct ieee80211_tx_info *info; |
974 | int total[NUM_TX_QUEUES]; | 1027 | int total[NUM_TX_QUEUES]; |
1028 | struct wl1271_link *lnk = &wl->links[hlid]; | ||
975 | 1029 | ||
976 | for (i = 0; i < NUM_TX_QUEUES; i++) { | 1030 | for (i = 0; i < NUM_TX_QUEUES; i++) { |
977 | total[i] = 0; | 1031 | total[i] = 0; |
978 | while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) { | 1032 | while ((skb = skb_dequeue(&lnk->tx_queue[i]))) { |
979 | wl1271_debug(DEBUG_TX, "link freeing skb 0x%p", skb); | 1033 | wl1271_debug(DEBUG_TX, "link freeing skb 0x%p", skb); |
980 | 1034 | ||
981 | if (!wl12xx_is_dummy_packet(wl, skb)) { | 1035 | if (!wl12xx_is_dummy_packet(wl, skb)) { |
@@ -990,8 +1044,11 @@ void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid) | |||
990 | } | 1044 | } |
991 | 1045 | ||
992 | spin_lock_irqsave(&wl->wl_lock, flags); | 1046 | spin_lock_irqsave(&wl->wl_lock, flags); |
993 | for (i = 0; i < NUM_TX_QUEUES; i++) | 1047 | for (i = 0; i < NUM_TX_QUEUES; i++) { |
994 | wl->tx_queue_count[i] -= total[i]; | 1048 | wl->tx_queue_count[i] -= total[i]; |
1049 | if (lnk->wlvif) | ||
1050 | lnk->wlvif->tx_queue_count[i] -= total[i]; | ||
1051 | } | ||
995 | spin_unlock_irqrestore(&wl->wl_lock, flags); | 1052 | spin_unlock_irqrestore(&wl->wl_lock, flags); |
996 | 1053 | ||
997 | wl1271_handle_tx_low_watermark(wl); | 1054 | wl1271_handle_tx_low_watermark(wl); |
@@ -1004,16 +1061,18 @@ void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif) | |||
1004 | 1061 | ||
1005 | /* TX failure */ | 1062 | /* TX failure */ |
1006 | for_each_set_bit(i, wlvif->links_map, WL12XX_MAX_LINKS) { | 1063 | for_each_set_bit(i, wlvif->links_map, WL12XX_MAX_LINKS) { |
1007 | if (wlvif->bss_type == BSS_TYPE_AP_BSS) | 1064 | if (wlvif->bss_type == BSS_TYPE_AP_BSS) { |
1065 | /* this calls wl12xx_free_link */ | ||
1008 | wl1271_free_sta(wl, wlvif, i); | 1066 | wl1271_free_sta(wl, wlvif, i); |
1009 | else | 1067 | } else { |
1010 | wlvif->sta.ba_rx_bitmap = 0; | 1068 | u8 hlid = i; |
1011 | 1069 | wl12xx_free_link(wl, wlvif, &hlid); | |
1012 | wl->links[i].allocated_pkts = 0; | 1070 | } |
1013 | wl->links[i].prev_freed_pkts = 0; | ||
1014 | } | 1071 | } |
1015 | wlvif->last_tx_hlid = 0; | 1072 | wlvif->last_tx_hlid = 0; |
1016 | 1073 | ||
1074 | for (i = 0; i < NUM_TX_QUEUES; i++) | ||
1075 | wlvif->tx_queue_count[i] = 0; | ||
1017 | } | 1076 | } |
1018 | /* caller must hold wl->mutex and TX must be stopped */ | 1077 | /* caller must hold wl->mutex and TX must be stopped */ |
1019 | void wl12xx_tx_reset(struct wl1271 *wl) | 1078 | void wl12xx_tx_reset(struct wl1271 *wl) |
@@ -1023,7 +1082,7 @@ void wl12xx_tx_reset(struct wl1271 *wl) | |||
1023 | struct ieee80211_tx_info *info; | 1082 | struct ieee80211_tx_info *info; |
1024 | 1083 | ||
1025 | /* only reset the queues if something bad happened */ | 1084 | /* only reset the queues if something bad happened */ |
1026 | if (WARN_ON_ONCE(wl1271_tx_total_queue_count(wl) != 0)) { | 1085 | if (wl1271_tx_total_queue_count(wl) != 0) { |
1027 | for (i = 0; i < WL12XX_MAX_LINKS; i++) | 1086 | for (i = 0; i < WL12XX_MAX_LINKS; i++) |
1028 | wl1271_tx_reset_link_queues(wl, i); | 1087 | wl1271_tx_reset_link_queues(wl, i); |
1029 | 1088 | ||
@@ -1135,45 +1194,48 @@ u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set) | |||
1135 | 1194 | ||
1136 | return BIT(__ffs(rate_set)); | 1195 | return BIT(__ffs(rate_set)); |
1137 | } | 1196 | } |
1197 | EXPORT_SYMBOL_GPL(wl1271_tx_min_rate_get); | ||
1138 | 1198 | ||
1139 | void wlcore_stop_queue_locked(struct wl1271 *wl, u8 queue, | 1199 | void wlcore_stop_queue_locked(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
1140 | enum wlcore_queue_stop_reason reason) | 1200 | u8 queue, enum wlcore_queue_stop_reason reason) |
1141 | { | 1201 | { |
1142 | bool stopped = !!wl->queue_stop_reasons[queue]; | 1202 | int hwq = wlcore_tx_get_mac80211_queue(wlvif, queue); |
1203 | bool stopped = !!wl->queue_stop_reasons[hwq]; | ||
1143 | 1204 | ||
1144 | /* queue should not be stopped for this reason */ | 1205 | /* queue should not be stopped for this reason */ |
1145 | WARN_ON(test_and_set_bit(reason, &wl->queue_stop_reasons[queue])); | 1206 | WARN_ON_ONCE(test_and_set_bit(reason, &wl->queue_stop_reasons[hwq])); |
1146 | 1207 | ||
1147 | if (stopped) | 1208 | if (stopped) |
1148 | return; | 1209 | return; |
1149 | 1210 | ||
1150 | ieee80211_stop_queue(wl->hw, wl1271_tx_get_mac80211_queue(queue)); | 1211 | ieee80211_stop_queue(wl->hw, hwq); |
1151 | } | 1212 | } |
1152 | 1213 | ||
1153 | void wlcore_stop_queue(struct wl1271 *wl, u8 queue, | 1214 | void wlcore_stop_queue(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 queue, |
1154 | enum wlcore_queue_stop_reason reason) | 1215 | enum wlcore_queue_stop_reason reason) |
1155 | { | 1216 | { |
1156 | unsigned long flags; | 1217 | unsigned long flags; |
1157 | 1218 | ||
1158 | spin_lock_irqsave(&wl->wl_lock, flags); | 1219 | spin_lock_irqsave(&wl->wl_lock, flags); |
1159 | wlcore_stop_queue_locked(wl, queue, reason); | 1220 | wlcore_stop_queue_locked(wl, wlvif, queue, reason); |
1160 | spin_unlock_irqrestore(&wl->wl_lock, flags); | 1221 | spin_unlock_irqrestore(&wl->wl_lock, flags); |
1161 | } | 1222 | } |
1162 | 1223 | ||
1163 | void wlcore_wake_queue(struct wl1271 *wl, u8 queue, | 1224 | void wlcore_wake_queue(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 queue, |
1164 | enum wlcore_queue_stop_reason reason) | 1225 | enum wlcore_queue_stop_reason reason) |
1165 | { | 1226 | { |
1166 | unsigned long flags; | 1227 | unsigned long flags; |
1228 | int hwq = wlcore_tx_get_mac80211_queue(wlvif, queue); | ||
1167 | 1229 | ||
1168 | spin_lock_irqsave(&wl->wl_lock, flags); | 1230 | spin_lock_irqsave(&wl->wl_lock, flags); |
1169 | 1231 | ||
1170 | /* queue should not be clear for this reason */ | 1232 | /* queue should not be clear for this reason */ |
1171 | WARN_ON(!test_and_clear_bit(reason, &wl->queue_stop_reasons[queue])); | 1233 | WARN_ON_ONCE(!test_and_clear_bit(reason, &wl->queue_stop_reasons[hwq])); |
1172 | 1234 | ||
1173 | if (wl->queue_stop_reasons[queue]) | 1235 | if (wl->queue_stop_reasons[hwq]) |
1174 | goto out; | 1236 | goto out; |
1175 | 1237 | ||
1176 | ieee80211_wake_queue(wl->hw, wl1271_tx_get_mac80211_queue(queue)); | 1238 | ieee80211_wake_queue(wl->hw, hwq); |
1177 | 1239 | ||
1178 | out: | 1240 | out: |
1179 | spin_unlock_irqrestore(&wl->wl_lock, flags); | 1241 | spin_unlock_irqrestore(&wl->wl_lock, flags); |
@@ -1183,48 +1245,74 @@ void wlcore_stop_queues(struct wl1271 *wl, | |||
1183 | enum wlcore_queue_stop_reason reason) | 1245 | enum wlcore_queue_stop_reason reason) |
1184 | { | 1246 | { |
1185 | int i; | 1247 | int i; |
1248 | unsigned long flags; | ||
1186 | 1249 | ||
1187 | for (i = 0; i < NUM_TX_QUEUES; i++) | 1250 | spin_lock_irqsave(&wl->wl_lock, flags); |
1188 | wlcore_stop_queue(wl, i, reason); | 1251 | |
1252 | /* mark all possible queues as stopped */ | ||
1253 | for (i = 0; i < WLCORE_NUM_MAC_ADDRESSES * NUM_TX_QUEUES; i++) | ||
1254 | WARN_ON_ONCE(test_and_set_bit(reason, | ||
1255 | &wl->queue_stop_reasons[i])); | ||
1256 | |||
1257 | /* use the global version to make sure all vifs in mac80211 we don't | ||
1258 | * know are stopped. | ||
1259 | */ | ||
1260 | ieee80211_stop_queues(wl->hw); | ||
1261 | |||
1262 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
1189 | } | 1263 | } |
1190 | EXPORT_SYMBOL_GPL(wlcore_stop_queues); | ||
1191 | 1264 | ||
1192 | void wlcore_wake_queues(struct wl1271 *wl, | 1265 | void wlcore_wake_queues(struct wl1271 *wl, |
1193 | enum wlcore_queue_stop_reason reason) | 1266 | enum wlcore_queue_stop_reason reason) |
1194 | { | 1267 | { |
1195 | int i; | 1268 | int i; |
1269 | unsigned long flags; | ||
1196 | 1270 | ||
1197 | for (i = 0; i < NUM_TX_QUEUES; i++) | 1271 | spin_lock_irqsave(&wl->wl_lock, flags); |
1198 | wlcore_wake_queue(wl, i, reason); | 1272 | |
1273 | /* mark all possible queues as awake */ | ||
1274 | for (i = 0; i < WLCORE_NUM_MAC_ADDRESSES * NUM_TX_QUEUES; i++) | ||
1275 | WARN_ON_ONCE(!test_and_clear_bit(reason, | ||
1276 | &wl->queue_stop_reasons[i])); | ||
1277 | |||
1278 | /* use the global version to make sure all vifs in mac80211 we don't | ||
1279 | * know are woken up. | ||
1280 | */ | ||
1281 | ieee80211_wake_queues(wl->hw); | ||
1282 | |||
1283 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
1199 | } | 1284 | } |
1200 | EXPORT_SYMBOL_GPL(wlcore_wake_queues); | ||
1201 | 1285 | ||
1202 | void wlcore_reset_stopped_queues(struct wl1271 *wl) | 1286 | bool wlcore_is_queue_stopped_by_reason(struct wl1271 *wl, |
1287 | struct wl12xx_vif *wlvif, u8 queue, | ||
1288 | enum wlcore_queue_stop_reason reason) | ||
1203 | { | 1289 | { |
1204 | int i; | ||
1205 | unsigned long flags; | 1290 | unsigned long flags; |
1291 | bool stopped; | ||
1206 | 1292 | ||
1207 | spin_lock_irqsave(&wl->wl_lock, flags); | 1293 | spin_lock_irqsave(&wl->wl_lock, flags); |
1208 | 1294 | stopped = wlcore_is_queue_stopped_by_reason_locked(wl, wlvif, queue, | |
1209 | for (i = 0; i < NUM_TX_QUEUES; i++) { | 1295 | reason); |
1210 | if (!wl->queue_stop_reasons[i]) | ||
1211 | continue; | ||
1212 | |||
1213 | wl->queue_stop_reasons[i] = 0; | ||
1214 | ieee80211_wake_queue(wl->hw, | ||
1215 | wl1271_tx_get_mac80211_queue(i)); | ||
1216 | } | ||
1217 | |||
1218 | spin_unlock_irqrestore(&wl->wl_lock, flags); | 1296 | spin_unlock_irqrestore(&wl->wl_lock, flags); |
1297 | |||
1298 | return stopped; | ||
1219 | } | 1299 | } |
1220 | 1300 | ||
1221 | bool wlcore_is_queue_stopped_by_reason(struct wl1271 *wl, u8 queue, | 1301 | bool wlcore_is_queue_stopped_by_reason_locked(struct wl1271 *wl, |
1222 | enum wlcore_queue_stop_reason reason) | 1302 | struct wl12xx_vif *wlvif, u8 queue, |
1303 | enum wlcore_queue_stop_reason reason) | ||
1223 | { | 1304 | { |
1224 | return test_bit(reason, &wl->queue_stop_reasons[queue]); | 1305 | int hwq = wlcore_tx_get_mac80211_queue(wlvif, queue); |
1306 | |||
1307 | WARN_ON_ONCE(!spin_is_locked(&wl->wl_lock)); | ||
1308 | return test_bit(reason, &wl->queue_stop_reasons[hwq]); | ||
1225 | } | 1309 | } |
1226 | 1310 | ||
1227 | bool wlcore_is_queue_stopped(struct wl1271 *wl, u8 queue) | 1311 | bool wlcore_is_queue_stopped_locked(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
1312 | u8 queue) | ||
1228 | { | 1313 | { |
1229 | return !!wl->queue_stop_reasons[queue]; | 1314 | int hwq = wlcore_tx_get_mac80211_queue(wlvif, queue); |
1315 | |||
1316 | WARN_ON_ONCE(!spin_is_locked(&wl->wl_lock)); | ||
1317 | return !!wl->queue_stop_reasons[hwq]; | ||
1230 | } | 1318 | } |
diff --git a/drivers/net/wireless/ti/wlcore/tx.h b/drivers/net/wireless/ti/wlcore/tx.h index 349520d8b724..55aa4acf9105 100644 --- a/drivers/net/wireless/ti/wlcore/tx.h +++ b/drivers/net/wireless/ti/wlcore/tx.h | |||
@@ -207,19 +207,22 @@ static inline int wl1271_tx_get_queue(int queue) | |||
207 | } | 207 | } |
208 | } | 208 | } |
209 | 209 | ||
210 | static inline int wl1271_tx_get_mac80211_queue(int queue) | 210 | static inline |
211 | int wlcore_tx_get_mac80211_queue(struct wl12xx_vif *wlvif, int queue) | ||
211 | { | 212 | { |
213 | int mac_queue = wlvif->hw_queue_base; | ||
214 | |||
212 | switch (queue) { | 215 | switch (queue) { |
213 | case CONF_TX_AC_VO: | 216 | case CONF_TX_AC_VO: |
214 | return 0; | 217 | return mac_queue + 0; |
215 | case CONF_TX_AC_VI: | 218 | case CONF_TX_AC_VI: |
216 | return 1; | 219 | return mac_queue + 1; |
217 | case CONF_TX_AC_BE: | 220 | case CONF_TX_AC_BE: |
218 | return 2; | 221 | return mac_queue + 2; |
219 | case CONF_TX_AC_BK: | 222 | case CONF_TX_AC_BK: |
220 | return 3; | 223 | return mac_queue + 3; |
221 | default: | 224 | default: |
222 | return 2; | 225 | return mac_queue + 2; |
223 | } | 226 | } |
224 | } | 227 | } |
225 | 228 | ||
@@ -252,20 +255,26 @@ void wl12xx_rearm_rx_streaming(struct wl1271 *wl, unsigned long *active_hlids); | |||
252 | unsigned int wlcore_calc_packet_alignment(struct wl1271 *wl, | 255 | unsigned int wlcore_calc_packet_alignment(struct wl1271 *wl, |
253 | unsigned int packet_length); | 256 | unsigned int packet_length); |
254 | void wl1271_free_tx_id(struct wl1271 *wl, int id); | 257 | void wl1271_free_tx_id(struct wl1271 *wl, int id); |
255 | void wlcore_stop_queue_locked(struct wl1271 *wl, u8 queue, | 258 | void wlcore_stop_queue_locked(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
256 | enum wlcore_queue_stop_reason reason); | 259 | u8 queue, enum wlcore_queue_stop_reason reason); |
257 | void wlcore_stop_queue(struct wl1271 *wl, u8 queue, | 260 | void wlcore_stop_queue(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 queue, |
258 | enum wlcore_queue_stop_reason reason); | 261 | enum wlcore_queue_stop_reason reason); |
259 | void wlcore_wake_queue(struct wl1271 *wl, u8 queue, | 262 | void wlcore_wake_queue(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 queue, |
260 | enum wlcore_queue_stop_reason reason); | 263 | enum wlcore_queue_stop_reason reason); |
261 | void wlcore_stop_queues(struct wl1271 *wl, | 264 | void wlcore_stop_queues(struct wl1271 *wl, |
262 | enum wlcore_queue_stop_reason reason); | 265 | enum wlcore_queue_stop_reason reason); |
263 | void wlcore_wake_queues(struct wl1271 *wl, | 266 | void wlcore_wake_queues(struct wl1271 *wl, |
264 | enum wlcore_queue_stop_reason reason); | 267 | enum wlcore_queue_stop_reason reason); |
265 | void wlcore_reset_stopped_queues(struct wl1271 *wl); | 268 | bool wlcore_is_queue_stopped_by_reason(struct wl1271 *wl, |
266 | bool wlcore_is_queue_stopped_by_reason(struct wl1271 *wl, u8 queue, | 269 | struct wl12xx_vif *wlvif, u8 queue, |
267 | enum wlcore_queue_stop_reason reason); | 270 | enum wlcore_queue_stop_reason reason); |
268 | bool wlcore_is_queue_stopped(struct wl1271 *wl, u8 queue); | 271 | bool |
272 | wlcore_is_queue_stopped_by_reason_locked(struct wl1271 *wl, | ||
273 | struct wl12xx_vif *wlvif, | ||
274 | u8 queue, | ||
275 | enum wlcore_queue_stop_reason reason); | ||
276 | bool wlcore_is_queue_stopped_locked(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
277 | u8 queue); | ||
269 | 278 | ||
270 | /* from main.c */ | 279 | /* from main.c */ |
271 | void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid); | 280 | void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid); |
diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h index c3884937c007..ebd8c6fad7cd 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore.h +++ b/drivers/net/wireless/ti/wlcore/wlcore.h | |||
@@ -37,6 +37,9 @@ | |||
37 | */ | 37 | */ |
38 | #define WLCORE_NUM_MAC_ADDRESSES 3 | 38 | #define WLCORE_NUM_MAC_ADDRESSES 3 |
39 | 39 | ||
40 | /* wl12xx/wl18xx maximum transmission power (in dBm) */ | ||
41 | #define WLCORE_MAX_TXPWR 25 | ||
42 | |||
40 | /* forward declaration */ | 43 | /* forward declaration */ |
41 | struct wl1271_tx_hw_descr; | 44 | struct wl1271_tx_hw_descr; |
42 | enum wl_rx_buf_align; | 45 | enum wl_rx_buf_align; |
@@ -51,6 +54,9 @@ struct wlcore_ops { | |||
51 | int (*trigger_cmd)(struct wl1271 *wl, int cmd_box_addr, | 54 | int (*trigger_cmd)(struct wl1271 *wl, int cmd_box_addr, |
52 | void *buf, size_t len); | 55 | void *buf, size_t len); |
53 | int (*ack_event)(struct wl1271 *wl); | 56 | int (*ack_event)(struct wl1271 *wl); |
57 | int (*wait_for_event)(struct wl1271 *wl, enum wlcore_wait_event event, | ||
58 | bool *timeout); | ||
59 | int (*process_mailbox_events)(struct wl1271 *wl); | ||
54 | u32 (*calc_tx_blocks)(struct wl1271 *wl, u32 len, u32 spare_blks); | 60 | u32 (*calc_tx_blocks)(struct wl1271 *wl, u32 len, u32 spare_blks); |
55 | void (*set_tx_desc_blocks)(struct wl1271 *wl, | 61 | void (*set_tx_desc_blocks)(struct wl1271 *wl, |
56 | struct wl1271_tx_hw_descr *desc, | 62 | struct wl1271_tx_hw_descr *desc, |
@@ -82,12 +88,32 @@ struct wlcore_ops { | |||
82 | int (*debugfs_init)(struct wl1271 *wl, struct dentry *rootdir); | 88 | int (*debugfs_init)(struct wl1271 *wl, struct dentry *rootdir); |
83 | int (*handle_static_data)(struct wl1271 *wl, | 89 | int (*handle_static_data)(struct wl1271 *wl, |
84 | struct wl1271_static_data *static_data); | 90 | struct wl1271_static_data *static_data); |
91 | int (*scan_start)(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
92 | struct cfg80211_scan_request *req); | ||
93 | int (*scan_stop)(struct wl1271 *wl, struct wl12xx_vif *wlvif); | ||
94 | int (*sched_scan_start)(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
95 | struct cfg80211_sched_scan_request *req, | ||
96 | struct ieee80211_sched_scan_ies *ies); | ||
97 | void (*sched_scan_stop)(struct wl1271 *wl, struct wl12xx_vif *wlvif); | ||
85 | int (*get_spare_blocks)(struct wl1271 *wl, bool is_gem); | 98 | int (*get_spare_blocks)(struct wl1271 *wl, bool is_gem); |
86 | int (*set_key)(struct wl1271 *wl, enum set_key_cmd cmd, | 99 | int (*set_key)(struct wl1271 *wl, enum set_key_cmd cmd, |
87 | struct ieee80211_vif *vif, | 100 | struct ieee80211_vif *vif, |
88 | struct ieee80211_sta *sta, | 101 | struct ieee80211_sta *sta, |
89 | struct ieee80211_key_conf *key_conf); | 102 | struct ieee80211_key_conf *key_conf); |
103 | int (*channel_switch)(struct wl1271 *wl, | ||
104 | struct wl12xx_vif *wlvif, | ||
105 | struct ieee80211_channel_switch *ch_switch); | ||
90 | u32 (*pre_pkt_send)(struct wl1271 *wl, u32 buf_offset, u32 last_len); | 106 | u32 (*pre_pkt_send)(struct wl1271 *wl, u32 buf_offset, u32 last_len); |
107 | void (*sta_rc_update)(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
108 | struct ieee80211_sta *sta, u32 changed); | ||
109 | int (*set_peer_cap)(struct wl1271 *wl, | ||
110 | struct ieee80211_sta_ht_cap *ht_cap, | ||
111 | bool allow_ht_operation, | ||
112 | u32 rate_set, u8 hlid); | ||
113 | bool (*lnk_high_prio)(struct wl1271 *wl, u8 hlid, | ||
114 | struct wl1271_link *lnk); | ||
115 | bool (*lnk_low_prio)(struct wl1271 *wl, u8 hlid, | ||
116 | struct wl1271_link *lnk); | ||
91 | }; | 117 | }; |
92 | 118 | ||
93 | enum wlcore_partitions { | 119 | enum wlcore_partitions { |
@@ -202,6 +228,8 @@ struct wl1271 { | |||
202 | unsigned long klv_templates_map[ | 228 | unsigned long klv_templates_map[ |
203 | BITS_TO_LONGS(WLCORE_MAX_KLV_TEMPLATES)]; | 229 | BITS_TO_LONGS(WLCORE_MAX_KLV_TEMPLATES)]; |
204 | 230 | ||
231 | u8 session_ids[WL12XX_MAX_LINKS]; | ||
232 | |||
205 | struct list_head wlvif_list; | 233 | struct list_head wlvif_list; |
206 | 234 | ||
207 | u8 sta_count; | 235 | u8 sta_count; |
@@ -227,7 +255,8 @@ struct wl1271 { | |||
227 | 255 | ||
228 | /* Frames scheduled for transmission, not handled yet */ | 256 | /* Frames scheduled for transmission, not handled yet */ |
229 | int tx_queue_count[NUM_TX_QUEUES]; | 257 | int tx_queue_count[NUM_TX_QUEUES]; |
230 | unsigned long queue_stop_reasons[NUM_TX_QUEUES]; | 258 | unsigned long queue_stop_reasons[ |
259 | NUM_TX_QUEUES * WLCORE_NUM_MAC_ADDRESSES]; | ||
231 | 260 | ||
232 | /* Frames received, not handled yet by mac80211 */ | 261 | /* Frames received, not handled yet by mac80211 */ |
233 | struct sk_buff_head deferred_rx_queue; | 262 | struct sk_buff_head deferred_rx_queue; |
@@ -269,24 +298,30 @@ struct wl1271 { | |||
269 | struct work_struct recovery_work; | 298 | struct work_struct recovery_work; |
270 | bool watchdog_recovery; | 299 | bool watchdog_recovery; |
271 | 300 | ||
301 | /* Reg domain last configuration */ | ||
302 | u32 reg_ch_conf_last[2]; | ||
303 | /* Reg domain pending configuration */ | ||
304 | u32 reg_ch_conf_pending[2]; | ||
305 | |||
272 | /* Pointer that holds DMA-friendly block for the mailbox */ | 306 | /* Pointer that holds DMA-friendly block for the mailbox */ |
273 | struct event_mailbox *mbox; | 307 | void *mbox; |
274 | 308 | ||
275 | /* The mbox event mask */ | 309 | /* The mbox event mask */ |
276 | u32 event_mask; | 310 | u32 event_mask; |
277 | 311 | ||
278 | /* Mailbox pointers */ | 312 | /* Mailbox pointers */ |
313 | u32 mbox_size; | ||
279 | u32 mbox_ptr[2]; | 314 | u32 mbox_ptr[2]; |
280 | 315 | ||
281 | /* Are we currently scanning */ | 316 | /* Are we currently scanning */ |
282 | struct ieee80211_vif *scan_vif; | 317 | struct wl12xx_vif *scan_wlvif; |
283 | struct wl1271_scan scan; | 318 | struct wl1271_scan scan; |
284 | struct delayed_work scan_complete_work; | 319 | struct delayed_work scan_complete_work; |
285 | 320 | ||
286 | /* Connection loss work */ | 321 | struct ieee80211_vif *roc_vif; |
287 | struct delayed_work connection_loss_work; | 322 | struct delayed_work roc_complete_work; |
288 | 323 | ||
289 | bool sched_scanning; | 324 | struct wl12xx_vif *sched_vif; |
290 | 325 | ||
291 | /* The current band */ | 326 | /* The current band */ |
292 | enum ieee80211_band band; | 327 | enum ieee80211_band band; |
@@ -299,7 +334,7 @@ struct wl1271 { | |||
299 | 334 | ||
300 | struct wl1271_stats stats; | 335 | struct wl1271_stats stats; |
301 | 336 | ||
302 | __le32 buffer_32; | 337 | __le32 *buffer_32; |
303 | u32 buffer_cmd; | 338 | u32 buffer_cmd; |
304 | u32 buffer_busyword[WL1271_BUSY_WORD_CNT]; | 339 | u32 buffer_busyword[WL1271_BUSY_WORD_CNT]; |
305 | 340 | ||
@@ -314,6 +349,8 @@ struct wl1271 { | |||
314 | 349 | ||
315 | bool enable_11a; | 350 | bool enable_11a; |
316 | 351 | ||
352 | int recovery_count; | ||
353 | |||
317 | /* Most recently reported noise in dBm */ | 354 | /* Most recently reported noise in dBm */ |
318 | s8 noise; | 355 | s8 noise; |
319 | 356 | ||
@@ -333,6 +370,12 @@ struct wl1271 { | |||
333 | */ | 370 | */ |
334 | struct wl1271_link links[WL12XX_MAX_LINKS]; | 371 | struct wl1271_link links[WL12XX_MAX_LINKS]; |
335 | 372 | ||
373 | /* number of currently active links */ | ||
374 | int active_link_count; | ||
375 | |||
376 | /* Fast/slow links bitmap according to FW */ | ||
377 | u32 fw_fast_lnk_map; | ||
378 | |||
336 | /* AP-mode - a bitmap of links currently in PS mode according to FW */ | 379 | /* AP-mode - a bitmap of links currently in PS mode according to FW */ |
337 | u32 ap_fw_ps_map; | 380 | u32 ap_fw_ps_map; |
338 | 381 | ||
@@ -367,6 +410,12 @@ struct wl1271 { | |||
367 | const char *sr_fw_name; | 410 | const char *sr_fw_name; |
368 | const char *mr_fw_name; | 411 | const char *mr_fw_name; |
369 | 412 | ||
413 | u8 scan_templ_id_2_4; | ||
414 | u8 scan_templ_id_5; | ||
415 | u8 sched_scan_templ_id_2_4; | ||
416 | u8 sched_scan_templ_id_5; | ||
417 | u8 max_channels_5; | ||
418 | |||
370 | /* per-chip-family private structure */ | 419 | /* per-chip-family private structure */ |
371 | void *priv; | 420 | void *priv; |
372 | 421 | ||
@@ -408,20 +457,28 @@ struct wl1271 { | |||
408 | /* the number of allocated MAC addresses in this chip */ | 457 | /* the number of allocated MAC addresses in this chip */ |
409 | int num_mac_addr; | 458 | int num_mac_addr; |
410 | 459 | ||
411 | /* the minimum FW version required for the driver to work */ | 460 | /* minimum FW version required for the driver to work in single-role */ |
412 | unsigned int min_fw_ver[NUM_FW_VER]; | 461 | unsigned int min_sr_fw_ver[NUM_FW_VER]; |
462 | |||
463 | /* minimum FW version required for the driver to work in multi-role */ | ||
464 | unsigned int min_mr_fw_ver[NUM_FW_VER]; | ||
413 | 465 | ||
414 | struct completion nvs_loading_complete; | 466 | struct completion nvs_loading_complete; |
467 | |||
468 | /* number of concurrent channels the HW supports */ | ||
469 | u32 num_channels; | ||
415 | }; | 470 | }; |
416 | 471 | ||
417 | int wlcore_probe(struct wl1271 *wl, struct platform_device *pdev); | 472 | int wlcore_probe(struct wl1271 *wl, struct platform_device *pdev); |
418 | int wlcore_remove(struct platform_device *pdev); | 473 | int wlcore_remove(struct platform_device *pdev); |
419 | struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size); | 474 | struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size, |
475 | u32 mbox_size); | ||
420 | int wlcore_free_hw(struct wl1271 *wl); | 476 | int wlcore_free_hw(struct wl1271 *wl); |
421 | int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd, | 477 | int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd, |
422 | struct ieee80211_vif *vif, | 478 | struct ieee80211_vif *vif, |
423 | struct ieee80211_sta *sta, | 479 | struct ieee80211_sta *sta, |
424 | struct ieee80211_key_conf *key_conf); | 480 | struct ieee80211_key_conf *key_conf); |
481 | void wlcore_regdomain_config(struct wl1271 *wl); | ||
425 | 482 | ||
426 | static inline void | 483 | static inline void |
427 | wlcore_set_ht_cap(struct wl1271 *wl, enum ieee80211_band band, | 484 | wlcore_set_ht_cap(struct wl1271 *wl, enum ieee80211_band band, |
@@ -430,16 +487,27 @@ wlcore_set_ht_cap(struct wl1271 *wl, enum ieee80211_band band, | |||
430 | memcpy(&wl->ht_cap[band], ht_cap, sizeof(*ht_cap)); | 487 | memcpy(&wl->ht_cap[band], ht_cap, sizeof(*ht_cap)); |
431 | } | 488 | } |
432 | 489 | ||
490 | /* Tell wlcore not to care about this element when checking the version */ | ||
491 | #define WLCORE_FW_VER_IGNORE -1 | ||
492 | |||
433 | static inline void | 493 | static inline void |
434 | wlcore_set_min_fw_ver(struct wl1271 *wl, unsigned int chip, | 494 | wlcore_set_min_fw_ver(struct wl1271 *wl, unsigned int chip, |
435 | unsigned int iftype, unsigned int major, | 495 | unsigned int iftype_sr, unsigned int major_sr, |
436 | unsigned int subtype, unsigned int minor) | 496 | unsigned int subtype_sr, unsigned int minor_sr, |
497 | unsigned int iftype_mr, unsigned int major_mr, | ||
498 | unsigned int subtype_mr, unsigned int minor_mr) | ||
437 | { | 499 | { |
438 | wl->min_fw_ver[FW_VER_CHIP] = chip; | 500 | wl->min_sr_fw_ver[FW_VER_CHIP] = chip; |
439 | wl->min_fw_ver[FW_VER_IF_TYPE] = iftype; | 501 | wl->min_sr_fw_ver[FW_VER_IF_TYPE] = iftype_sr; |
440 | wl->min_fw_ver[FW_VER_MAJOR] = major; | 502 | wl->min_sr_fw_ver[FW_VER_MAJOR] = major_sr; |
441 | wl->min_fw_ver[FW_VER_SUBTYPE] = subtype; | 503 | wl->min_sr_fw_ver[FW_VER_SUBTYPE] = subtype_sr; |
442 | wl->min_fw_ver[FW_VER_MINOR] = minor; | 504 | wl->min_sr_fw_ver[FW_VER_MINOR] = minor_sr; |
505 | |||
506 | wl->min_mr_fw_ver[FW_VER_CHIP] = chip; | ||
507 | wl->min_mr_fw_ver[FW_VER_IF_TYPE] = iftype_mr; | ||
508 | wl->min_mr_fw_ver[FW_VER_MAJOR] = major_mr; | ||
509 | wl->min_mr_fw_ver[FW_VER_SUBTYPE] = subtype_mr; | ||
510 | wl->min_mr_fw_ver[FW_VER_MINOR] = minor_mr; | ||
443 | } | 511 | } |
444 | 512 | ||
445 | /* Firmware image load chunk size */ | 513 | /* Firmware image load chunk size */ |
@@ -450,6 +518,9 @@ wlcore_set_min_fw_ver(struct wl1271 *wl, unsigned int chip, | |||
450 | /* Each RX/TX transaction requires an end-of-transaction transfer */ | 518 | /* Each RX/TX transaction requires an end-of-transaction transfer */ |
451 | #define WLCORE_QUIRK_END_OF_TRANSACTION BIT(0) | 519 | #define WLCORE_QUIRK_END_OF_TRANSACTION BIT(0) |
452 | 520 | ||
521 | /* the first start_role(sta) sometimes doesn't work on wl12xx */ | ||
522 | #define WLCORE_QUIRK_START_STA_FAILS BIT(1) | ||
523 | |||
453 | /* wl127x and SPI don't support SDIO block size alignment */ | 524 | /* wl127x and SPI don't support SDIO block size alignment */ |
454 | #define WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN BIT(2) | 525 | #define WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN BIT(2) |
455 | 526 | ||
@@ -462,9 +533,6 @@ wlcore_set_min_fw_ver(struct wl1271 *wl, unsigned int chip, | |||
462 | /* Older firmwares use an old NVS format */ | 533 | /* Older firmwares use an old NVS format */ |
463 | #define WLCORE_QUIRK_LEGACY_NVS BIT(5) | 534 | #define WLCORE_QUIRK_LEGACY_NVS BIT(5) |
464 | 535 | ||
465 | /* Some firmwares may not support ELP */ | ||
466 | #define WLCORE_QUIRK_NO_ELP BIT(6) | ||
467 | |||
468 | /* pad only the last frame in the aggregate buffer */ | 536 | /* pad only the last frame in the aggregate buffer */ |
469 | #define WLCORE_QUIRK_TX_PAD_LAST_FRAME BIT(7) | 537 | #define WLCORE_QUIRK_TX_PAD_LAST_FRAME BIT(7) |
470 | 538 | ||
@@ -477,11 +545,11 @@ wlcore_set_min_fw_ver(struct wl1271 *wl, unsigned int chip, | |||
477 | /* separate probe response templates for one-shot and sched scans */ | 545 | /* separate probe response templates for one-shot and sched scans */ |
478 | #define WLCORE_QUIRK_DUAL_PROBE_TMPL BIT(10) | 546 | #define WLCORE_QUIRK_DUAL_PROBE_TMPL BIT(10) |
479 | 547 | ||
480 | /* TODO: move to the lower drivers when all usages are abstracted */ | 548 | /* Firmware requires reg domain configuration for active calibration */ |
481 | #define CHIP_ID_1271_PG10 (0x4030101) | 549 | #define WLCORE_QUIRK_REGDOMAIN_CONF BIT(11) |
482 | #define CHIP_ID_1271_PG20 (0x4030111) | 550 | |
483 | #define CHIP_ID_1283_PG10 (0x05030101) | 551 | /* The FW only support a zero session id for AP */ |
484 | #define CHIP_ID_1283_PG20 (0x05030111) | 552 | #define WLCORE_QUIRK_AP_ZERO_SESSION_ID BIT(12) |
485 | 553 | ||
486 | /* TODO: move all these common registers and values elsewhere */ | 554 | /* TODO: move all these common registers and values elsewhere */ |
487 | #define HW_ACCESS_ELP_CTRL_REG 0x1FFFC | 555 | #define HW_ACCESS_ELP_CTRL_REG 0x1FFFC |
diff --git a/drivers/net/wireless/ti/wlcore/wlcore_i.h b/drivers/net/wireless/ti/wlcore/wlcore_i.h index 5ce26cf402fc..910f8e2e556a 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore_i.h +++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h | |||
@@ -109,17 +109,6 @@ enum { | |||
109 | NUM_FW_VER | 109 | NUM_FW_VER |
110 | }; | 110 | }; |
111 | 111 | ||
112 | #define FW_VER_CHIP_WL127X 6 | ||
113 | #define FW_VER_CHIP_WL128X 7 | ||
114 | |||
115 | #define FW_VER_IF_TYPE_STA 1 | ||
116 | #define FW_VER_IF_TYPE_AP 2 | ||
117 | |||
118 | #define FW_VER_MINOR_1_SPARE_STA_MIN 58 | ||
119 | #define FW_VER_MINOR_1_SPARE_AP_MIN 47 | ||
120 | |||
121 | #define FW_VER_MINOR_FWLOG_STA_MIN 70 | ||
122 | |||
123 | struct wl1271_chip { | 112 | struct wl1271_chip { |
124 | u32 id; | 113 | u32 id; |
125 | char fw_ver_str[ETHTOOL_FWVERS_LEN]; | 114 | char fw_ver_str[ETHTOOL_FWVERS_LEN]; |
@@ -141,7 +130,10 @@ struct wl_fw_packet_counters { | |||
141 | /* Cumulative counter of released Voice memory blocks */ | 130 | /* Cumulative counter of released Voice memory blocks */ |
142 | u8 tx_voice_released_blks; | 131 | u8 tx_voice_released_blks; |
143 | 132 | ||
144 | u8 padding[3]; | 133 | /* Tx rate of the last transmitted packet */ |
134 | u8 tx_last_rate; | ||
135 | |||
136 | u8 padding[2]; | ||
145 | } __packed; | 137 | } __packed; |
146 | 138 | ||
147 | /* FW status registers */ | 139 | /* FW status registers */ |
@@ -260,6 +252,8 @@ enum wl12xx_vif_flags { | |||
260 | WLVIF_FLAG_IN_USE, | 252 | WLVIF_FLAG_IN_USE, |
261 | }; | 253 | }; |
262 | 254 | ||
255 | struct wl12xx_vif; | ||
256 | |||
263 | struct wl1271_link { | 257 | struct wl1271_link { |
264 | /* AP-mode - TX queue per AC in link */ | 258 | /* AP-mode - TX queue per AC in link */ |
265 | struct sk_buff_head tx_queue[NUM_TX_QUEUES]; | 259 | struct sk_buff_head tx_queue[NUM_TX_QUEUES]; |
@@ -272,6 +266,9 @@ struct wl1271_link { | |||
272 | 266 | ||
273 | /* bitmap of TIDs where RX BA sessions are active for this link */ | 267 | /* bitmap of TIDs where RX BA sessions are active for this link */ |
274 | u8 ba_bitmap; | 268 | u8 ba_bitmap; |
269 | |||
270 | /* The wlvif this link belongs to. Might be null for global links */ | ||
271 | struct wl12xx_vif *wlvif; | ||
275 | }; | 272 | }; |
276 | 273 | ||
277 | #define WL1271_MAX_RX_FILTERS 5 | 274 | #define WL1271_MAX_RX_FILTERS 5 |
@@ -315,6 +312,7 @@ struct wl12xx_rx_filter { | |||
315 | 312 | ||
316 | struct wl1271_station { | 313 | struct wl1271_station { |
317 | u8 hlid; | 314 | u8 hlid; |
315 | bool in_connection; | ||
318 | }; | 316 | }; |
319 | 317 | ||
320 | struct wl12xx_vif { | 318 | struct wl12xx_vif { |
@@ -332,7 +330,6 @@ struct wl12xx_vif { | |||
332 | union { | 330 | union { |
333 | struct { | 331 | struct { |
334 | u8 hlid; | 332 | u8 hlid; |
335 | u8 ba_rx_bitmap; | ||
336 | 333 | ||
337 | u8 basic_rate_idx; | 334 | u8 basic_rate_idx; |
338 | u8 ap_rate_idx; | 335 | u8 ap_rate_idx; |
@@ -341,6 +338,8 @@ struct wl12xx_vif { | |||
341 | u8 klv_template_id; | 338 | u8 klv_template_id; |
342 | 339 | ||
343 | bool qos; | 340 | bool qos; |
341 | /* channel type we started the STA role with */ | ||
342 | enum nl80211_channel_type role_chan_type; | ||
344 | } sta; | 343 | } sta; |
345 | struct { | 344 | struct { |
346 | u8 global_hlid; | 345 | u8 global_hlid; |
@@ -362,6 +361,9 @@ struct wl12xx_vif { | |||
362 | /* the hlid of the last transmitted skb */ | 361 | /* the hlid of the last transmitted skb */ |
363 | int last_tx_hlid; | 362 | int last_tx_hlid; |
364 | 363 | ||
364 | /* counters of packets per AC, across all links in the vif */ | ||
365 | int tx_queue_count[NUM_TX_QUEUES]; | ||
366 | |||
365 | unsigned long links_map[BITS_TO_LONGS(WL12XX_MAX_LINKS)]; | 367 | unsigned long links_map[BITS_TO_LONGS(WL12XX_MAX_LINKS)]; |
366 | 368 | ||
367 | u8 ssid[IEEE80211_MAX_SSID_LEN + 1]; | 369 | u8 ssid[IEEE80211_MAX_SSID_LEN + 1]; |
@@ -396,9 +398,6 @@ struct wl12xx_vif { | |||
396 | /* Our association ID */ | 398 | /* Our association ID */ |
397 | u16 aid; | 399 | u16 aid; |
398 | 400 | ||
399 | /* Session counter for the chipset */ | ||
400 | int session_counter; | ||
401 | |||
402 | /* retry counter for PSM entries */ | 401 | /* retry counter for PSM entries */ |
403 | u8 psm_entry_retry; | 402 | u8 psm_entry_retry; |
404 | 403 | ||
@@ -416,11 +415,28 @@ struct wl12xx_vif { | |||
416 | bool ba_support; | 415 | bool ba_support; |
417 | bool ba_allowed; | 416 | bool ba_allowed; |
418 | 417 | ||
418 | bool wmm_enabled; | ||
419 | |||
419 | /* Rx Streaming */ | 420 | /* Rx Streaming */ |
420 | struct work_struct rx_streaming_enable_work; | 421 | struct work_struct rx_streaming_enable_work; |
421 | struct work_struct rx_streaming_disable_work; | 422 | struct work_struct rx_streaming_disable_work; |
422 | struct timer_list rx_streaming_timer; | 423 | struct timer_list rx_streaming_timer; |
423 | 424 | ||
425 | struct delayed_work channel_switch_work; | ||
426 | struct delayed_work connection_loss_work; | ||
427 | |||
428 | /* number of in connection stations */ | ||
429 | int inconn_count; | ||
430 | |||
431 | /* | ||
432 | * This vif's queues are mapped to mac80211 HW queues as: | ||
433 | * VO - hw_queue_base | ||
434 | * VI - hw_queue_base + 1 | ||
435 | * BE - hw_queue_base + 2 | ||
436 | * BK - hw_queue_base + 3 | ||
437 | */ | ||
438 | int hw_queue_base; | ||
439 | |||
424 | /* | 440 | /* |
425 | * This struct must be last! | 441 | * This struct must be last! |
426 | * data that has to be saved acrossed reconfigs (e.g. recovery) | 442 | * data that has to be saved acrossed reconfigs (e.g. recovery) |
@@ -443,6 +459,7 @@ struct wl12xx_vif { | |||
443 | 459 | ||
444 | static inline struct wl12xx_vif *wl12xx_vif_to_data(struct ieee80211_vif *vif) | 460 | static inline struct wl12xx_vif *wl12xx_vif_to_data(struct ieee80211_vif *vif) |
445 | { | 461 | { |
462 | WARN_ON(!vif); | ||
446 | return (struct wl12xx_vif *)vif->drv_priv; | 463 | return (struct wl12xx_vif *)vif->drv_priv; |
447 | } | 464 | } |
448 | 465 | ||
diff --git a/drivers/ssb/driver_gpio.c b/drivers/ssb/driver_gpio.c index 97ac0a38e3d0..accabe39b320 100644 --- a/drivers/ssb/driver_gpio.c +++ b/drivers/ssb/driver_gpio.c | |||
@@ -74,6 +74,16 @@ static void ssb_gpio_chipco_free(struct gpio_chip *chip, unsigned gpio) | |||
74 | ssb_chipco_gpio_pullup(&bus->chipco, 1 << gpio, 0); | 74 | ssb_chipco_gpio_pullup(&bus->chipco, 1 << gpio, 0); |
75 | } | 75 | } |
76 | 76 | ||
77 | static int ssb_gpio_chipco_to_irq(struct gpio_chip *chip, unsigned gpio) | ||
78 | { | ||
79 | struct ssb_bus *bus = ssb_gpio_get_bus(chip); | ||
80 | |||
81 | if (bus->bustype == SSB_BUSTYPE_SSB) | ||
82 | return ssb_mips_irq(bus->chipco.dev) + 2; | ||
83 | else | ||
84 | return -EINVAL; | ||
85 | } | ||
86 | |||
77 | static int ssb_gpio_chipco_init(struct ssb_bus *bus) | 87 | static int ssb_gpio_chipco_init(struct ssb_bus *bus) |
78 | { | 88 | { |
79 | struct gpio_chip *chip = &bus->gpio; | 89 | struct gpio_chip *chip = &bus->gpio; |
@@ -86,6 +96,7 @@ static int ssb_gpio_chipco_init(struct ssb_bus *bus) | |||
86 | chip->set = ssb_gpio_chipco_set_value; | 96 | chip->set = ssb_gpio_chipco_set_value; |
87 | chip->direction_input = ssb_gpio_chipco_direction_input; | 97 | chip->direction_input = ssb_gpio_chipco_direction_input; |
88 | chip->direction_output = ssb_gpio_chipco_direction_output; | 98 | chip->direction_output = ssb_gpio_chipco_direction_output; |
99 | chip->to_irq = ssb_gpio_chipco_to_irq; | ||
89 | chip->ngpio = 16; | 100 | chip->ngpio = 16; |
90 | /* There is just one SoC in one device and its GPIO addresses should be | 101 | /* There is just one SoC in one device and its GPIO addresses should be |
91 | * deterministic to address them more easily. The other buses could get | 102 | * deterministic to address them more easily. The other buses could get |
@@ -134,6 +145,16 @@ static int ssb_gpio_extif_direction_output(struct gpio_chip *chip, | |||
134 | return 0; | 145 | return 0; |
135 | } | 146 | } |
136 | 147 | ||
148 | static int ssb_gpio_extif_to_irq(struct gpio_chip *chip, unsigned gpio) | ||
149 | { | ||
150 | struct ssb_bus *bus = ssb_gpio_get_bus(chip); | ||
151 | |||
152 | if (bus->bustype == SSB_BUSTYPE_SSB) | ||
153 | return ssb_mips_irq(bus->extif.dev) + 2; | ||
154 | else | ||
155 | return -EINVAL; | ||
156 | } | ||
157 | |||
137 | static int ssb_gpio_extif_init(struct ssb_bus *bus) | 158 | static int ssb_gpio_extif_init(struct ssb_bus *bus) |
138 | { | 159 | { |
139 | struct gpio_chip *chip = &bus->gpio; | 160 | struct gpio_chip *chip = &bus->gpio; |
@@ -144,6 +165,7 @@ static int ssb_gpio_extif_init(struct ssb_bus *bus) | |||
144 | chip->set = ssb_gpio_extif_set_value; | 165 | chip->set = ssb_gpio_extif_set_value; |
145 | chip->direction_input = ssb_gpio_extif_direction_input; | 166 | chip->direction_input = ssb_gpio_extif_direction_input; |
146 | chip->direction_output = ssb_gpio_extif_direction_output; | 167 | chip->direction_output = ssb_gpio_extif_direction_output; |
168 | chip->to_irq = ssb_gpio_extif_to_irq; | ||
147 | chip->ngpio = 5; | 169 | chip->ngpio = 5; |
148 | /* There is just one SoC in one device and its GPIO addresses should be | 170 | /* There is just one SoC in one device and its GPIO addresses should be |
149 | * deterministic to address them more easily. The other buses could get | 171 | * deterministic to address them more easily. The other buses could get |
diff --git a/drivers/ssb/driver_mipscore.c b/drivers/ssb/driver_mipscore.c index 2a7684c90243..33b37dac40bd 100644 --- a/drivers/ssb/driver_mipscore.c +++ b/drivers/ssb/driver_mipscore.c | |||
@@ -10,6 +10,7 @@ | |||
10 | 10 | ||
11 | #include <linux/ssb/ssb.h> | 11 | #include <linux/ssb/ssb.h> |
12 | 12 | ||
13 | #include <linux/mtd/physmap.h> | ||
13 | #include <linux/serial.h> | 14 | #include <linux/serial.h> |
14 | #include <linux/serial_core.h> | 15 | #include <linux/serial_core.h> |
15 | #include <linux/serial_reg.h> | 16 | #include <linux/serial_reg.h> |
@@ -17,6 +18,25 @@ | |||
17 | 18 | ||
18 | #include "ssb_private.h" | 19 | #include "ssb_private.h" |
19 | 20 | ||
21 | static const char *part_probes[] = { "bcm47xxpart", NULL }; | ||
22 | |||
23 | static struct physmap_flash_data ssb_pflash_data = { | ||
24 | .part_probe_types = part_probes, | ||
25 | }; | ||
26 | |||
27 | static struct resource ssb_pflash_resource = { | ||
28 | .name = "ssb_pflash", | ||
29 | .flags = IORESOURCE_MEM, | ||
30 | }; | ||
31 | |||
32 | struct platform_device ssb_pflash_dev = { | ||
33 | .name = "physmap-flash", | ||
34 | .dev = { | ||
35 | .platform_data = &ssb_pflash_data, | ||
36 | }, | ||
37 | .resource = &ssb_pflash_resource, | ||
38 | .num_resources = 1, | ||
39 | }; | ||
20 | 40 | ||
21 | static inline u32 mips_read32(struct ssb_mipscore *mcore, | 41 | static inline u32 mips_read32(struct ssb_mipscore *mcore, |
22 | u16 offset) | 42 | u16 offset) |
@@ -189,14 +209,15 @@ static void ssb_mips_serial_init(struct ssb_mipscore *mcore) | |||
189 | static void ssb_mips_flash_detect(struct ssb_mipscore *mcore) | 209 | static void ssb_mips_flash_detect(struct ssb_mipscore *mcore) |
190 | { | 210 | { |
191 | struct ssb_bus *bus = mcore->dev->bus; | 211 | struct ssb_bus *bus = mcore->dev->bus; |
212 | struct ssb_pflash *pflash = &mcore->pflash; | ||
192 | 213 | ||
193 | /* When there is no chipcommon on the bus there is 4MB flash */ | 214 | /* When there is no chipcommon on the bus there is 4MB flash */ |
194 | if (!ssb_chipco_available(&bus->chipco)) { | 215 | if (!ssb_chipco_available(&bus->chipco)) { |
195 | mcore->pflash.present = true; | 216 | pflash->present = true; |
196 | mcore->pflash.buswidth = 2; | 217 | pflash->buswidth = 2; |
197 | mcore->pflash.window = SSB_FLASH1; | 218 | pflash->window = SSB_FLASH1; |
198 | mcore->pflash.window_size = SSB_FLASH1_SZ; | 219 | pflash->window_size = SSB_FLASH1_SZ; |
199 | return; | 220 | goto ssb_pflash; |
200 | } | 221 | } |
201 | 222 | ||
202 | /* There is ChipCommon, so use it to read info about flash */ | 223 | /* There is ChipCommon, so use it to read info about flash */ |
@@ -208,16 +229,23 @@ static void ssb_mips_flash_detect(struct ssb_mipscore *mcore) | |||
208 | break; | 229 | break; |
209 | case SSB_CHIPCO_FLASHT_PARA: | 230 | case SSB_CHIPCO_FLASHT_PARA: |
210 | pr_debug("Found parallel flash\n"); | 231 | pr_debug("Found parallel flash\n"); |
211 | mcore->pflash.present = true; | 232 | pflash->present = true; |
212 | mcore->pflash.window = SSB_FLASH2; | 233 | pflash->window = SSB_FLASH2; |
213 | mcore->pflash.window_size = SSB_FLASH2_SZ; | 234 | pflash->window_size = SSB_FLASH2_SZ; |
214 | if ((ssb_read32(bus->chipco.dev, SSB_CHIPCO_FLASH_CFG) | 235 | if ((ssb_read32(bus->chipco.dev, SSB_CHIPCO_FLASH_CFG) |
215 | & SSB_CHIPCO_CFG_DS16) == 0) | 236 | & SSB_CHIPCO_CFG_DS16) == 0) |
216 | mcore->pflash.buswidth = 1; | 237 | pflash->buswidth = 1; |
217 | else | 238 | else |
218 | mcore->pflash.buswidth = 2; | 239 | pflash->buswidth = 2; |
219 | break; | 240 | break; |
220 | } | 241 | } |
242 | |||
243 | ssb_pflash: | ||
244 | if (pflash->present) { | ||
245 | ssb_pflash_data.width = pflash->buswidth; | ||
246 | ssb_pflash_resource.start = pflash->window; | ||
247 | ssb_pflash_resource.end = pflash->window + pflash->window_size; | ||
248 | } | ||
221 | } | 249 | } |
222 | 250 | ||
223 | u32 ssb_cpu_clock(struct ssb_mipscore *mcore) | 251 | u32 ssb_cpu_clock(struct ssb_mipscore *mcore) |
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index 772ad9b5c304..9987d9f366f4 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c | |||
@@ -540,6 +540,14 @@ static int ssb_devices_register(struct ssb_bus *bus) | |||
540 | dev_idx++; | 540 | dev_idx++; |
541 | } | 541 | } |
542 | 542 | ||
543 | #ifdef CONFIG_SSB_DRIVER_MIPS | ||
544 | if (bus->mipscore.pflash.present) { | ||
545 | err = platform_device_register(&ssb_pflash_dev); | ||
546 | if (err) | ||
547 | pr_err("Error registering parallel flash\n"); | ||
548 | } | ||
549 | #endif | ||
550 | |||
543 | return 0; | 551 | return 0; |
544 | error: | 552 | error: |
545 | /* Unwind the already registered devices. */ | 553 | /* Unwind the already registered devices. */ |
diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h index 77d942630750..53198dcec90e 100644 --- a/drivers/ssb/ssb_private.h +++ b/drivers/ssb/ssb_private.h | |||
@@ -228,6 +228,10 @@ static inline int ssb_sflash_init(struct ssb_chipcommon *cc) | |||
228 | } | 228 | } |
229 | #endif /* CONFIG_SSB_SFLASH */ | 229 | #endif /* CONFIG_SSB_SFLASH */ |
230 | 230 | ||
231 | #ifdef CONFIG_SSB_DRIVER_MIPS | ||
232 | extern struct platform_device ssb_pflash_dev; | ||
233 | #endif | ||
234 | |||
231 | #ifdef CONFIG_SSB_DRIVER_EXTIF | 235 | #ifdef CONFIG_SSB_DRIVER_EXTIF |
232 | extern u32 ssb_extif_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt, u32 ticks); | 236 | extern u32 ssb_extif_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt, u32 ticks); |
233 | extern u32 ssb_extif_watchdog_timer_set_ms(struct bcm47xx_wdt *wdt, u32 ms); | 237 | extern u32 ssb_extif_watchdog_timer_set_ms(struct bcm47xx_wdt *wdt, u32 ms); |