diff options
Diffstat (limited to 'drivers/net/wireless/wl12xx')
47 files changed, 11109 insertions, 1553 deletions
diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig index 82a0f97975de..7b14d5bc63d6 100644 --- a/drivers/net/wireless/wl12xx/Kconfig +++ b/drivers/net/wireless/wl12xx/Kconfig | |||
@@ -7,12 +7,46 @@ menuconfig WL12XX | |||
7 | 7 | ||
8 | config WL1251 | 8 | config WL1251 |
9 | tristate "TI wl1251 support" | 9 | tristate "TI wl1251 support" |
10 | depends on WL12XX && SPI_MASTER && GENERIC_HARDIRQS | 10 | depends on WL12XX && GENERIC_HARDIRQS |
11 | select FW_LOADER | 11 | select FW_LOADER |
12 | select CRC7 | 12 | select CRC7 |
13 | ---help--- | 13 | ---help--- |
14 | This module adds support for wireless adapters based on | 14 | This module adds support for wireless adapters based on |
15 | TI wl1251 chipset. | 15 | TI wl1251 chipset. |
16 | 16 | ||
17 | If you choose to build a module, it'll be called wl1251. Say N if | 17 | If you choose to build a module, it'll be called wl1251. Say |
18 | N if unsure. | ||
19 | |||
20 | config WL1251_SPI | ||
21 | tristate "TI wl1251 SPI support" | ||
22 | depends on WL1251 && SPI_MASTER | ||
23 | ---help--- | ||
24 | This module adds support for the SPI interface of adapters using | ||
25 | TI wl1251 chipset. Select this if your platform is using | ||
26 | the SPI bus. | ||
27 | |||
28 | If you choose to build a module, it'll be called wl1251_spi. | ||
29 | Say N if unsure. | ||
30 | |||
31 | config WL1251_SDIO | ||
32 | tristate "TI wl1251 SDIO support" | ||
33 | depends on WL1251 && MMC | ||
34 | ---help--- | ||
35 | This module adds support for the SDIO interface of adapters using | ||
36 | TI wl1251 chipset. Select this if your platform is using | ||
37 | the SDIO bus. | ||
38 | |||
39 | If you choose to build a module, it'll be called | ||
40 | wl1251_sdio. Say N if unsure. | ||
41 | |||
42 | config WL1271 | ||
43 | tristate "TI wl1271 support" | ||
44 | depends on WL12XX && SPI_MASTER && GENERIC_HARDIRQS | ||
45 | select FW_LOADER | ||
46 | select CRC7 | ||
47 | ---help--- | ||
48 | This module adds support for wireless adapters based on the | ||
49 | TI wl1271 chipset. | ||
50 | |||
51 | If you choose to build a module, it'll be called wl1271. Say N if | ||
18 | unsure. | 52 | unsure. |
diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile index d5595a841f5f..62e37ad01cc0 100644 --- a/drivers/net/wireless/wl12xx/Makefile +++ b/drivers/net/wireless/wl12xx/Makefile | |||
@@ -1,5 +1,14 @@ | |||
1 | wl1251-objs = wl1251_main.o wl1251_spi.o wl1251_event.o \ | 1 | wl1251-objs = wl1251_main.o wl1251_event.o \ |
2 | wl1251_tx.o wl1251_rx.o wl1251_ps.o wl1251_cmd.o \ | 2 | wl1251_tx.o wl1251_rx.o wl1251_ps.o wl1251_cmd.o \ |
3 | wl1251_acx.o wl1251_boot.o wl1251_init.o \ | 3 | wl1251_acx.o wl1251_boot.o wl1251_init.o \ |
4 | wl1251_ops.o wl1251_debugfs.o | 4 | wl1251_debugfs.o wl1251_io.o |
5 | |||
5 | obj-$(CONFIG_WL1251) += wl1251.o | 6 | obj-$(CONFIG_WL1251) += wl1251.o |
7 | obj-$(CONFIG_WL1251_SPI) += wl1251_spi.o | ||
8 | obj-$(CONFIG_WL1251_SDIO) += wl1251_sdio.o | ||
9 | |||
10 | wl1271-objs = wl1271_main.o wl1271_spi.o wl1271_cmd.o \ | ||
11 | wl1271_event.o wl1271_tx.o wl1271_rx.o \ | ||
12 | wl1271_ps.o wl1271_acx.o wl1271_boot.o \ | ||
13 | wl1271_init.o wl1271_debugfs.o | ||
14 | obj-$(CONFIG_WL1271) += wl1271.o | ||
diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h index 665aca02bea9..998e4b6252bd 100644 --- a/drivers/net/wireless/wl12xx/wl1251.h +++ b/drivers/net/wireless/wl12xx/wl1251.h | |||
@@ -143,35 +143,6 @@ struct wl1251_partition_set { | |||
143 | 143 | ||
144 | struct wl1251; | 144 | struct wl1251; |
145 | 145 | ||
146 | /* FIXME: I'm not sure about this structure name */ | ||
147 | struct wl1251_chip { | ||
148 | u32 id; | ||
149 | |||
150 | const char *fw_filename; | ||
151 | const char *nvs_filename; | ||
152 | |||
153 | char fw_ver[21]; | ||
154 | |||
155 | unsigned int power_on_sleep; | ||
156 | int intr_cmd_complete; | ||
157 | int intr_init_complete; | ||
158 | |||
159 | int (*op_upload_fw)(struct wl1251 *wl); | ||
160 | int (*op_upload_nvs)(struct wl1251 *wl); | ||
161 | int (*op_boot)(struct wl1251 *wl); | ||
162 | void (*op_set_ecpu_ctrl)(struct wl1251 *wl, u32 flag); | ||
163 | void (*op_target_enable_interrupts)(struct wl1251 *wl); | ||
164 | int (*op_hw_init)(struct wl1251 *wl); | ||
165 | int (*op_plt_init)(struct wl1251 *wl); | ||
166 | void (*op_tx_flush)(struct wl1251 *wl); | ||
167 | void (*op_fw_version)(struct wl1251 *wl); | ||
168 | int (*op_cmd_join)(struct wl1251 *wl, u8 bss_type, u8 dtim_interval, | ||
169 | u16 beacon_interval, u8 wait); | ||
170 | |||
171 | struct wl1251_partition_set *p_table; | ||
172 | enum wl12xx_acx_int_reg *acx_reg_table; | ||
173 | }; | ||
174 | |||
175 | struct wl1251_stats { | 146 | struct wl1251_stats { |
176 | struct acx_statistics *fw_stats; | 147 | struct acx_statistics *fw_stats; |
177 | unsigned long fw_stats_update; | 148 | unsigned long fw_stats_update; |
@@ -281,11 +252,20 @@ struct wl1251_debugfs { | |||
281 | struct dentry *excessive_retries; | 252 | struct dentry *excessive_retries; |
282 | }; | 253 | }; |
283 | 254 | ||
255 | struct wl1251_if_operations { | ||
256 | void (*read)(struct wl1251 *wl, int addr, void *buf, size_t len); | ||
257 | void (*write)(struct wl1251 *wl, int addr, void *buf, size_t len); | ||
258 | void (*reset)(struct wl1251 *wl); | ||
259 | void (*enable_irq)(struct wl1251 *wl); | ||
260 | void (*disable_irq)(struct wl1251 *wl); | ||
261 | }; | ||
262 | |||
284 | struct wl1251 { | 263 | struct wl1251 { |
285 | struct ieee80211_hw *hw; | 264 | struct ieee80211_hw *hw; |
286 | bool mac80211_registered; | 265 | bool mac80211_registered; |
287 | 266 | ||
288 | struct spi_device *spi; | 267 | void *if_priv; |
268 | const struct wl1251_if_operations *if_ops; | ||
289 | 269 | ||
290 | void (*set_power)(bool enable); | 270 | void (*set_power)(bool enable); |
291 | int irq; | 271 | int irq; |
@@ -298,8 +278,6 @@ struct wl1251 { | |||
298 | int virtual_mem_addr; | 278 | int virtual_mem_addr; |
299 | int virtual_reg_addr; | 279 | int virtual_reg_addr; |
300 | 280 | ||
301 | struct wl1251_chip chip; | ||
302 | |||
303 | int cmd_box_addr; | 281 | int cmd_box_addr; |
304 | int event_box_addr; | 282 | int event_box_addr; |
305 | struct boot_attr boot_attr; | 283 | struct boot_attr boot_attr; |
@@ -382,6 +360,9 @@ struct wl1251 { | |||
382 | /* PSM mode requested */ | 360 | /* PSM mode requested */ |
383 | bool psm_requested; | 361 | bool psm_requested; |
384 | 362 | ||
363 | u16 beacon_int; | ||
364 | u8 dtim_period; | ||
365 | |||
385 | /* in dBm */ | 366 | /* in dBm */ |
386 | int power_level; | 367 | int power_level; |
387 | 368 | ||
@@ -392,11 +373,20 @@ struct wl1251 { | |||
392 | u32 buffer_cmd; | 373 | u32 buffer_cmd; |
393 | u8 buffer_busyword[WL1251_BUSY_WORD_LEN]; | 374 | u8 buffer_busyword[WL1251_BUSY_WORD_LEN]; |
394 | struct wl1251_rx_descriptor *rx_descriptor; | 375 | struct wl1251_rx_descriptor *rx_descriptor; |
376 | |||
377 | u32 chip_id; | ||
378 | char fw_ver[21]; | ||
395 | }; | 379 | }; |
396 | 380 | ||
397 | int wl1251_plt_start(struct wl1251 *wl); | 381 | int wl1251_plt_start(struct wl1251 *wl); |
398 | int wl1251_plt_stop(struct wl1251 *wl); | 382 | int wl1251_plt_stop(struct wl1251 *wl); |
399 | 383 | ||
384 | struct ieee80211_hw *wl1251_alloc_hw(void); | ||
385 | int wl1251_free_hw(struct wl1251 *wl); | ||
386 | int wl1251_init_ieee80211(struct wl1251 *wl); | ||
387 | void wl1251_enable_interrupts(struct wl1251 *wl); | ||
388 | void wl1251_disable_interrupts(struct wl1251 *wl); | ||
389 | |||
400 | #define DEFAULT_HW_GEN_MODULATION_TYPE CCK_LONG /* Long Preamble */ | 390 | #define DEFAULT_HW_GEN_MODULATION_TYPE CCK_LONG /* Long Preamble */ |
401 | #define DEFAULT_HW_GEN_TX_RATE RATE_2MBPS | 391 | #define DEFAULT_HW_GEN_TX_RATE RATE_2MBPS |
402 | #define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */ | 392 | #define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */ |
@@ -405,11 +395,10 @@ int wl1251_plt_stop(struct wl1251 *wl); | |||
405 | 395 | ||
406 | #define WL1251_TX_QUEUE_MAX_LENGTH 20 | 396 | #define WL1251_TX_QUEUE_MAX_LENGTH 20 |
407 | 397 | ||
408 | /* Different chips need different sleep times after power on. WL1271 needs | 398 | #define WL1251_DEFAULT_BEACON_INT 100 |
409 | * 200ms, WL1251 needs only 10ms. By default we use 200ms, but as soon as we | 399 | #define WL1251_DEFAULT_DTIM_PERIOD 1 |
410 | * know the chip ID, we change the sleep value in the wl1251 chip structure, | 400 | |
411 | * so in subsequent power ons, we don't waste more time then needed. */ | 401 | #define WL1251_DEFAULT_CHANNEL 0 |
412 | #define WL1251_DEFAULT_POWER_ON_SLEEP 200 | ||
413 | 402 | ||
414 | #define CHIP_ID_1251_PG10 (0x7010101) | 403 | #define CHIP_ID_1251_PG10 (0x7010101) |
415 | #define CHIP_ID_1251_PG11 (0x7020101) | 404 | #define CHIP_ID_1251_PG11 (0x7020101) |
@@ -417,4 +406,19 @@ int wl1251_plt_stop(struct wl1251 *wl); | |||
417 | #define CHIP_ID_1271_PG10 (0x4030101) | 406 | #define CHIP_ID_1271_PG10 (0x4030101) |
418 | #define CHIP_ID_1271_PG20 (0x4030111) | 407 | #define CHIP_ID_1271_PG20 (0x4030111) |
419 | 408 | ||
409 | #define WL1251_FW_NAME "wl1251-fw.bin" | ||
410 | #define WL1251_NVS_NAME "wl1251-nvs.bin" | ||
411 | |||
412 | #define WL1251_POWER_ON_SLEEP 10 /* in miliseconds */ | ||
413 | |||
414 | #define WL1251_PART_DOWN_MEM_START 0x0 | ||
415 | #define WL1251_PART_DOWN_MEM_SIZE 0x16800 | ||
416 | #define WL1251_PART_DOWN_REG_START REGISTERS_BASE | ||
417 | #define WL1251_PART_DOWN_REG_SIZE REGISTERS_DOWN_SIZE | ||
418 | |||
419 | #define WL1251_PART_WORK_MEM_START 0x28000 | ||
420 | #define WL1251_PART_WORK_MEM_SIZE 0x14000 | ||
421 | #define WL1251_PART_WORK_REG_START REGISTERS_BASE | ||
422 | #define WL1251_PART_WORK_REG_SIZE REGISTERS_WORK_SIZE | ||
423 | |||
420 | #endif | 424 | #endif |
diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.c b/drivers/net/wireless/wl12xx/wl1251_acx.c index a46c92a29526..10b26c4532c9 100644 --- a/drivers/net/wireless/wl12xx/wl1251_acx.c +++ b/drivers/net/wireless/wl12xx/wl1251_acx.c | |||
@@ -2,11 +2,10 @@ | |||
2 | 2 | ||
3 | #include <linux/module.h> | 3 | #include <linux/module.h> |
4 | #include <linux/crc7.h> | 4 | #include <linux/crc7.h> |
5 | #include <linux/spi/spi.h> | ||
6 | 5 | ||
7 | #include "wl1251.h" | 6 | #include "wl1251.h" |
8 | #include "reg.h" | 7 | #include "wl1251_reg.h" |
9 | #include "wl1251_spi.h" | 8 | #include "wl1251_cmd.h" |
10 | #include "wl1251_ps.h" | 9 | #include "wl1251_ps.h" |
11 | 10 | ||
12 | int wl1251_acx_frame_rates(struct wl1251 *wl, u8 ctrl_rate, u8 ctrl_mod, | 11 | int wl1251_acx_frame_rates(struct wl1251 *wl, u8 ctrl_rate, u8 ctrl_mod, |
@@ -838,3 +837,82 @@ int wl1251_acx_statistics(struct wl1251 *wl, struct acx_statistics *stats) | |||
838 | 837 | ||
839 | return 0; | 838 | return 0; |
840 | } | 839 | } |
840 | |||
841 | int wl1251_acx_rate_policies(struct wl1251 *wl) | ||
842 | { | ||
843 | struct acx_rate_policy *acx; | ||
844 | int ret = 0; | ||
845 | |||
846 | wl1251_debug(DEBUG_ACX, "acx rate policies"); | ||
847 | |||
848 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
849 | |||
850 | if (!acx) { | ||
851 | ret = -ENOMEM; | ||
852 | goto out; | ||
853 | } | ||
854 | |||
855 | /* configure one default (one-size-fits-all) rate class */ | ||
856 | acx->rate_class_cnt = 1; | ||
857 | acx->rate_class[0].enabled_rates = ACX_RATE_MASK_UNSPECIFIED; | ||
858 | acx->rate_class[0].short_retry_limit = ACX_RATE_RETRY_LIMIT; | ||
859 | acx->rate_class[0].long_retry_limit = ACX_RATE_RETRY_LIMIT; | ||
860 | acx->rate_class[0].aflags = 0; | ||
861 | |||
862 | ret = wl1251_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); | ||
863 | if (ret < 0) { | ||
864 | wl1251_warning("Setting of rate policies failed: %d", ret); | ||
865 | goto out; | ||
866 | } | ||
867 | |||
868 | out: | ||
869 | kfree(acx); | ||
870 | return ret; | ||
871 | } | ||
872 | |||
873 | int wl1251_acx_mem_cfg(struct wl1251 *wl) | ||
874 | { | ||
875 | struct wl1251_acx_config_memory *mem_conf; | ||
876 | int ret, i; | ||
877 | |||
878 | wl1251_debug(DEBUG_ACX, "acx mem cfg"); | ||
879 | |||
880 | mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL); | ||
881 | if (!mem_conf) { | ||
882 | ret = -ENOMEM; | ||
883 | goto out; | ||
884 | } | ||
885 | |||
886 | /* memory config */ | ||
887 | mem_conf->mem_config.num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS); | ||
888 | mem_conf->mem_config.rx_mem_block_num = 35; | ||
889 | mem_conf->mem_config.tx_min_mem_block_num = 64; | ||
890 | mem_conf->mem_config.num_tx_queues = MAX_TX_QUEUES; | ||
891 | mem_conf->mem_config.host_if_options = HOSTIF_PKT_RING; | ||
892 | mem_conf->mem_config.num_ssid_profiles = 1; | ||
893 | mem_conf->mem_config.debug_buffer_size = | ||
894 | cpu_to_le16(TRACE_BUFFER_MAX_SIZE); | ||
895 | |||
896 | /* RX queue config */ | ||
897 | mem_conf->rx_queue_config.dma_address = 0; | ||
898 | mem_conf->rx_queue_config.num_descs = ACX_RX_DESC_DEF; | ||
899 | mem_conf->rx_queue_config.priority = DEFAULT_RXQ_PRIORITY; | ||
900 | mem_conf->rx_queue_config.type = DEFAULT_RXQ_TYPE; | ||
901 | |||
902 | /* TX queue config */ | ||
903 | for (i = 0; i < MAX_TX_QUEUES; i++) { | ||
904 | mem_conf->tx_queue_config[i].num_descs = ACX_TX_DESC_DEF; | ||
905 | mem_conf->tx_queue_config[i].attributes = i; | ||
906 | } | ||
907 | |||
908 | ret = wl1251_cmd_configure(wl, ACX_MEM_CFG, mem_conf, | ||
909 | sizeof(*mem_conf)); | ||
910 | if (ret < 0) { | ||
911 | wl1251_warning("wl1251 mem config failed: %d", ret); | ||
912 | goto out; | ||
913 | } | ||
914 | |||
915 | out: | ||
916 | kfree(mem_conf); | ||
917 | return ret; | ||
918 | } | ||
diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.h b/drivers/net/wireless/wl12xx/wl1251_acx.h index 2e7b1933a8f9..cafb91459504 100644 --- a/drivers/net/wireless/wl12xx/wl1251_acx.h +++ b/drivers/net/wireless/wl12xx/wl1251_acx.h | |||
@@ -1031,6 +1031,150 @@ struct acx_statistics { | |||
1031 | struct acx_rxpipe_statistics rxpipe; | 1031 | struct acx_rxpipe_statistics rxpipe; |
1032 | } __attribute__ ((packed)); | 1032 | } __attribute__ ((packed)); |
1033 | 1033 | ||
1034 | #define ACX_MAX_RATE_CLASSES 8 | ||
1035 | #define ACX_RATE_MASK_UNSPECIFIED 0 | ||
1036 | #define ACX_RATE_RETRY_LIMIT 10 | ||
1037 | |||
1038 | struct acx_rate_class { | ||
1039 | u32 enabled_rates; | ||
1040 | u8 short_retry_limit; | ||
1041 | u8 long_retry_limit; | ||
1042 | u8 aflags; | ||
1043 | u8 reserved; | ||
1044 | }; | ||
1045 | |||
1046 | struct acx_rate_policy { | ||
1047 | struct acx_header header; | ||
1048 | |||
1049 | u32 rate_class_cnt; | ||
1050 | struct acx_rate_class rate_class[ACX_MAX_RATE_CLASSES]; | ||
1051 | } __attribute__ ((packed)); | ||
1052 | |||
1053 | struct wl1251_acx_memory { | ||
1054 | __le16 num_stations; /* number of STAs to be supported. */ | ||
1055 | u16 reserved_1; | ||
1056 | |||
1057 | /* | ||
1058 | * Nmber of memory buffers for the RX mem pool. | ||
1059 | * The actual number may be less if there are | ||
1060 | * not enough blocks left for the minimum num | ||
1061 | * of TX ones. | ||
1062 | */ | ||
1063 | u8 rx_mem_block_num; | ||
1064 | u8 reserved_2; | ||
1065 | u8 num_tx_queues; /* From 1 to 16 */ | ||
1066 | u8 host_if_options; /* HOST_IF* */ | ||
1067 | u8 tx_min_mem_block_num; | ||
1068 | u8 num_ssid_profiles; | ||
1069 | __le16 debug_buffer_size; | ||
1070 | } __attribute__ ((packed)); | ||
1071 | |||
1072 | |||
1073 | #define ACX_RX_DESC_MIN 1 | ||
1074 | #define ACX_RX_DESC_MAX 127 | ||
1075 | #define ACX_RX_DESC_DEF 32 | ||
1076 | struct wl1251_acx_rx_queue_config { | ||
1077 | u8 num_descs; | ||
1078 | u8 pad; | ||
1079 | u8 type; | ||
1080 | u8 priority; | ||
1081 | __le32 dma_address; | ||
1082 | } __attribute__ ((packed)); | ||
1083 | |||
1084 | #define ACX_TX_DESC_MIN 1 | ||
1085 | #define ACX_TX_DESC_MAX 127 | ||
1086 | #define ACX_TX_DESC_DEF 16 | ||
1087 | struct wl1251_acx_tx_queue_config { | ||
1088 | u8 num_descs; | ||
1089 | u8 pad[2]; | ||
1090 | u8 attributes; | ||
1091 | } __attribute__ ((packed)); | ||
1092 | |||
1093 | #define MAX_TX_QUEUE_CONFIGS 5 | ||
1094 | #define MAX_TX_QUEUES 4 | ||
1095 | struct wl1251_acx_config_memory { | ||
1096 | struct acx_header header; | ||
1097 | |||
1098 | struct wl1251_acx_memory mem_config; | ||
1099 | struct wl1251_acx_rx_queue_config rx_queue_config; | ||
1100 | struct wl1251_acx_tx_queue_config tx_queue_config[MAX_TX_QUEUE_CONFIGS]; | ||
1101 | } __attribute__ ((packed)); | ||
1102 | |||
1103 | struct wl1251_acx_mem_map { | ||
1104 | struct acx_header header; | ||
1105 | |||
1106 | void *code_start; | ||
1107 | void *code_end; | ||
1108 | |||
1109 | void *wep_defkey_start; | ||
1110 | void *wep_defkey_end; | ||
1111 | |||
1112 | void *sta_table_start; | ||
1113 | void *sta_table_end; | ||
1114 | |||
1115 | void *packet_template_start; | ||
1116 | void *packet_template_end; | ||
1117 | |||
1118 | void *queue_memory_start; | ||
1119 | void *queue_memory_end; | ||
1120 | |||
1121 | void *packet_memory_pool_start; | ||
1122 | void *packet_memory_pool_end; | ||
1123 | |||
1124 | void *debug_buffer1_start; | ||
1125 | void *debug_buffer1_end; | ||
1126 | |||
1127 | void *debug_buffer2_start; | ||
1128 | void *debug_buffer2_end; | ||
1129 | |||
1130 | /* Number of blocks FW allocated for TX packets */ | ||
1131 | u32 num_tx_mem_blocks; | ||
1132 | |||
1133 | /* Number of blocks FW allocated for RX packets */ | ||
1134 | u32 num_rx_mem_blocks; | ||
1135 | } __attribute__ ((packed)); | ||
1136 | |||
1137 | /************************************************************************* | ||
1138 | |||
1139 | Host Interrupt Register (WiLink -> Host) | ||
1140 | |||
1141 | **************************************************************************/ | ||
1142 | |||
1143 | /* RX packet is ready in Xfer buffer #0 */ | ||
1144 | #define WL1251_ACX_INTR_RX0_DATA BIT(0) | ||
1145 | |||
1146 | /* TX result(s) are in the TX complete buffer */ | ||
1147 | #define WL1251_ACX_INTR_TX_RESULT BIT(1) | ||
1148 | |||
1149 | /* OBSOLETE */ | ||
1150 | #define WL1251_ACX_INTR_TX_XFR BIT(2) | ||
1151 | |||
1152 | /* RX packet is ready in Xfer buffer #1 */ | ||
1153 | #define WL1251_ACX_INTR_RX1_DATA BIT(3) | ||
1154 | |||
1155 | /* Event was entered to Event MBOX #A */ | ||
1156 | #define WL1251_ACX_INTR_EVENT_A BIT(4) | ||
1157 | |||
1158 | /* Event was entered to Event MBOX #B */ | ||
1159 | #define WL1251_ACX_INTR_EVENT_B BIT(5) | ||
1160 | |||
1161 | /* OBSOLETE */ | ||
1162 | #define WL1251_ACX_INTR_WAKE_ON_HOST BIT(6) | ||
1163 | |||
1164 | /* Trace meassge on MBOX #A */ | ||
1165 | #define WL1251_ACX_INTR_TRACE_A BIT(7) | ||
1166 | |||
1167 | /* Trace meassge on MBOX #B */ | ||
1168 | #define WL1251_ACX_INTR_TRACE_B BIT(8) | ||
1169 | |||
1170 | /* Command processing completion */ | ||
1171 | #define WL1251_ACX_INTR_CMD_COMPLETE BIT(9) | ||
1172 | |||
1173 | /* Init sequence is done */ | ||
1174 | #define WL1251_ACX_INTR_INIT_COMPLETE BIT(14) | ||
1175 | |||
1176 | #define WL1251_ACX_INTR_ALL 0xFFFFFFFF | ||
1177 | |||
1034 | enum { | 1178 | enum { |
1035 | ACX_WAKE_UP_CONDITIONS = 0x0002, | 1179 | ACX_WAKE_UP_CONDITIONS = 0x0002, |
1036 | ACX_MEM_CFG = 0x0003, | 1180 | ACX_MEM_CFG = 0x0003, |
@@ -1142,5 +1286,7 @@ int wl1251_acx_cts_protect(struct wl1251 *wl, | |||
1142 | enum acx_ctsprotect_type ctsprotect); | 1286 | enum acx_ctsprotect_type ctsprotect); |
1143 | int wl1251_acx_statistics(struct wl1251 *wl, struct acx_statistics *stats); | 1287 | int wl1251_acx_statistics(struct wl1251 *wl, struct acx_statistics *stats); |
1144 | int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime); | 1288 | int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime); |
1289 | int wl1251_acx_rate_policies(struct wl1251 *wl); | ||
1290 | int wl1251_acx_mem_cfg(struct wl1251 *wl); | ||
1145 | 1291 | ||
1146 | #endif /* __WL1251_ACX_H__ */ | 1292 | #endif /* __WL1251_ACX_H__ */ |
diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.c b/drivers/net/wireless/wl12xx/wl1251_boot.c index d8a155dc2fa1..592c3b5cc8f8 100644 --- a/drivers/net/wireless/wl12xx/wl1251_boot.c +++ b/drivers/net/wireless/wl12xx/wl1251_boot.c | |||
@@ -23,15 +23,12 @@ | |||
23 | 23 | ||
24 | #include <linux/gpio.h> | 24 | #include <linux/gpio.h> |
25 | 25 | ||
26 | #include "reg.h" | 26 | #include "wl1251_reg.h" |
27 | #include "wl1251_boot.h" | 27 | #include "wl1251_boot.h" |
28 | #include "wl1251_io.h" | ||
28 | #include "wl1251_spi.h" | 29 | #include "wl1251_spi.h" |
29 | #include "wl1251_event.h" | 30 | #include "wl1251_event.h" |
30 | 31 | #include "wl1251_acx.h" | |
31 | static void wl1251_boot_enable_interrupts(struct wl1251 *wl) | ||
32 | { | ||
33 | enable_irq(wl->irq); | ||
34 | } | ||
35 | 32 | ||
36 | void wl1251_boot_target_enable_interrupts(struct wl1251 *wl) | 33 | void wl1251_boot_target_enable_interrupts(struct wl1251 *wl) |
37 | { | 34 | { |
@@ -212,18 +209,30 @@ int wl1251_boot_init_seq(struct wl1251 *wl) | |||
212 | return 0; | 209 | return 0; |
213 | } | 210 | } |
214 | 211 | ||
212 | static void wl1251_boot_set_ecpu_ctrl(struct wl1251 *wl, u32 flag) | ||
213 | { | ||
214 | u32 cpu_ctrl; | ||
215 | |||
216 | /* 10.5.0 run the firmware (I) */ | ||
217 | cpu_ctrl = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL); | ||
218 | |||
219 | /* 10.5.1 run the firmware (II) */ | ||
220 | cpu_ctrl &= ~flag; | ||
221 | wl1251_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl); | ||
222 | } | ||
223 | |||
215 | int wl1251_boot_run_firmware(struct wl1251 *wl) | 224 | int wl1251_boot_run_firmware(struct wl1251 *wl) |
216 | { | 225 | { |
217 | int loop, ret; | 226 | int loop, ret; |
218 | u32 chip_id, interrupt; | 227 | u32 chip_id, interrupt; |
219 | 228 | ||
220 | wl->chip.op_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT); | 229 | wl1251_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT); |
221 | 230 | ||
222 | chip_id = wl1251_reg_read32(wl, CHIP_ID_B); | 231 | chip_id = wl1251_reg_read32(wl, CHIP_ID_B); |
223 | 232 | ||
224 | wl1251_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id); | 233 | wl1251_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id); |
225 | 234 | ||
226 | if (chip_id != wl->chip.id) { | 235 | if (chip_id != wl->chip_id) { |
227 | wl1251_error("chip id doesn't match after firmware boot"); | 236 | wl1251_error("chip id doesn't match after firmware boot"); |
228 | return -EIO; | 237 | return -EIO; |
229 | } | 238 | } |
@@ -240,9 +249,9 @@ int wl1251_boot_run_firmware(struct wl1251 *wl) | |||
240 | return -EIO; | 249 | return -EIO; |
241 | } | 250 | } |
242 | /* check that ACX_INTR_INIT_COMPLETE is enabled */ | 251 | /* check that ACX_INTR_INIT_COMPLETE is enabled */ |
243 | else if (interrupt & wl->chip.intr_init_complete) { | 252 | else if (interrupt & WL1251_ACX_INTR_INIT_COMPLETE) { |
244 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_ACK, | 253 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_ACK, |
245 | wl->chip.intr_init_complete); | 254 | WL1251_ACX_INTR_INIT_COMPLETE); |
246 | break; | 255 | break; |
247 | } | 256 | } |
248 | } | 257 | } |
@@ -260,16 +269,15 @@ int wl1251_boot_run_firmware(struct wl1251 *wl) | |||
260 | wl->event_box_addr = wl1251_reg_read32(wl, REG_EVENT_MAILBOX_PTR); | 269 | wl->event_box_addr = wl1251_reg_read32(wl, REG_EVENT_MAILBOX_PTR); |
261 | 270 | ||
262 | /* set the working partition to its "running" mode offset */ | 271 | /* set the working partition to its "running" mode offset */ |
263 | wl1251_set_partition(wl, | 272 | wl1251_set_partition(wl, WL1251_PART_WORK_MEM_START, |
264 | wl->chip.p_table[PART_WORK].mem.start, | 273 | WL1251_PART_WORK_MEM_SIZE, |
265 | wl->chip.p_table[PART_WORK].mem.size, | 274 | WL1251_PART_WORK_REG_START, |
266 | wl->chip.p_table[PART_WORK].reg.start, | 275 | WL1251_PART_WORK_REG_SIZE); |
267 | wl->chip.p_table[PART_WORK].reg.size); | ||
268 | 276 | ||
269 | wl1251_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x", | 277 | wl1251_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x", |
270 | wl->cmd_box_addr, wl->event_box_addr); | 278 | wl->cmd_box_addr, wl->event_box_addr); |
271 | 279 | ||
272 | wl->chip.op_fw_version(wl); | 280 | wl1251_acx_fw_version(wl, wl->fw_ver, sizeof(wl->fw_ver)); |
273 | 281 | ||
274 | /* | 282 | /* |
275 | * in case of full asynchronous mode the firmware event must be | 283 | * in case of full asynchronous mode the firmware event must be |
@@ -277,9 +285,16 @@ int wl1251_boot_run_firmware(struct wl1251 *wl) | |||
277 | */ | 285 | */ |
278 | 286 | ||
279 | /* enable gpio interrupts */ | 287 | /* enable gpio interrupts */ |
280 | wl1251_boot_enable_interrupts(wl); | 288 | wl1251_enable_interrupts(wl); |
281 | 289 | ||
282 | wl->chip.op_target_enable_interrupts(wl); | 290 | /* Enable target's interrupts */ |
291 | wl->intr_mask = WL1251_ACX_INTR_RX0_DATA | | ||
292 | WL1251_ACX_INTR_RX1_DATA | | ||
293 | WL1251_ACX_INTR_TX_RESULT | | ||
294 | WL1251_ACX_INTR_EVENT_A | | ||
295 | WL1251_ACX_INTR_EVENT_B | | ||
296 | WL1251_ACX_INTR_INIT_COMPLETE; | ||
297 | wl1251_boot_target_enable_interrupts(wl); | ||
283 | 298 | ||
284 | /* unmask all mbox events */ | 299 | /* unmask all mbox events */ |
285 | wl->event_mask = 0xffffffff; | 300 | wl->event_mask = 0xffffffff; |
@@ -295,3 +310,218 @@ int wl1251_boot_run_firmware(struct wl1251 *wl) | |||
295 | /* firmware startup completed */ | 310 | /* firmware startup completed */ |
296 | return 0; | 311 | return 0; |
297 | } | 312 | } |
313 | |||
314 | static int wl1251_boot_upload_firmware(struct wl1251 *wl) | ||
315 | { | ||
316 | int addr, chunk_num, partition_limit; | ||
317 | size_t fw_data_len; | ||
318 | u8 *p; | ||
319 | |||
320 | /* whal_FwCtrl_LoadFwImageSm() */ | ||
321 | |||
322 | wl1251_debug(DEBUG_BOOT, "chip id before fw upload: 0x%x", | ||
323 | wl1251_reg_read32(wl, CHIP_ID_B)); | ||
324 | |||
325 | /* 10.0 check firmware length and set partition */ | ||
326 | fw_data_len = (wl->fw[4] << 24) | (wl->fw[5] << 16) | | ||
327 | (wl->fw[6] << 8) | (wl->fw[7]); | ||
328 | |||
329 | wl1251_debug(DEBUG_BOOT, "fw_data_len %zu chunk_size %d", fw_data_len, | ||
330 | CHUNK_SIZE); | ||
331 | |||
332 | if ((fw_data_len % 4) != 0) { | ||
333 | wl1251_error("firmware length not multiple of four"); | ||
334 | return -EIO; | ||
335 | } | ||
336 | |||
337 | wl1251_set_partition(wl, WL1251_PART_DOWN_MEM_START, | ||
338 | WL1251_PART_DOWN_MEM_SIZE, | ||
339 | WL1251_PART_DOWN_REG_START, | ||
340 | WL1251_PART_DOWN_REG_SIZE); | ||
341 | |||
342 | /* 10.1 set partition limit and chunk num */ | ||
343 | chunk_num = 0; | ||
344 | partition_limit = WL1251_PART_DOWN_MEM_SIZE; | ||
345 | |||
346 | while (chunk_num < fw_data_len / CHUNK_SIZE) { | ||
347 | /* 10.2 update partition, if needed */ | ||
348 | addr = WL1251_PART_DOWN_MEM_START + | ||
349 | (chunk_num + 2) * CHUNK_SIZE; | ||
350 | if (addr > partition_limit) { | ||
351 | addr = WL1251_PART_DOWN_MEM_START + | ||
352 | chunk_num * CHUNK_SIZE; | ||
353 | partition_limit = chunk_num * CHUNK_SIZE + | ||
354 | WL1251_PART_DOWN_MEM_SIZE; | ||
355 | wl1251_set_partition(wl, | ||
356 | addr, | ||
357 | WL1251_PART_DOWN_MEM_SIZE, | ||
358 | WL1251_PART_DOWN_REG_START, | ||
359 | WL1251_PART_DOWN_REG_SIZE); | ||
360 | } | ||
361 | |||
362 | /* 10.3 upload the chunk */ | ||
363 | addr = WL1251_PART_DOWN_MEM_START + chunk_num * CHUNK_SIZE; | ||
364 | p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; | ||
365 | wl1251_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x", | ||
366 | p, addr); | ||
367 | wl1251_mem_write(wl, addr, p, CHUNK_SIZE); | ||
368 | |||
369 | chunk_num++; | ||
370 | } | ||
371 | |||
372 | /* 10.4 upload the last chunk */ | ||
373 | addr = WL1251_PART_DOWN_MEM_START + chunk_num * CHUNK_SIZE; | ||
374 | p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; | ||
375 | wl1251_debug(DEBUG_BOOT, "uploading fw last chunk (%zu B) 0x%p to 0x%x", | ||
376 | fw_data_len % CHUNK_SIZE, p, addr); | ||
377 | wl1251_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE); | ||
378 | |||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | static int wl1251_boot_upload_nvs(struct wl1251 *wl) | ||
383 | { | ||
384 | size_t nvs_len, nvs_bytes_written, burst_len; | ||
385 | int nvs_start, i; | ||
386 | u32 dest_addr, val; | ||
387 | u8 *nvs_ptr, *nvs; | ||
388 | |||
389 | nvs = wl->nvs; | ||
390 | if (nvs == NULL) | ||
391 | return -ENODEV; | ||
392 | |||
393 | nvs_ptr = nvs; | ||
394 | |||
395 | nvs_len = wl->nvs_len; | ||
396 | nvs_start = wl->fw_len; | ||
397 | |||
398 | /* | ||
399 | * Layout before the actual NVS tables: | ||
400 | * 1 byte : burst length. | ||
401 | * 2 bytes: destination address. | ||
402 | * n bytes: data to burst copy. | ||
403 | * | ||
404 | * This is ended by a 0 length, then the NVS tables. | ||
405 | */ | ||
406 | |||
407 | while (nvs_ptr[0]) { | ||
408 | burst_len = nvs_ptr[0]; | ||
409 | dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8)); | ||
410 | |||
411 | /* We move our pointer to the data */ | ||
412 | nvs_ptr += 3; | ||
413 | |||
414 | for (i = 0; i < burst_len; i++) { | ||
415 | val = (nvs_ptr[0] | (nvs_ptr[1] << 8) | ||
416 | | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); | ||
417 | |||
418 | wl1251_debug(DEBUG_BOOT, | ||
419 | "nvs burst write 0x%x: 0x%x", | ||
420 | dest_addr, val); | ||
421 | wl1251_mem_write32(wl, dest_addr, val); | ||
422 | |||
423 | nvs_ptr += 4; | ||
424 | dest_addr += 4; | ||
425 | } | ||
426 | } | ||
427 | |||
428 | /* | ||
429 | * We've reached the first zero length, the first NVS table | ||
430 | * is 7 bytes further. | ||
431 | */ | ||
432 | nvs_ptr += 7; | ||
433 | nvs_len -= nvs_ptr - nvs; | ||
434 | nvs_len = ALIGN(nvs_len, 4); | ||
435 | |||
436 | /* Now we must set the partition correctly */ | ||
437 | wl1251_set_partition(wl, nvs_start, | ||
438 | WL1251_PART_DOWN_MEM_SIZE, | ||
439 | WL1251_PART_DOWN_REG_START, | ||
440 | WL1251_PART_DOWN_REG_SIZE); | ||
441 | |||
442 | /* And finally we upload the NVS tables */ | ||
443 | nvs_bytes_written = 0; | ||
444 | while (nvs_bytes_written < nvs_len) { | ||
445 | val = (nvs_ptr[0] | (nvs_ptr[1] << 8) | ||
446 | | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); | ||
447 | |||
448 | val = cpu_to_le32(val); | ||
449 | |||
450 | wl1251_debug(DEBUG_BOOT, | ||
451 | "nvs write table 0x%x: 0x%x", | ||
452 | nvs_start, val); | ||
453 | wl1251_mem_write32(wl, nvs_start, val); | ||
454 | |||
455 | nvs_ptr += 4; | ||
456 | nvs_bytes_written += 4; | ||
457 | nvs_start += 4; | ||
458 | } | ||
459 | |||
460 | return 0; | ||
461 | } | ||
462 | |||
463 | int wl1251_boot(struct wl1251 *wl) | ||
464 | { | ||
465 | int ret = 0, minor_minor_e2_ver; | ||
466 | u32 tmp, boot_data; | ||
467 | |||
468 | ret = wl1251_boot_soft_reset(wl); | ||
469 | if (ret < 0) | ||
470 | goto out; | ||
471 | |||
472 | /* 2. start processing NVS file */ | ||
473 | ret = wl1251_boot_upload_nvs(wl); | ||
474 | if (ret < 0) | ||
475 | goto out; | ||
476 | |||
477 | /* write firmware's last address (ie. it's length) to | ||
478 | * ACX_EEPROMLESS_IND_REG */ | ||
479 | wl1251_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len); | ||
480 | |||
481 | /* 6. read the EEPROM parameters */ | ||
482 | tmp = wl1251_reg_read32(wl, SCR_PAD2); | ||
483 | |||
484 | /* 7. read bootdata */ | ||
485 | wl->boot_attr.radio_type = (tmp & 0x0000FF00) >> 8; | ||
486 | wl->boot_attr.major = (tmp & 0x00FF0000) >> 16; | ||
487 | tmp = wl1251_reg_read32(wl, SCR_PAD3); | ||
488 | |||
489 | /* 8. check bootdata and call restart sequence */ | ||
490 | wl->boot_attr.minor = (tmp & 0x00FF0000) >> 16; | ||
491 | minor_minor_e2_ver = (tmp & 0xFF000000) >> 24; | ||
492 | |||
493 | wl1251_debug(DEBUG_BOOT, "radioType 0x%x majorE2Ver 0x%x " | ||
494 | "minorE2Ver 0x%x minor_minor_e2_ver 0x%x", | ||
495 | wl->boot_attr.radio_type, wl->boot_attr.major, | ||
496 | wl->boot_attr.minor, minor_minor_e2_ver); | ||
497 | |||
498 | ret = wl1251_boot_init_seq(wl); | ||
499 | if (ret < 0) | ||
500 | goto out; | ||
501 | |||
502 | /* 9. NVS processing done */ | ||
503 | boot_data = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL); | ||
504 | |||
505 | wl1251_debug(DEBUG_BOOT, "halt boot_data 0x%x", boot_data); | ||
506 | |||
507 | /* 10. check that ECPU_CONTROL_HALT bits are set in | ||
508 | * pWhalBus->uBootData and start uploading firmware | ||
509 | */ | ||
510 | if ((boot_data & ECPU_CONTROL_HALT) == 0) { | ||
511 | wl1251_error("boot failed, ECPU_CONTROL_HALT not set"); | ||
512 | ret = -EIO; | ||
513 | goto out; | ||
514 | } | ||
515 | |||
516 | ret = wl1251_boot_upload_firmware(wl); | ||
517 | if (ret < 0) | ||
518 | goto out; | ||
519 | |||
520 | /* 10.5 start firmware */ | ||
521 | ret = wl1251_boot_run_firmware(wl); | ||
522 | if (ret < 0) | ||
523 | goto out; | ||
524 | |||
525 | out: | ||
526 | return ret; | ||
527 | } | ||
diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.h b/drivers/net/wireless/wl12xx/wl1251_boot.h index 798362d71e3f..90063697e8f2 100644 --- a/drivers/net/wireless/wl12xx/wl1251_boot.h +++ b/drivers/net/wireless/wl12xx/wl1251_boot.h | |||
@@ -30,6 +30,7 @@ int wl1251_boot_soft_reset(struct wl1251 *wl); | |||
30 | int wl1251_boot_init_seq(struct wl1251 *wl); | 30 | int wl1251_boot_init_seq(struct wl1251 *wl); |
31 | int wl1251_boot_run_firmware(struct wl1251 *wl); | 31 | int wl1251_boot_run_firmware(struct wl1251 *wl); |
32 | void wl1251_boot_target_enable_interrupts(struct wl1251 *wl); | 32 | void wl1251_boot_target_enable_interrupts(struct wl1251 *wl); |
33 | int wl1251_boot(struct wl1251 *wl); | ||
33 | 34 | ||
34 | /* number of times we try to read the INIT interrupt */ | 35 | /* number of times we try to read the INIT interrupt */ |
35 | #define INIT_LOOP 20000 | 36 | #define INIT_LOOP 20000 |
diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c index dc04d1fc2ee4..770f260726bd 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.c | |||
@@ -2,11 +2,10 @@ | |||
2 | 2 | ||
3 | #include <linux/module.h> | 3 | #include <linux/module.h> |
4 | #include <linux/crc7.h> | 4 | #include <linux/crc7.h> |
5 | #include <linux/spi/spi.h> | ||
6 | 5 | ||
7 | #include "wl1251.h" | 6 | #include "wl1251.h" |
8 | #include "reg.h" | 7 | #include "wl1251_reg.h" |
9 | #include "wl1251_spi.h" | 8 | #include "wl1251_io.h" |
10 | #include "wl1251_ps.h" | 9 | #include "wl1251_ps.h" |
11 | #include "wl1251_acx.h" | 10 | #include "wl1251_acx.h" |
12 | 11 | ||
@@ -31,14 +30,14 @@ int wl1251_cmd_send(struct wl1251 *wl, u16 id, void *buf, size_t len) | |||
31 | 30 | ||
32 | WARN_ON(len % 4 != 0); | 31 | WARN_ON(len % 4 != 0); |
33 | 32 | ||
34 | wl1251_spi_mem_write(wl, wl->cmd_box_addr, buf, len); | 33 | wl1251_mem_write(wl, wl->cmd_box_addr, buf, len); |
35 | 34 | ||
36 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); | 35 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); |
37 | 36 | ||
38 | timeout = jiffies + msecs_to_jiffies(WL1251_COMMAND_TIMEOUT); | 37 | timeout = jiffies + msecs_to_jiffies(WL1251_COMMAND_TIMEOUT); |
39 | 38 | ||
40 | intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); | 39 | intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); |
41 | while (!(intr & wl->chip.intr_cmd_complete)) { | 40 | while (!(intr & WL1251_ACX_INTR_CMD_COMPLETE)) { |
42 | if (time_after(jiffies, timeout)) { | 41 | if (time_after(jiffies, timeout)) { |
43 | wl1251_error("command complete timeout"); | 42 | wl1251_error("command complete timeout"); |
44 | ret = -ETIMEDOUT; | 43 | ret = -ETIMEDOUT; |
@@ -51,7 +50,7 @@ int wl1251_cmd_send(struct wl1251 *wl, u16 id, void *buf, size_t len) | |||
51 | } | 50 | } |
52 | 51 | ||
53 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_ACK, | 52 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_ACK, |
54 | wl->chip.intr_cmd_complete); | 53 | WL1251_ACX_INTR_CMD_COMPLETE); |
55 | 54 | ||
56 | out: | 55 | out: |
57 | return ret; | 56 | return ret; |
@@ -86,7 +85,7 @@ int wl1251_cmd_test(struct wl1251 *wl, void *buf, size_t buf_len, u8 answer) | |||
86 | * The answer would be a wl1251_command, where the | 85 | * The answer would be a wl1251_command, where the |
87 | * parameter array contains the actual answer. | 86 | * parameter array contains the actual answer. |
88 | */ | 87 | */ |
89 | wl1251_spi_mem_read(wl, wl->cmd_box_addr, buf, buf_len); | 88 | wl1251_mem_read(wl, wl->cmd_box_addr, buf, buf_len); |
90 | 89 | ||
91 | cmd_answer = buf; | 90 | cmd_answer = buf; |
92 | 91 | ||
@@ -125,7 +124,7 @@ int wl1251_cmd_interrogate(struct wl1251 *wl, u16 id, void *buf, size_t len) | |||
125 | } | 124 | } |
126 | 125 | ||
127 | /* the interrogate command got in, we can read the answer */ | 126 | /* the interrogate command got in, we can read the answer */ |
128 | wl1251_spi_mem_read(wl, wl->cmd_box_addr, buf, len); | 127 | wl1251_mem_read(wl, wl->cmd_box_addr, buf, len); |
129 | 128 | ||
130 | acx = buf; | 129 | acx = buf; |
131 | if (acx->cmd.status != CMD_STATUS_SUCCESS) | 130 | if (acx->cmd.status != CMD_STATUS_SUCCESS) |
@@ -252,10 +251,9 @@ out: | |||
252 | return ret; | 251 | return ret; |
253 | } | 252 | } |
254 | 253 | ||
255 | int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 dtim_interval, | 254 | int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 channel, |
256 | u16 beacon_interval, u8 wait) | 255 | u16 beacon_interval, u8 dtim_interval) |
257 | { | 256 | { |
258 | unsigned long timeout; | ||
259 | struct cmd_join *join; | 257 | struct cmd_join *join; |
260 | int ret, i; | 258 | int ret, i; |
261 | u8 *bssid; | 259 | u8 *bssid; |
@@ -266,15 +264,9 @@ int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 dtim_interval, | |||
266 | goto out; | 264 | goto out; |
267 | } | 265 | } |
268 | 266 | ||
269 | /* FIXME: this should be in main.c */ | 267 | wl1251_debug(DEBUG_CMD, "cmd join%s ch %d %d/%d", |
270 | ret = wl1251_acx_frame_rates(wl, DEFAULT_HW_GEN_TX_RATE, | 268 | bss_type == BSS_TYPE_IBSS ? " ibss" : "", |
271 | DEFAULT_HW_GEN_MODULATION_TYPE, | 269 | channel, beacon_interval, dtim_interval); |
272 | wl->tx_mgmt_frm_rate, | ||
273 | wl->tx_mgmt_frm_mod); | ||
274 | if (ret < 0) | ||
275 | goto out; | ||
276 | |||
277 | wl1251_debug(DEBUG_CMD, "cmd join"); | ||
278 | 270 | ||
279 | /* Reverse order BSSID */ | 271 | /* Reverse order BSSID */ |
280 | bssid = (u8 *) &join->bssid_lsb; | 272 | bssid = (u8 *) &join->bssid_lsb; |
@@ -284,13 +276,22 @@ int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 dtim_interval, | |||
284 | join->rx_config_options = wl->rx_config; | 276 | join->rx_config_options = wl->rx_config; |
285 | join->rx_filter_options = wl->rx_filter; | 277 | join->rx_filter_options = wl->rx_filter; |
286 | 278 | ||
279 | /* | ||
280 | * FIXME: disable temporarily all filters because after commit | ||
281 | * 9cef8737 "mac80211: fix managed mode BSSID handling" broke | ||
282 | * association. The filter logic needs to be implemented properly | ||
283 | * and once that is done, this hack can be removed. | ||
284 | */ | ||
285 | join->rx_config_options = 0; | ||
286 | join->rx_filter_options = WL1251_DEFAULT_RX_FILTER; | ||
287 | |||
287 | join->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS | | 288 | join->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS | |
288 | RATE_MASK_5_5MBPS | RATE_MASK_11MBPS; | 289 | RATE_MASK_5_5MBPS | RATE_MASK_11MBPS; |
289 | 290 | ||
290 | join->beacon_interval = beacon_interval; | 291 | join->beacon_interval = beacon_interval; |
291 | join->dtim_interval = dtim_interval; | 292 | join->dtim_interval = dtim_interval; |
292 | join->bss_type = bss_type; | 293 | join->bss_type = bss_type; |
293 | join->channel = wl->channel; | 294 | join->channel = channel; |
294 | join->ctrl = JOIN_CMD_CTRL_TX_FLUSH; | 295 | join->ctrl = JOIN_CMD_CTRL_TX_FLUSH; |
295 | 296 | ||
296 | ret = wl1251_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join)); | 297 | ret = wl1251_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join)); |
@@ -299,15 +300,6 @@ int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 dtim_interval, | |||
299 | goto out; | 300 | goto out; |
300 | } | 301 | } |
301 | 302 | ||
302 | timeout = msecs_to_jiffies(JOIN_TIMEOUT); | ||
303 | |||
304 | /* | ||
305 | * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to | ||
306 | * simplify locking we just sleep instead, for now | ||
307 | */ | ||
308 | if (wait) | ||
309 | msleep(10); | ||
310 | |||
311 | out: | 303 | out: |
312 | kfree(join); | 304 | kfree(join); |
313 | return ret; | 305 | return ret; |
@@ -318,14 +310,6 @@ int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode) | |||
318 | struct wl1251_cmd_ps_params *ps_params = NULL; | 310 | struct wl1251_cmd_ps_params *ps_params = NULL; |
319 | int ret = 0; | 311 | int ret = 0; |
320 | 312 | ||
321 | /* FIXME: this should be in ps.c */ | ||
322 | ret = wl1251_acx_wake_up_conditions(wl, WAKE_UP_EVENT_DTIM_BITMAP, | ||
323 | wl->listen_int); | ||
324 | if (ret < 0) { | ||
325 | wl1251_error("couldn't set wake up conditions"); | ||
326 | goto out; | ||
327 | } | ||
328 | |||
329 | wl1251_debug(DEBUG_CMD, "cmd set ps mode"); | 313 | wl1251_debug(DEBUG_CMD, "cmd set ps mode"); |
330 | 314 | ||
331 | ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL); | 315 | ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL); |
@@ -379,7 +363,7 @@ int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer, | |||
379 | } | 363 | } |
380 | 364 | ||
381 | /* the read command got in, we can now read the answer */ | 365 | /* the read command got in, we can now read the answer */ |
382 | wl1251_spi_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd)); | 366 | wl1251_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd)); |
383 | 367 | ||
384 | if (cmd->header.status != CMD_STATUS_SUCCESS) | 368 | if (cmd->header.status != CMD_STATUS_SUCCESS) |
385 | wl1251_error("error in read command result: %d", | 369 | wl1251_error("error in read command result: %d", |
diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.h b/drivers/net/wireless/wl12xx/wl1251_cmd.h index 64f228dd9a9b..dff798ad0ef5 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.h +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.h | |||
@@ -36,8 +36,8 @@ int wl1251_cmd_configure(struct wl1251 *wl, u16 id, void *buf, size_t len); | |||
36 | int wl1251_cmd_vbm(struct wl1251 *wl, u8 identity, | 36 | int wl1251_cmd_vbm(struct wl1251 *wl, u8 identity, |
37 | void *bitmap, u16 bitmap_len, u8 bitmap_control); | 37 | void *bitmap, u16 bitmap_len, u8 bitmap_control); |
38 | int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable); | 38 | int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable); |
39 | int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 dtim_interval, | 39 | int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 channel, |
40 | u16 beacon_interval, u8 wait); | 40 | u16 beacon_interval, u8 dtim_interval); |
41 | int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode); | 41 | int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode); |
42 | int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer, | 42 | int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer, |
43 | size_t len); | 43 | size_t len); |
diff --git a/drivers/net/wireless/wl12xx/wl1251_event.c b/drivers/net/wireless/wl12xx/wl1251_event.c index 1a0a0bc1a31f..00076c4a8a21 100644 --- a/drivers/net/wireless/wl12xx/wl1251_event.c +++ b/drivers/net/wireless/wl12xx/wl1251_event.c | |||
@@ -23,8 +23,8 @@ | |||
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include "wl1251.h" | 25 | #include "wl1251.h" |
26 | #include "reg.h" | 26 | #include "wl1251_reg.h" |
27 | #include "wl1251_spi.h" | 27 | #include "wl1251_io.h" |
28 | #include "wl1251_event.h" | 28 | #include "wl1251_event.h" |
29 | #include "wl1251_ps.h" | 29 | #include "wl1251_ps.h" |
30 | 30 | ||
@@ -39,6 +39,7 @@ static int wl1251_event_scan_complete(struct wl1251 *wl, | |||
39 | mutex_unlock(&wl->mutex); | 39 | mutex_unlock(&wl->mutex); |
40 | ieee80211_scan_completed(wl->hw, false); | 40 | ieee80211_scan_completed(wl->hw, false); |
41 | mutex_lock(&wl->mutex); | 41 | mutex_lock(&wl->mutex); |
42 | wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan completed"); | ||
42 | wl->scanning = false; | 43 | wl->scanning = false; |
43 | } | 44 | } |
44 | 45 | ||
@@ -112,7 +113,7 @@ int wl1251_event_handle(struct wl1251 *wl, u8 mbox_num) | |||
112 | return -EINVAL; | 113 | return -EINVAL; |
113 | 114 | ||
114 | /* first we read the mbox descriptor */ | 115 | /* first we read the mbox descriptor */ |
115 | wl1251_spi_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox, | 116 | wl1251_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox, |
116 | sizeof(struct event_mailbox)); | 117 | sizeof(struct event_mailbox)); |
117 | 118 | ||
118 | /* process the descriptor */ | 119 | /* process the descriptor */ |
diff --git a/drivers/net/wireless/wl12xx/wl1251_init.c b/drivers/net/wireless/wl12xx/wl1251_init.c index df6c60f0fd66..b2ee4f468fc4 100644 --- a/drivers/net/wireless/wl12xx/wl1251_init.c +++ b/drivers/net/wireless/wl12xx/wl1251_init.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include "wl12xx_80211.h" | 28 | #include "wl12xx_80211.h" |
29 | #include "wl1251_acx.h" | 29 | #include "wl1251_acx.h" |
30 | #include "wl1251_cmd.h" | 30 | #include "wl1251_cmd.h" |
31 | #include "wl1251_reg.h" | ||
31 | 32 | ||
32 | int wl1251_hw_init_hwenc_config(struct wl1251 *wl) | 33 | int wl1251_hw_init_hwenc_config(struct wl1251 *wl) |
33 | { | 34 | { |
@@ -198,3 +199,215 @@ int wl1251_hw_init_power_auth(struct wl1251 *wl) | |||
198 | { | 199 | { |
199 | return wl1251_acx_sleep_auth(wl, WL1251_PSM_CAM); | 200 | return wl1251_acx_sleep_auth(wl, WL1251_PSM_CAM); |
200 | } | 201 | } |
202 | |||
203 | int wl1251_hw_init_mem_config(struct wl1251 *wl) | ||
204 | { | ||
205 | int ret; | ||
206 | |||
207 | ret = wl1251_acx_mem_cfg(wl); | ||
208 | if (ret < 0) | ||
209 | return ret; | ||
210 | |||
211 | wl->target_mem_map = kzalloc(sizeof(struct wl1251_acx_mem_map), | ||
212 | GFP_KERNEL); | ||
213 | if (!wl->target_mem_map) { | ||
214 | wl1251_error("couldn't allocate target memory map"); | ||
215 | return -ENOMEM; | ||
216 | } | ||
217 | |||
218 | /* we now ask for the firmware built memory map */ | ||
219 | ret = wl1251_acx_mem_map(wl, wl->target_mem_map, | ||
220 | sizeof(struct wl1251_acx_mem_map)); | ||
221 | if (ret < 0) { | ||
222 | wl1251_error("couldn't retrieve firmware memory map"); | ||
223 | kfree(wl->target_mem_map); | ||
224 | wl->target_mem_map = NULL; | ||
225 | return ret; | ||
226 | } | ||
227 | |||
228 | return 0; | ||
229 | } | ||
230 | |||
231 | static int wl1251_hw_init_txq_fill(u8 qid, | ||
232 | struct acx_tx_queue_qos_config *config, | ||
233 | u32 num_blocks) | ||
234 | { | ||
235 | config->qid = qid; | ||
236 | |||
237 | switch (qid) { | ||
238 | case QOS_AC_BE: | ||
239 | config->high_threshold = | ||
240 | (QOS_TX_HIGH_BE_DEF * num_blocks) / 100; | ||
241 | config->low_threshold = | ||
242 | (QOS_TX_LOW_BE_DEF * num_blocks) / 100; | ||
243 | break; | ||
244 | case QOS_AC_BK: | ||
245 | config->high_threshold = | ||
246 | (QOS_TX_HIGH_BK_DEF * num_blocks) / 100; | ||
247 | config->low_threshold = | ||
248 | (QOS_TX_LOW_BK_DEF * num_blocks) / 100; | ||
249 | break; | ||
250 | case QOS_AC_VI: | ||
251 | config->high_threshold = | ||
252 | (QOS_TX_HIGH_VI_DEF * num_blocks) / 100; | ||
253 | config->low_threshold = | ||
254 | (QOS_TX_LOW_VI_DEF * num_blocks) / 100; | ||
255 | break; | ||
256 | case QOS_AC_VO: | ||
257 | config->high_threshold = | ||
258 | (QOS_TX_HIGH_VO_DEF * num_blocks) / 100; | ||
259 | config->low_threshold = | ||
260 | (QOS_TX_LOW_VO_DEF * num_blocks) / 100; | ||
261 | break; | ||
262 | default: | ||
263 | wl1251_error("Invalid TX queue id: %d", qid); | ||
264 | return -EINVAL; | ||
265 | } | ||
266 | |||
267 | return 0; | ||
268 | } | ||
269 | |||
270 | static int wl1251_hw_init_tx_queue_config(struct wl1251 *wl) | ||
271 | { | ||
272 | struct acx_tx_queue_qos_config *config; | ||
273 | struct wl1251_acx_mem_map *wl_mem_map = wl->target_mem_map; | ||
274 | int ret, i; | ||
275 | |||
276 | wl1251_debug(DEBUG_ACX, "acx tx queue config"); | ||
277 | |||
278 | config = kzalloc(sizeof(*config), GFP_KERNEL); | ||
279 | if (!config) { | ||
280 | ret = -ENOMEM; | ||
281 | goto out; | ||
282 | } | ||
283 | |||
284 | for (i = 0; i < MAX_NUM_OF_AC; i++) { | ||
285 | ret = wl1251_hw_init_txq_fill(i, config, | ||
286 | wl_mem_map->num_tx_mem_blocks); | ||
287 | if (ret < 0) | ||
288 | goto out; | ||
289 | |||
290 | ret = wl1251_cmd_configure(wl, ACX_TX_QUEUE_CFG, | ||
291 | config, sizeof(*config)); | ||
292 | if (ret < 0) | ||
293 | goto out; | ||
294 | } | ||
295 | |||
296 | out: | ||
297 | kfree(config); | ||
298 | return ret; | ||
299 | } | ||
300 | |||
301 | static int wl1251_hw_init_data_path_config(struct wl1251 *wl) | ||
302 | { | ||
303 | int ret; | ||
304 | |||
305 | /* asking for the data path parameters */ | ||
306 | wl->data_path = kzalloc(sizeof(struct acx_data_path_params_resp), | ||
307 | GFP_KERNEL); | ||
308 | if (!wl->data_path) { | ||
309 | wl1251_error("Couldnt allocate data path parameters"); | ||
310 | return -ENOMEM; | ||
311 | } | ||
312 | |||
313 | ret = wl1251_acx_data_path_params(wl, wl->data_path); | ||
314 | if (ret < 0) { | ||
315 | kfree(wl->data_path); | ||
316 | wl->data_path = NULL; | ||
317 | return ret; | ||
318 | } | ||
319 | |||
320 | return 0; | ||
321 | } | ||
322 | |||
323 | |||
324 | int wl1251_hw_init(struct wl1251 *wl) | ||
325 | { | ||
326 | struct wl1251_acx_mem_map *wl_mem_map; | ||
327 | int ret; | ||
328 | |||
329 | ret = wl1251_hw_init_hwenc_config(wl); | ||
330 | if (ret < 0) | ||
331 | return ret; | ||
332 | |||
333 | /* Template settings */ | ||
334 | ret = wl1251_hw_init_templates_config(wl); | ||
335 | if (ret < 0) | ||
336 | return ret; | ||
337 | |||
338 | /* Default memory configuration */ | ||
339 | ret = wl1251_hw_init_mem_config(wl); | ||
340 | if (ret < 0) | ||
341 | return ret; | ||
342 | |||
343 | /* Default data path configuration */ | ||
344 | ret = wl1251_hw_init_data_path_config(wl); | ||
345 | if (ret < 0) | ||
346 | goto out_free_memmap; | ||
347 | |||
348 | /* RX config */ | ||
349 | ret = wl1251_hw_init_rx_config(wl, | ||
350 | RX_CFG_PROMISCUOUS | RX_CFG_TSF, | ||
351 | RX_FILTER_OPTION_DEF); | ||
352 | /* RX_CONFIG_OPTION_ANY_DST_ANY_BSS, | ||
353 | RX_FILTER_OPTION_FILTER_ALL); */ | ||
354 | if (ret < 0) | ||
355 | goto out_free_data_path; | ||
356 | |||
357 | /* TX queues config */ | ||
358 | ret = wl1251_hw_init_tx_queue_config(wl); | ||
359 | if (ret < 0) | ||
360 | goto out_free_data_path; | ||
361 | |||
362 | /* PHY layer config */ | ||
363 | ret = wl1251_hw_init_phy_config(wl); | ||
364 | if (ret < 0) | ||
365 | goto out_free_data_path; | ||
366 | |||
367 | /* Beacon filtering */ | ||
368 | ret = wl1251_hw_init_beacon_filter(wl); | ||
369 | if (ret < 0) | ||
370 | goto out_free_data_path; | ||
371 | |||
372 | /* Bluetooth WLAN coexistence */ | ||
373 | ret = wl1251_hw_init_pta(wl); | ||
374 | if (ret < 0) | ||
375 | goto out_free_data_path; | ||
376 | |||
377 | /* Energy detection */ | ||
378 | ret = wl1251_hw_init_energy_detection(wl); | ||
379 | if (ret < 0) | ||
380 | goto out_free_data_path; | ||
381 | |||
382 | /* Beacons and boradcast settings */ | ||
383 | ret = wl1251_hw_init_beacon_broadcast(wl); | ||
384 | if (ret < 0) | ||
385 | goto out_free_data_path; | ||
386 | |||
387 | /* Enable data path */ | ||
388 | ret = wl1251_cmd_data_path(wl, wl->channel, 1); | ||
389 | if (ret < 0) | ||
390 | goto out_free_data_path; | ||
391 | |||
392 | /* Default power state */ | ||
393 | ret = wl1251_hw_init_power_auth(wl); | ||
394 | if (ret < 0) | ||
395 | goto out_free_data_path; | ||
396 | |||
397 | wl_mem_map = wl->target_mem_map; | ||
398 | wl1251_info("%d tx blocks at 0x%x, %d rx blocks at 0x%x", | ||
399 | wl_mem_map->num_tx_mem_blocks, | ||
400 | wl->data_path->tx_control_addr, | ||
401 | wl_mem_map->num_rx_mem_blocks, | ||
402 | wl->data_path->rx_control_addr); | ||
403 | |||
404 | return 0; | ||
405 | |||
406 | out_free_data_path: | ||
407 | kfree(wl->data_path); | ||
408 | |||
409 | out_free_memmap: | ||
410 | kfree(wl->target_mem_map); | ||
411 | |||
412 | return ret; | ||
413 | } | ||
diff --git a/drivers/net/wireless/wl12xx/wl1251_init.h b/drivers/net/wireless/wl12xx/wl1251_init.h index 8596188e834e..b3b25ec885ea 100644 --- a/drivers/net/wireless/wl12xx/wl1251_init.h +++ b/drivers/net/wireless/wl12xx/wl1251_init.h | |||
@@ -35,5 +35,7 @@ int wl1251_hw_init_pta(struct wl1251 *wl); | |||
35 | int wl1251_hw_init_energy_detection(struct wl1251 *wl); | 35 | int wl1251_hw_init_energy_detection(struct wl1251 *wl); |
36 | int wl1251_hw_init_beacon_broadcast(struct wl1251 *wl); | 36 | int wl1251_hw_init_beacon_broadcast(struct wl1251 *wl); |
37 | int wl1251_hw_init_power_auth(struct wl1251 *wl); | 37 | int wl1251_hw_init_power_auth(struct wl1251 *wl); |
38 | int wl1251_hw_init_mem_config(struct wl1251 *wl); | ||
39 | int wl1251_hw_init(struct wl1251 *wl); | ||
38 | 40 | ||
39 | #endif | 41 | #endif |
diff --git a/drivers/net/wireless/wl12xx/wl1251_io.c b/drivers/net/wireless/wl12xx/wl1251_io.c new file mode 100644 index 000000000000..f1c232e0887f --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_io.c | |||
@@ -0,0 +1,196 @@ | |||
1 | /* | ||
2 | * This file is part of wl12xx | ||
3 | * | ||
4 | * Copyright (C) 2008 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Kalle Valo <kalle.valo@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include "wl1251.h" | ||
25 | #include "wl1251_reg.h" | ||
26 | #include "wl1251_io.h" | ||
27 | |||
28 | /* FIXME: this is static data nowadays and the table can be removed */ | ||
29 | static enum wl12xx_acx_int_reg wl1251_io_reg_table[ACX_REG_TABLE_LEN] = { | ||
30 | [ACX_REG_INTERRUPT_TRIG] = (REGISTERS_BASE + 0x0474), | ||
31 | [ACX_REG_INTERRUPT_TRIG_H] = (REGISTERS_BASE + 0x0478), | ||
32 | [ACX_REG_INTERRUPT_MASK] = (REGISTERS_BASE + 0x0494), | ||
33 | [ACX_REG_HINT_MASK_SET] = (REGISTERS_BASE + 0x0498), | ||
34 | [ACX_REG_HINT_MASK_CLR] = (REGISTERS_BASE + 0x049C), | ||
35 | [ACX_REG_INTERRUPT_NO_CLEAR] = (REGISTERS_BASE + 0x04B0), | ||
36 | [ACX_REG_INTERRUPT_CLEAR] = (REGISTERS_BASE + 0x04A4), | ||
37 | [ACX_REG_INTERRUPT_ACK] = (REGISTERS_BASE + 0x04A8), | ||
38 | [ACX_REG_SLV_SOFT_RESET] = (REGISTERS_BASE + 0x0000), | ||
39 | [ACX_REG_EE_START] = (REGISTERS_BASE + 0x080C), | ||
40 | [ACX_REG_ECPU_CONTROL] = (REGISTERS_BASE + 0x0804) | ||
41 | }; | ||
42 | |||
43 | static int wl1251_translate_reg_addr(struct wl1251 *wl, int addr) | ||
44 | { | ||
45 | /* If the address is lower than REGISTERS_BASE, it means that this is | ||
46 | * a chip-specific register address, so look it up in the registers | ||
47 | * table */ | ||
48 | if (addr < REGISTERS_BASE) { | ||
49 | /* Make sure we don't go over the table */ | ||
50 | if (addr >= ACX_REG_TABLE_LEN) { | ||
51 | wl1251_error("address out of range (%d)", addr); | ||
52 | return -EINVAL; | ||
53 | } | ||
54 | addr = wl1251_io_reg_table[addr]; | ||
55 | } | ||
56 | |||
57 | return addr - wl->physical_reg_addr + wl->virtual_reg_addr; | ||
58 | } | ||
59 | |||
60 | static int wl1251_translate_mem_addr(struct wl1251 *wl, int addr) | ||
61 | { | ||
62 | return addr - wl->physical_mem_addr + wl->virtual_mem_addr; | ||
63 | } | ||
64 | |||
65 | void wl1251_mem_read(struct wl1251 *wl, int addr, void *buf, size_t len) | ||
66 | { | ||
67 | int physical; | ||
68 | |||
69 | physical = wl1251_translate_mem_addr(wl, addr); | ||
70 | |||
71 | wl->if_ops->read(wl, physical, buf, len); | ||
72 | } | ||
73 | |||
74 | void wl1251_mem_write(struct wl1251 *wl, int addr, void *buf, size_t len) | ||
75 | { | ||
76 | int physical; | ||
77 | |||
78 | physical = wl1251_translate_mem_addr(wl, addr); | ||
79 | |||
80 | wl->if_ops->write(wl, physical, buf, len); | ||
81 | } | ||
82 | |||
83 | u32 wl1251_mem_read32(struct wl1251 *wl, int addr) | ||
84 | { | ||
85 | return wl1251_read32(wl, wl1251_translate_mem_addr(wl, addr)); | ||
86 | } | ||
87 | |||
88 | void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val) | ||
89 | { | ||
90 | wl1251_write32(wl, wl1251_translate_mem_addr(wl, addr), val); | ||
91 | } | ||
92 | |||
93 | u32 wl1251_reg_read32(struct wl1251 *wl, int addr) | ||
94 | { | ||
95 | return wl1251_read32(wl, wl1251_translate_reg_addr(wl, addr)); | ||
96 | } | ||
97 | |||
98 | void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val) | ||
99 | { | ||
100 | wl1251_write32(wl, wl1251_translate_reg_addr(wl, addr), val); | ||
101 | } | ||
102 | |||
103 | /* Set the partitions to access the chip addresses. | ||
104 | * | ||
105 | * There are two VIRTUAL partitions (the memory partition and the | ||
106 | * registers partition), which are mapped to two different areas of the | ||
107 | * PHYSICAL (hardware) memory. This function also makes other checks to | ||
108 | * ensure that the partitions are not overlapping. In the diagram below, the | ||
109 | * memory partition comes before the register partition, but the opposite is | ||
110 | * also supported. | ||
111 | * | ||
112 | * PHYSICAL address | ||
113 | * space | ||
114 | * | ||
115 | * | | | ||
116 | * ...+----+--> mem_start | ||
117 | * VIRTUAL address ... | | | ||
118 | * space ... | | [PART_0] | ||
119 | * ... | | | ||
120 | * 0x00000000 <--+----+... ...+----+--> mem_start + mem_size | ||
121 | * | | ... | | | ||
122 | * |MEM | ... | | | ||
123 | * | | ... | | | ||
124 | * part_size <--+----+... | | {unused area) | ||
125 | * | | ... | | | ||
126 | * |REG | ... | | | ||
127 | * part_size | | ... | | | ||
128 | * + <--+----+... ...+----+--> reg_start | ||
129 | * reg_size ... | | | ||
130 | * ... | | [PART_1] | ||
131 | * ... | | | ||
132 | * ...+----+--> reg_start + reg_size | ||
133 | * | | | ||
134 | * | ||
135 | */ | ||
136 | void wl1251_set_partition(struct wl1251 *wl, | ||
137 | u32 mem_start, u32 mem_size, | ||
138 | u32 reg_start, u32 reg_size) | ||
139 | { | ||
140 | struct wl1251_partition partition[2]; | ||
141 | |||
142 | wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", | ||
143 | mem_start, mem_size); | ||
144 | wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", | ||
145 | reg_start, reg_size); | ||
146 | |||
147 | /* Make sure that the two partitions together don't exceed the | ||
148 | * address range */ | ||
149 | if ((mem_size + reg_size) > HW_ACCESS_MEMORY_MAX_RANGE) { | ||
150 | wl1251_debug(DEBUG_SPI, "Total size exceeds maximum virtual" | ||
151 | " address range. Truncating partition[0]."); | ||
152 | mem_size = HW_ACCESS_MEMORY_MAX_RANGE - reg_size; | ||
153 | wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", | ||
154 | mem_start, mem_size); | ||
155 | wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", | ||
156 | reg_start, reg_size); | ||
157 | } | ||
158 | |||
159 | if ((mem_start < reg_start) && | ||
160 | ((mem_start + mem_size) > reg_start)) { | ||
161 | /* Guarantee that the memory partition doesn't overlap the | ||
162 | * registers partition */ | ||
163 | wl1251_debug(DEBUG_SPI, "End of partition[0] is " | ||
164 | "overlapping partition[1]. Adjusted."); | ||
165 | mem_size = reg_start - mem_start; | ||
166 | wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", | ||
167 | mem_start, mem_size); | ||
168 | wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", | ||
169 | reg_start, reg_size); | ||
170 | } else if ((reg_start < mem_start) && | ||
171 | ((reg_start + reg_size) > mem_start)) { | ||
172 | /* Guarantee that the register partition doesn't overlap the | ||
173 | * memory partition */ | ||
174 | wl1251_debug(DEBUG_SPI, "End of partition[1] is" | ||
175 | " overlapping partition[0]. Adjusted."); | ||
176 | reg_size = mem_start - reg_start; | ||
177 | wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", | ||
178 | mem_start, mem_size); | ||
179 | wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", | ||
180 | reg_start, reg_size); | ||
181 | } | ||
182 | |||
183 | partition[0].start = mem_start; | ||
184 | partition[0].size = mem_size; | ||
185 | partition[1].start = reg_start; | ||
186 | partition[1].size = reg_size; | ||
187 | |||
188 | wl->physical_mem_addr = mem_start; | ||
189 | wl->physical_reg_addr = reg_start; | ||
190 | |||
191 | wl->virtual_mem_addr = 0; | ||
192 | wl->virtual_reg_addr = mem_size; | ||
193 | |||
194 | wl->if_ops->write(wl, HW_ACCESS_PART0_SIZE_ADDR, partition, | ||
195 | sizeof(partition)); | ||
196 | } | ||
diff --git a/drivers/net/wireless/wl12xx/wl1251_io.h b/drivers/net/wireless/wl12xx/wl1251_io.h new file mode 100644 index 000000000000..b89d2ac62efb --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_io.h | |||
@@ -0,0 +1,64 @@ | |||
1 | /* | ||
2 | * This file is part of wl12xx | ||
3 | * | ||
4 | * Copyright (C) 2008 Nokia Corporation | ||
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 | #ifndef __WL1251_IO_H__ | ||
22 | #define __WL1251_IO_H__ | ||
23 | |||
24 | #include "wl1251.h" | ||
25 | |||
26 | #define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0 | ||
27 | |||
28 | #define HW_ACCESS_PART0_SIZE_ADDR 0x1FFC0 | ||
29 | #define HW_ACCESS_PART0_START_ADDR 0x1FFC4 | ||
30 | #define HW_ACCESS_PART1_SIZE_ADDR 0x1FFC8 | ||
31 | #define HW_ACCESS_PART1_START_ADDR 0x1FFCC | ||
32 | |||
33 | #define HW_ACCESS_REGISTER_SIZE 4 | ||
34 | |||
35 | #define HW_ACCESS_PRAM_MAX_RANGE 0x3c000 | ||
36 | |||
37 | static inline u32 wl1251_read32(struct wl1251 *wl, int addr) | ||
38 | { | ||
39 | u32 response; | ||
40 | |||
41 | wl->if_ops->read(wl, addr, &response, sizeof(u32)); | ||
42 | |||
43 | return response; | ||
44 | } | ||
45 | |||
46 | static inline void wl1251_write32(struct wl1251 *wl, int addr, u32 val) | ||
47 | { | ||
48 | wl->if_ops->write(wl, addr, &val, sizeof(u32)); | ||
49 | } | ||
50 | |||
51 | /* Memory target IO, address is translated to partition 0 */ | ||
52 | void wl1251_mem_read(struct wl1251 *wl, int addr, void *buf, size_t len); | ||
53 | void wl1251_mem_write(struct wl1251 *wl, int addr, void *buf, size_t len); | ||
54 | u32 wl1251_mem_read32(struct wl1251 *wl, int addr); | ||
55 | void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val); | ||
56 | /* Registers IO */ | ||
57 | u32 wl1251_reg_read32(struct wl1251 *wl, int addr); | ||
58 | void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val); | ||
59 | |||
60 | void wl1251_set_partition(struct wl1251 *wl, | ||
61 | u32 part_start, u32 part_size, | ||
62 | u32 reg_start, u32 reg_size); | ||
63 | |||
64 | #endif | ||
diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index da4c688c46af..7148934e464d 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c | |||
@@ -26,26 +26,30 @@ | |||
26 | #include <linux/firmware.h> | 26 | #include <linux/firmware.h> |
27 | #include <linux/delay.h> | 27 | #include <linux/delay.h> |
28 | #include <linux/irq.h> | 28 | #include <linux/irq.h> |
29 | #include <linux/spi/spi.h> | ||
30 | #include <linux/crc32.h> | 29 | #include <linux/crc32.h> |
31 | #include <linux/etherdevice.h> | 30 | #include <linux/etherdevice.h> |
32 | #include <linux/spi/wl12xx.h> | ||
33 | 31 | ||
34 | #include "wl1251.h" | 32 | #include "wl1251.h" |
35 | #include "wl12xx_80211.h" | 33 | #include "wl12xx_80211.h" |
36 | #include "reg.h" | 34 | #include "wl1251_reg.h" |
37 | #include "wl1251_ops.h" | 35 | #include "wl1251_io.h" |
38 | #include "wl1251_spi.h" | 36 | #include "wl1251_cmd.h" |
39 | #include "wl1251_event.h" | 37 | #include "wl1251_event.h" |
40 | #include "wl1251_tx.h" | 38 | #include "wl1251_tx.h" |
41 | #include "wl1251_rx.h" | 39 | #include "wl1251_rx.h" |
42 | #include "wl1251_ps.h" | 40 | #include "wl1251_ps.h" |
43 | #include "wl1251_init.h" | 41 | #include "wl1251_init.h" |
44 | #include "wl1251_debugfs.h" | 42 | #include "wl1251_debugfs.h" |
43 | #include "wl1251_boot.h" | ||
45 | 44 | ||
46 | static void wl1251_disable_interrupts(struct wl1251 *wl) | 45 | void wl1251_enable_interrupts(struct wl1251 *wl) |
47 | { | 46 | { |
48 | disable_irq(wl->irq); | 47 | wl->if_ops->enable_irq(wl); |
48 | } | ||
49 | |||
50 | void wl1251_disable_interrupts(struct wl1251 *wl) | ||
51 | { | ||
52 | wl->if_ops->disable_irq(wl); | ||
49 | } | 53 | } |
50 | 54 | ||
51 | static void wl1251_power_off(struct wl1251 *wl) | 55 | static void wl1251_power_off(struct wl1251 *wl) |
@@ -58,25 +62,13 @@ static void wl1251_power_on(struct wl1251 *wl) | |||
58 | wl->set_power(true); | 62 | wl->set_power(true); |
59 | } | 63 | } |
60 | 64 | ||
61 | static irqreturn_t wl1251_irq(int irq, void *cookie) | ||
62 | { | ||
63 | struct wl1251 *wl; | ||
64 | |||
65 | wl1251_debug(DEBUG_IRQ, "IRQ"); | ||
66 | |||
67 | wl = cookie; | ||
68 | |||
69 | schedule_work(&wl->irq_work); | ||
70 | |||
71 | return IRQ_HANDLED; | ||
72 | } | ||
73 | |||
74 | static int wl1251_fetch_firmware(struct wl1251 *wl) | 65 | static int wl1251_fetch_firmware(struct wl1251 *wl) |
75 | { | 66 | { |
76 | const struct firmware *fw; | 67 | const struct firmware *fw; |
68 | struct device *dev = wiphy_dev(wl->hw->wiphy); | ||
77 | int ret; | 69 | int ret; |
78 | 70 | ||
79 | ret = request_firmware(&fw, wl->chip.fw_filename, &wl->spi->dev); | 71 | ret = request_firmware(&fw, WL1251_FW_NAME, dev); |
80 | 72 | ||
81 | if (ret < 0) { | 73 | if (ret < 0) { |
82 | wl1251_error("could not get firmware: %d", ret); | 74 | wl1251_error("could not get firmware: %d", ret); |
@@ -112,9 +104,10 @@ out: | |||
112 | static int wl1251_fetch_nvs(struct wl1251 *wl) | 104 | static int wl1251_fetch_nvs(struct wl1251 *wl) |
113 | { | 105 | { |
114 | const struct firmware *fw; | 106 | const struct firmware *fw; |
107 | struct device *dev = wiphy_dev(wl->hw->wiphy); | ||
115 | int ret; | 108 | int ret; |
116 | 109 | ||
117 | ret = request_firmware(&fw, wl->chip.nvs_filename, &wl->spi->dev); | 110 | ret = request_firmware(&fw, WL1251_NVS_NAME, dev); |
118 | 111 | ||
119 | if (ret < 0) { | 112 | if (ret < 0) { |
120 | wl1251_error("could not get nvs file: %d", ret); | 113 | wl1251_error("could not get nvs file: %d", ret); |
@@ -164,9 +157,8 @@ static int wl1251_chip_wakeup(struct wl1251 *wl) | |||
164 | int ret = 0; | 157 | int ret = 0; |
165 | 158 | ||
166 | wl1251_power_on(wl); | 159 | wl1251_power_on(wl); |
167 | msleep(wl->chip.power_on_sleep); | 160 | msleep(WL1251_POWER_ON_SLEEP); |
168 | wl1251_spi_reset(wl); | 161 | wl->if_ops->reset(wl); |
169 | wl1251_spi_init(wl); | ||
170 | 162 | ||
171 | /* We don't need a real memory partition here, because we only want | 163 | /* We don't need a real memory partition here, because we only want |
172 | * to use the registers at this point. */ | 164 | * to use the registers at this point. */ |
@@ -182,22 +174,19 @@ static int wl1251_chip_wakeup(struct wl1251 *wl) | |||
182 | /* whal_FwCtrl_BootSm() */ | 174 | /* whal_FwCtrl_BootSm() */ |
183 | 175 | ||
184 | /* 0. read chip id from CHIP_ID */ | 176 | /* 0. read chip id from CHIP_ID */ |
185 | wl->chip.id = wl1251_reg_read32(wl, CHIP_ID_B); | 177 | wl->chip_id = wl1251_reg_read32(wl, CHIP_ID_B); |
186 | 178 | ||
187 | /* 1. check if chip id is valid */ | 179 | /* 1. check if chip id is valid */ |
188 | 180 | ||
189 | switch (wl->chip.id) { | 181 | switch (wl->chip_id) { |
190 | case CHIP_ID_1251_PG12: | 182 | case CHIP_ID_1251_PG12: |
191 | wl1251_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG12)", | 183 | wl1251_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG12)", |
192 | wl->chip.id); | 184 | wl->chip_id); |
193 | |||
194 | wl1251_setup(wl); | ||
195 | |||
196 | break; | 185 | break; |
197 | case CHIP_ID_1251_PG10: | 186 | case CHIP_ID_1251_PG10: |
198 | case CHIP_ID_1251_PG11: | 187 | case CHIP_ID_1251_PG11: |
199 | default: | 188 | default: |
200 | wl1251_error("unsupported chip id: 0x%x", wl->chip.id); | 189 | wl1251_error("unsupported chip id: 0x%x", wl->chip_id); |
201 | ret = -ENODEV; | 190 | ret = -ENODEV; |
202 | goto out; | 191 | goto out; |
203 | } | 192 | } |
@@ -219,6 +208,135 @@ out: | |||
219 | return ret; | 208 | return ret; |
220 | } | 209 | } |
221 | 210 | ||
211 | static void wl1251_irq_work(struct work_struct *work) | ||
212 | { | ||
213 | u32 intr; | ||
214 | struct wl1251 *wl = | ||
215 | container_of(work, struct wl1251, irq_work); | ||
216 | int ret; | ||
217 | |||
218 | mutex_lock(&wl->mutex); | ||
219 | |||
220 | wl1251_debug(DEBUG_IRQ, "IRQ work"); | ||
221 | |||
222 | if (wl->state == WL1251_STATE_OFF) | ||
223 | goto out; | ||
224 | |||
225 | ret = wl1251_ps_elp_wakeup(wl); | ||
226 | if (ret < 0) | ||
227 | goto out; | ||
228 | |||
229 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1251_ACX_INTR_ALL); | ||
230 | |||
231 | intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); | ||
232 | wl1251_debug(DEBUG_IRQ, "intr: 0x%x", intr); | ||
233 | |||
234 | if (wl->data_path) { | ||
235 | wl->rx_counter = | ||
236 | wl1251_mem_read32(wl, wl->data_path->rx_control_addr); | ||
237 | |||
238 | /* We handle a frmware bug here */ | ||
239 | switch ((wl->rx_counter - wl->rx_handled) & 0xf) { | ||
240 | case 0: | ||
241 | wl1251_debug(DEBUG_IRQ, "RX: FW and host in sync"); | ||
242 | intr &= ~WL1251_ACX_INTR_RX0_DATA; | ||
243 | intr &= ~WL1251_ACX_INTR_RX1_DATA; | ||
244 | break; | ||
245 | case 1: | ||
246 | wl1251_debug(DEBUG_IRQ, "RX: FW +1"); | ||
247 | intr |= WL1251_ACX_INTR_RX0_DATA; | ||
248 | intr &= ~WL1251_ACX_INTR_RX1_DATA; | ||
249 | break; | ||
250 | case 2: | ||
251 | wl1251_debug(DEBUG_IRQ, "RX: FW +2"); | ||
252 | intr |= WL1251_ACX_INTR_RX0_DATA; | ||
253 | intr |= WL1251_ACX_INTR_RX1_DATA; | ||
254 | break; | ||
255 | default: | ||
256 | wl1251_warning("RX: FW and host out of sync: %d", | ||
257 | wl->rx_counter - wl->rx_handled); | ||
258 | break; | ||
259 | } | ||
260 | |||
261 | wl->rx_handled = wl->rx_counter; | ||
262 | |||
263 | |||
264 | wl1251_debug(DEBUG_IRQ, "RX counter: %d", wl->rx_counter); | ||
265 | } | ||
266 | |||
267 | intr &= wl->intr_mask; | ||
268 | |||
269 | if (intr == 0) { | ||
270 | wl1251_debug(DEBUG_IRQ, "INTR is 0"); | ||
271 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, | ||
272 | ~(wl->intr_mask)); | ||
273 | |||
274 | goto out_sleep; | ||
275 | } | ||
276 | |||
277 | if (intr & WL1251_ACX_INTR_RX0_DATA) { | ||
278 | wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA"); | ||
279 | wl1251_rx(wl); | ||
280 | } | ||
281 | |||
282 | if (intr & WL1251_ACX_INTR_RX1_DATA) { | ||
283 | wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA"); | ||
284 | wl1251_rx(wl); | ||
285 | } | ||
286 | |||
287 | if (intr & WL1251_ACX_INTR_TX_RESULT) { | ||
288 | wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT"); | ||
289 | wl1251_tx_complete(wl); | ||
290 | } | ||
291 | |||
292 | if (intr & (WL1251_ACX_INTR_EVENT_A | WL1251_ACX_INTR_EVENT_B)) { | ||
293 | wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)", intr); | ||
294 | if (intr & WL1251_ACX_INTR_EVENT_A) | ||
295 | wl1251_event_handle(wl, 0); | ||
296 | else | ||
297 | wl1251_event_handle(wl, 1); | ||
298 | } | ||
299 | |||
300 | if (intr & WL1251_ACX_INTR_INIT_COMPLETE) | ||
301 | wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_INIT_COMPLETE"); | ||
302 | |||
303 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); | ||
304 | |||
305 | out_sleep: | ||
306 | wl1251_ps_elp_sleep(wl); | ||
307 | |||
308 | out: | ||
309 | mutex_unlock(&wl->mutex); | ||
310 | } | ||
311 | |||
312 | static int wl1251_join(struct wl1251 *wl, u8 bss_type, u8 channel, | ||
313 | u16 beacon_interval, u8 dtim_period) | ||
314 | { | ||
315 | int ret; | ||
316 | |||
317 | ret = wl1251_acx_frame_rates(wl, DEFAULT_HW_GEN_TX_RATE, | ||
318 | DEFAULT_HW_GEN_MODULATION_TYPE, | ||
319 | wl->tx_mgmt_frm_rate, | ||
320 | wl->tx_mgmt_frm_mod); | ||
321 | if (ret < 0) | ||
322 | goto out; | ||
323 | |||
324 | |||
325 | ret = wl1251_cmd_join(wl, bss_type, channel, beacon_interval, | ||
326 | dtim_period); | ||
327 | if (ret < 0) | ||
328 | goto out; | ||
329 | |||
330 | /* | ||
331 | * FIXME: we should wait for JOIN_EVENT_COMPLETE_ID but to simplify | ||
332 | * locking we just sleep instead, for now | ||
333 | */ | ||
334 | msleep(10); | ||
335 | |||
336 | out: | ||
337 | return ret; | ||
338 | } | ||
339 | |||
222 | static void wl1251_filter_work(struct work_struct *work) | 340 | static void wl1251_filter_work(struct work_struct *work) |
223 | { | 341 | { |
224 | struct wl1251 *wl = | 342 | struct wl1251 *wl = |
@@ -234,8 +352,8 @@ static void wl1251_filter_work(struct work_struct *work) | |||
234 | if (ret < 0) | 352 | if (ret < 0) |
235 | goto out; | 353 | goto out; |
236 | 354 | ||
237 | /* FIXME: replace the magic numbers with proper definitions */ | 355 | ret = wl1251_join(wl, wl->bss_type, wl->channel, wl->beacon_int, |
238 | ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0); | 356 | wl->dtim_period); |
239 | if (ret < 0) | 357 | if (ret < 0) |
240 | goto out_sleep; | 358 | goto out_sleep; |
241 | 359 | ||
@@ -257,7 +375,7 @@ static int wl1251_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
257 | * before that, the tx_work will not be initialized! | 375 | * before that, the tx_work will not be initialized! |
258 | */ | 376 | */ |
259 | 377 | ||
260 | schedule_work(&wl->tx_work); | 378 | ieee80211_queue_work(wl->hw, &wl->tx_work); |
261 | 379 | ||
262 | /* | 380 | /* |
263 | * The workqueue is slow to process the tx_queue and we need stop | 381 | * The workqueue is slow to process the tx_queue and we need stop |
@@ -297,11 +415,11 @@ static int wl1251_op_start(struct ieee80211_hw *hw) | |||
297 | if (ret < 0) | 415 | if (ret < 0) |
298 | goto out; | 416 | goto out; |
299 | 417 | ||
300 | ret = wl->chip.op_boot(wl); | 418 | ret = wl1251_boot(wl); |
301 | if (ret < 0) | 419 | if (ret < 0) |
302 | goto out; | 420 | goto out; |
303 | 421 | ||
304 | ret = wl->chip.op_hw_init(wl); | 422 | ret = wl1251_hw_init(wl); |
305 | if (ret < 0) | 423 | if (ret < 0) |
306 | goto out; | 424 | goto out; |
307 | 425 | ||
@@ -311,7 +429,7 @@ static int wl1251_op_start(struct ieee80211_hw *hw) | |||
311 | 429 | ||
312 | wl->state = WL1251_STATE_ON; | 430 | wl->state = WL1251_STATE_ON; |
313 | 431 | ||
314 | wl1251_info("firmware booted (%s)", wl->chip.fw_ver); | 432 | wl1251_info("firmware booted (%s)", wl->fw_ver); |
315 | 433 | ||
316 | out: | 434 | out: |
317 | if (ret < 0) | 435 | if (ret < 0) |
@@ -354,7 +472,7 @@ static void wl1251_op_stop(struct ieee80211_hw *hw) | |||
354 | mutex_lock(&wl->mutex); | 472 | mutex_lock(&wl->mutex); |
355 | 473 | ||
356 | /* let's notify MAC80211 about the remaining pending TX frames */ | 474 | /* let's notify MAC80211 about the remaining pending TX frames */ |
357 | wl->chip.op_tx_flush(wl); | 475 | wl1251_tx_flush(wl); |
358 | wl1251_power_off(wl); | 476 | wl1251_power_off(wl); |
359 | 477 | ||
360 | memset(wl->bssid, 0, ETH_ALEN); | 478 | memset(wl->bssid, 0, ETH_ALEN); |
@@ -371,6 +489,7 @@ static void wl1251_op_stop(struct ieee80211_hw *hw) | |||
371 | wl->psm = 0; | 489 | wl->psm = 0; |
372 | wl->tx_queue_stopped = false; | 490 | wl->tx_queue_stopped = false; |
373 | wl->power_level = WL1251_DEFAULT_POWER_LEVEL; | 491 | wl->power_level = WL1251_DEFAULT_POWER_LEVEL; |
492 | wl->channel = WL1251_DEFAULT_CHANNEL; | ||
374 | 493 | ||
375 | wl1251_debugfs_reset(wl); | 494 | wl1251_debugfs_reset(wl); |
376 | 495 | ||
@@ -474,12 +593,12 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) | |||
474 | goto out; | 593 | goto out; |
475 | 594 | ||
476 | if (channel != wl->channel) { | 595 | if (channel != wl->channel) { |
477 | /* FIXME: use beacon interval provided by mac80211 */ | 596 | wl->channel = channel; |
478 | ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0); | 597 | |
598 | ret = wl1251_join(wl, wl->bss_type, wl->channel, | ||
599 | wl->beacon_int, wl->dtim_period); | ||
479 | if (ret < 0) | 600 | if (ret < 0) |
480 | goto out_sleep; | 601 | goto out_sleep; |
481 | |||
482 | wl->channel = channel; | ||
483 | } | 602 | } |
484 | 603 | ||
485 | ret = wl1251_build_null_data(wl); | 604 | ret = wl1251_build_null_data(wl); |
@@ -877,7 +996,7 @@ static int wl1251_hw_scan(struct wl1251 *wl, u8 *ssid, size_t len, | |||
877 | if (ret < 0) | 996 | if (ret < 0) |
878 | wl1251_error("SCAN failed"); | 997 | wl1251_error("SCAN failed"); |
879 | 998 | ||
880 | wl1251_spi_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params)); | 999 | wl1251_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params)); |
881 | 1000 | ||
882 | if (params->header.status != CMD_STATUS_SUCCESS) { | 1001 | if (params->header.status != CMD_STATUS_SUCCESS) { |
883 | wl1251_error("TEST command answer error: %d", | 1002 | wl1251_error("TEST command answer error: %d", |
@@ -967,6 +1086,11 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, | |||
967 | 1086 | ||
968 | if (changed & BSS_CHANGED_ASSOC) { | 1087 | if (changed & BSS_CHANGED_ASSOC) { |
969 | if (bss_conf->assoc) { | 1088 | if (bss_conf->assoc) { |
1089 | wl->beacon_int = bss_conf->beacon_int; | ||
1090 | wl->dtim_period = bss_conf->dtim_period; | ||
1091 | |||
1092 | /* FIXME: call join */ | ||
1093 | |||
970 | wl->aid = bss_conf->aid; | 1094 | wl->aid = bss_conf->aid; |
971 | 1095 | ||
972 | ret = wl1251_build_ps_poll(wl, wl->aid); | 1096 | ret = wl1251_build_ps_poll(wl, wl->aid); |
@@ -984,6 +1108,10 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, | |||
984 | if (ret < 0) | 1108 | if (ret < 0) |
985 | goto out_sleep; | 1109 | goto out_sleep; |
986 | } | 1110 | } |
1111 | } else { | ||
1112 | /* use defaults when not associated */ | ||
1113 | wl->beacon_int = WL1251_DEFAULT_BEACON_INT; | ||
1114 | wl->dtim_period = WL1251_DEFAULT_DTIM_PERIOD; | ||
987 | } | 1115 | } |
988 | } | 1116 | } |
989 | if (changed & BSS_CHANGED_ERP_SLOT) { | 1117 | if (changed & BSS_CHANGED_ERP_SLOT) { |
@@ -1023,7 +1151,8 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, | |||
1023 | goto out; | 1151 | goto out; |
1024 | 1152 | ||
1025 | if (wl->bss_type != BSS_TYPE_IBSS) { | 1153 | if (wl->bss_type != BSS_TYPE_IBSS) { |
1026 | ret = wl1251_cmd_join(wl, wl->bss_type, 5, 100, 1); | 1154 | ret = wl1251_join(wl, wl->bss_type, wl->channel, |
1155 | wl->beacon_int, wl->dtim_period); | ||
1027 | if (ret < 0) | 1156 | if (ret < 0) |
1028 | goto out_sleep; | 1157 | goto out_sleep; |
1029 | wl1251_warning("Set ctsprotect failed %d", ret); | 1158 | wl1251_warning("Set ctsprotect failed %d", ret); |
@@ -1049,7 +1178,8 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, | |||
1049 | if (ret < 0) | 1178 | if (ret < 0) |
1050 | goto out; | 1179 | goto out; |
1051 | 1180 | ||
1052 | ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0); | 1181 | ret = wl1251_join(wl, wl->bss_type, wl->beacon_int, |
1182 | wl->channel, wl->dtim_period); | ||
1053 | 1183 | ||
1054 | if (ret < 0) | 1184 | if (ret < 0) |
1055 | goto out; | 1185 | goto out; |
@@ -1167,8 +1297,10 @@ static int wl1251_register_hw(struct wl1251 *wl) | |||
1167 | return 0; | 1297 | return 0; |
1168 | } | 1298 | } |
1169 | 1299 | ||
1170 | static int wl1251_init_ieee80211(struct wl1251 *wl) | 1300 | int wl1251_init_ieee80211(struct wl1251 *wl) |
1171 | { | 1301 | { |
1302 | int ret; | ||
1303 | |||
1172 | /* The tx descriptor buffer and the TKIP space */ | 1304 | /* The tx descriptor buffer and the TKIP space */ |
1173 | wl->hw->extra_tx_headroom = sizeof(struct tx_double_buffer_desc) | 1305 | wl->hw->extra_tx_headroom = sizeof(struct tx_double_buffer_desc) |
1174 | + WL1251_TKIP_IV_SPACE; | 1306 | + WL1251_TKIP_IV_SPACE; |
@@ -1184,38 +1316,37 @@ static int wl1251_init_ieee80211(struct wl1251 *wl) | |||
1184 | wl->hw->wiphy->max_scan_ssids = 1; | 1316 | wl->hw->wiphy->max_scan_ssids = 1; |
1185 | wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1251_band_2ghz; | 1317 | wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1251_band_2ghz; |
1186 | 1318 | ||
1187 | SET_IEEE80211_DEV(wl->hw, &wl->spi->dev); | 1319 | ret = wl1251_register_hw(wl); |
1320 | if (ret) | ||
1321 | goto out; | ||
1188 | 1322 | ||
1189 | return 0; | 1323 | wl1251_debugfs_init(wl); |
1324 | wl1251_notice("initialized"); | ||
1325 | |||
1326 | ret = 0; | ||
1327 | |||
1328 | out: | ||
1329 | return ret; | ||
1190 | } | 1330 | } |
1331 | EXPORT_SYMBOL_GPL(wl1251_init_ieee80211); | ||
1191 | 1332 | ||
1192 | #define WL1251_DEFAULT_CHANNEL 1 | 1333 | struct ieee80211_hw *wl1251_alloc_hw(void) |
1193 | static int __devinit wl1251_probe(struct spi_device *spi) | ||
1194 | { | 1334 | { |
1195 | struct wl12xx_platform_data *pdata; | ||
1196 | struct ieee80211_hw *hw; | 1335 | struct ieee80211_hw *hw; |
1197 | struct wl1251 *wl; | 1336 | struct wl1251 *wl; |
1198 | int ret, i; | 1337 | int i; |
1199 | static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf}; | 1338 | static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf}; |
1200 | 1339 | ||
1201 | pdata = spi->dev.platform_data; | ||
1202 | if (!pdata) { | ||
1203 | wl1251_error("no platform data"); | ||
1204 | return -ENODEV; | ||
1205 | } | ||
1206 | |||
1207 | hw = ieee80211_alloc_hw(sizeof(*wl), &wl1251_ops); | 1340 | hw = ieee80211_alloc_hw(sizeof(*wl), &wl1251_ops); |
1208 | if (!hw) { | 1341 | if (!hw) { |
1209 | wl1251_error("could not alloc ieee80211_hw"); | 1342 | wl1251_error("could not alloc ieee80211_hw"); |
1210 | return -ENOMEM; | 1343 | return ERR_PTR(-ENOMEM); |
1211 | } | 1344 | } |
1212 | 1345 | ||
1213 | wl = hw->priv; | 1346 | wl = hw->priv; |
1214 | memset(wl, 0, sizeof(*wl)); | 1347 | memset(wl, 0, sizeof(*wl)); |
1215 | 1348 | ||
1216 | wl->hw = hw; | 1349 | wl->hw = hw; |
1217 | dev_set_drvdata(&spi->dev, wl); | ||
1218 | wl->spi = spi; | ||
1219 | 1350 | ||
1220 | wl->data_in_count = 0; | 1351 | wl->data_in_count = 0; |
1221 | 1352 | ||
@@ -1237,16 +1368,17 @@ static int __devinit wl1251_probe(struct spi_device *spi) | |||
1237 | wl->psm_requested = false; | 1368 | wl->psm_requested = false; |
1238 | wl->tx_queue_stopped = false; | 1369 | wl->tx_queue_stopped = false; |
1239 | wl->power_level = WL1251_DEFAULT_POWER_LEVEL; | 1370 | wl->power_level = WL1251_DEFAULT_POWER_LEVEL; |
1240 | 1371 | wl->beacon_int = WL1251_DEFAULT_BEACON_INT; | |
1241 | /* We use the default power on sleep time until we know which chip | 1372 | wl->dtim_period = WL1251_DEFAULT_DTIM_PERIOD; |
1242 | * we're using */ | ||
1243 | wl->chip.power_on_sleep = WL1251_DEFAULT_POWER_ON_SLEEP; | ||
1244 | 1373 | ||
1245 | for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) | 1374 | for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) |
1246 | wl->tx_frames[i] = NULL; | 1375 | wl->tx_frames[i] = NULL; |
1247 | 1376 | ||
1248 | wl->next_tx_complete = 0; | 1377 | wl->next_tx_complete = 0; |
1249 | 1378 | ||
1379 | INIT_WORK(&wl->irq_work, wl1251_irq_work); | ||
1380 | INIT_WORK(&wl->tx_work, wl1251_tx_work); | ||
1381 | |||
1250 | /* | 1382 | /* |
1251 | * In case our MAC address is not correctly set, | 1383 | * In case our MAC address is not correctly set, |
1252 | * we use a random but Nokia MAC. | 1384 | * we use a random but Nokia MAC. |
@@ -1263,79 +1395,20 @@ static int __devinit wl1251_probe(struct spi_device *spi) | |||
1263 | wl->rx_descriptor = kmalloc(sizeof(*wl->rx_descriptor), GFP_KERNEL); | 1395 | wl->rx_descriptor = kmalloc(sizeof(*wl->rx_descriptor), GFP_KERNEL); |
1264 | if (!wl->rx_descriptor) { | 1396 | if (!wl->rx_descriptor) { |
1265 | wl1251_error("could not allocate memory for rx descriptor"); | 1397 | wl1251_error("could not allocate memory for rx descriptor"); |
1266 | ret = -ENOMEM; | 1398 | ieee80211_free_hw(hw); |
1267 | goto out_free; | 1399 | return ERR_PTR(-ENOMEM); |
1268 | } | ||
1269 | |||
1270 | /* This is the only SPI value that we need to set here, the rest | ||
1271 | * comes from the board-peripherals file */ | ||
1272 | spi->bits_per_word = 32; | ||
1273 | |||
1274 | ret = spi_setup(spi); | ||
1275 | if (ret < 0) { | ||
1276 | wl1251_error("spi_setup failed"); | ||
1277 | goto out_free; | ||
1278 | } | 1400 | } |
1279 | 1401 | ||
1280 | wl->set_power = pdata->set_power; | 1402 | return hw; |
1281 | if (!wl->set_power) { | ||
1282 | wl1251_error("set power function missing in platform data"); | ||
1283 | ret = -ENODEV; | ||
1284 | goto out_free; | ||
1285 | } | ||
1286 | |||
1287 | wl->irq = spi->irq; | ||
1288 | if (wl->irq < 0) { | ||
1289 | wl1251_error("irq missing in platform data"); | ||
1290 | ret = -ENODEV; | ||
1291 | goto out_free; | ||
1292 | } | ||
1293 | |||
1294 | ret = request_irq(wl->irq, wl1251_irq, 0, DRIVER_NAME, wl); | ||
1295 | if (ret < 0) { | ||
1296 | wl1251_error("request_irq() failed: %d", ret); | ||
1297 | goto out_free; | ||
1298 | } | ||
1299 | |||
1300 | set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); | ||
1301 | |||
1302 | disable_irq(wl->irq); | ||
1303 | |||
1304 | ret = wl1251_init_ieee80211(wl); | ||
1305 | if (ret) | ||
1306 | goto out_irq; | ||
1307 | |||
1308 | ret = wl1251_register_hw(wl); | ||
1309 | if (ret) | ||
1310 | goto out_irq; | ||
1311 | |||
1312 | wl1251_debugfs_init(wl); | ||
1313 | |||
1314 | wl1251_notice("initialized"); | ||
1315 | |||
1316 | return 0; | ||
1317 | |||
1318 | out_irq: | ||
1319 | free_irq(wl->irq, wl); | ||
1320 | |||
1321 | out_free: | ||
1322 | kfree(wl->rx_descriptor); | ||
1323 | wl->rx_descriptor = NULL; | ||
1324 | |||
1325 | ieee80211_free_hw(hw); | ||
1326 | |||
1327 | return ret; | ||
1328 | } | 1403 | } |
1404 | EXPORT_SYMBOL_GPL(wl1251_alloc_hw); | ||
1329 | 1405 | ||
1330 | static int __devexit wl1251_remove(struct spi_device *spi) | 1406 | int wl1251_free_hw(struct wl1251 *wl) |
1331 | { | 1407 | { |
1332 | struct wl1251 *wl = dev_get_drvdata(&spi->dev); | ||
1333 | |||
1334 | ieee80211_unregister_hw(wl->hw); | 1408 | ieee80211_unregister_hw(wl->hw); |
1335 | 1409 | ||
1336 | wl1251_debugfs_exit(wl); | 1410 | wl1251_debugfs_exit(wl); |
1337 | 1411 | ||
1338 | free_irq(wl->irq, wl); | ||
1339 | kfree(wl->target_mem_map); | 1412 | kfree(wl->target_mem_map); |
1340 | kfree(wl->data_path); | 1413 | kfree(wl->data_path); |
1341 | kfree(wl->fw); | 1414 | kfree(wl->fw); |
@@ -1350,44 +1423,8 @@ static int __devexit wl1251_remove(struct spi_device *spi) | |||
1350 | 1423 | ||
1351 | return 0; | 1424 | return 0; |
1352 | } | 1425 | } |
1426 | EXPORT_SYMBOL_GPL(wl1251_free_hw); | ||
1353 | 1427 | ||
1354 | 1428 | MODULE_DESCRIPTION("TI wl1251 Wireles LAN Driver Core"); | |
1355 | static struct spi_driver wl1251_spi_driver = { | ||
1356 | .driver = { | ||
1357 | /* FIXME: use wl12xx name to not break the user space */ | ||
1358 | .name = "wl12xx", | ||
1359 | .bus = &spi_bus_type, | ||
1360 | .owner = THIS_MODULE, | ||
1361 | }, | ||
1362 | |||
1363 | .probe = wl1251_probe, | ||
1364 | .remove = __devexit_p(wl1251_remove), | ||
1365 | }; | ||
1366 | |||
1367 | static int __init wl1251_init(void) | ||
1368 | { | ||
1369 | int ret; | ||
1370 | |||
1371 | ret = spi_register_driver(&wl1251_spi_driver); | ||
1372 | if (ret < 0) { | ||
1373 | wl1251_error("failed to register spi driver: %d", ret); | ||
1374 | goto out; | ||
1375 | } | ||
1376 | |||
1377 | out: | ||
1378 | return ret; | ||
1379 | } | ||
1380 | |||
1381 | static void __exit wl1251_exit(void) | ||
1382 | { | ||
1383 | spi_unregister_driver(&wl1251_spi_driver); | ||
1384 | |||
1385 | wl1251_notice("unloaded"); | ||
1386 | } | ||
1387 | |||
1388 | module_init(wl1251_init); | ||
1389 | module_exit(wl1251_exit); | ||
1390 | |||
1391 | MODULE_LICENSE("GPL"); | 1429 | MODULE_LICENSE("GPL"); |
1392 | MODULE_AUTHOR("Kalle Valo <Kalle.Valo@nokia.com>, " | 1430 | MODULE_AUTHOR("Kalle Valo <kalle.valo@nokia.com>"); |
1393 | "Luciano Coelho <luciano.coelho@nokia.com>"); | ||
diff --git a/drivers/net/wireless/wl12xx/wl1251_ops.c b/drivers/net/wireless/wl12xx/wl1251_ops.c deleted file mode 100644 index e7b9aab3682f..000000000000 --- a/drivers/net/wireless/wl12xx/wl1251_ops.c +++ /dev/null | |||
@@ -1,728 +0,0 @@ | |||
1 | /* | ||
2 | * This file is part of wl1251 | ||
3 | * | ||
4 | * Copyright (C) 2008-2009 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Kalle Valo <kalle.valo@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/module.h> | ||
26 | |||
27 | #include "wl1251_ops.h" | ||
28 | #include "reg.h" | ||
29 | #include "wl1251_spi.h" | ||
30 | #include "wl1251_boot.h" | ||
31 | #include "wl1251_event.h" | ||
32 | #include "wl1251_acx.h" | ||
33 | #include "wl1251_tx.h" | ||
34 | #include "wl1251_rx.h" | ||
35 | #include "wl1251_ps.h" | ||
36 | #include "wl1251_init.h" | ||
37 | |||
38 | static struct wl1251_partition_set wl1251_part_table[PART_TABLE_LEN] = { | ||
39 | [PART_DOWN] = { | ||
40 | .mem = { | ||
41 | .start = 0x00000000, | ||
42 | .size = 0x00016800 | ||
43 | }, | ||
44 | .reg = { | ||
45 | .start = REGISTERS_BASE, | ||
46 | .size = REGISTERS_DOWN_SIZE | ||
47 | }, | ||
48 | }, | ||
49 | |||
50 | [PART_WORK] = { | ||
51 | .mem = { | ||
52 | .start = 0x00028000, | ||
53 | .size = 0x00014000 | ||
54 | }, | ||
55 | .reg = { | ||
56 | .start = REGISTERS_BASE, | ||
57 | .size = REGISTERS_WORK_SIZE | ||
58 | }, | ||
59 | }, | ||
60 | |||
61 | /* WL1251 doesn't use the DRPW partition, so we don't set it here */ | ||
62 | }; | ||
63 | |||
64 | static enum wl12xx_acx_int_reg wl1251_acx_reg_table[ACX_REG_TABLE_LEN] = { | ||
65 | [ACX_REG_INTERRUPT_TRIG] = (REGISTERS_BASE + 0x0474), | ||
66 | [ACX_REG_INTERRUPT_TRIG_H] = (REGISTERS_BASE + 0x0478), | ||
67 | [ACX_REG_INTERRUPT_MASK] = (REGISTERS_BASE + 0x0494), | ||
68 | [ACX_REG_HINT_MASK_SET] = (REGISTERS_BASE + 0x0498), | ||
69 | [ACX_REG_HINT_MASK_CLR] = (REGISTERS_BASE + 0x049C), | ||
70 | [ACX_REG_INTERRUPT_NO_CLEAR] = (REGISTERS_BASE + 0x04B0), | ||
71 | [ACX_REG_INTERRUPT_CLEAR] = (REGISTERS_BASE + 0x04A4), | ||
72 | [ACX_REG_INTERRUPT_ACK] = (REGISTERS_BASE + 0x04A8), | ||
73 | [ACX_REG_SLV_SOFT_RESET] = (REGISTERS_BASE + 0x0000), | ||
74 | [ACX_REG_EE_START] = (REGISTERS_BASE + 0x080C), | ||
75 | [ACX_REG_ECPU_CONTROL] = (REGISTERS_BASE + 0x0804) | ||
76 | }; | ||
77 | |||
78 | static int wl1251_upload_firmware(struct wl1251 *wl) | ||
79 | { | ||
80 | struct wl1251_partition_set *p_table = wl->chip.p_table; | ||
81 | int addr, chunk_num, partition_limit; | ||
82 | size_t fw_data_len; | ||
83 | u8 *p; | ||
84 | |||
85 | /* whal_FwCtrl_LoadFwImageSm() */ | ||
86 | |||
87 | wl1251_debug(DEBUG_BOOT, "chip id before fw upload: 0x%x", | ||
88 | wl1251_reg_read32(wl, CHIP_ID_B)); | ||
89 | |||
90 | /* 10.0 check firmware length and set partition */ | ||
91 | fw_data_len = (wl->fw[4] << 24) | (wl->fw[5] << 16) | | ||
92 | (wl->fw[6] << 8) | (wl->fw[7]); | ||
93 | |||
94 | wl1251_debug(DEBUG_BOOT, "fw_data_len %zu chunk_size %d", fw_data_len, | ||
95 | CHUNK_SIZE); | ||
96 | |||
97 | if ((fw_data_len % 4) != 0) { | ||
98 | wl1251_error("firmware length not multiple of four"); | ||
99 | return -EIO; | ||
100 | } | ||
101 | |||
102 | wl1251_set_partition(wl, | ||
103 | p_table[PART_DOWN].mem.start, | ||
104 | p_table[PART_DOWN].mem.size, | ||
105 | p_table[PART_DOWN].reg.start, | ||
106 | p_table[PART_DOWN].reg.size); | ||
107 | |||
108 | /* 10.1 set partition limit and chunk num */ | ||
109 | chunk_num = 0; | ||
110 | partition_limit = p_table[PART_DOWN].mem.size; | ||
111 | |||
112 | while (chunk_num < fw_data_len / CHUNK_SIZE) { | ||
113 | /* 10.2 update partition, if needed */ | ||
114 | addr = p_table[PART_DOWN].mem.start + | ||
115 | (chunk_num + 2) * CHUNK_SIZE; | ||
116 | if (addr > partition_limit) { | ||
117 | addr = p_table[PART_DOWN].mem.start + | ||
118 | chunk_num * CHUNK_SIZE; | ||
119 | partition_limit = chunk_num * CHUNK_SIZE + | ||
120 | p_table[PART_DOWN].mem.size; | ||
121 | wl1251_set_partition(wl, | ||
122 | addr, | ||
123 | p_table[PART_DOWN].mem.size, | ||
124 | p_table[PART_DOWN].reg.start, | ||
125 | p_table[PART_DOWN].reg.size); | ||
126 | } | ||
127 | |||
128 | /* 10.3 upload the chunk */ | ||
129 | addr = p_table[PART_DOWN].mem.start + chunk_num * CHUNK_SIZE; | ||
130 | p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; | ||
131 | wl1251_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x", | ||
132 | p, addr); | ||
133 | wl1251_spi_mem_write(wl, addr, p, CHUNK_SIZE); | ||
134 | |||
135 | chunk_num++; | ||
136 | } | ||
137 | |||
138 | /* 10.4 upload the last chunk */ | ||
139 | addr = p_table[PART_DOWN].mem.start + chunk_num * CHUNK_SIZE; | ||
140 | p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; | ||
141 | wl1251_debug(DEBUG_BOOT, "uploading fw last chunk (%zu B) 0x%p to 0x%x", | ||
142 | fw_data_len % CHUNK_SIZE, p, addr); | ||
143 | wl1251_spi_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE); | ||
144 | |||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | static int wl1251_upload_nvs(struct wl1251 *wl) | ||
149 | { | ||
150 | size_t nvs_len, nvs_bytes_written, burst_len; | ||
151 | int nvs_start, i; | ||
152 | u32 dest_addr, val; | ||
153 | u8 *nvs_ptr, *nvs; | ||
154 | |||
155 | nvs = wl->nvs; | ||
156 | if (nvs == NULL) | ||
157 | return -ENODEV; | ||
158 | |||
159 | nvs_ptr = nvs; | ||
160 | |||
161 | nvs_len = wl->nvs_len; | ||
162 | nvs_start = wl->fw_len; | ||
163 | |||
164 | /* | ||
165 | * Layout before the actual NVS tables: | ||
166 | * 1 byte : burst length. | ||
167 | * 2 bytes: destination address. | ||
168 | * n bytes: data to burst copy. | ||
169 | * | ||
170 | * This is ended by a 0 length, then the NVS tables. | ||
171 | */ | ||
172 | |||
173 | while (nvs_ptr[0]) { | ||
174 | burst_len = nvs_ptr[0]; | ||
175 | dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8)); | ||
176 | |||
177 | /* We move our pointer to the data */ | ||
178 | nvs_ptr += 3; | ||
179 | |||
180 | for (i = 0; i < burst_len; i++) { | ||
181 | val = (nvs_ptr[0] | (nvs_ptr[1] << 8) | ||
182 | | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); | ||
183 | |||
184 | wl1251_debug(DEBUG_BOOT, | ||
185 | "nvs burst write 0x%x: 0x%x", | ||
186 | dest_addr, val); | ||
187 | wl1251_mem_write32(wl, dest_addr, val); | ||
188 | |||
189 | nvs_ptr += 4; | ||
190 | dest_addr += 4; | ||
191 | } | ||
192 | } | ||
193 | |||
194 | /* | ||
195 | * We've reached the first zero length, the first NVS table | ||
196 | * is 7 bytes further. | ||
197 | */ | ||
198 | nvs_ptr += 7; | ||
199 | nvs_len -= nvs_ptr - nvs; | ||
200 | nvs_len = ALIGN(nvs_len, 4); | ||
201 | |||
202 | /* Now we must set the partition correctly */ | ||
203 | wl1251_set_partition(wl, nvs_start, | ||
204 | wl->chip.p_table[PART_DOWN].mem.size, | ||
205 | wl->chip.p_table[PART_DOWN].reg.start, | ||
206 | wl->chip.p_table[PART_DOWN].reg.size); | ||
207 | |||
208 | /* And finally we upload the NVS tables */ | ||
209 | nvs_bytes_written = 0; | ||
210 | while (nvs_bytes_written < nvs_len) { | ||
211 | val = (nvs_ptr[0] | (nvs_ptr[1] << 8) | ||
212 | | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); | ||
213 | |||
214 | val = cpu_to_le32(val); | ||
215 | |||
216 | wl1251_debug(DEBUG_BOOT, | ||
217 | "nvs write table 0x%x: 0x%x", | ||
218 | nvs_start, val); | ||
219 | wl1251_mem_write32(wl, nvs_start, val); | ||
220 | |||
221 | nvs_ptr += 4; | ||
222 | nvs_bytes_written += 4; | ||
223 | nvs_start += 4; | ||
224 | } | ||
225 | |||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | static int wl1251_boot(struct wl1251 *wl) | ||
230 | { | ||
231 | int ret = 0, minor_minor_e2_ver; | ||
232 | u32 tmp, boot_data; | ||
233 | |||
234 | ret = wl1251_boot_soft_reset(wl); | ||
235 | if (ret < 0) | ||
236 | goto out; | ||
237 | |||
238 | /* 2. start processing NVS file */ | ||
239 | ret = wl->chip.op_upload_nvs(wl); | ||
240 | if (ret < 0) | ||
241 | goto out; | ||
242 | |||
243 | /* write firmware's last address (ie. it's length) to | ||
244 | * ACX_EEPROMLESS_IND_REG */ | ||
245 | wl1251_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len); | ||
246 | |||
247 | /* 6. read the EEPROM parameters */ | ||
248 | tmp = wl1251_reg_read32(wl, SCR_PAD2); | ||
249 | |||
250 | /* 7. read bootdata */ | ||
251 | wl->boot_attr.radio_type = (tmp & 0x0000FF00) >> 8; | ||
252 | wl->boot_attr.major = (tmp & 0x00FF0000) >> 16; | ||
253 | tmp = wl1251_reg_read32(wl, SCR_PAD3); | ||
254 | |||
255 | /* 8. check bootdata and call restart sequence */ | ||
256 | wl->boot_attr.minor = (tmp & 0x00FF0000) >> 16; | ||
257 | minor_minor_e2_ver = (tmp & 0xFF000000) >> 24; | ||
258 | |||
259 | wl1251_debug(DEBUG_BOOT, "radioType 0x%x majorE2Ver 0x%x " | ||
260 | "minorE2Ver 0x%x minor_minor_e2_ver 0x%x", | ||
261 | wl->boot_attr.radio_type, wl->boot_attr.major, | ||
262 | wl->boot_attr.minor, minor_minor_e2_ver); | ||
263 | |||
264 | ret = wl1251_boot_init_seq(wl); | ||
265 | if (ret < 0) | ||
266 | goto out; | ||
267 | |||
268 | /* 9. NVS processing done */ | ||
269 | boot_data = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL); | ||
270 | |||
271 | wl1251_debug(DEBUG_BOOT, "halt boot_data 0x%x", boot_data); | ||
272 | |||
273 | /* 10. check that ECPU_CONTROL_HALT bits are set in | ||
274 | * pWhalBus->uBootData and start uploading firmware | ||
275 | */ | ||
276 | if ((boot_data & ECPU_CONTROL_HALT) == 0) { | ||
277 | wl1251_error("boot failed, ECPU_CONTROL_HALT not set"); | ||
278 | ret = -EIO; | ||
279 | goto out; | ||
280 | } | ||
281 | |||
282 | ret = wl->chip.op_upload_fw(wl); | ||
283 | if (ret < 0) | ||
284 | goto out; | ||
285 | |||
286 | /* 10.5 start firmware */ | ||
287 | ret = wl1251_boot_run_firmware(wl); | ||
288 | if (ret < 0) | ||
289 | goto out; | ||
290 | |||
291 | out: | ||
292 | return ret; | ||
293 | } | ||
294 | |||
295 | static int wl1251_mem_cfg(struct wl1251 *wl) | ||
296 | { | ||
297 | struct wl1251_acx_config_memory *mem_conf; | ||
298 | int ret, i; | ||
299 | |||
300 | wl1251_debug(DEBUG_ACX, "wl1251 mem cfg"); | ||
301 | |||
302 | mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL); | ||
303 | if (!mem_conf) { | ||
304 | ret = -ENOMEM; | ||
305 | goto out; | ||
306 | } | ||
307 | |||
308 | /* memory config */ | ||
309 | mem_conf->mem_config.num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS); | ||
310 | mem_conf->mem_config.rx_mem_block_num = 35; | ||
311 | mem_conf->mem_config.tx_min_mem_block_num = 64; | ||
312 | mem_conf->mem_config.num_tx_queues = MAX_TX_QUEUES; | ||
313 | mem_conf->mem_config.host_if_options = HOSTIF_PKT_RING; | ||
314 | mem_conf->mem_config.num_ssid_profiles = 1; | ||
315 | mem_conf->mem_config.debug_buffer_size = | ||
316 | cpu_to_le16(TRACE_BUFFER_MAX_SIZE); | ||
317 | |||
318 | /* RX queue config */ | ||
319 | mem_conf->rx_queue_config.dma_address = 0; | ||
320 | mem_conf->rx_queue_config.num_descs = ACX_RX_DESC_DEF; | ||
321 | mem_conf->rx_queue_config.priority = DEFAULT_RXQ_PRIORITY; | ||
322 | mem_conf->rx_queue_config.type = DEFAULT_RXQ_TYPE; | ||
323 | |||
324 | /* TX queue config */ | ||
325 | for (i = 0; i < MAX_TX_QUEUES; i++) { | ||
326 | mem_conf->tx_queue_config[i].num_descs = ACX_TX_DESC_DEF; | ||
327 | mem_conf->tx_queue_config[i].attributes = i; | ||
328 | } | ||
329 | |||
330 | ret = wl1251_cmd_configure(wl, ACX_MEM_CFG, mem_conf, | ||
331 | sizeof(*mem_conf)); | ||
332 | if (ret < 0) { | ||
333 | wl1251_warning("wl1251 mem config failed: %d", ret); | ||
334 | goto out; | ||
335 | } | ||
336 | |||
337 | out: | ||
338 | kfree(mem_conf); | ||
339 | return ret; | ||
340 | } | ||
341 | |||
342 | static int wl1251_hw_init_mem_config(struct wl1251 *wl) | ||
343 | { | ||
344 | int ret; | ||
345 | |||
346 | ret = wl1251_mem_cfg(wl); | ||
347 | if (ret < 0) | ||
348 | return ret; | ||
349 | |||
350 | wl->target_mem_map = kzalloc(sizeof(struct wl1251_acx_mem_map), | ||
351 | GFP_KERNEL); | ||
352 | if (!wl->target_mem_map) { | ||
353 | wl1251_error("couldn't allocate target memory map"); | ||
354 | return -ENOMEM; | ||
355 | } | ||
356 | |||
357 | /* we now ask for the firmware built memory map */ | ||
358 | ret = wl1251_acx_mem_map(wl, wl->target_mem_map, | ||
359 | sizeof(struct wl1251_acx_mem_map)); | ||
360 | if (ret < 0) { | ||
361 | wl1251_error("couldn't retrieve firmware memory map"); | ||
362 | kfree(wl->target_mem_map); | ||
363 | wl->target_mem_map = NULL; | ||
364 | return ret; | ||
365 | } | ||
366 | |||
367 | return 0; | ||
368 | } | ||
369 | |||
370 | static void wl1251_set_ecpu_ctrl(struct wl1251 *wl, u32 flag) | ||
371 | { | ||
372 | u32 cpu_ctrl; | ||
373 | |||
374 | /* 10.5.0 run the firmware (I) */ | ||
375 | cpu_ctrl = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL); | ||
376 | |||
377 | /* 10.5.1 run the firmware (II) */ | ||
378 | cpu_ctrl &= ~flag; | ||
379 | wl1251_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl); | ||
380 | } | ||
381 | |||
382 | static void wl1251_target_enable_interrupts(struct wl1251 *wl) | ||
383 | { | ||
384 | /* Enable target's interrupts */ | ||
385 | wl->intr_mask = WL1251_ACX_INTR_RX0_DATA | | ||
386 | WL1251_ACX_INTR_RX1_DATA | | ||
387 | WL1251_ACX_INTR_TX_RESULT | | ||
388 | WL1251_ACX_INTR_EVENT_A | | ||
389 | WL1251_ACX_INTR_EVENT_B | | ||
390 | WL1251_ACX_INTR_INIT_COMPLETE; | ||
391 | wl1251_boot_target_enable_interrupts(wl); | ||
392 | } | ||
393 | |||
394 | static void wl1251_fw_version(struct wl1251 *wl) | ||
395 | { | ||
396 | wl1251_acx_fw_version(wl, wl->chip.fw_ver, sizeof(wl->chip.fw_ver)); | ||
397 | } | ||
398 | |||
399 | static void wl1251_irq_work(struct work_struct *work) | ||
400 | { | ||
401 | u32 intr; | ||
402 | struct wl1251 *wl = | ||
403 | container_of(work, struct wl1251, irq_work); | ||
404 | int ret; | ||
405 | |||
406 | mutex_lock(&wl->mutex); | ||
407 | |||
408 | wl1251_debug(DEBUG_IRQ, "IRQ work"); | ||
409 | |||
410 | if (wl->state == WL1251_STATE_OFF) | ||
411 | goto out; | ||
412 | |||
413 | ret = wl1251_ps_elp_wakeup(wl); | ||
414 | if (ret < 0) | ||
415 | goto out; | ||
416 | |||
417 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1251_ACX_INTR_ALL); | ||
418 | |||
419 | intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); | ||
420 | wl1251_debug(DEBUG_IRQ, "intr: 0x%x", intr); | ||
421 | |||
422 | if (wl->data_path) { | ||
423 | wl->rx_counter = | ||
424 | wl1251_mem_read32(wl, wl->data_path->rx_control_addr); | ||
425 | |||
426 | /* We handle a firmware bug here */ | ||
427 | switch ((wl->rx_counter - wl->rx_handled) & 0xf) { | ||
428 | case 0: | ||
429 | wl1251_debug(DEBUG_IRQ, "RX: FW and host in sync"); | ||
430 | intr &= ~WL1251_ACX_INTR_RX0_DATA; | ||
431 | intr &= ~WL1251_ACX_INTR_RX1_DATA; | ||
432 | break; | ||
433 | case 1: | ||
434 | wl1251_debug(DEBUG_IRQ, "RX: FW +1"); | ||
435 | intr |= WL1251_ACX_INTR_RX0_DATA; | ||
436 | intr &= ~WL1251_ACX_INTR_RX1_DATA; | ||
437 | break; | ||
438 | case 2: | ||
439 | wl1251_debug(DEBUG_IRQ, "RX: FW +2"); | ||
440 | intr |= WL1251_ACX_INTR_RX0_DATA; | ||
441 | intr |= WL1251_ACX_INTR_RX1_DATA; | ||
442 | break; | ||
443 | default: | ||
444 | wl1251_warning("RX: FW and host out of sync: %d", | ||
445 | wl->rx_counter - wl->rx_handled); | ||
446 | break; | ||
447 | } | ||
448 | |||
449 | wl->rx_handled = wl->rx_counter; | ||
450 | |||
451 | |||
452 | wl1251_debug(DEBUG_IRQ, "RX counter: %d", wl->rx_counter); | ||
453 | } | ||
454 | |||
455 | intr &= wl->intr_mask; | ||
456 | |||
457 | if (intr == 0) { | ||
458 | wl1251_debug(DEBUG_IRQ, "INTR is 0"); | ||
459 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, | ||
460 | ~(wl->intr_mask)); | ||
461 | |||
462 | goto out_sleep; | ||
463 | } | ||
464 | |||
465 | if (intr & WL1251_ACX_INTR_RX0_DATA) { | ||
466 | wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA"); | ||
467 | wl1251_rx(wl); | ||
468 | } | ||
469 | |||
470 | if (intr & WL1251_ACX_INTR_RX1_DATA) { | ||
471 | wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA"); | ||
472 | wl1251_rx(wl); | ||
473 | } | ||
474 | |||
475 | if (intr & WL1251_ACX_INTR_TX_RESULT) { | ||
476 | wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT"); | ||
477 | wl1251_tx_complete(wl); | ||
478 | } | ||
479 | |||
480 | if (intr & (WL1251_ACX_INTR_EVENT_A | WL1251_ACX_INTR_EVENT_B)) { | ||
481 | wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)", intr); | ||
482 | if (intr & WL1251_ACX_INTR_EVENT_A) | ||
483 | wl1251_event_handle(wl, 0); | ||
484 | else | ||
485 | wl1251_event_handle(wl, 1); | ||
486 | } | ||
487 | |||
488 | if (intr & WL1251_ACX_INTR_INIT_COMPLETE) | ||
489 | wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_INIT_COMPLETE"); | ||
490 | |||
491 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); | ||
492 | |||
493 | out_sleep: | ||
494 | wl1251_ps_elp_sleep(wl); | ||
495 | |||
496 | out: | ||
497 | mutex_unlock(&wl->mutex); | ||
498 | } | ||
499 | |||
500 | static int wl1251_hw_init_txq_fill(u8 qid, | ||
501 | struct acx_tx_queue_qos_config *config, | ||
502 | u32 num_blocks) | ||
503 | { | ||
504 | config->qid = qid; | ||
505 | |||
506 | switch (qid) { | ||
507 | case QOS_AC_BE: | ||
508 | config->high_threshold = | ||
509 | (QOS_TX_HIGH_BE_DEF * num_blocks) / 100; | ||
510 | config->low_threshold = | ||
511 | (QOS_TX_LOW_BE_DEF * num_blocks) / 100; | ||
512 | break; | ||
513 | case QOS_AC_BK: | ||
514 | config->high_threshold = | ||
515 | (QOS_TX_HIGH_BK_DEF * num_blocks) / 100; | ||
516 | config->low_threshold = | ||
517 | (QOS_TX_LOW_BK_DEF * num_blocks) / 100; | ||
518 | break; | ||
519 | case QOS_AC_VI: | ||
520 | config->high_threshold = | ||
521 | (QOS_TX_HIGH_VI_DEF * num_blocks) / 100; | ||
522 | config->low_threshold = | ||
523 | (QOS_TX_LOW_VI_DEF * num_blocks) / 100; | ||
524 | break; | ||
525 | case QOS_AC_VO: | ||
526 | config->high_threshold = | ||
527 | (QOS_TX_HIGH_VO_DEF * num_blocks) / 100; | ||
528 | config->low_threshold = | ||
529 | (QOS_TX_LOW_VO_DEF * num_blocks) / 100; | ||
530 | break; | ||
531 | default: | ||
532 | wl1251_error("Invalid TX queue id: %d", qid); | ||
533 | return -EINVAL; | ||
534 | } | ||
535 | |||
536 | return 0; | ||
537 | } | ||
538 | |||
539 | static int wl1251_hw_init_tx_queue_config(struct wl1251 *wl) | ||
540 | { | ||
541 | struct acx_tx_queue_qos_config *config; | ||
542 | struct wl1251_acx_mem_map *wl_mem_map = wl->target_mem_map; | ||
543 | int ret, i; | ||
544 | |||
545 | wl1251_debug(DEBUG_ACX, "acx tx queue config"); | ||
546 | |||
547 | config = kzalloc(sizeof(*config), GFP_KERNEL); | ||
548 | if (!config) { | ||
549 | ret = -ENOMEM; | ||
550 | goto out; | ||
551 | } | ||
552 | |||
553 | for (i = 0; i < MAX_NUM_OF_AC; i++) { | ||
554 | ret = wl1251_hw_init_txq_fill(i, config, | ||
555 | wl_mem_map->num_tx_mem_blocks); | ||
556 | if (ret < 0) | ||
557 | goto out; | ||
558 | |||
559 | ret = wl1251_cmd_configure(wl, ACX_TX_QUEUE_CFG, | ||
560 | config, sizeof(*config)); | ||
561 | if (ret < 0) | ||
562 | goto out; | ||
563 | } | ||
564 | |||
565 | out: | ||
566 | kfree(config); | ||
567 | return ret; | ||
568 | } | ||
569 | |||
570 | static int wl1251_hw_init_data_path_config(struct wl1251 *wl) | ||
571 | { | ||
572 | int ret; | ||
573 | |||
574 | /* asking for the data path parameters */ | ||
575 | wl->data_path = kzalloc(sizeof(struct acx_data_path_params_resp), | ||
576 | GFP_KERNEL); | ||
577 | if (!wl->data_path) { | ||
578 | wl1251_error("Couldn't allocate data path parameters"); | ||
579 | return -ENOMEM; | ||
580 | } | ||
581 | |||
582 | ret = wl1251_acx_data_path_params(wl, wl->data_path); | ||
583 | if (ret < 0) { | ||
584 | kfree(wl->data_path); | ||
585 | wl->data_path = NULL; | ||
586 | return ret; | ||
587 | } | ||
588 | |||
589 | return 0; | ||
590 | } | ||
591 | |||
592 | static int wl1251_hw_init(struct wl1251 *wl) | ||
593 | { | ||
594 | struct wl1251_acx_mem_map *wl_mem_map; | ||
595 | int ret; | ||
596 | |||
597 | ret = wl1251_hw_init_hwenc_config(wl); | ||
598 | if (ret < 0) | ||
599 | return ret; | ||
600 | |||
601 | /* Template settings */ | ||
602 | ret = wl1251_hw_init_templates_config(wl); | ||
603 | if (ret < 0) | ||
604 | return ret; | ||
605 | |||
606 | /* Default memory configuration */ | ||
607 | ret = wl1251_hw_init_mem_config(wl); | ||
608 | if (ret < 0) | ||
609 | return ret; | ||
610 | |||
611 | /* Default data path configuration */ | ||
612 | ret = wl1251_hw_init_data_path_config(wl); | ||
613 | if (ret < 0) | ||
614 | goto out_free_memmap; | ||
615 | |||
616 | /* RX config */ | ||
617 | ret = wl1251_hw_init_rx_config(wl, | ||
618 | RX_CFG_PROMISCUOUS | RX_CFG_TSF, | ||
619 | RX_FILTER_OPTION_DEF); | ||
620 | /* RX_CONFIG_OPTION_ANY_DST_ANY_BSS, | ||
621 | RX_FILTER_OPTION_FILTER_ALL); */ | ||
622 | if (ret < 0) | ||
623 | goto out_free_data_path; | ||
624 | |||
625 | /* TX queues config */ | ||
626 | ret = wl1251_hw_init_tx_queue_config(wl); | ||
627 | if (ret < 0) | ||
628 | goto out_free_data_path; | ||
629 | |||
630 | /* PHY layer config */ | ||
631 | ret = wl1251_hw_init_phy_config(wl); | ||
632 | if (ret < 0) | ||
633 | goto out_free_data_path; | ||
634 | |||
635 | /* Beacon filtering */ | ||
636 | ret = wl1251_hw_init_beacon_filter(wl); | ||
637 | if (ret < 0) | ||
638 | goto out_free_data_path; | ||
639 | |||
640 | /* Bluetooth WLAN coexistence */ | ||
641 | ret = wl1251_hw_init_pta(wl); | ||
642 | if (ret < 0) | ||
643 | goto out_free_data_path; | ||
644 | |||
645 | /* Energy detection */ | ||
646 | ret = wl1251_hw_init_energy_detection(wl); | ||
647 | if (ret < 0) | ||
648 | goto out_free_data_path; | ||
649 | |||
650 | /* Beacons and boradcast settings */ | ||
651 | ret = wl1251_hw_init_beacon_broadcast(wl); | ||
652 | if (ret < 0) | ||
653 | goto out_free_data_path; | ||
654 | |||
655 | /* Enable data path */ | ||
656 | ret = wl1251_cmd_data_path(wl, wl->channel, 1); | ||
657 | if (ret < 0) | ||
658 | goto out_free_data_path; | ||
659 | |||
660 | /* Default power state */ | ||
661 | ret = wl1251_hw_init_power_auth(wl); | ||
662 | if (ret < 0) | ||
663 | goto out_free_data_path; | ||
664 | |||
665 | wl_mem_map = wl->target_mem_map; | ||
666 | wl1251_info("%d tx blocks at 0x%x, %d rx blocks at 0x%x", | ||
667 | wl_mem_map->num_tx_mem_blocks, | ||
668 | wl->data_path->tx_control_addr, | ||
669 | wl_mem_map->num_rx_mem_blocks, | ||
670 | wl->data_path->rx_control_addr); | ||
671 | |||
672 | return 0; | ||
673 | |||
674 | out_free_data_path: | ||
675 | kfree(wl->data_path); | ||
676 | |||
677 | out_free_memmap: | ||
678 | kfree(wl->target_mem_map); | ||
679 | |||
680 | return ret; | ||
681 | } | ||
682 | |||
683 | static int wl1251_plt_init(struct wl1251 *wl) | ||
684 | { | ||
685 | int ret; | ||
686 | |||
687 | ret = wl1251_hw_init_mem_config(wl); | ||
688 | if (ret < 0) | ||
689 | return ret; | ||
690 | |||
691 | ret = wl1251_cmd_data_path(wl, wl->channel, 1); | ||
692 | if (ret < 0) | ||
693 | return ret; | ||
694 | |||
695 | return 0; | ||
696 | } | ||
697 | |||
698 | void wl1251_setup(struct wl1251 *wl) | ||
699 | { | ||
700 | /* FIXME: Is it better to use strncpy here or is this ok? */ | ||
701 | wl->chip.fw_filename = WL1251_FW_NAME; | ||
702 | wl->chip.nvs_filename = WL1251_NVS_NAME; | ||
703 | |||
704 | /* Now we know what chip we're using, so adjust the power on sleep | ||
705 | * time accordingly */ | ||
706 | wl->chip.power_on_sleep = WL1251_POWER_ON_SLEEP; | ||
707 | |||
708 | wl->chip.intr_cmd_complete = WL1251_ACX_INTR_CMD_COMPLETE; | ||
709 | wl->chip.intr_init_complete = WL1251_ACX_INTR_INIT_COMPLETE; | ||
710 | |||
711 | wl->chip.op_upload_nvs = wl1251_upload_nvs; | ||
712 | wl->chip.op_upload_fw = wl1251_upload_firmware; | ||
713 | wl->chip.op_boot = wl1251_boot; | ||
714 | wl->chip.op_set_ecpu_ctrl = wl1251_set_ecpu_ctrl; | ||
715 | wl->chip.op_target_enable_interrupts = wl1251_target_enable_interrupts; | ||
716 | wl->chip.op_hw_init = wl1251_hw_init; | ||
717 | wl->chip.op_plt_init = wl1251_plt_init; | ||
718 | wl->chip.op_fw_version = wl1251_fw_version; | ||
719 | wl->chip.op_tx_flush = wl1251_tx_flush; | ||
720 | wl->chip.op_cmd_join = wl1251_cmd_join; | ||
721 | |||
722 | wl->chip.p_table = wl1251_part_table; | ||
723 | wl->chip.acx_reg_table = wl1251_acx_reg_table; | ||
724 | |||
725 | INIT_WORK(&wl->irq_work, wl1251_irq_work); | ||
726 | INIT_WORK(&wl->tx_work, wl1251_tx_work); | ||
727 | |||
728 | } | ||
diff --git a/drivers/net/wireless/wl12xx/wl1251_ops.h b/drivers/net/wireless/wl12xx/wl1251_ops.h deleted file mode 100644 index 68183c472e43..000000000000 --- a/drivers/net/wireless/wl12xx/wl1251_ops.h +++ /dev/null | |||
@@ -1,165 +0,0 @@ | |||
1 | /* | ||
2 | * This file is part of wl1251 | ||
3 | * | ||
4 | * Copyright (C) 2008 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Kalle Valo <kalle.valo@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifndef __WL1251_OPS_H__ | ||
25 | #define __WL1251_OPS_H__ | ||
26 | |||
27 | #include <linux/bitops.h> | ||
28 | |||
29 | #include "wl1251.h" | ||
30 | #include "wl1251_acx.h" | ||
31 | |||
32 | #define WL1251_FW_NAME "wl1251-fw.bin" | ||
33 | #define WL1251_NVS_NAME "wl1251-nvs.bin" | ||
34 | |||
35 | #define WL1251_POWER_ON_SLEEP 10 /* in miliseconds */ | ||
36 | |||
37 | void wl1251_setup(struct wl1251 *wl); | ||
38 | |||
39 | |||
40 | struct wl1251_acx_memory { | ||
41 | __le16 num_stations; /* number of STAs to be supported. */ | ||
42 | u16 reserved_1; | ||
43 | |||
44 | /* | ||
45 | * Nmber of memory buffers for the RX mem pool. | ||
46 | * The actual number may be less if there are | ||
47 | * not enough blocks left for the minimum num | ||
48 | * of TX ones. | ||
49 | */ | ||
50 | u8 rx_mem_block_num; | ||
51 | u8 reserved_2; | ||
52 | u8 num_tx_queues; /* From 1 to 16 */ | ||
53 | u8 host_if_options; /* HOST_IF* */ | ||
54 | u8 tx_min_mem_block_num; | ||
55 | u8 num_ssid_profiles; | ||
56 | __le16 debug_buffer_size; | ||
57 | } __attribute__ ((packed)); | ||
58 | |||
59 | |||
60 | #define ACX_RX_DESC_MIN 1 | ||
61 | #define ACX_RX_DESC_MAX 127 | ||
62 | #define ACX_RX_DESC_DEF 32 | ||
63 | struct wl1251_acx_rx_queue_config { | ||
64 | u8 num_descs; | ||
65 | u8 pad; | ||
66 | u8 type; | ||
67 | u8 priority; | ||
68 | __le32 dma_address; | ||
69 | } __attribute__ ((packed)); | ||
70 | |||
71 | #define ACX_TX_DESC_MIN 1 | ||
72 | #define ACX_TX_DESC_MAX 127 | ||
73 | #define ACX_TX_DESC_DEF 16 | ||
74 | struct wl1251_acx_tx_queue_config { | ||
75 | u8 num_descs; | ||
76 | u8 pad[2]; | ||
77 | u8 attributes; | ||
78 | } __attribute__ ((packed)); | ||
79 | |||
80 | #define MAX_TX_QUEUE_CONFIGS 5 | ||
81 | #define MAX_TX_QUEUES 4 | ||
82 | struct wl1251_acx_config_memory { | ||
83 | struct acx_header header; | ||
84 | |||
85 | struct wl1251_acx_memory mem_config; | ||
86 | struct wl1251_acx_rx_queue_config rx_queue_config; | ||
87 | struct wl1251_acx_tx_queue_config tx_queue_config[MAX_TX_QUEUE_CONFIGS]; | ||
88 | } __attribute__ ((packed)); | ||
89 | |||
90 | struct wl1251_acx_mem_map { | ||
91 | struct acx_header header; | ||
92 | |||
93 | void *code_start; | ||
94 | void *code_end; | ||
95 | |||
96 | void *wep_defkey_start; | ||
97 | void *wep_defkey_end; | ||
98 | |||
99 | void *sta_table_start; | ||
100 | void *sta_table_end; | ||
101 | |||
102 | void *packet_template_start; | ||
103 | void *packet_template_end; | ||
104 | |||
105 | void *queue_memory_start; | ||
106 | void *queue_memory_end; | ||
107 | |||
108 | void *packet_memory_pool_start; | ||
109 | void *packet_memory_pool_end; | ||
110 | |||
111 | void *debug_buffer1_start; | ||
112 | void *debug_buffer1_end; | ||
113 | |||
114 | void *debug_buffer2_start; | ||
115 | void *debug_buffer2_end; | ||
116 | |||
117 | /* Number of blocks FW allocated for TX packets */ | ||
118 | u32 num_tx_mem_blocks; | ||
119 | |||
120 | /* Number of blocks FW allocated for RX packets */ | ||
121 | u32 num_rx_mem_blocks; | ||
122 | } __attribute__ ((packed)); | ||
123 | |||
124 | /************************************************************************* | ||
125 | |||
126 | Host Interrupt Register (WiLink -> Host) | ||
127 | |||
128 | **************************************************************************/ | ||
129 | |||
130 | /* RX packet is ready in Xfer buffer #0 */ | ||
131 | #define WL1251_ACX_INTR_RX0_DATA BIT(0) | ||
132 | |||
133 | /* TX result(s) are in the TX complete buffer */ | ||
134 | #define WL1251_ACX_INTR_TX_RESULT BIT(1) | ||
135 | |||
136 | /* OBSOLETE */ | ||
137 | #define WL1251_ACX_INTR_TX_XFR BIT(2) | ||
138 | |||
139 | /* RX packet is ready in Xfer buffer #1 */ | ||
140 | #define WL1251_ACX_INTR_RX1_DATA BIT(3) | ||
141 | |||
142 | /* Event was entered to Event MBOX #A */ | ||
143 | #define WL1251_ACX_INTR_EVENT_A BIT(4) | ||
144 | |||
145 | /* Event was entered to Event MBOX #B */ | ||
146 | #define WL1251_ACX_INTR_EVENT_B BIT(5) | ||
147 | |||
148 | /* OBSOLETE */ | ||
149 | #define WL1251_ACX_INTR_WAKE_ON_HOST BIT(6) | ||
150 | |||
151 | /* Trace meassge on MBOX #A */ | ||
152 | #define WL1251_ACX_INTR_TRACE_A BIT(7) | ||
153 | |||
154 | /* Trace meassge on MBOX #B */ | ||
155 | #define WL1251_ACX_INTR_TRACE_B BIT(8) | ||
156 | |||
157 | /* Command processing completion */ | ||
158 | #define WL1251_ACX_INTR_CMD_COMPLETE BIT(9) | ||
159 | |||
160 | /* Init sequence is done */ | ||
161 | #define WL1251_ACX_INTR_INIT_COMPLETE BIT(14) | ||
162 | |||
163 | #define WL1251_ACX_INTR_ALL 0xFFFFFFFF | ||
164 | |||
165 | #endif | ||
diff --git a/drivers/net/wireless/wl12xx/wl1251_ps.c b/drivers/net/wireless/wl12xx/wl1251_ps.c index 68ff7f1900ed..c53e28727ed4 100644 --- a/drivers/net/wireless/wl12xx/wl1251_ps.c +++ b/drivers/net/wireless/wl12xx/wl1251_ps.c | |||
@@ -21,9 +21,10 @@ | |||
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include "reg.h" | 24 | #include "wl1251_reg.h" |
25 | #include "wl1251_ps.h" | 25 | #include "wl1251_ps.h" |
26 | #include "wl1251_spi.h" | 26 | #include "wl1251_cmd.h" |
27 | #include "wl1251_io.h" | ||
27 | 28 | ||
28 | #define WL1251_WAKEUP_TIMEOUT 2000 | 29 | #define WL1251_WAKEUP_TIMEOUT 2000 |
29 | 30 | ||
@@ -117,6 +118,13 @@ int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode) | |||
117 | switch (mode) { | 118 | switch (mode) { |
118 | case STATION_POWER_SAVE_MODE: | 119 | case STATION_POWER_SAVE_MODE: |
119 | wl1251_debug(DEBUG_PSM, "entering psm"); | 120 | wl1251_debug(DEBUG_PSM, "entering psm"); |
121 | |||
122 | ret = wl1251_acx_wake_up_conditions(wl, | ||
123 | WAKE_UP_EVENT_DTIM_BITMAP, | ||
124 | wl->listen_int); | ||
125 | if (ret < 0) | ||
126 | return ret; | ||
127 | |||
120 | ret = wl1251_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE); | 128 | ret = wl1251_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE); |
121 | if (ret < 0) | 129 | if (ret < 0) |
122 | return ret; | 130 | return ret; |
@@ -134,6 +142,12 @@ int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode) | |||
134 | if (ret < 0) | 142 | if (ret < 0) |
135 | return ret; | 143 | return ret; |
136 | 144 | ||
145 | ret = wl1251_acx_wake_up_conditions(wl, | ||
146 | WAKE_UP_EVENT_DTIM_BITMAP, | ||
147 | wl->listen_int); | ||
148 | if (ret < 0) | ||
149 | return ret; | ||
150 | |||
137 | ret = wl1251_cmd_ps_mode(wl, STATION_ACTIVE_MODE); | 151 | ret = wl1251_cmd_ps_mode(wl, STATION_ACTIVE_MODE); |
138 | if (ret < 0) | 152 | if (ret < 0) |
139 | return ret; | 153 | return ret; |
diff --git a/drivers/net/wireless/wl12xx/wl1251_reg.h b/drivers/net/wireless/wl12xx/wl1251_reg.h new file mode 100644 index 000000000000..bdd561001dcb --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_reg.h | |||
@@ -0,0 +1,644 @@ | |||
1 | /* | ||
2 | * This file is part of wl12xx | ||
3 | * | ||
4 | * Copyright (c) 1998-2007 Texas Instruments Incorporated | ||
5 | * Copyright (C) 2008 Nokia Corporation | ||
6 | * | ||
7 | * Contact: Kalle Valo <kalle.valo@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef __REG_H__ | ||
26 | #define __REG_H__ | ||
27 | |||
28 | #include <linux/bitops.h> | ||
29 | |||
30 | #define REGISTERS_BASE 0x00300000 | ||
31 | #define DRPW_BASE 0x00310000 | ||
32 | |||
33 | #define REGISTERS_DOWN_SIZE 0x00008800 | ||
34 | #define REGISTERS_WORK_SIZE 0x0000b000 | ||
35 | |||
36 | #define HW_ACCESS_ELP_CTRL_REG_ADDR 0x1FFFC | ||
37 | |||
38 | /* ELP register commands */ | ||
39 | #define ELPCTRL_WAKE_UP 0x1 | ||
40 | #define ELPCTRL_WAKE_UP_WLAN_READY 0x5 | ||
41 | #define ELPCTRL_SLEEP 0x0 | ||
42 | /* ELP WLAN_READY bit */ | ||
43 | #define ELPCTRL_WLAN_READY 0x2 | ||
44 | |||
45 | /* Device Configuration registers*/ | ||
46 | #define SOR_CFG (REGISTERS_BASE + 0x0800) | ||
47 | #define ECPU_CTRL (REGISTERS_BASE + 0x0804) | ||
48 | #define HI_CFG (REGISTERS_BASE + 0x0808) | ||
49 | #define EE_START (REGISTERS_BASE + 0x080C) | ||
50 | |||
51 | #define CHIP_ID_B (REGISTERS_BASE + 0x5674) | ||
52 | |||
53 | #define CHIP_ID_1251_PG10 (0x7010101) | ||
54 | #define CHIP_ID_1251_PG11 (0x7020101) | ||
55 | #define CHIP_ID_1251_PG12 (0x7030101) | ||
56 | |||
57 | #define ENABLE (REGISTERS_BASE + 0x5450) | ||
58 | |||
59 | /* Power Management registers */ | ||
60 | #define ELP_CFG_MODE (REGISTERS_BASE + 0x5804) | ||
61 | #define ELP_CMD (REGISTERS_BASE + 0x5808) | ||
62 | #define PLL_CAL_TIME (REGISTERS_BASE + 0x5810) | ||
63 | #define CLK_REQ_TIME (REGISTERS_BASE + 0x5814) | ||
64 | #define CLK_BUF_TIME (REGISTERS_BASE + 0x5818) | ||
65 | |||
66 | #define CFG_PLL_SYNC_CNT (REGISTERS_BASE + 0x5820) | ||
67 | |||
68 | /* Scratch Pad registers*/ | ||
69 | #define SCR_PAD0 (REGISTERS_BASE + 0x5608) | ||
70 | #define SCR_PAD1 (REGISTERS_BASE + 0x560C) | ||
71 | #define SCR_PAD2 (REGISTERS_BASE + 0x5610) | ||
72 | #define SCR_PAD3 (REGISTERS_BASE + 0x5614) | ||
73 | #define SCR_PAD4 (REGISTERS_BASE + 0x5618) | ||
74 | #define SCR_PAD4_SET (REGISTERS_BASE + 0x561C) | ||
75 | #define SCR_PAD4_CLR (REGISTERS_BASE + 0x5620) | ||
76 | #define SCR_PAD5 (REGISTERS_BASE + 0x5624) | ||
77 | #define SCR_PAD5_SET (REGISTERS_BASE + 0x5628) | ||
78 | #define SCR_PAD5_CLR (REGISTERS_BASE + 0x562C) | ||
79 | #define SCR_PAD6 (REGISTERS_BASE + 0x5630) | ||
80 | #define SCR_PAD7 (REGISTERS_BASE + 0x5634) | ||
81 | #define SCR_PAD8 (REGISTERS_BASE + 0x5638) | ||
82 | #define SCR_PAD9 (REGISTERS_BASE + 0x563C) | ||
83 | |||
84 | /* Spare registers*/ | ||
85 | #define SPARE_A1 (REGISTERS_BASE + 0x0994) | ||
86 | #define SPARE_A2 (REGISTERS_BASE + 0x0998) | ||
87 | #define SPARE_A3 (REGISTERS_BASE + 0x099C) | ||
88 | #define SPARE_A4 (REGISTERS_BASE + 0x09A0) | ||
89 | #define SPARE_A5 (REGISTERS_BASE + 0x09A4) | ||
90 | #define SPARE_A6 (REGISTERS_BASE + 0x09A8) | ||
91 | #define SPARE_A7 (REGISTERS_BASE + 0x09AC) | ||
92 | #define SPARE_A8 (REGISTERS_BASE + 0x09B0) | ||
93 | #define SPARE_B1 (REGISTERS_BASE + 0x5420) | ||
94 | #define SPARE_B2 (REGISTERS_BASE + 0x5424) | ||
95 | #define SPARE_B3 (REGISTERS_BASE + 0x5428) | ||
96 | #define SPARE_B4 (REGISTERS_BASE + 0x542C) | ||
97 | #define SPARE_B5 (REGISTERS_BASE + 0x5430) | ||
98 | #define SPARE_B6 (REGISTERS_BASE + 0x5434) | ||
99 | #define SPARE_B7 (REGISTERS_BASE + 0x5438) | ||
100 | #define SPARE_B8 (REGISTERS_BASE + 0x543C) | ||
101 | |||
102 | enum wl12xx_acx_int_reg { | ||
103 | ACX_REG_INTERRUPT_TRIG, | ||
104 | ACX_REG_INTERRUPT_TRIG_H, | ||
105 | |||
106 | /*============================================= | ||
107 | Host Interrupt Mask Register - 32bit (RW) | ||
108 | ------------------------------------------ | ||
109 | Setting a bit in this register masks the | ||
110 | corresponding interrupt to the host. | ||
111 | 0 - RX0 - Rx first dubble buffer Data Interrupt | ||
112 | 1 - TXD - Tx Data Interrupt | ||
113 | 2 - TXXFR - Tx Transfer Interrupt | ||
114 | 3 - RX1 - Rx second dubble buffer Data Interrupt | ||
115 | 4 - RXXFR - Rx Transfer Interrupt | ||
116 | 5 - EVENT_A - Event Mailbox interrupt | ||
117 | 6 - EVENT_B - Event Mailbox interrupt | ||
118 | 7 - WNONHST - Wake On Host Interrupt | ||
119 | 8 - TRACE_A - Debug Trace interrupt | ||
120 | 9 - TRACE_B - Debug Trace interrupt | ||
121 | 10 - CDCMP - Command Complete Interrupt | ||
122 | 11 - | ||
123 | 12 - | ||
124 | 13 - | ||
125 | 14 - ICOMP - Initialization Complete Interrupt | ||
126 | 16 - SG SE - Soft Gemini - Sense enable interrupt | ||
127 | 17 - SG SD - Soft Gemini - Sense disable interrupt | ||
128 | 18 - - | ||
129 | 19 - - | ||
130 | 20 - - | ||
131 | 21- - | ||
132 | Default: 0x0001 | ||
133 | *==============================================*/ | ||
134 | ACX_REG_INTERRUPT_MASK, | ||
135 | |||
136 | /*============================================= | ||
137 | Host Interrupt Mask Set 16bit, (Write only) | ||
138 | ------------------------------------------ | ||
139 | Setting a bit in this register sets | ||
140 | the corresponding bin in ACX_HINT_MASK register | ||
141 | without effecting the mask | ||
142 | state of other bits (0 = no effect). | ||
143 | ==============================================*/ | ||
144 | ACX_REG_HINT_MASK_SET, | ||
145 | |||
146 | /*============================================= | ||
147 | Host Interrupt Mask Clear 16bit,(Write only) | ||
148 | ------------------------------------------ | ||
149 | Setting a bit in this register clears | ||
150 | the corresponding bin in ACX_HINT_MASK register | ||
151 | without effecting the mask | ||
152 | state of other bits (0 = no effect). | ||
153 | =============================================*/ | ||
154 | ACX_REG_HINT_MASK_CLR, | ||
155 | |||
156 | /*============================================= | ||
157 | Host Interrupt Status Nondestructive Read | ||
158 | 16bit,(Read only) | ||
159 | ------------------------------------------ | ||
160 | The host can read this register to determine | ||
161 | which interrupts are active. | ||
162 | Reading this register doesn't | ||
163 | effect its content. | ||
164 | =============================================*/ | ||
165 | ACX_REG_INTERRUPT_NO_CLEAR, | ||
166 | |||
167 | /*============================================= | ||
168 | Host Interrupt Status Clear on Read Register | ||
169 | 16bit,(Read only) | ||
170 | ------------------------------------------ | ||
171 | The host can read this register to determine | ||
172 | which interrupts are active. | ||
173 | Reading this register clears it, | ||
174 | thus making all interrupts inactive. | ||
175 | ==============================================*/ | ||
176 | ACX_REG_INTERRUPT_CLEAR, | ||
177 | |||
178 | /*============================================= | ||
179 | Host Interrupt Acknowledge Register | ||
180 | 16bit,(Write only) | ||
181 | ------------------------------------------ | ||
182 | The host can set individual bits in this | ||
183 | register to clear (acknowledge) the corresp. | ||
184 | interrupt status bits in the HINT_STS_CLR and | ||
185 | HINT_STS_ND registers, thus making the | ||
186 | assotiated interrupt inactive. (0-no effect) | ||
187 | ==============================================*/ | ||
188 | ACX_REG_INTERRUPT_ACK, | ||
189 | |||
190 | /*=============================================== | ||
191 | Host Software Reset - 32bit RW | ||
192 | ------------------------------------------ | ||
193 | [31:1] Reserved | ||
194 | 0 SOFT_RESET Soft Reset - When this bit is set, | ||
195 | it holds the Wlan hardware in a soft reset state. | ||
196 | This reset disables all MAC and baseband processor | ||
197 | clocks except the CardBus/PCI interface clock. | ||
198 | It also initializes all MAC state machines except | ||
199 | the host interface. It does not reload the | ||
200 | contents of the EEPROM. When this bit is cleared | ||
201 | (not self-clearing), the Wlan hardware | ||
202 | exits the software reset state. | ||
203 | ===============================================*/ | ||
204 | ACX_REG_SLV_SOFT_RESET, | ||
205 | |||
206 | /*=============================================== | ||
207 | EEPROM Burst Read Start - 32bit RW | ||
208 | ------------------------------------------ | ||
209 | [31:1] Reserved | ||
210 | 0 ACX_EE_START - EEPROM Burst Read Start 0 | ||
211 | Setting this bit starts a burst read from | ||
212 | the external EEPROM. | ||
213 | If this bit is set (after reset) before an EEPROM read/write, | ||
214 | the burst read starts at EEPROM address 0. | ||
215 | Otherwise, it starts at the address | ||
216 | following the address of the previous access. | ||
217 | TheWlan hardware hardware clears this bit automatically. | ||
218 | |||
219 | Default: 0x00000000 | ||
220 | *================================================*/ | ||
221 | ACX_REG_EE_START, | ||
222 | |||
223 | /* Embedded ARM CPU Control */ | ||
224 | |||
225 | /*=============================================== | ||
226 | Halt eCPU - 32bit RW | ||
227 | ------------------------------------------ | ||
228 | 0 HALT_ECPU Halt Embedded CPU - This bit is the | ||
229 | compliment of bit 1 (MDATA2) in the SOR_CFG register. | ||
230 | During a hardware reset, this bit holds | ||
231 | the inverse of MDATA2. | ||
232 | When downloading firmware from the host, | ||
233 | set this bit (pull down MDATA2). | ||
234 | The host clears this bit after downloading the firmware into | ||
235 | zero-wait-state SSRAM. | ||
236 | When loading firmware from Flash, clear this bit (pull up MDATA2) | ||
237 | so that the eCPU can run the bootloader code in Flash | ||
238 | HALT_ECPU eCPU State | ||
239 | -------------------- | ||
240 | 1 halt eCPU | ||
241 | 0 enable eCPU | ||
242 | ===============================================*/ | ||
243 | ACX_REG_ECPU_CONTROL, | ||
244 | |||
245 | ACX_REG_TABLE_LEN | ||
246 | }; | ||
247 | |||
248 | #define ACX_SLV_SOFT_RESET_BIT BIT(1) | ||
249 | #define ACX_REG_EEPROM_START_BIT BIT(1) | ||
250 | |||
251 | /* Command/Information Mailbox Pointers */ | ||
252 | |||
253 | /*=============================================== | ||
254 | Command Mailbox Pointer - 32bit RW | ||
255 | ------------------------------------------ | ||
256 | This register holds the start address of | ||
257 | the command mailbox located in the Wlan hardware memory. | ||
258 | The host must read this pointer after a reset to | ||
259 | find the location of the command mailbox. | ||
260 | The Wlan hardware initializes the command mailbox | ||
261 | pointer with the default address of the command mailbox. | ||
262 | The command mailbox pointer is not valid until after | ||
263 | the host receives the Init Complete interrupt from | ||
264 | the Wlan hardware. | ||
265 | ===============================================*/ | ||
266 | #define REG_COMMAND_MAILBOX_PTR (SCR_PAD0) | ||
267 | |||
268 | /*=============================================== | ||
269 | Information Mailbox Pointer - 32bit RW | ||
270 | ------------------------------------------ | ||
271 | This register holds the start address of | ||
272 | the information mailbox located in the Wlan hardware memory. | ||
273 | The host must read this pointer after a reset to find | ||
274 | the location of the information mailbox. | ||
275 | The Wlan hardware initializes the information mailbox pointer | ||
276 | with the default address of the information mailbox. | ||
277 | The information mailbox pointer is not valid | ||
278 | until after the host receives the Init Complete interrupt from | ||
279 | the Wlan hardware. | ||
280 | ===============================================*/ | ||
281 | #define REG_EVENT_MAILBOX_PTR (SCR_PAD1) | ||
282 | |||
283 | |||
284 | /* Misc */ | ||
285 | |||
286 | #define REG_ENABLE_TX_RX (ENABLE) | ||
287 | /* | ||
288 | * Rx configuration (filter) information element | ||
289 | * --------------------------------------------- | ||
290 | */ | ||
291 | #define REG_RX_CONFIG (RX_CFG) | ||
292 | #define REG_RX_FILTER (RX_FILTER_CFG) | ||
293 | |||
294 | |||
295 | #define RX_CFG_ENABLE_PHY_HEADER_PLCP 0x0002 | ||
296 | |||
297 | /* promiscuous - receives all valid frames */ | ||
298 | #define RX_CFG_PROMISCUOUS 0x0008 | ||
299 | |||
300 | /* receives frames from any BSSID */ | ||
301 | #define RX_CFG_BSSID 0x0020 | ||
302 | |||
303 | /* receives frames destined to any MAC address */ | ||
304 | #define RX_CFG_MAC 0x0010 | ||
305 | |||
306 | #define RX_CFG_ENABLE_ONLY_MY_DEST_MAC 0x0010 | ||
307 | #define RX_CFG_ENABLE_ANY_DEST_MAC 0x0000 | ||
308 | #define RX_CFG_ENABLE_ONLY_MY_BSSID 0x0020 | ||
309 | #define RX_CFG_ENABLE_ANY_BSSID 0x0000 | ||
310 | |||
311 | /* discards all broadcast frames */ | ||
312 | #define RX_CFG_DISABLE_BCAST 0x0200 | ||
313 | |||
314 | #define RX_CFG_ENABLE_ONLY_MY_SSID 0x0400 | ||
315 | #define RX_CFG_ENABLE_RX_CMPLT_FCS_ERROR 0x0800 | ||
316 | #define RX_CFG_COPY_RX_STATUS 0x2000 | ||
317 | #define RX_CFG_TSF 0x10000 | ||
318 | |||
319 | #define RX_CONFIG_OPTION_ANY_DST_MY_BSS (RX_CFG_ENABLE_ANY_DEST_MAC | \ | ||
320 | RX_CFG_ENABLE_ONLY_MY_BSSID) | ||
321 | |||
322 | #define RX_CONFIG_OPTION_MY_DST_ANY_BSS (RX_CFG_ENABLE_ONLY_MY_DEST_MAC\ | ||
323 | | RX_CFG_ENABLE_ANY_BSSID) | ||
324 | |||
325 | #define RX_CONFIG_OPTION_ANY_DST_ANY_BSS (RX_CFG_ENABLE_ANY_DEST_MAC | \ | ||
326 | RX_CFG_ENABLE_ANY_BSSID) | ||
327 | |||
328 | #define RX_CONFIG_OPTION_MY_DST_MY_BSS (RX_CFG_ENABLE_ONLY_MY_DEST_MAC\ | ||
329 | | RX_CFG_ENABLE_ONLY_MY_BSSID) | ||
330 | |||
331 | #define RX_CONFIG_OPTION_FOR_SCAN (RX_CFG_ENABLE_PHY_HEADER_PLCP \ | ||
332 | | RX_CFG_ENABLE_RX_CMPLT_FCS_ERROR \ | ||
333 | | RX_CFG_COPY_RX_STATUS | RX_CFG_TSF) | ||
334 | |||
335 | #define RX_CONFIG_OPTION_FOR_MEASUREMENT (RX_CFG_ENABLE_ANY_DEST_MAC) | ||
336 | |||
337 | #define RX_CONFIG_OPTION_FOR_JOIN (RX_CFG_ENABLE_ONLY_MY_BSSID | \ | ||
338 | RX_CFG_ENABLE_ONLY_MY_DEST_MAC) | ||
339 | |||
340 | #define RX_CONFIG_OPTION_FOR_IBSS_JOIN (RX_CFG_ENABLE_ONLY_MY_SSID | \ | ||
341 | RX_CFG_ENABLE_ONLY_MY_DEST_MAC) | ||
342 | |||
343 | #define RX_FILTER_OPTION_DEF (CFG_RX_MGMT_EN | CFG_RX_DATA_EN\ | ||
344 | | CFG_RX_CTL_EN | CFG_RX_BCN_EN\ | ||
345 | | CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN) | ||
346 | |||
347 | #define RX_FILTER_OPTION_FILTER_ALL 0 | ||
348 | |||
349 | #define RX_FILTER_OPTION_DEF_PRSP_BCN (CFG_RX_PRSP_EN | CFG_RX_MGMT_EN\ | ||
350 | | CFG_RX_RCTS_ACK | CFG_RX_BCN_EN) | ||
351 | |||
352 | #define RX_FILTER_OPTION_JOIN (CFG_RX_MGMT_EN | CFG_RX_DATA_EN\ | ||
353 | | CFG_RX_BCN_EN | CFG_RX_AUTH_EN\ | ||
354 | | CFG_RX_ASSOC_EN | CFG_RX_RCTS_ACK\ | ||
355 | | CFG_RX_PRSP_EN) | ||
356 | |||
357 | |||
358 | /*=============================================== | ||
359 | EEPROM Read/Write Request 32bit RW | ||
360 | ------------------------------------------ | ||
361 | 1 EE_READ - EEPROM Read Request 1 - Setting this bit | ||
362 | loads a single byte of data into the EE_DATA | ||
363 | register from the EEPROM location specified in | ||
364 | the EE_ADDR register. | ||
365 | The Wlan hardware hardware clears this bit automatically. | ||
366 | EE_DATA is valid when this bit is cleared. | ||
367 | |||
368 | 0 EE_WRITE - EEPROM Write Request - Setting this bit | ||
369 | writes a single byte of data from the EE_DATA register into the | ||
370 | EEPROM location specified in the EE_ADDR register. | ||
371 | The Wlan hardware hardware clears this bit automatically. | ||
372 | *===============================================*/ | ||
373 | #define ACX_EE_CTL_REG EE_CTL | ||
374 | #define EE_WRITE 0x00000001ul | ||
375 | #define EE_READ 0x00000002ul | ||
376 | |||
377 | /*=============================================== | ||
378 | EEPROM Address - 32bit RW | ||
379 | ------------------------------------------ | ||
380 | This register specifies the address | ||
381 | within the EEPROM from/to which to read/write data. | ||
382 | ===============================================*/ | ||
383 | #define ACX_EE_ADDR_REG EE_ADDR | ||
384 | |||
385 | /*=============================================== | ||
386 | EEPROM Data - 32bit RW | ||
387 | ------------------------------------------ | ||
388 | This register either holds the read 8 bits of | ||
389 | data from the EEPROM or the write data | ||
390 | to be written to the EEPROM. | ||
391 | ===============================================*/ | ||
392 | #define ACX_EE_DATA_REG EE_DATA | ||
393 | |||
394 | /*=============================================== | ||
395 | EEPROM Base Address - 32bit RW | ||
396 | ------------------------------------------ | ||
397 | This register holds the upper nine bits | ||
398 | [23:15] of the 24-bit Wlan hardware memory | ||
399 | address for burst reads from EEPROM accesses. | ||
400 | The EEPROM provides the lower 15 bits of this address. | ||
401 | The MSB of the address from the EEPROM is ignored. | ||
402 | ===============================================*/ | ||
403 | #define ACX_EE_CFG EE_CFG | ||
404 | |||
405 | /*=============================================== | ||
406 | GPIO Output Values -32bit, RW | ||
407 | ------------------------------------------ | ||
408 | [31:16] Reserved | ||
409 | [15: 0] Specify the output values (at the output driver inputs) for | ||
410 | GPIO[15:0], respectively. | ||
411 | ===============================================*/ | ||
412 | #define ACX_GPIO_OUT_REG GPIO_OUT | ||
413 | #define ACX_MAX_GPIO_LINES 15 | ||
414 | |||
415 | /*=============================================== | ||
416 | Contention window -32bit, RW | ||
417 | ------------------------------------------ | ||
418 | [31:26] Reserved | ||
419 | [25:16] Max (0x3ff) | ||
420 | [15:07] Reserved | ||
421 | [06:00] Current contention window value - default is 0x1F | ||
422 | ===============================================*/ | ||
423 | #define ACX_CONT_WIND_CFG_REG CONT_WIND_CFG | ||
424 | #define ACX_CONT_WIND_MIN_MASK 0x0000007f | ||
425 | #define ACX_CONT_WIND_MAX 0x03ff0000 | ||
426 | |||
427 | /*=============================================== | ||
428 | HI_CFG Interface Configuration Register Values | ||
429 | ------------------------------------------ | ||
430 | ===============================================*/ | ||
431 | #define HI_CFG_UART_ENABLE 0x00000004 | ||
432 | #define HI_CFG_RST232_ENABLE 0x00000008 | ||
433 | #define HI_CFG_CLOCK_REQ_SELECT 0x00000010 | ||
434 | #define HI_CFG_HOST_INT_ENABLE 0x00000020 | ||
435 | #define HI_CFG_VLYNQ_OUTPUT_ENABLE 0x00000040 | ||
436 | #define HI_CFG_HOST_INT_ACTIVE_LOW 0x00000080 | ||
437 | #define HI_CFG_UART_TX_OUT_GPIO_15 0x00000100 | ||
438 | #define HI_CFG_UART_TX_OUT_GPIO_14 0x00000200 | ||
439 | #define HI_CFG_UART_TX_OUT_GPIO_7 0x00000400 | ||
440 | |||
441 | /* | ||
442 | * NOTE: USE_ACTIVE_HIGH compilation flag should be defined in makefile | ||
443 | * for platforms using active high interrupt level | ||
444 | */ | ||
445 | #ifdef USE_ACTIVE_HIGH | ||
446 | #define HI_CFG_DEF_VAL \ | ||
447 | (HI_CFG_UART_ENABLE | \ | ||
448 | HI_CFG_RST232_ENABLE | \ | ||
449 | HI_CFG_CLOCK_REQ_SELECT | \ | ||
450 | HI_CFG_HOST_INT_ENABLE) | ||
451 | #else | ||
452 | #define HI_CFG_DEF_VAL \ | ||
453 | (HI_CFG_UART_ENABLE | \ | ||
454 | HI_CFG_RST232_ENABLE | \ | ||
455 | HI_CFG_CLOCK_REQ_SELECT | \ | ||
456 | HI_CFG_HOST_INT_ENABLE) | ||
457 | |||
458 | #endif | ||
459 | |||
460 | #define REF_FREQ_19_2 0 | ||
461 | #define REF_FREQ_26_0 1 | ||
462 | #define REF_FREQ_38_4 2 | ||
463 | #define REF_FREQ_40_0 3 | ||
464 | #define REF_FREQ_33_6 4 | ||
465 | #define REF_FREQ_NUM 5 | ||
466 | |||
467 | #define LUT_PARAM_INTEGER_DIVIDER 0 | ||
468 | #define LUT_PARAM_FRACTIONAL_DIVIDER 1 | ||
469 | #define LUT_PARAM_ATTN_BB 2 | ||
470 | #define LUT_PARAM_ALPHA_BB 3 | ||
471 | #define LUT_PARAM_STOP_TIME_BB 4 | ||
472 | #define LUT_PARAM_BB_PLL_LOOP_FILTER 5 | ||
473 | #define LUT_PARAM_NUM 6 | ||
474 | |||
475 | #define ACX_EEPROMLESS_IND_REG (SCR_PAD4) | ||
476 | #define USE_EEPROM 0 | ||
477 | #define SOFT_RESET_MAX_TIME 1000000 | ||
478 | #define SOFT_RESET_STALL_TIME 1000 | ||
479 | #define NVS_DATA_BUNDARY_ALIGNMENT 4 | ||
480 | |||
481 | |||
482 | /* Firmware image load chunk size */ | ||
483 | #define CHUNK_SIZE 512 | ||
484 | |||
485 | /* Firmware image header size */ | ||
486 | #define FW_HDR_SIZE 8 | ||
487 | |||
488 | #define ECPU_CONTROL_HALT 0x00000101 | ||
489 | |||
490 | |||
491 | /****************************************************************************** | ||
492 | |||
493 | CHANNELS, BAND & REG DOMAINS definitions | ||
494 | |||
495 | ******************************************************************************/ | ||
496 | |||
497 | |||
498 | enum { | ||
499 | RADIO_BAND_2_4GHZ = 0, /* 2.4 Ghz band */ | ||
500 | RADIO_BAND_5GHZ = 1, /* 5 Ghz band */ | ||
501 | RADIO_BAND_JAPAN_4_9_GHZ = 2, | ||
502 | DEFAULT_BAND = RADIO_BAND_2_4GHZ, | ||
503 | INVALID_BAND = 0xFE, | ||
504 | MAX_RADIO_BANDS = 0xFF | ||
505 | }; | ||
506 | |||
507 | enum { | ||
508 | NO_RATE = 0, | ||
509 | RATE_1MBPS = 0x0A, | ||
510 | RATE_2MBPS = 0x14, | ||
511 | RATE_5_5MBPS = 0x37, | ||
512 | RATE_6MBPS = 0x0B, | ||
513 | RATE_9MBPS = 0x0F, | ||
514 | RATE_11MBPS = 0x6E, | ||
515 | RATE_12MBPS = 0x0A, | ||
516 | RATE_18MBPS = 0x0E, | ||
517 | RATE_22MBPS = 0xDC, | ||
518 | RATE_24MBPS = 0x09, | ||
519 | RATE_36MBPS = 0x0D, | ||
520 | RATE_48MBPS = 0x08, | ||
521 | RATE_54MBPS = 0x0C | ||
522 | }; | ||
523 | |||
524 | enum { | ||
525 | RATE_INDEX_1MBPS = 0, | ||
526 | RATE_INDEX_2MBPS = 1, | ||
527 | RATE_INDEX_5_5MBPS = 2, | ||
528 | RATE_INDEX_6MBPS = 3, | ||
529 | RATE_INDEX_9MBPS = 4, | ||
530 | RATE_INDEX_11MBPS = 5, | ||
531 | RATE_INDEX_12MBPS = 6, | ||
532 | RATE_INDEX_18MBPS = 7, | ||
533 | RATE_INDEX_22MBPS = 8, | ||
534 | RATE_INDEX_24MBPS = 9, | ||
535 | RATE_INDEX_36MBPS = 10, | ||
536 | RATE_INDEX_48MBPS = 11, | ||
537 | RATE_INDEX_54MBPS = 12, | ||
538 | RATE_INDEX_MAX = RATE_INDEX_54MBPS, | ||
539 | MAX_RATE_INDEX, | ||
540 | INVALID_RATE_INDEX = MAX_RATE_INDEX, | ||
541 | RATE_INDEX_ENUM_MAX_SIZE = 0x7FFFFFFF | ||
542 | }; | ||
543 | |||
544 | enum { | ||
545 | RATE_MASK_1MBPS = 0x1, | ||
546 | RATE_MASK_2MBPS = 0x2, | ||
547 | RATE_MASK_5_5MBPS = 0x4, | ||
548 | RATE_MASK_11MBPS = 0x20, | ||
549 | }; | ||
550 | |||
551 | #define SHORT_PREAMBLE_BIT BIT(0) /* CCK or Barker depending on the rate */ | ||
552 | #define OFDM_RATE_BIT BIT(6) | ||
553 | #define PBCC_RATE_BIT BIT(7) | ||
554 | |||
555 | enum { | ||
556 | CCK_LONG = 0, | ||
557 | CCK_SHORT = SHORT_PREAMBLE_BIT, | ||
558 | PBCC_LONG = PBCC_RATE_BIT, | ||
559 | PBCC_SHORT = PBCC_RATE_BIT | SHORT_PREAMBLE_BIT, | ||
560 | OFDM = OFDM_RATE_BIT | ||
561 | }; | ||
562 | |||
563 | /****************************************************************************** | ||
564 | |||
565 | Transmit-Descriptor RATE-SET field definitions... | ||
566 | |||
567 | Define a new "Rate-Set" for TX path that incorporates the | ||
568 | Rate & Modulation info into a single 16-bit field. | ||
569 | |||
570 | TxdRateSet_t: | ||
571 | b15 - Indicates Preamble type (1=SHORT, 0=LONG). | ||
572 | Notes: | ||
573 | Must be LONG (0) for 1Mbps rate. | ||
574 | Does not apply (set to 0) for RevG-OFDM rates. | ||
575 | b14 - Indicates PBCC encoding (1=PBCC, 0=not). | ||
576 | Notes: | ||
577 | Does not apply (set to 0) for rates 1 and 2 Mbps. | ||
578 | Does not apply (set to 0) for RevG-OFDM rates. | ||
579 | b13 - Unused (set to 0). | ||
580 | b12-b0 - Supported Rate indicator bits as defined below. | ||
581 | |||
582 | ******************************************************************************/ | ||
583 | |||
584 | |||
585 | /************************************************************************* | ||
586 | |||
587 | Interrupt Trigger Register (Host -> WiLink) | ||
588 | |||
589 | **************************************************************************/ | ||
590 | |||
591 | /* Hardware to Embedded CPU Interrupts - first 32-bit register set */ | ||
592 | |||
593 | /* | ||
594 | * Host Command Interrupt. Setting this bit masks | ||
595 | * the interrupt that the host issues to inform | ||
596 | * the FW that it has sent a command | ||
597 | * to the Wlan hardware Command Mailbox. | ||
598 | */ | ||
599 | #define INTR_TRIG_CMD BIT(0) | ||
600 | |||
601 | /* | ||
602 | * Host Event Acknowlegde Interrupt. The host | ||
603 | * sets this bit to acknowledge that it received | ||
604 | * the unsolicited information from the event | ||
605 | * mailbox. | ||
606 | */ | ||
607 | #define INTR_TRIG_EVENT_ACK BIT(1) | ||
608 | |||
609 | /* | ||
610 | * The host sets this bit to inform the Wlan | ||
611 | * FW that a TX packet is in the XFER | ||
612 | * Buffer #0. | ||
613 | */ | ||
614 | #define INTR_TRIG_TX_PROC0 BIT(2) | ||
615 | |||
616 | /* | ||
617 | * The host sets this bit to inform the FW | ||
618 | * that it read a packet from RX XFER | ||
619 | * Buffer #0. | ||
620 | */ | ||
621 | #define INTR_TRIG_RX_PROC0 BIT(3) | ||
622 | |||
623 | #define INTR_TRIG_DEBUG_ACK BIT(4) | ||
624 | |||
625 | #define INTR_TRIG_STATE_CHANGED BIT(5) | ||
626 | |||
627 | |||
628 | /* Hardware to Embedded CPU Interrupts - second 32-bit register set */ | ||
629 | |||
630 | /* | ||
631 | * The host sets this bit to inform the FW | ||
632 | * that it read a packet from RX XFER | ||
633 | * Buffer #1. | ||
634 | */ | ||
635 | #define INTR_TRIG_RX_PROC1 BIT(17) | ||
636 | |||
637 | /* | ||
638 | * The host sets this bit to inform the Wlan | ||
639 | * hardware that a TX packet is in the XFER | ||
640 | * Buffer #1. | ||
641 | */ | ||
642 | #define INTR_TRIG_TX_PROC1 BIT(18) | ||
643 | |||
644 | #endif | ||
diff --git a/drivers/net/wireless/wl12xx/wl1251_rx.c b/drivers/net/wireless/wl12xx/wl1251_rx.c index 0dbb483a0973..17c54b59ef86 100644 --- a/drivers/net/wireless/wl12xx/wl1251_rx.c +++ b/drivers/net/wireless/wl12xx/wl1251_rx.c | |||
@@ -26,9 +26,10 @@ | |||
26 | #include <net/mac80211.h> | 26 | #include <net/mac80211.h> |
27 | 27 | ||
28 | #include "wl1251.h" | 28 | #include "wl1251.h" |
29 | #include "reg.h" | 29 | #include "wl1251_reg.h" |
30 | #include "wl1251_spi.h" | 30 | #include "wl1251_io.h" |
31 | #include "wl1251_rx.h" | 31 | #include "wl1251_rx.h" |
32 | #include "wl1251_cmd.h" | ||
32 | #include "wl1251_acx.h" | 33 | #include "wl1251_acx.h" |
33 | 34 | ||
34 | static void wl1251_rx_header(struct wl1251 *wl, | 35 | static void wl1251_rx_header(struct wl1251 *wl, |
@@ -40,7 +41,7 @@ static void wl1251_rx_header(struct wl1251 *wl, | |||
40 | if (wl->rx_current_buffer) | 41 | if (wl->rx_current_buffer) |
41 | rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size; | 42 | rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size; |
42 | 43 | ||
43 | wl1251_spi_mem_read(wl, rx_packet_ring_addr, desc, sizeof(*desc)); | 44 | wl1251_mem_read(wl, rx_packet_ring_addr, desc, sizeof(*desc)); |
44 | } | 45 | } |
45 | 46 | ||
46 | static void wl1251_rx_status(struct wl1251 *wl, | 47 | static void wl1251_rx_status(struct wl1251 *wl, |
@@ -136,7 +137,7 @@ static void wl1251_rx_body(struct wl1251 *wl, | |||
136 | } | 137 | } |
137 | 138 | ||
138 | rx_buffer = skb_put(skb, length); | 139 | rx_buffer = skb_put(skb, length); |
139 | wl1251_spi_mem_read(wl, rx_packet_ring_addr, rx_buffer, length); | 140 | wl1251_mem_read(wl, rx_packet_ring_addr, rx_buffer, length); |
140 | 141 | ||
141 | /* The actual lenght doesn't include the target's alignment */ | 142 | /* The actual lenght doesn't include the target's alignment */ |
142 | skb->len = desc->length - PLCP_HEADER_LENGTH; | 143 | skb->len = desc->length - PLCP_HEADER_LENGTH; |
diff --git a/drivers/net/wireless/wl12xx/wl1251_sdio.c b/drivers/net/wireless/wl12xx/wl1251_sdio.c new file mode 100644 index 000000000000..9423f22bdced --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_sdio.c | |||
@@ -0,0 +1,205 @@ | |||
1 | /* | ||
2 | * wl12xx SDIO routines | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, but | ||
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
11 | * General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program; if not, write to the Free Software | ||
15 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
16 | * 02110-1301 USA | ||
17 | * | ||
18 | * Copyright (C) 2005 Texas Instruments Incorporated | ||
19 | * Copyright (C) 2008 Google Inc | ||
20 | * Copyright (C) 2009 Bob Copeland (me@bobcopeland.com) | ||
21 | */ | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/crc7.h> | ||
24 | #include <linux/mod_devicetable.h> | ||
25 | #include <linux/irq.h> | ||
26 | #include <linux/mmc/sdio_func.h> | ||
27 | #include <linux/mmc/sdio_ids.h> | ||
28 | #include <linux/platform_device.h> | ||
29 | |||
30 | #include "wl1251.h" | ||
31 | #include "wl12xx_80211.h" | ||
32 | #include "wl1251_reg.h" | ||
33 | #include "wl1251_ps.h" | ||
34 | #include "wl1251_io.h" | ||
35 | #include "wl1251_tx.h" | ||
36 | #include "wl1251_debugfs.h" | ||
37 | |||
38 | #ifndef SDIO_VENDOR_ID_TI | ||
39 | #define SDIO_VENDOR_ID_TI 0x104c | ||
40 | #endif | ||
41 | |||
42 | #ifndef SDIO_DEVICE_ID_TI_WL1251 | ||
43 | #define SDIO_DEVICE_ID_TI_WL1251 0x9066 | ||
44 | #endif | ||
45 | |||
46 | static struct sdio_func *wl_to_func(struct wl1251 *wl) | ||
47 | { | ||
48 | return wl->if_priv; | ||
49 | } | ||
50 | |||
51 | static void wl1251_sdio_interrupt(struct sdio_func *func) | ||
52 | { | ||
53 | struct wl1251 *wl = sdio_get_drvdata(func); | ||
54 | |||
55 | wl1251_debug(DEBUG_IRQ, "IRQ"); | ||
56 | |||
57 | /* FIXME should be synchronous for sdio */ | ||
58 | ieee80211_queue_work(wl->hw, &wl->irq_work); | ||
59 | } | ||
60 | |||
61 | static const struct sdio_device_id wl1251_devices[] = { | ||
62 | { SDIO_DEVICE(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1251) }, | ||
63 | {} | ||
64 | }; | ||
65 | MODULE_DEVICE_TABLE(sdio, wl1251_devices); | ||
66 | |||
67 | |||
68 | void wl1251_sdio_read(struct wl1251 *wl, int addr, void *buf, size_t len) | ||
69 | { | ||
70 | int ret; | ||
71 | struct sdio_func *func = wl_to_func(wl); | ||
72 | |||
73 | sdio_claim_host(func); | ||
74 | ret = sdio_memcpy_fromio(func, buf, addr, len); | ||
75 | if (ret) | ||
76 | wl1251_error("sdio read failed (%d)", ret); | ||
77 | sdio_release_host(func); | ||
78 | } | ||
79 | |||
80 | void wl1251_sdio_write(struct wl1251 *wl, int addr, void *buf, size_t len) | ||
81 | { | ||
82 | int ret; | ||
83 | struct sdio_func *func = wl_to_func(wl); | ||
84 | |||
85 | sdio_claim_host(func); | ||
86 | ret = sdio_memcpy_toio(func, addr, buf, len); | ||
87 | if (ret) | ||
88 | wl1251_error("sdio write failed (%d)", ret); | ||
89 | sdio_release_host(func); | ||
90 | } | ||
91 | |||
92 | void wl1251_sdio_reset(struct wl1251 *wl) | ||
93 | { | ||
94 | } | ||
95 | |||
96 | static void wl1251_sdio_enable_irq(struct wl1251 *wl) | ||
97 | { | ||
98 | struct sdio_func *func = wl_to_func(wl); | ||
99 | |||
100 | sdio_claim_host(func); | ||
101 | sdio_claim_irq(func, wl1251_sdio_interrupt); | ||
102 | sdio_release_host(func); | ||
103 | } | ||
104 | |||
105 | static void wl1251_sdio_disable_irq(struct wl1251 *wl) | ||
106 | { | ||
107 | struct sdio_func *func = wl_to_func(wl); | ||
108 | |||
109 | sdio_claim_host(func); | ||
110 | sdio_release_irq(func); | ||
111 | sdio_release_host(func); | ||
112 | } | ||
113 | |||
114 | void wl1251_sdio_set_power(bool enable) | ||
115 | { | ||
116 | } | ||
117 | |||
118 | struct wl1251_if_operations wl1251_sdio_ops = { | ||
119 | .read = wl1251_sdio_read, | ||
120 | .write = wl1251_sdio_write, | ||
121 | .reset = wl1251_sdio_reset, | ||
122 | .enable_irq = wl1251_sdio_enable_irq, | ||
123 | .disable_irq = wl1251_sdio_disable_irq, | ||
124 | }; | ||
125 | |||
126 | int wl1251_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) | ||
127 | { | ||
128 | int ret; | ||
129 | struct wl1251 *wl; | ||
130 | struct ieee80211_hw *hw; | ||
131 | |||
132 | hw = wl1251_alloc_hw(); | ||
133 | if (IS_ERR(hw)) | ||
134 | return PTR_ERR(hw); | ||
135 | |||
136 | wl = hw->priv; | ||
137 | |||
138 | sdio_claim_host(func); | ||
139 | ret = sdio_enable_func(func); | ||
140 | if (ret) | ||
141 | goto release; | ||
142 | |||
143 | sdio_set_block_size(func, 512); | ||
144 | |||
145 | SET_IEEE80211_DEV(hw, &func->dev); | ||
146 | wl->if_priv = func; | ||
147 | wl->if_ops = &wl1251_sdio_ops; | ||
148 | wl->set_power = wl1251_sdio_set_power; | ||
149 | |||
150 | sdio_release_host(func); | ||
151 | ret = wl1251_init_ieee80211(wl); | ||
152 | if (ret) | ||
153 | goto disable; | ||
154 | |||
155 | sdio_set_drvdata(func, wl); | ||
156 | return ret; | ||
157 | |||
158 | disable: | ||
159 | sdio_claim_host(func); | ||
160 | sdio_disable_func(func); | ||
161 | release: | ||
162 | sdio_release_host(func); | ||
163 | return ret; | ||
164 | } | ||
165 | |||
166 | static void __devexit wl1251_sdio_remove(struct sdio_func *func) | ||
167 | { | ||
168 | struct wl1251 *wl = sdio_get_drvdata(func); | ||
169 | |||
170 | wl1251_free_hw(wl); | ||
171 | |||
172 | sdio_claim_host(func); | ||
173 | sdio_release_irq(func); | ||
174 | sdio_disable_func(func); | ||
175 | sdio_release_host(func); | ||
176 | } | ||
177 | |||
178 | static struct sdio_driver wl1251_sdio_driver = { | ||
179 | .name = "wl1251_sdio", | ||
180 | .id_table = wl1251_devices, | ||
181 | .probe = wl1251_sdio_probe, | ||
182 | .remove = __devexit_p(wl1251_sdio_remove), | ||
183 | }; | ||
184 | |||
185 | static int __init wl1251_sdio_init(void) | ||
186 | { | ||
187 | int err; | ||
188 | |||
189 | err = sdio_register_driver(&wl1251_sdio_driver); | ||
190 | if (err) | ||
191 | wl1251_error("failed to register sdio driver: %d", err); | ||
192 | return err; | ||
193 | } | ||
194 | |||
195 | static void __exit wl1251_sdio_exit(void) | ||
196 | { | ||
197 | sdio_unregister_driver(&wl1251_sdio_driver); | ||
198 | wl1251_notice("unloaded"); | ||
199 | } | ||
200 | |||
201 | module_init(wl1251_sdio_init); | ||
202 | module_exit(wl1251_sdio_exit); | ||
203 | |||
204 | MODULE_LICENSE("GPL"); | ||
205 | MODULE_AUTHOR("Kalle Valo <kalle.valo@nokia.com>"); | ||
diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.c b/drivers/net/wireless/wl12xx/wl1251_spi.c index c5da79dbc49c..14eff2b3d4c6 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.c +++ b/drivers/net/wireless/wl12xx/wl1251_spi.c | |||
@@ -21,38 +21,35 @@ | |||
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <linux/irq.h> | ||
24 | #include <linux/module.h> | 25 | #include <linux/module.h> |
25 | #include <linux/crc7.h> | 26 | #include <linux/crc7.h> |
26 | #include <linux/spi/spi.h> | 27 | #include <linux/spi/spi.h> |
28 | #include <linux/spi/wl12xx.h> | ||
27 | 29 | ||
28 | #include "wl1251.h" | 30 | #include "wl1251.h" |
29 | #include "reg.h" | 31 | #include "wl1251_reg.h" |
30 | #include "wl1251_spi.h" | 32 | #include "wl1251_spi.h" |
31 | 33 | ||
32 | static int wl1251_translate_reg_addr(struct wl1251 *wl, int addr) | 34 | static irqreturn_t wl1251_irq(int irq, void *cookie) |
33 | { | 35 | { |
34 | /* If the address is lower than REGISTERS_BASE, it means that this is | 36 | struct wl1251 *wl; |
35 | * a chip-specific register address, so look it up in the registers | 37 | |
36 | * table */ | 38 | wl1251_debug(DEBUG_IRQ, "IRQ"); |
37 | if (addr < REGISTERS_BASE) { | 39 | |
38 | /* Make sure we don't go over the table */ | 40 | wl = cookie; |
39 | if (addr >= ACX_REG_TABLE_LEN) { | ||
40 | wl1251_error("address out of range (%d)", addr); | ||
41 | return -EINVAL; | ||
42 | } | ||
43 | addr = wl->chip.acx_reg_table[addr]; | ||
44 | } | ||
45 | 41 | ||
46 | return addr - wl->physical_reg_addr + wl->virtual_reg_addr; | 42 | ieee80211_queue_work(wl->hw, &wl->irq_work); |
43 | |||
44 | return IRQ_HANDLED; | ||
47 | } | 45 | } |
48 | 46 | ||
49 | static int wl1251_translate_mem_addr(struct wl1251 *wl, int addr) | 47 | static struct spi_device *wl_to_spi(struct wl1251 *wl) |
50 | { | 48 | { |
51 | return addr - wl->physical_mem_addr + wl->virtual_mem_addr; | 49 | return wl->if_priv; |
52 | } | 50 | } |
53 | 51 | ||
54 | 52 | static void wl1251_spi_reset(struct wl1251 *wl) | |
55 | void wl1251_spi_reset(struct wl1251 *wl) | ||
56 | { | 53 | { |
57 | u8 *cmd; | 54 | u8 *cmd; |
58 | struct spi_transfer t; | 55 | struct spi_transfer t; |
@@ -73,12 +70,12 @@ void wl1251_spi_reset(struct wl1251 *wl) | |||
73 | t.len = WSPI_INIT_CMD_LEN; | 70 | t.len = WSPI_INIT_CMD_LEN; |
74 | spi_message_add_tail(&t, &m); | 71 | spi_message_add_tail(&t, &m); |
75 | 72 | ||
76 | spi_sync(wl->spi, &m); | 73 | spi_sync(wl_to_spi(wl), &m); |
77 | 74 | ||
78 | wl1251_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN); | 75 | wl1251_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN); |
79 | } | 76 | } |
80 | 77 | ||
81 | void wl1251_spi_init(struct wl1251 *wl) | 78 | static void wl1251_spi_wake(struct wl1251 *wl) |
82 | { | 79 | { |
83 | u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd; | 80 | u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd; |
84 | struct spi_transfer t; | 81 | struct spi_transfer t; |
@@ -127,136 +124,19 @@ void wl1251_spi_init(struct wl1251 *wl) | |||
127 | t.len = WSPI_INIT_CMD_LEN; | 124 | t.len = WSPI_INIT_CMD_LEN; |
128 | spi_message_add_tail(&t, &m); | 125 | spi_message_add_tail(&t, &m); |
129 | 126 | ||
130 | spi_sync(wl->spi, &m); | 127 | spi_sync(wl_to_spi(wl), &m); |
131 | 128 | ||
132 | wl1251_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN); | 129 | wl1251_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN); |
133 | } | 130 | } |
134 | 131 | ||
135 | /* Set the SPI partitions to access the chip addresses | 132 | static void wl1251_spi_reset_wake(struct wl1251 *wl) |
136 | * | ||
137 | * There are two VIRTUAL (SPI) partitions (the memory partition and the | ||
138 | * registers partition), which are mapped to two different areas of the | ||
139 | * PHYSICAL (hardware) memory. This function also makes other checks to | ||
140 | * ensure that the partitions are not overlapping. In the diagram below, the | ||
141 | * memory partition comes before the register partition, but the opposite is | ||
142 | * also supported. | ||
143 | * | ||
144 | * PHYSICAL address | ||
145 | * space | ||
146 | * | ||
147 | * | | | ||
148 | * ...+----+--> mem_start | ||
149 | * VIRTUAL address ... | | | ||
150 | * space ... | | [PART_0] | ||
151 | * ... | | | ||
152 | * 0x00000000 <--+----+... ...+----+--> mem_start + mem_size | ||
153 | * | | ... | | | ||
154 | * |MEM | ... | | | ||
155 | * | | ... | | | ||
156 | * part_size <--+----+... | | {unused area) | ||
157 | * | | ... | | | ||
158 | * |REG | ... | | | ||
159 | * part_size | | ... | | | ||
160 | * + <--+----+... ...+----+--> reg_start | ||
161 | * reg_size ... | | | ||
162 | * ... | | [PART_1] | ||
163 | * ... | | | ||
164 | * ...+----+--> reg_start + reg_size | ||
165 | * | | | ||
166 | * | ||
167 | */ | ||
168 | int wl1251_set_partition(struct wl1251 *wl, | ||
169 | u32 mem_start, u32 mem_size, | ||
170 | u32 reg_start, u32 reg_size) | ||
171 | { | 133 | { |
172 | struct wl1251_partition *partition; | 134 | wl1251_spi_reset(wl); |
173 | struct spi_transfer t; | 135 | wl1251_spi_wake(wl); |
174 | struct spi_message m; | ||
175 | size_t len, cmd_len; | ||
176 | u32 *cmd; | ||
177 | int addr; | ||
178 | |||
179 | cmd_len = sizeof(u32) + 2 * sizeof(struct wl1251_partition); | ||
180 | cmd = kzalloc(cmd_len, GFP_KERNEL); | ||
181 | if (!cmd) | ||
182 | return -ENOMEM; | ||
183 | |||
184 | spi_message_init(&m); | ||
185 | memset(&t, 0, sizeof(t)); | ||
186 | |||
187 | partition = (struct wl1251_partition *) (cmd + 1); | ||
188 | addr = HW_ACCESS_PART0_SIZE_ADDR; | ||
189 | len = 2 * sizeof(struct wl1251_partition); | ||
190 | |||
191 | *cmd |= WSPI_CMD_WRITE; | ||
192 | *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; | ||
193 | *cmd |= addr & WSPI_CMD_BYTE_ADDR; | ||
194 | |||
195 | wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", | ||
196 | mem_start, mem_size); | ||
197 | wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", | ||
198 | reg_start, reg_size); | ||
199 | |||
200 | /* Make sure that the two partitions together don't exceed the | ||
201 | * address range */ | ||
202 | if ((mem_size + reg_size) > HW_ACCESS_MEMORY_MAX_RANGE) { | ||
203 | wl1251_debug(DEBUG_SPI, "Total size exceeds maximum virtual" | ||
204 | " address range. Truncating partition[0]."); | ||
205 | mem_size = HW_ACCESS_MEMORY_MAX_RANGE - reg_size; | ||
206 | wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", | ||
207 | mem_start, mem_size); | ||
208 | wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", | ||
209 | reg_start, reg_size); | ||
210 | } | ||
211 | |||
212 | if ((mem_start < reg_start) && | ||
213 | ((mem_start + mem_size) > reg_start)) { | ||
214 | /* Guarantee that the memory partition doesn't overlap the | ||
215 | * registers partition */ | ||
216 | wl1251_debug(DEBUG_SPI, "End of partition[0] is " | ||
217 | "overlapping partition[1]. Adjusted."); | ||
218 | mem_size = reg_start - mem_start; | ||
219 | wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", | ||
220 | mem_start, mem_size); | ||
221 | wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", | ||
222 | reg_start, reg_size); | ||
223 | } else if ((reg_start < mem_start) && | ||
224 | ((reg_start + reg_size) > mem_start)) { | ||
225 | /* Guarantee that the register partition doesn't overlap the | ||
226 | * memory partition */ | ||
227 | wl1251_debug(DEBUG_SPI, "End of partition[1] is" | ||
228 | " overlapping partition[0]. Adjusted."); | ||
229 | reg_size = mem_start - reg_start; | ||
230 | wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", | ||
231 | mem_start, mem_size); | ||
232 | wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", | ||
233 | reg_start, reg_size); | ||
234 | } | ||
235 | |||
236 | partition[0].start = mem_start; | ||
237 | partition[0].size = mem_size; | ||
238 | partition[1].start = reg_start; | ||
239 | partition[1].size = reg_size; | ||
240 | |||
241 | wl->physical_mem_addr = mem_start; | ||
242 | wl->physical_reg_addr = reg_start; | ||
243 | |||
244 | wl->virtual_mem_addr = 0; | ||
245 | wl->virtual_reg_addr = mem_size; | ||
246 | |||
247 | t.tx_buf = cmd; | ||
248 | t.len = cmd_len; | ||
249 | spi_message_add_tail(&t, &m); | ||
250 | |||
251 | spi_sync(wl->spi, &m); | ||
252 | |||
253 | kfree(cmd); | ||
254 | |||
255 | return 0; | ||
256 | } | 136 | } |
257 | 137 | ||
258 | void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, | 138 | static void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, |
259 | size_t len, bool fixed) | 139 | size_t len) |
260 | { | 140 | { |
261 | struct spi_transfer t[3]; | 141 | struct spi_transfer t[3]; |
262 | struct spi_message m; | 142 | struct spi_message m; |
@@ -271,9 +151,6 @@ void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, | |||
271 | *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; | 151 | *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; |
272 | *cmd |= addr & WSPI_CMD_BYTE_ADDR; | 152 | *cmd |= addr & WSPI_CMD_BYTE_ADDR; |
273 | 153 | ||
274 | if (fixed) | ||
275 | *cmd |= WSPI_CMD_FIXED; | ||
276 | |||
277 | spi_message_init(&m); | 154 | spi_message_init(&m); |
278 | memset(t, 0, sizeof(t)); | 155 | memset(t, 0, sizeof(t)); |
279 | 156 | ||
@@ -290,7 +167,7 @@ void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, | |||
290 | t[2].len = len; | 167 | t[2].len = len; |
291 | spi_message_add_tail(&t[2], &m); | 168 | spi_message_add_tail(&t[2], &m); |
292 | 169 | ||
293 | spi_sync(wl->spi, &m); | 170 | spi_sync(wl_to_spi(wl), &m); |
294 | 171 | ||
295 | /* FIXME: check busy words */ | 172 | /* FIXME: check busy words */ |
296 | 173 | ||
@@ -298,8 +175,8 @@ void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, | |||
298 | wl1251_dump(DEBUG_SPI, "spi_read buf <- ", buf, len); | 175 | wl1251_dump(DEBUG_SPI, "spi_read buf <- ", buf, len); |
299 | } | 176 | } |
300 | 177 | ||
301 | void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, | 178 | static void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, |
302 | size_t len, bool fixed) | 179 | size_t len) |
303 | { | 180 | { |
304 | struct spi_transfer t[2]; | 181 | struct spi_transfer t[2]; |
305 | struct spi_message m; | 182 | struct spi_message m; |
@@ -312,9 +189,6 @@ void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, | |||
312 | *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; | 189 | *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; |
313 | *cmd |= addr & WSPI_CMD_BYTE_ADDR; | 190 | *cmd |= addr & WSPI_CMD_BYTE_ADDR; |
314 | 191 | ||
315 | if (fixed) | ||
316 | *cmd |= WSPI_CMD_FIXED; | ||
317 | |||
318 | spi_message_init(&m); | 192 | spi_message_init(&m); |
319 | memset(t, 0, sizeof(t)); | 193 | memset(t, 0, sizeof(t)); |
320 | 194 | ||
@@ -326,68 +200,145 @@ void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, | |||
326 | t[1].len = len; | 200 | t[1].len = len; |
327 | spi_message_add_tail(&t[1], &m); | 201 | spi_message_add_tail(&t[1], &m); |
328 | 202 | ||
329 | spi_sync(wl->spi, &m); | 203 | spi_sync(wl_to_spi(wl), &m); |
330 | 204 | ||
331 | wl1251_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); | 205 | wl1251_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); |
332 | wl1251_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); | 206 | wl1251_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); |
333 | } | 207 | } |
334 | 208 | ||
335 | void wl1251_spi_mem_read(struct wl1251 *wl, int addr, void *buf, | 209 | static void wl1251_spi_enable_irq(struct wl1251 *wl) |
336 | size_t len) | ||
337 | { | 210 | { |
338 | int physical; | 211 | return enable_irq(wl->irq); |
339 | 212 | } | |
340 | physical = wl1251_translate_mem_addr(wl, addr); | ||
341 | 213 | ||
342 | wl1251_spi_read(wl, physical, buf, len, false); | 214 | static void wl1251_spi_disable_irq(struct wl1251 *wl) |
215 | { | ||
216 | return disable_irq(wl->irq); | ||
343 | } | 217 | } |
344 | 218 | ||
345 | void wl1251_spi_mem_write(struct wl1251 *wl, int addr, void *buf, | 219 | static const struct wl1251_if_operations wl1251_spi_ops = { |
346 | size_t len) | 220 | .read = wl1251_spi_read, |
221 | .write = wl1251_spi_write, | ||
222 | .reset = wl1251_spi_reset_wake, | ||
223 | .enable_irq = wl1251_spi_enable_irq, | ||
224 | .disable_irq = wl1251_spi_disable_irq, | ||
225 | }; | ||
226 | |||
227 | static int __devinit wl1251_spi_probe(struct spi_device *spi) | ||
347 | { | 228 | { |
348 | int physical; | 229 | struct wl12xx_platform_data *pdata; |
230 | struct ieee80211_hw *hw; | ||
231 | struct wl1251 *wl; | ||
232 | int ret; | ||
233 | |||
234 | pdata = spi->dev.platform_data; | ||
235 | if (!pdata) { | ||
236 | wl1251_error("no platform data"); | ||
237 | return -ENODEV; | ||
238 | } | ||
349 | 239 | ||
350 | physical = wl1251_translate_mem_addr(wl, addr); | 240 | hw = wl1251_alloc_hw(); |
241 | if (IS_ERR(hw)) | ||
242 | return PTR_ERR(hw); | ||
351 | 243 | ||
352 | wl1251_spi_write(wl, physical, buf, len, false); | 244 | wl = hw->priv; |
353 | } | ||
354 | 245 | ||
355 | void wl1251_spi_reg_read(struct wl1251 *wl, int addr, void *buf, size_t len, | 246 | SET_IEEE80211_DEV(hw, &spi->dev); |
356 | bool fixed) | 247 | dev_set_drvdata(&spi->dev, wl); |
357 | { | 248 | wl->if_priv = spi; |
358 | int physical; | 249 | wl->if_ops = &wl1251_spi_ops; |
359 | 250 | ||
360 | physical = wl1251_translate_reg_addr(wl, addr); | 251 | /* This is the only SPI value that we need to set here, the rest |
252 | * comes from the board-peripherals file */ | ||
253 | spi->bits_per_word = 32; | ||
361 | 254 | ||
362 | wl1251_spi_read(wl, physical, buf, len, fixed); | 255 | ret = spi_setup(spi); |
363 | } | 256 | if (ret < 0) { |
257 | wl1251_error("spi_setup failed"); | ||
258 | goto out_free; | ||
259 | } | ||
364 | 260 | ||
365 | void wl1251_spi_reg_write(struct wl1251 *wl, int addr, void *buf, size_t len, | 261 | wl->set_power = pdata->set_power; |
366 | bool fixed) | 262 | if (!wl->set_power) { |
367 | { | 263 | wl1251_error("set power function missing in platform data"); |
368 | int physical; | 264 | return -ENODEV; |
265 | } | ||
369 | 266 | ||
370 | physical = wl1251_translate_reg_addr(wl, addr); | 267 | wl->irq = spi->irq; |
268 | if (wl->irq < 0) { | ||
269 | wl1251_error("irq missing in platform data"); | ||
270 | return -ENODEV; | ||
271 | } | ||
371 | 272 | ||
372 | wl1251_spi_write(wl, physical, buf, len, fixed); | 273 | ret = request_irq(wl->irq, wl1251_irq, 0, DRIVER_NAME, wl); |
373 | } | 274 | if (ret < 0) { |
275 | wl1251_error("request_irq() failed: %d", ret); | ||
276 | goto out_free; | ||
277 | } | ||
374 | 278 | ||
375 | u32 wl1251_mem_read32(struct wl1251 *wl, int addr) | 279 | set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); |
376 | { | 280 | |
377 | return wl1251_read32(wl, wl1251_translate_mem_addr(wl, addr)); | 281 | disable_irq(wl->irq); |
282 | |||
283 | ret = wl1251_init_ieee80211(wl); | ||
284 | if (ret) | ||
285 | goto out_irq; | ||
286 | |||
287 | return 0; | ||
288 | |||
289 | out_irq: | ||
290 | free_irq(wl->irq, wl); | ||
291 | |||
292 | out_free: | ||
293 | ieee80211_free_hw(hw); | ||
294 | |||
295 | return ret; | ||
378 | } | 296 | } |
379 | 297 | ||
380 | void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val) | 298 | static int __devexit wl1251_spi_remove(struct spi_device *spi) |
381 | { | 299 | { |
382 | wl1251_write32(wl, wl1251_translate_mem_addr(wl, addr), val); | 300 | struct wl1251 *wl = dev_get_drvdata(&spi->dev); |
301 | |||
302 | free_irq(wl->irq, wl); | ||
303 | wl1251_free_hw(wl); | ||
304 | |||
305 | return 0; | ||
383 | } | 306 | } |
384 | 307 | ||
385 | u32 wl1251_reg_read32(struct wl1251 *wl, int addr) | 308 | static struct spi_driver wl1251_spi_driver = { |
309 | .driver = { | ||
310 | .name = "wl12xx", | ||
311 | .bus = &spi_bus_type, | ||
312 | .owner = THIS_MODULE, | ||
313 | }, | ||
314 | |||
315 | .probe = wl1251_spi_probe, | ||
316 | .remove = __devexit_p(wl1251_spi_remove), | ||
317 | }; | ||
318 | |||
319 | static int __init wl1251_spi_init(void) | ||
386 | { | 320 | { |
387 | return wl1251_read32(wl, wl1251_translate_reg_addr(wl, addr)); | 321 | int ret; |
322 | |||
323 | ret = spi_register_driver(&wl1251_spi_driver); | ||
324 | if (ret < 0) { | ||
325 | wl1251_error("failed to register spi driver: %d", ret); | ||
326 | goto out; | ||
327 | } | ||
328 | |||
329 | out: | ||
330 | return ret; | ||
388 | } | 331 | } |
389 | 332 | ||
390 | void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val) | 333 | static void __exit wl1251_spi_exit(void) |
391 | { | 334 | { |
392 | wl1251_write32(wl, wl1251_translate_reg_addr(wl, addr), val); | 335 | spi_unregister_driver(&wl1251_spi_driver); |
336 | |||
337 | wl1251_notice("unloaded"); | ||
393 | } | 338 | } |
339 | |||
340 | module_init(wl1251_spi_init); | ||
341 | module_exit(wl1251_spi_exit); | ||
342 | |||
343 | MODULE_LICENSE("GPL"); | ||
344 | MODULE_AUTHOR("Kalle Valo <kalle.valo@nokia.com>"); | ||
diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.h b/drivers/net/wireless/wl12xx/wl1251_spi.h index 6e8daf4e1085..2e273a97e7f3 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.h +++ b/drivers/net/wireless/wl12xx/wl1251_spi.h | |||
@@ -27,18 +27,7 @@ | |||
27 | 27 | ||
28 | #include "wl1251_cmd.h" | 28 | #include "wl1251_cmd.h" |
29 | #include "wl1251_acx.h" | 29 | #include "wl1251_acx.h" |
30 | #include "reg.h" | 30 | #include "wl1251_reg.h" |
31 | |||
32 | #define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0 | ||
33 | |||
34 | #define HW_ACCESS_PART0_SIZE_ADDR 0x1FFC0 | ||
35 | #define HW_ACCESS_PART0_START_ADDR 0x1FFC4 | ||
36 | #define HW_ACCESS_PART1_SIZE_ADDR 0x1FFC8 | ||
37 | #define HW_ACCESS_PART1_START_ADDR 0x1FFCC | ||
38 | |||
39 | #define HW_ACCESS_REGISTER_SIZE 4 | ||
40 | |||
41 | #define HW_ACCESS_PRAM_MAX_RANGE 0x3c000 | ||
42 | 31 | ||
43 | #define WSPI_CMD_READ 0x40000000 | 32 | #define WSPI_CMD_READ 0x40000000 |
44 | #define WSPI_CMD_WRITE 0x00000000 | 33 | #define WSPI_CMD_WRITE 0x00000000 |
@@ -69,47 +58,4 @@ | |||
69 | ((WL1251_BUSY_WORD_LEN - 4) / sizeof(u32)) | 58 | ((WL1251_BUSY_WORD_LEN - 4) / sizeof(u32)) |
70 | #define HW_ACCESS_WSPI_INIT_CMD_MASK 0 | 59 | #define HW_ACCESS_WSPI_INIT_CMD_MASK 0 |
71 | 60 | ||
72 | |||
73 | /* Raw target IO, address is not translated */ | ||
74 | void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, | ||
75 | size_t len, bool fixed); | ||
76 | void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, | ||
77 | size_t len, bool fixed); | ||
78 | |||
79 | /* Memory target IO, address is tranlated to partition 0 */ | ||
80 | void wl1251_spi_mem_read(struct wl1251 *wl, int addr, void *buf, size_t len); | ||
81 | void wl1251_spi_mem_write(struct wl1251 *wl, int addr, void *buf, size_t len); | ||
82 | u32 wl1251_mem_read32(struct wl1251 *wl, int addr); | ||
83 | void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val); | ||
84 | |||
85 | /* Registers IO */ | ||
86 | void wl1251_spi_reg_read(struct wl1251 *wl, int addr, void *buf, size_t len, | ||
87 | bool fixed); | ||
88 | void wl1251_spi_reg_write(struct wl1251 *wl, int addr, void *buf, size_t len, | ||
89 | bool fixed); | ||
90 | u32 wl1251_reg_read32(struct wl1251 *wl, int addr); | ||
91 | void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val); | ||
92 | |||
93 | /* INIT and RESET words */ | ||
94 | void wl1251_spi_reset(struct wl1251 *wl); | ||
95 | void wl1251_spi_init(struct wl1251 *wl); | ||
96 | int wl1251_set_partition(struct wl1251 *wl, | ||
97 | u32 part_start, u32 part_size, | ||
98 | u32 reg_start, u32 reg_size); | ||
99 | |||
100 | static inline u32 wl1251_read32(struct wl1251 *wl, int addr) | ||
101 | { | ||
102 | wl1251_spi_read(wl, addr, &wl->buffer_32, | ||
103 | sizeof(wl->buffer_32), false); | ||
104 | |||
105 | return wl->buffer_32; | ||
106 | } | ||
107 | |||
108 | static inline void wl1251_write32(struct wl1251 *wl, int addr, u32 val) | ||
109 | { | ||
110 | wl->buffer_32 = val; | ||
111 | wl1251_spi_write(wl, addr, &wl->buffer_32, | ||
112 | sizeof(wl->buffer_32), false); | ||
113 | } | ||
114 | |||
115 | #endif /* __WL1251_SPI_H__ */ | 61 | #endif /* __WL1251_SPI_H__ */ |
diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.c b/drivers/net/wireless/wl12xx/wl1251_tx.c index 2652a222383a..f85970615849 100644 --- a/drivers/net/wireless/wl12xx/wl1251_tx.c +++ b/drivers/net/wireless/wl12xx/wl1251_tx.c | |||
@@ -26,10 +26,10 @@ | |||
26 | #include <linux/module.h> | 26 | #include <linux/module.h> |
27 | 27 | ||
28 | #include "wl1251.h" | 28 | #include "wl1251.h" |
29 | #include "reg.h" | 29 | #include "wl1251_reg.h" |
30 | #include "wl1251_spi.h" | ||
31 | #include "wl1251_tx.h" | 30 | #include "wl1251_tx.h" |
32 | #include "wl1251_ps.h" | 31 | #include "wl1251_ps.h" |
32 | #include "wl1251_io.h" | ||
33 | 33 | ||
34 | static bool wl1251_tx_double_buffer_busy(struct wl1251 *wl, u32 data_out_count) | 34 | static bool wl1251_tx_double_buffer_busy(struct wl1251 *wl, u32 data_out_count) |
35 | { | 35 | { |
@@ -235,7 +235,7 @@ static int wl1251_tx_send_packet(struct wl1251 *wl, struct sk_buff *skb, | |||
235 | else | 235 | else |
236 | addr = wl->data_path->tx_packet_ring_addr; | 236 | addr = wl->data_path->tx_packet_ring_addr; |
237 | 237 | ||
238 | wl1251_spi_mem_write(wl, addr, skb->data, len); | 238 | wl1251_mem_write(wl, addr, skb->data, len); |
239 | 239 | ||
240 | wl1251_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x", | 240 | wl1251_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x", |
241 | tx_hdr->id, skb, tx_hdr->length, tx_hdr->rate); | 241 | tx_hdr->id, skb, tx_hdr->length, tx_hdr->rate); |
@@ -451,7 +451,7 @@ void wl1251_tx_complete(struct wl1251 *wl) | |||
451 | return; | 451 | return; |
452 | 452 | ||
453 | /* First we read the result */ | 453 | /* First we read the result */ |
454 | wl1251_spi_mem_read(wl, wl->data_path->tx_complete_addr, | 454 | wl1251_mem_read(wl, wl->data_path->tx_complete_addr, |
455 | result, sizeof(result)); | 455 | result, sizeof(result)); |
456 | 456 | ||
457 | result_index = wl->next_tx_complete; | 457 | result_index = wl->next_tx_complete; |
@@ -482,41 +482,41 @@ void wl1251_tx_complete(struct wl1251 *wl) | |||
482 | */ | 482 | */ |
483 | if (result_index > wl->next_tx_complete) { | 483 | if (result_index > wl->next_tx_complete) { |
484 | /* Only 1 write is needed */ | 484 | /* Only 1 write is needed */ |
485 | wl1251_spi_mem_write(wl, | 485 | wl1251_mem_write(wl, |
486 | wl->data_path->tx_complete_addr + | 486 | wl->data_path->tx_complete_addr + |
487 | (wl->next_tx_complete * | 487 | (wl->next_tx_complete * |
488 | sizeof(struct tx_result)), | 488 | sizeof(struct tx_result)), |
489 | &result[wl->next_tx_complete], | 489 | &result[wl->next_tx_complete], |
490 | num_complete * | 490 | num_complete * |
491 | sizeof(struct tx_result)); | 491 | sizeof(struct tx_result)); |
492 | 492 | ||
493 | 493 | ||
494 | } else if (result_index < wl->next_tx_complete) { | 494 | } else if (result_index < wl->next_tx_complete) { |
495 | /* 2 writes are needed */ | 495 | /* 2 writes are needed */ |
496 | wl1251_spi_mem_write(wl, | 496 | wl1251_mem_write(wl, |
497 | wl->data_path->tx_complete_addr + | 497 | wl->data_path->tx_complete_addr + |
498 | (wl->next_tx_complete * | 498 | (wl->next_tx_complete * |
499 | sizeof(struct tx_result)), | 499 | sizeof(struct tx_result)), |
500 | &result[wl->next_tx_complete], | 500 | &result[wl->next_tx_complete], |
501 | (FW_TX_CMPLT_BLOCK_SIZE - | 501 | (FW_TX_CMPLT_BLOCK_SIZE - |
502 | wl->next_tx_complete) * | 502 | wl->next_tx_complete) * |
503 | sizeof(struct tx_result)); | 503 | sizeof(struct tx_result)); |
504 | 504 | ||
505 | wl1251_spi_mem_write(wl, | 505 | wl1251_mem_write(wl, |
506 | wl->data_path->tx_complete_addr, | 506 | wl->data_path->tx_complete_addr, |
507 | result, | 507 | result, |
508 | (num_complete - | 508 | (num_complete - |
509 | FW_TX_CMPLT_BLOCK_SIZE + | 509 | FW_TX_CMPLT_BLOCK_SIZE + |
510 | wl->next_tx_complete) * | 510 | wl->next_tx_complete) * |
511 | sizeof(struct tx_result)); | 511 | sizeof(struct tx_result)); |
512 | 512 | ||
513 | } else { | 513 | } else { |
514 | /* We have to write the whole array */ | 514 | /* We have to write the whole array */ |
515 | wl1251_spi_mem_write(wl, | 515 | wl1251_mem_write(wl, |
516 | wl->data_path->tx_complete_addr, | 516 | wl->data_path->tx_complete_addr, |
517 | result, | 517 | result, |
518 | FW_TX_CMPLT_BLOCK_SIZE * | 518 | FW_TX_CMPLT_BLOCK_SIZE * |
519 | sizeof(struct tx_result)); | 519 | sizeof(struct tx_result)); |
520 | } | 520 | } |
521 | 521 | ||
522 | } | 522 | } |
diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h new file mode 100644 index 000000000000..55818f94017b --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271.h | |||
@@ -0,0 +1,407 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. | ||
5 | * Copyright (C) 2008-2009 Nokia Corporation | ||
6 | * | ||
7 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef __WL1271_H__ | ||
26 | #define __WL1271_H__ | ||
27 | |||
28 | #include <linux/mutex.h> | ||
29 | #include <linux/completion.h> | ||
30 | #include <linux/spinlock.h> | ||
31 | #include <linux/list.h> | ||
32 | #include <linux/bitops.h> | ||
33 | #include <net/mac80211.h> | ||
34 | |||
35 | #define DRIVER_NAME "wl1271" | ||
36 | #define DRIVER_PREFIX DRIVER_NAME ": " | ||
37 | |||
38 | enum { | ||
39 | DEBUG_NONE = 0, | ||
40 | DEBUG_IRQ = BIT(0), | ||
41 | DEBUG_SPI = BIT(1), | ||
42 | DEBUG_BOOT = BIT(2), | ||
43 | DEBUG_MAILBOX = BIT(3), | ||
44 | DEBUG_NETLINK = BIT(4), | ||
45 | DEBUG_EVENT = BIT(5), | ||
46 | DEBUG_TX = BIT(6), | ||
47 | DEBUG_RX = BIT(7), | ||
48 | DEBUG_SCAN = BIT(8), | ||
49 | DEBUG_CRYPT = BIT(9), | ||
50 | DEBUG_PSM = BIT(10), | ||
51 | DEBUG_MAC80211 = BIT(11), | ||
52 | DEBUG_CMD = BIT(12), | ||
53 | DEBUG_ACX = BIT(13), | ||
54 | DEBUG_ALL = ~0, | ||
55 | }; | ||
56 | |||
57 | #define DEBUG_LEVEL (DEBUG_NONE) | ||
58 | |||
59 | #define DEBUG_DUMP_LIMIT 1024 | ||
60 | |||
61 | #define wl1271_error(fmt, arg...) \ | ||
62 | printk(KERN_ERR DRIVER_PREFIX "ERROR " fmt "\n", ##arg) | ||
63 | |||
64 | #define wl1271_warning(fmt, arg...) \ | ||
65 | printk(KERN_WARNING DRIVER_PREFIX "WARNING " fmt "\n", ##arg) | ||
66 | |||
67 | #define wl1271_notice(fmt, arg...) \ | ||
68 | printk(KERN_INFO DRIVER_PREFIX fmt "\n", ##arg) | ||
69 | |||
70 | #define wl1271_info(fmt, arg...) \ | ||
71 | printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg) | ||
72 | |||
73 | #define wl1271_debug(level, fmt, arg...) \ | ||
74 | do { \ | ||
75 | if (level & DEBUG_LEVEL) \ | ||
76 | printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg); \ | ||
77 | } while (0) | ||
78 | |||
79 | #define wl1271_dump(level, prefix, buf, len) \ | ||
80 | do { \ | ||
81 | if (level & DEBUG_LEVEL) \ | ||
82 | print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ | ||
83 | DUMP_PREFIX_OFFSET, 16, 1, \ | ||
84 | buf, \ | ||
85 | min_t(size_t, len, DEBUG_DUMP_LIMIT), \ | ||
86 | 0); \ | ||
87 | } while (0) | ||
88 | |||
89 | #define wl1271_dump_ascii(level, prefix, buf, len) \ | ||
90 | do { \ | ||
91 | if (level & DEBUG_LEVEL) \ | ||
92 | print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ | ||
93 | DUMP_PREFIX_OFFSET, 16, 1, \ | ||
94 | buf, \ | ||
95 | min_t(size_t, len, DEBUG_DUMP_LIMIT), \ | ||
96 | true); \ | ||
97 | } while (0) | ||
98 | |||
99 | #define WL1271_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \ | ||
100 | CFG_BSSID_FILTER_EN) | ||
101 | |||
102 | #define WL1271_DEFAULT_RX_FILTER (CFG_RX_RCTS_ACK | CFG_RX_PRSP_EN | \ | ||
103 | CFG_RX_MGMT_EN | CFG_RX_DATA_EN | \ | ||
104 | CFG_RX_CTL_EN | CFG_RX_BCN_EN | \ | ||
105 | CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN) | ||
106 | |||
107 | #define WL1271_FW_NAME "wl1271-fw.bin" | ||
108 | #define WL1271_NVS_NAME "wl1271-nvs.bin" | ||
109 | |||
110 | #define WL1271_BUSY_WORD_LEN 8 | ||
111 | |||
112 | #define WL1271_ELP_HW_STATE_ASLEEP 0 | ||
113 | #define WL1271_ELP_HW_STATE_IRQ 1 | ||
114 | |||
115 | enum wl1271_state { | ||
116 | WL1271_STATE_OFF, | ||
117 | WL1271_STATE_ON, | ||
118 | WL1271_STATE_PLT, | ||
119 | }; | ||
120 | |||
121 | enum wl1271_partition_type { | ||
122 | PART_DOWN, | ||
123 | PART_WORK, | ||
124 | PART_DRPW, | ||
125 | |||
126 | PART_TABLE_LEN | ||
127 | }; | ||
128 | |||
129 | struct wl1271_partition { | ||
130 | u32 size; | ||
131 | u32 start; | ||
132 | }; | ||
133 | |||
134 | struct wl1271_partition_set { | ||
135 | struct wl1271_partition mem; | ||
136 | struct wl1271_partition reg; | ||
137 | }; | ||
138 | |||
139 | struct wl1271; | ||
140 | |||
141 | /* FIXME: I'm not sure about this structure name */ | ||
142 | struct wl1271_chip { | ||
143 | u32 id; | ||
144 | char fw_ver[21]; | ||
145 | }; | ||
146 | |||
147 | struct wl1271_stats { | ||
148 | struct acx_statistics *fw_stats; | ||
149 | unsigned long fw_stats_update; | ||
150 | |||
151 | unsigned int retry_count; | ||
152 | unsigned int excessive_retries; | ||
153 | }; | ||
154 | |||
155 | struct wl1271_debugfs { | ||
156 | struct dentry *rootdir; | ||
157 | struct dentry *fw_statistics; | ||
158 | |||
159 | struct dentry *tx_internal_desc_overflow; | ||
160 | |||
161 | struct dentry *rx_out_of_mem; | ||
162 | struct dentry *rx_hdr_overflow; | ||
163 | struct dentry *rx_hw_stuck; | ||
164 | struct dentry *rx_dropped; | ||
165 | struct dentry *rx_fcs_err; | ||
166 | struct dentry *rx_xfr_hint_trig; | ||
167 | struct dentry *rx_path_reset; | ||
168 | struct dentry *rx_reset_counter; | ||
169 | |||
170 | struct dentry *dma_rx_requested; | ||
171 | struct dentry *dma_rx_errors; | ||
172 | struct dentry *dma_tx_requested; | ||
173 | struct dentry *dma_tx_errors; | ||
174 | |||
175 | struct dentry *isr_cmd_cmplt; | ||
176 | struct dentry *isr_fiqs; | ||
177 | struct dentry *isr_rx_headers; | ||
178 | struct dentry *isr_rx_mem_overflow; | ||
179 | struct dentry *isr_rx_rdys; | ||
180 | struct dentry *isr_irqs; | ||
181 | struct dentry *isr_tx_procs; | ||
182 | struct dentry *isr_decrypt_done; | ||
183 | struct dentry *isr_dma0_done; | ||
184 | struct dentry *isr_dma1_done; | ||
185 | struct dentry *isr_tx_exch_complete; | ||
186 | struct dentry *isr_commands; | ||
187 | struct dentry *isr_rx_procs; | ||
188 | struct dentry *isr_hw_pm_mode_changes; | ||
189 | struct dentry *isr_host_acknowledges; | ||
190 | struct dentry *isr_pci_pm; | ||
191 | struct dentry *isr_wakeups; | ||
192 | struct dentry *isr_low_rssi; | ||
193 | |||
194 | struct dentry *wep_addr_key_count; | ||
195 | struct dentry *wep_default_key_count; | ||
196 | /* skipping wep.reserved */ | ||
197 | struct dentry *wep_key_not_found; | ||
198 | struct dentry *wep_decrypt_fail; | ||
199 | struct dentry *wep_packets; | ||
200 | struct dentry *wep_interrupt; | ||
201 | |||
202 | struct dentry *pwr_ps_enter; | ||
203 | struct dentry *pwr_elp_enter; | ||
204 | struct dentry *pwr_missing_bcns; | ||
205 | struct dentry *pwr_wake_on_host; | ||
206 | struct dentry *pwr_wake_on_timer_exp; | ||
207 | struct dentry *pwr_tx_with_ps; | ||
208 | struct dentry *pwr_tx_without_ps; | ||
209 | struct dentry *pwr_rcvd_beacons; | ||
210 | struct dentry *pwr_power_save_off; | ||
211 | struct dentry *pwr_enable_ps; | ||
212 | struct dentry *pwr_disable_ps; | ||
213 | struct dentry *pwr_fix_tsf_ps; | ||
214 | /* skipping cont_miss_bcns_spread for now */ | ||
215 | struct dentry *pwr_rcvd_awake_beacons; | ||
216 | |||
217 | struct dentry *mic_rx_pkts; | ||
218 | struct dentry *mic_calc_failure; | ||
219 | |||
220 | struct dentry *aes_encrypt_fail; | ||
221 | struct dentry *aes_decrypt_fail; | ||
222 | struct dentry *aes_encrypt_packets; | ||
223 | struct dentry *aes_decrypt_packets; | ||
224 | struct dentry *aes_encrypt_interrupt; | ||
225 | struct dentry *aes_decrypt_interrupt; | ||
226 | |||
227 | struct dentry *event_heart_beat; | ||
228 | struct dentry *event_calibration; | ||
229 | struct dentry *event_rx_mismatch; | ||
230 | struct dentry *event_rx_mem_empty; | ||
231 | struct dentry *event_rx_pool; | ||
232 | struct dentry *event_oom_late; | ||
233 | struct dentry *event_phy_transmit_error; | ||
234 | struct dentry *event_tx_stuck; | ||
235 | |||
236 | struct dentry *ps_pspoll_timeouts; | ||
237 | struct dentry *ps_upsd_timeouts; | ||
238 | struct dentry *ps_upsd_max_sptime; | ||
239 | struct dentry *ps_upsd_max_apturn; | ||
240 | struct dentry *ps_pspoll_max_apturn; | ||
241 | struct dentry *ps_pspoll_utilization; | ||
242 | struct dentry *ps_upsd_utilization; | ||
243 | |||
244 | struct dentry *rxpipe_rx_prep_beacon_drop; | ||
245 | struct dentry *rxpipe_descr_host_int_trig_rx_data; | ||
246 | struct dentry *rxpipe_beacon_buffer_thres_host_int_trig_rx_data; | ||
247 | struct dentry *rxpipe_missed_beacon_host_int_trig_rx_data; | ||
248 | struct dentry *rxpipe_tx_xfr_host_int_trig_rx_data; | ||
249 | |||
250 | struct dentry *tx_queue_len; | ||
251 | |||
252 | struct dentry *retry_count; | ||
253 | struct dentry *excessive_retries; | ||
254 | }; | ||
255 | |||
256 | #define NUM_TX_QUEUES 4 | ||
257 | #define NUM_RX_PKT_DESC 8 | ||
258 | |||
259 | /* FW status registers */ | ||
260 | struct wl1271_fw_status { | ||
261 | u32 intr; | ||
262 | u8 fw_rx_counter; | ||
263 | u8 drv_rx_counter; | ||
264 | u8 reserved; | ||
265 | u8 tx_results_counter; | ||
266 | u32 rx_pkt_descs[NUM_RX_PKT_DESC]; | ||
267 | u32 tx_released_blks[NUM_TX_QUEUES]; | ||
268 | u32 fw_localtime; | ||
269 | u32 padding[2]; | ||
270 | } __attribute__ ((packed)); | ||
271 | |||
272 | struct wl1271_rx_mem_pool_addr { | ||
273 | u32 addr; | ||
274 | u32 addr_extra; | ||
275 | }; | ||
276 | |||
277 | struct wl1271 { | ||
278 | struct ieee80211_hw *hw; | ||
279 | bool mac80211_registered; | ||
280 | |||
281 | struct spi_device *spi; | ||
282 | |||
283 | void (*set_power)(bool enable); | ||
284 | int irq; | ||
285 | |||
286 | spinlock_t wl_lock; | ||
287 | |||
288 | enum wl1271_state state; | ||
289 | struct mutex mutex; | ||
290 | |||
291 | int physical_mem_addr; | ||
292 | int physical_reg_addr; | ||
293 | int virtual_mem_addr; | ||
294 | int virtual_reg_addr; | ||
295 | |||
296 | struct wl1271_chip chip; | ||
297 | |||
298 | int cmd_box_addr; | ||
299 | int event_box_addr; | ||
300 | |||
301 | u8 *fw; | ||
302 | size_t fw_len; | ||
303 | u8 *nvs; | ||
304 | size_t nvs_len; | ||
305 | |||
306 | u8 bssid[ETH_ALEN]; | ||
307 | u8 mac_addr[ETH_ALEN]; | ||
308 | u8 bss_type; | ||
309 | u8 ssid[IW_ESSID_MAX_SIZE + 1]; | ||
310 | u8 ssid_len; | ||
311 | u8 listen_int; | ||
312 | int channel; | ||
313 | |||
314 | struct wl1271_acx_mem_map *target_mem_map; | ||
315 | |||
316 | /* Accounting for allocated / available TX blocks on HW */ | ||
317 | u32 tx_blocks_freed[NUM_TX_QUEUES]; | ||
318 | u32 tx_blocks_available; | ||
319 | u8 tx_results_count; | ||
320 | |||
321 | /* Transmitted TX packets counter for chipset interface */ | ||
322 | int tx_packets_count; | ||
323 | |||
324 | /* Time-offset between host and chipset clocks */ | ||
325 | int time_offset; | ||
326 | |||
327 | /* Session counter for the chipset */ | ||
328 | int session_counter; | ||
329 | |||
330 | /* Frames scheduled for transmission, not handled yet */ | ||
331 | struct sk_buff_head tx_queue; | ||
332 | bool tx_queue_stopped; | ||
333 | |||
334 | struct work_struct tx_work; | ||
335 | struct work_struct filter_work; | ||
336 | |||
337 | /* Pending TX frames */ | ||
338 | struct sk_buff *tx_frames[16]; | ||
339 | |||
340 | /* FW Rx counter */ | ||
341 | u32 rx_counter; | ||
342 | |||
343 | /* Rx memory pool address */ | ||
344 | struct wl1271_rx_mem_pool_addr rx_mem_pool_addr; | ||
345 | |||
346 | /* The target interrupt mask */ | ||
347 | struct work_struct irq_work; | ||
348 | |||
349 | /* The mbox event mask */ | ||
350 | u32 event_mask; | ||
351 | |||
352 | /* Mailbox pointers */ | ||
353 | u32 mbox_ptr[2]; | ||
354 | |||
355 | /* Are we currently scanning */ | ||
356 | bool scanning; | ||
357 | |||
358 | /* Our association ID */ | ||
359 | u16 aid; | ||
360 | |||
361 | /* Default key (for WEP) */ | ||
362 | u32 default_key; | ||
363 | |||
364 | unsigned int rx_config; | ||
365 | unsigned int rx_filter; | ||
366 | |||
367 | /* is firmware in elp mode */ | ||
368 | bool elp; | ||
369 | |||
370 | struct completion *elp_compl; | ||
371 | |||
372 | /* we can be in psm, but not in elp, we have to differentiate */ | ||
373 | bool psm; | ||
374 | |||
375 | /* PSM mode requested */ | ||
376 | bool psm_requested; | ||
377 | |||
378 | /* in dBm */ | ||
379 | int power_level; | ||
380 | |||
381 | struct wl1271_stats stats; | ||
382 | struct wl1271_debugfs debugfs; | ||
383 | |||
384 | u32 buffer_32; | ||
385 | u32 buffer_cmd; | ||
386 | u8 buffer_busyword[WL1271_BUSY_WORD_LEN]; | ||
387 | struct wl1271_rx_descriptor *rx_descriptor; | ||
388 | |||
389 | struct wl1271_fw_status *fw_status; | ||
390 | struct wl1271_tx_hw_res_if *tx_res_if; | ||
391 | }; | ||
392 | |||
393 | int wl1271_plt_start(struct wl1271 *wl); | ||
394 | int wl1271_plt_stop(struct wl1271 *wl); | ||
395 | |||
396 | #define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */ | ||
397 | |||
398 | #define SESSION_COUNTER_MAX 7 /* maximum value for the session counter */ | ||
399 | |||
400 | #define WL1271_DEFAULT_POWER_LEVEL 0 | ||
401 | |||
402 | #define WL1271_TX_QUEUE_MAX_LENGTH 20 | ||
403 | |||
404 | /* WL1271 needs a 200ms sleep after power on */ | ||
405 | #define WL1271_POWER_ON_SLEEP 200 /* in miliseconds */ | ||
406 | |||
407 | #endif | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/wl1271_acx.c new file mode 100644 index 000000000000..f622a4092615 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_acx.c | |||
@@ -0,0 +1,961 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2008-2009 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include "wl1271_acx.h" | ||
25 | |||
26 | #include <linux/module.h> | ||
27 | #include <linux/platform_device.h> | ||
28 | #include <linux/crc7.h> | ||
29 | #include <linux/spi/spi.h> | ||
30 | |||
31 | #include "wl1271.h" | ||
32 | #include "wl12xx_80211.h" | ||
33 | #include "wl1271_reg.h" | ||
34 | #include "wl1271_spi.h" | ||
35 | #include "wl1271_ps.h" | ||
36 | |||
37 | int wl1271_acx_wake_up_conditions(struct wl1271 *wl, u8 wake_up_event, | ||
38 | u8 listen_interval) | ||
39 | { | ||
40 | struct acx_wake_up_condition *wake_up; | ||
41 | int ret; | ||
42 | |||
43 | wl1271_debug(DEBUG_ACX, "acx wake up conditions"); | ||
44 | |||
45 | wake_up = kzalloc(sizeof(*wake_up), GFP_KERNEL); | ||
46 | if (!wake_up) { | ||
47 | ret = -ENOMEM; | ||
48 | goto out; | ||
49 | } | ||
50 | |||
51 | wake_up->wake_up_event = wake_up_event; | ||
52 | wake_up->listen_interval = listen_interval; | ||
53 | |||
54 | ret = wl1271_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS, | ||
55 | wake_up, sizeof(*wake_up)); | ||
56 | if (ret < 0) { | ||
57 | wl1271_warning("could not set wake up conditions: %d", ret); | ||
58 | goto out; | ||
59 | } | ||
60 | |||
61 | out: | ||
62 | kfree(wake_up); | ||
63 | return ret; | ||
64 | } | ||
65 | |||
66 | int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth) | ||
67 | { | ||
68 | struct acx_sleep_auth *auth; | ||
69 | int ret; | ||
70 | |||
71 | wl1271_debug(DEBUG_ACX, "acx sleep auth"); | ||
72 | |||
73 | auth = kzalloc(sizeof(*auth), GFP_KERNEL); | ||
74 | if (!auth) { | ||
75 | ret = -ENOMEM; | ||
76 | goto out; | ||
77 | } | ||
78 | |||
79 | auth->sleep_auth = sleep_auth; | ||
80 | |||
81 | ret = wl1271_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth)); | ||
82 | if (ret < 0) | ||
83 | return ret; | ||
84 | |||
85 | out: | ||
86 | kfree(auth); | ||
87 | return ret; | ||
88 | } | ||
89 | |||
90 | int wl1271_acx_fw_version(struct wl1271 *wl, char *buf, size_t len) | ||
91 | { | ||
92 | struct acx_revision *rev; | ||
93 | int ret; | ||
94 | |||
95 | wl1271_debug(DEBUG_ACX, "acx fw rev"); | ||
96 | |||
97 | rev = kzalloc(sizeof(*rev), GFP_KERNEL); | ||
98 | if (!rev) { | ||
99 | ret = -ENOMEM; | ||
100 | goto out; | ||
101 | } | ||
102 | |||
103 | ret = wl1271_cmd_interrogate(wl, ACX_FW_REV, rev, sizeof(*rev)); | ||
104 | if (ret < 0) { | ||
105 | wl1271_warning("ACX_FW_REV interrogate failed"); | ||
106 | goto out; | ||
107 | } | ||
108 | |||
109 | /* be careful with the buffer sizes */ | ||
110 | strncpy(buf, rev->fw_version, min(len, sizeof(rev->fw_version))); | ||
111 | |||
112 | /* | ||
113 | * if the firmware version string is exactly | ||
114 | * sizeof(rev->fw_version) long or fw_len is less than | ||
115 | * sizeof(rev->fw_version) it won't be null terminated | ||
116 | */ | ||
117 | buf[min(len, sizeof(rev->fw_version)) - 1] = '\0'; | ||
118 | |||
119 | out: | ||
120 | kfree(rev); | ||
121 | return ret; | ||
122 | } | ||
123 | |||
124 | int wl1271_acx_tx_power(struct wl1271 *wl, int power) | ||
125 | { | ||
126 | struct acx_current_tx_power *acx; | ||
127 | int ret; | ||
128 | |||
129 | wl1271_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr"); | ||
130 | |||
131 | if (power < 0 || power > 25) | ||
132 | return -EINVAL; | ||
133 | |||
134 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
135 | if (!acx) { | ||
136 | ret = -ENOMEM; | ||
137 | goto out; | ||
138 | } | ||
139 | |||
140 | acx->current_tx_power = power * 10; | ||
141 | |||
142 | ret = wl1271_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx)); | ||
143 | if (ret < 0) { | ||
144 | wl1271_warning("configure of tx power failed: %d", ret); | ||
145 | goto out; | ||
146 | } | ||
147 | |||
148 | out: | ||
149 | kfree(acx); | ||
150 | return ret; | ||
151 | } | ||
152 | |||
153 | int wl1271_acx_feature_cfg(struct wl1271 *wl) | ||
154 | { | ||
155 | struct acx_feature_config *feature; | ||
156 | int ret; | ||
157 | |||
158 | wl1271_debug(DEBUG_ACX, "acx feature cfg"); | ||
159 | |||
160 | feature = kzalloc(sizeof(*feature), GFP_KERNEL); | ||
161 | if (!feature) { | ||
162 | ret = -ENOMEM; | ||
163 | goto out; | ||
164 | } | ||
165 | |||
166 | /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */ | ||
167 | feature->data_flow_options = 0; | ||
168 | feature->options = 0; | ||
169 | |||
170 | ret = wl1271_cmd_configure(wl, ACX_FEATURE_CFG, | ||
171 | feature, sizeof(*feature)); | ||
172 | if (ret < 0) { | ||
173 | wl1271_error("Couldnt set HW encryption"); | ||
174 | goto out; | ||
175 | } | ||
176 | |||
177 | out: | ||
178 | kfree(feature); | ||
179 | return ret; | ||
180 | } | ||
181 | |||
182 | int wl1271_acx_mem_map(struct wl1271 *wl, struct acx_header *mem_map, | ||
183 | size_t len) | ||
184 | { | ||
185 | int ret; | ||
186 | |||
187 | wl1271_debug(DEBUG_ACX, "acx mem map"); | ||
188 | |||
189 | ret = wl1271_cmd_interrogate(wl, ACX_MEM_MAP, mem_map, len); | ||
190 | if (ret < 0) | ||
191 | return ret; | ||
192 | |||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl, u32 life_time) | ||
197 | { | ||
198 | struct acx_rx_msdu_lifetime *acx; | ||
199 | int ret; | ||
200 | |||
201 | wl1271_debug(DEBUG_ACX, "acx rx msdu life time"); | ||
202 | |||
203 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
204 | if (!acx) { | ||
205 | ret = -ENOMEM; | ||
206 | goto out; | ||
207 | } | ||
208 | |||
209 | acx->lifetime = life_time; | ||
210 | ret = wl1271_cmd_configure(wl, DOT11_RX_MSDU_LIFE_TIME, | ||
211 | acx, sizeof(*acx)); | ||
212 | if (ret < 0) { | ||
213 | wl1271_warning("failed to set rx msdu life time: %d", ret); | ||
214 | goto out; | ||
215 | } | ||
216 | |||
217 | out: | ||
218 | kfree(acx); | ||
219 | return ret; | ||
220 | } | ||
221 | |||
222 | int wl1271_acx_rx_config(struct wl1271 *wl, u32 config, u32 filter) | ||
223 | { | ||
224 | struct acx_rx_config *rx_config; | ||
225 | int ret; | ||
226 | |||
227 | wl1271_debug(DEBUG_ACX, "acx rx config"); | ||
228 | |||
229 | rx_config = kzalloc(sizeof(*rx_config), GFP_KERNEL); | ||
230 | if (!rx_config) { | ||
231 | ret = -ENOMEM; | ||
232 | goto out; | ||
233 | } | ||
234 | |||
235 | rx_config->config_options = config; | ||
236 | rx_config->filter_options = filter; | ||
237 | |||
238 | ret = wl1271_cmd_configure(wl, ACX_RX_CFG, | ||
239 | rx_config, sizeof(*rx_config)); | ||
240 | if (ret < 0) { | ||
241 | wl1271_warning("failed to set rx config: %d", ret); | ||
242 | goto out; | ||
243 | } | ||
244 | |||
245 | out: | ||
246 | kfree(rx_config); | ||
247 | return ret; | ||
248 | } | ||
249 | |||
250 | int wl1271_acx_pd_threshold(struct wl1271 *wl) | ||
251 | { | ||
252 | struct acx_packet_detection *pd; | ||
253 | int ret; | ||
254 | |||
255 | wl1271_debug(DEBUG_ACX, "acx data pd threshold"); | ||
256 | |||
257 | pd = kzalloc(sizeof(*pd), GFP_KERNEL); | ||
258 | if (!pd) { | ||
259 | ret = -ENOMEM; | ||
260 | goto out; | ||
261 | } | ||
262 | |||
263 | /* FIXME: threshold value not set */ | ||
264 | |||
265 | ret = wl1271_cmd_configure(wl, ACX_PD_THRESHOLD, pd, sizeof(*pd)); | ||
266 | if (ret < 0) { | ||
267 | wl1271_warning("failed to set pd threshold: %d", ret); | ||
268 | goto out; | ||
269 | } | ||
270 | |||
271 | out: | ||
272 | kfree(pd); | ||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | int wl1271_acx_slot(struct wl1271 *wl, enum acx_slot_type slot_time) | ||
277 | { | ||
278 | struct acx_slot *slot; | ||
279 | int ret; | ||
280 | |||
281 | wl1271_debug(DEBUG_ACX, "acx slot"); | ||
282 | |||
283 | slot = kzalloc(sizeof(*slot), GFP_KERNEL); | ||
284 | if (!slot) { | ||
285 | ret = -ENOMEM; | ||
286 | goto out; | ||
287 | } | ||
288 | |||
289 | slot->wone_index = STATION_WONE_INDEX; | ||
290 | slot->slot_time = slot_time; | ||
291 | |||
292 | ret = wl1271_cmd_configure(wl, ACX_SLOT, slot, sizeof(*slot)); | ||
293 | if (ret < 0) { | ||
294 | wl1271_warning("failed to set slot time: %d", ret); | ||
295 | goto out; | ||
296 | } | ||
297 | |||
298 | out: | ||
299 | kfree(slot); | ||
300 | return ret; | ||
301 | } | ||
302 | |||
303 | int wl1271_acx_group_address_tbl(struct wl1271 *wl) | ||
304 | { | ||
305 | struct acx_dot11_grp_addr_tbl *acx; | ||
306 | int ret; | ||
307 | |||
308 | wl1271_debug(DEBUG_ACX, "acx group address tbl"); | ||
309 | |||
310 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
311 | if (!acx) { | ||
312 | ret = -ENOMEM; | ||
313 | goto out; | ||
314 | } | ||
315 | |||
316 | /* MAC filtering */ | ||
317 | acx->enabled = 0; | ||
318 | acx->num_groups = 0; | ||
319 | memset(acx->mac_table, 0, ADDRESS_GROUP_MAX_LEN); | ||
320 | |||
321 | ret = wl1271_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL, | ||
322 | acx, sizeof(*acx)); | ||
323 | if (ret < 0) { | ||
324 | wl1271_warning("failed to set group addr table: %d", ret); | ||
325 | goto out; | ||
326 | } | ||
327 | |||
328 | out: | ||
329 | kfree(acx); | ||
330 | return ret; | ||
331 | } | ||
332 | |||
333 | int wl1271_acx_service_period_timeout(struct wl1271 *wl) | ||
334 | { | ||
335 | struct acx_rx_timeout *rx_timeout; | ||
336 | int ret; | ||
337 | |||
338 | rx_timeout = kzalloc(sizeof(*rx_timeout), GFP_KERNEL); | ||
339 | if (!rx_timeout) { | ||
340 | ret = -ENOMEM; | ||
341 | goto out; | ||
342 | } | ||
343 | |||
344 | wl1271_debug(DEBUG_ACX, "acx service period timeout"); | ||
345 | |||
346 | rx_timeout->ps_poll_timeout = RX_TIMEOUT_PS_POLL_DEF; | ||
347 | rx_timeout->upsd_timeout = RX_TIMEOUT_UPSD_DEF; | ||
348 | |||
349 | ret = wl1271_cmd_configure(wl, ACX_SERVICE_PERIOD_TIMEOUT, | ||
350 | rx_timeout, sizeof(*rx_timeout)); | ||
351 | if (ret < 0) { | ||
352 | wl1271_warning("failed to set service period timeout: %d", | ||
353 | ret); | ||
354 | goto out; | ||
355 | } | ||
356 | |||
357 | out: | ||
358 | kfree(rx_timeout); | ||
359 | return ret; | ||
360 | } | ||
361 | |||
362 | int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold) | ||
363 | { | ||
364 | struct acx_rts_threshold *rts; | ||
365 | int ret; | ||
366 | |||
367 | wl1271_debug(DEBUG_ACX, "acx rts threshold"); | ||
368 | |||
369 | rts = kzalloc(sizeof(*rts), GFP_KERNEL); | ||
370 | if (!rts) { | ||
371 | ret = -ENOMEM; | ||
372 | goto out; | ||
373 | } | ||
374 | |||
375 | rts->threshold = rts_threshold; | ||
376 | |||
377 | ret = wl1271_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts)); | ||
378 | if (ret < 0) { | ||
379 | wl1271_warning("failed to set rts threshold: %d", ret); | ||
380 | goto out; | ||
381 | } | ||
382 | |||
383 | out: | ||
384 | kfree(rts); | ||
385 | return ret; | ||
386 | } | ||
387 | |||
388 | int wl1271_acx_beacon_filter_opt(struct wl1271 *wl) | ||
389 | { | ||
390 | struct acx_beacon_filter_option *beacon_filter; | ||
391 | int ret; | ||
392 | |||
393 | wl1271_debug(DEBUG_ACX, "acx beacon filter opt"); | ||
394 | |||
395 | beacon_filter = kzalloc(sizeof(*beacon_filter), GFP_KERNEL); | ||
396 | if (!beacon_filter) { | ||
397 | ret = -ENOMEM; | ||
398 | goto out; | ||
399 | } | ||
400 | |||
401 | beacon_filter->enable = 0; | ||
402 | beacon_filter->max_num_beacons = 0; | ||
403 | |||
404 | ret = wl1271_cmd_configure(wl, ACX_BEACON_FILTER_OPT, | ||
405 | beacon_filter, sizeof(*beacon_filter)); | ||
406 | if (ret < 0) { | ||
407 | wl1271_warning("failed to set beacon filter opt: %d", ret); | ||
408 | goto out; | ||
409 | } | ||
410 | |||
411 | out: | ||
412 | kfree(beacon_filter); | ||
413 | return ret; | ||
414 | } | ||
415 | |||
416 | int wl1271_acx_beacon_filter_table(struct wl1271 *wl) | ||
417 | { | ||
418 | struct acx_beacon_filter_ie_table *ie_table; | ||
419 | int ret; | ||
420 | |||
421 | wl1271_debug(DEBUG_ACX, "acx beacon filter table"); | ||
422 | |||
423 | ie_table = kzalloc(sizeof(*ie_table), GFP_KERNEL); | ||
424 | if (!ie_table) { | ||
425 | ret = -ENOMEM; | ||
426 | goto out; | ||
427 | } | ||
428 | |||
429 | ie_table->num_ie = 0; | ||
430 | memset(ie_table->table, 0, BEACON_FILTER_TABLE_MAX_SIZE); | ||
431 | |||
432 | ret = wl1271_cmd_configure(wl, ACX_BEACON_FILTER_TABLE, | ||
433 | ie_table, sizeof(*ie_table)); | ||
434 | if (ret < 0) { | ||
435 | wl1271_warning("failed to set beacon filter table: %d", ret); | ||
436 | goto out; | ||
437 | } | ||
438 | |||
439 | out: | ||
440 | kfree(ie_table); | ||
441 | return ret; | ||
442 | } | ||
443 | |||
444 | int wl1271_acx_sg_enable(struct wl1271 *wl) | ||
445 | { | ||
446 | struct acx_bt_wlan_coex *pta; | ||
447 | int ret; | ||
448 | |||
449 | wl1271_debug(DEBUG_ACX, "acx sg enable"); | ||
450 | |||
451 | pta = kzalloc(sizeof(*pta), GFP_KERNEL); | ||
452 | if (!pta) { | ||
453 | ret = -ENOMEM; | ||
454 | goto out; | ||
455 | } | ||
456 | |||
457 | pta->enable = SG_ENABLE; | ||
458 | |||
459 | ret = wl1271_cmd_configure(wl, ACX_SG_ENABLE, pta, sizeof(*pta)); | ||
460 | if (ret < 0) { | ||
461 | wl1271_warning("failed to set softgemini enable: %d", ret); | ||
462 | goto out; | ||
463 | } | ||
464 | |||
465 | out: | ||
466 | kfree(pta); | ||
467 | return ret; | ||
468 | } | ||
469 | |||
470 | int wl1271_acx_sg_cfg(struct wl1271 *wl) | ||
471 | { | ||
472 | struct acx_bt_wlan_coex_param *param; | ||
473 | int ret; | ||
474 | |||
475 | wl1271_debug(DEBUG_ACX, "acx sg cfg"); | ||
476 | |||
477 | param = kzalloc(sizeof(*param), GFP_KERNEL); | ||
478 | if (!param) { | ||
479 | ret = -ENOMEM; | ||
480 | goto out; | ||
481 | } | ||
482 | |||
483 | /* BT-WLAN coext parameters */ | ||
484 | param->min_rate = RATE_INDEX_24MBPS; | ||
485 | param->bt_hp_max_time = PTA_BT_HP_MAXTIME_DEF; | ||
486 | param->wlan_hp_max_time = PTA_WLAN_HP_MAX_TIME_DEF; | ||
487 | param->sense_disable_timer = PTA_SENSE_DISABLE_TIMER_DEF; | ||
488 | param->rx_time_bt_hp = PTA_PROTECTIVE_RX_TIME_DEF; | ||
489 | param->tx_time_bt_hp = PTA_PROTECTIVE_TX_TIME_DEF; | ||
490 | param->rx_time_bt_hp_fast = PTA_PROTECTIVE_RX_TIME_FAST_DEF; | ||
491 | param->tx_time_bt_hp_fast = PTA_PROTECTIVE_TX_TIME_FAST_DEF; | ||
492 | param->wlan_cycle_fast = PTA_CYCLE_TIME_FAST_DEF; | ||
493 | param->bt_anti_starvation_period = PTA_ANTI_STARVE_PERIOD_DEF; | ||
494 | param->next_bt_lp_packet = PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF; | ||
495 | param->wake_up_beacon = PTA_TIME_BEFORE_BEACON_DEF; | ||
496 | param->hp_dm_max_guard_time = PTA_HPDM_MAX_TIME_DEF; | ||
497 | param->next_wlan_packet = PTA_TIME_OUT_NEXT_WLAN_DEF; | ||
498 | param->antenna_type = PTA_ANTENNA_TYPE_DEF; | ||
499 | param->signal_type = PTA_SIGNALING_TYPE_DEF; | ||
500 | param->afh_leverage_on = PTA_AFH_LEVERAGE_ON_DEF; | ||
501 | param->quiet_cycle_num = PTA_NUMBER_QUIET_CYCLE_DEF; | ||
502 | param->max_cts = PTA_MAX_NUM_CTS_DEF; | ||
503 | param->wlan_packets_num = PTA_NUMBER_OF_WLAN_PACKETS_DEF; | ||
504 | param->bt_packets_num = PTA_NUMBER_OF_BT_PACKETS_DEF; | ||
505 | param->missed_rx_avalanche = PTA_RX_FOR_AVALANCHE_DEF; | ||
506 | param->wlan_elp_hp = PTA_ELP_HP_DEF; | ||
507 | param->bt_anti_starvation_cycles = PTA_ANTI_STARVE_NUM_CYCLE_DEF; | ||
508 | param->ack_mode_dual_ant = PTA_ACK_MODE_DEF; | ||
509 | param->pa_sd_enable = PTA_ALLOW_PA_SD_DEF; | ||
510 | param->pta_auto_mode_enable = PTA_AUTO_MODE_NO_CTS_DEF; | ||
511 | param->bt_hp_respected_num = PTA_BT_HP_RESPECTED_DEF; | ||
512 | |||
513 | ret = wl1271_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param)); | ||
514 | if (ret < 0) { | ||
515 | wl1271_warning("failed to set sg config: %d", ret); | ||
516 | goto out; | ||
517 | } | ||
518 | |||
519 | out: | ||
520 | kfree(param); | ||
521 | return ret; | ||
522 | } | ||
523 | |||
524 | int wl1271_acx_cca_threshold(struct wl1271 *wl) | ||
525 | { | ||
526 | struct acx_energy_detection *detection; | ||
527 | int ret; | ||
528 | |||
529 | wl1271_debug(DEBUG_ACX, "acx cca threshold"); | ||
530 | |||
531 | detection = kzalloc(sizeof(*detection), GFP_KERNEL); | ||
532 | if (!detection) { | ||
533 | ret = -ENOMEM; | ||
534 | goto out; | ||
535 | } | ||
536 | |||
537 | detection->rx_cca_threshold = CCA_THRSH_DISABLE_ENERGY_D; | ||
538 | detection->tx_energy_detection = 0; | ||
539 | |||
540 | ret = wl1271_cmd_configure(wl, ACX_CCA_THRESHOLD, | ||
541 | detection, sizeof(*detection)); | ||
542 | if (ret < 0) { | ||
543 | wl1271_warning("failed to set cca threshold: %d", ret); | ||
544 | return ret; | ||
545 | } | ||
546 | |||
547 | out: | ||
548 | kfree(detection); | ||
549 | return ret; | ||
550 | } | ||
551 | |||
552 | int wl1271_acx_bcn_dtim_options(struct wl1271 *wl) | ||
553 | { | ||
554 | struct acx_beacon_broadcast *bb; | ||
555 | int ret; | ||
556 | |||
557 | wl1271_debug(DEBUG_ACX, "acx bcn dtim options"); | ||
558 | |||
559 | bb = kzalloc(sizeof(*bb), GFP_KERNEL); | ||
560 | if (!bb) { | ||
561 | ret = -ENOMEM; | ||
562 | goto out; | ||
563 | } | ||
564 | |||
565 | bb->beacon_rx_timeout = BCN_RX_TIMEOUT_DEF_VALUE; | ||
566 | bb->broadcast_timeout = BROADCAST_RX_TIMEOUT_DEF_VALUE; | ||
567 | bb->rx_broadcast_in_ps = RX_BROADCAST_IN_PS_DEF_VALUE; | ||
568 | bb->ps_poll_threshold = CONSECUTIVE_PS_POLL_FAILURE_DEF; | ||
569 | |||
570 | ret = wl1271_cmd_configure(wl, ACX_BCN_DTIM_OPTIONS, bb, sizeof(*bb)); | ||
571 | if (ret < 0) { | ||
572 | wl1271_warning("failed to set rx config: %d", ret); | ||
573 | goto out; | ||
574 | } | ||
575 | |||
576 | out: | ||
577 | kfree(bb); | ||
578 | return ret; | ||
579 | } | ||
580 | |||
581 | int wl1271_acx_aid(struct wl1271 *wl, u16 aid) | ||
582 | { | ||
583 | struct acx_aid *acx_aid; | ||
584 | int ret; | ||
585 | |||
586 | wl1271_debug(DEBUG_ACX, "acx aid"); | ||
587 | |||
588 | acx_aid = kzalloc(sizeof(*acx_aid), GFP_KERNEL); | ||
589 | if (!acx_aid) { | ||
590 | ret = -ENOMEM; | ||
591 | goto out; | ||
592 | } | ||
593 | |||
594 | acx_aid->aid = aid; | ||
595 | |||
596 | ret = wl1271_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid)); | ||
597 | if (ret < 0) { | ||
598 | wl1271_warning("failed to set aid: %d", ret); | ||
599 | goto out; | ||
600 | } | ||
601 | |||
602 | out: | ||
603 | kfree(acx_aid); | ||
604 | return ret; | ||
605 | } | ||
606 | |||
607 | int wl1271_acx_event_mbox_mask(struct wl1271 *wl, u32 event_mask) | ||
608 | { | ||
609 | struct acx_event_mask *mask; | ||
610 | int ret; | ||
611 | |||
612 | wl1271_debug(DEBUG_ACX, "acx event mbox mask"); | ||
613 | |||
614 | mask = kzalloc(sizeof(*mask), GFP_KERNEL); | ||
615 | if (!mask) { | ||
616 | ret = -ENOMEM; | ||
617 | goto out; | ||
618 | } | ||
619 | |||
620 | /* high event mask is unused */ | ||
621 | mask->high_event_mask = 0xffffffff; | ||
622 | |||
623 | mask->event_mask = event_mask; | ||
624 | |||
625 | ret = wl1271_cmd_configure(wl, ACX_EVENT_MBOX_MASK, | ||
626 | mask, sizeof(*mask)); | ||
627 | if (ret < 0) { | ||
628 | wl1271_warning("failed to set acx_event_mbox_mask: %d", ret); | ||
629 | goto out; | ||
630 | } | ||
631 | |||
632 | out: | ||
633 | kfree(mask); | ||
634 | return ret; | ||
635 | } | ||
636 | |||
637 | int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble) | ||
638 | { | ||
639 | struct acx_preamble *acx; | ||
640 | int ret; | ||
641 | |||
642 | wl1271_debug(DEBUG_ACX, "acx_set_preamble"); | ||
643 | |||
644 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
645 | if (!acx) { | ||
646 | ret = -ENOMEM; | ||
647 | goto out; | ||
648 | } | ||
649 | |||
650 | acx->preamble = preamble; | ||
651 | |||
652 | ret = wl1271_cmd_configure(wl, ACX_PREAMBLE_TYPE, acx, sizeof(*acx)); | ||
653 | if (ret < 0) { | ||
654 | wl1271_warning("Setting of preamble failed: %d", ret); | ||
655 | goto out; | ||
656 | } | ||
657 | |||
658 | out: | ||
659 | kfree(acx); | ||
660 | return ret; | ||
661 | } | ||
662 | |||
663 | int wl1271_acx_cts_protect(struct wl1271 *wl, | ||
664 | enum acx_ctsprotect_type ctsprotect) | ||
665 | { | ||
666 | struct acx_ctsprotect *acx; | ||
667 | int ret; | ||
668 | |||
669 | wl1271_debug(DEBUG_ACX, "acx_set_ctsprotect"); | ||
670 | |||
671 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
672 | if (!acx) { | ||
673 | ret = -ENOMEM; | ||
674 | goto out; | ||
675 | } | ||
676 | |||
677 | acx->ctsprotect = ctsprotect; | ||
678 | |||
679 | ret = wl1271_cmd_configure(wl, ACX_CTS_PROTECTION, acx, sizeof(*acx)); | ||
680 | if (ret < 0) { | ||
681 | wl1271_warning("Setting of ctsprotect failed: %d", ret); | ||
682 | goto out; | ||
683 | } | ||
684 | |||
685 | out: | ||
686 | kfree(acx); | ||
687 | return ret; | ||
688 | } | ||
689 | |||
690 | int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats) | ||
691 | { | ||
692 | int ret; | ||
693 | |||
694 | wl1271_debug(DEBUG_ACX, "acx statistics"); | ||
695 | |||
696 | ret = wl1271_cmd_interrogate(wl, ACX_STATISTICS, stats, | ||
697 | sizeof(*stats)); | ||
698 | if (ret < 0) { | ||
699 | wl1271_warning("acx statistics failed: %d", ret); | ||
700 | return -ENOMEM; | ||
701 | } | ||
702 | |||
703 | return 0; | ||
704 | } | ||
705 | |||
706 | int wl1271_acx_rate_policies(struct wl1271 *wl) | ||
707 | { | ||
708 | struct acx_rate_policy *acx; | ||
709 | int ret = 0; | ||
710 | |||
711 | wl1271_debug(DEBUG_ACX, "acx rate policies"); | ||
712 | |||
713 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
714 | |||
715 | if (!acx) { | ||
716 | ret = -ENOMEM; | ||
717 | goto out; | ||
718 | } | ||
719 | |||
720 | /* configure one default (one-size-fits-all) rate class */ | ||
721 | acx->rate_class_cnt = 1; | ||
722 | acx->rate_class[0].enabled_rates = ACX_RATE_MASK_ALL; | ||
723 | acx->rate_class[0].short_retry_limit = ACX_RATE_RETRY_LIMIT; | ||
724 | acx->rate_class[0].long_retry_limit = ACX_RATE_RETRY_LIMIT; | ||
725 | acx->rate_class[0].aflags = 0; | ||
726 | |||
727 | ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); | ||
728 | if (ret < 0) { | ||
729 | wl1271_warning("Setting of rate policies failed: %d", ret); | ||
730 | goto out; | ||
731 | } | ||
732 | |||
733 | out: | ||
734 | kfree(acx); | ||
735 | return ret; | ||
736 | } | ||
737 | |||
738 | int wl1271_acx_ac_cfg(struct wl1271 *wl) | ||
739 | { | ||
740 | struct acx_ac_cfg *acx; | ||
741 | int i, ret = 0; | ||
742 | |||
743 | wl1271_debug(DEBUG_ACX, "acx access category config"); | ||
744 | |||
745 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
746 | |||
747 | if (!acx) { | ||
748 | ret = -ENOMEM; | ||
749 | goto out; | ||
750 | } | ||
751 | |||
752 | /* | ||
753 | * FIXME: Configure each AC with appropriate values (most suitable | ||
754 | * values will probably be different for each AC. | ||
755 | */ | ||
756 | for (i = 0; i < WL1271_ACX_AC_COUNT; i++) { | ||
757 | acx->ac = i; | ||
758 | |||
759 | /* | ||
760 | * FIXME: The following default values originate from | ||
761 | * the TI reference driver. What do they mean? | ||
762 | */ | ||
763 | acx->cw_min = 15; | ||
764 | acx->cw_max = 63; | ||
765 | acx->aifsn = 3; | ||
766 | acx->reserved = 0; | ||
767 | acx->tx_op_limit = 0; | ||
768 | |||
769 | ret = wl1271_cmd_configure(wl, ACX_AC_CFG, acx, sizeof(*acx)); | ||
770 | if (ret < 0) { | ||
771 | wl1271_warning("Setting of access category " | ||
772 | "config: %d", ret); | ||
773 | goto out; | ||
774 | } | ||
775 | } | ||
776 | |||
777 | out: | ||
778 | kfree(acx); | ||
779 | return ret; | ||
780 | } | ||
781 | |||
782 | int wl1271_acx_tid_cfg(struct wl1271 *wl) | ||
783 | { | ||
784 | struct acx_tid_config *acx; | ||
785 | int i, ret = 0; | ||
786 | |||
787 | wl1271_debug(DEBUG_ACX, "acx tid config"); | ||
788 | |||
789 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
790 | |||
791 | if (!acx) { | ||
792 | ret = -ENOMEM; | ||
793 | goto out; | ||
794 | } | ||
795 | |||
796 | /* FIXME: configure each TID with a different AC reference */ | ||
797 | for (i = 0; i < WL1271_ACX_TID_COUNT; i++) { | ||
798 | acx->queue_id = i; | ||
799 | acx->tsid = WL1271_ACX_AC_BE; | ||
800 | acx->ps_scheme = WL1271_ACX_PS_SCHEME_LEGACY; | ||
801 | acx->ack_policy = WL1271_ACX_ACK_POLICY_LEGACY; | ||
802 | |||
803 | ret = wl1271_cmd_configure(wl, ACX_TID_CFG, acx, sizeof(*acx)); | ||
804 | if (ret < 0) { | ||
805 | wl1271_warning("Setting of tid config failed: %d", ret); | ||
806 | goto out; | ||
807 | } | ||
808 | } | ||
809 | |||
810 | out: | ||
811 | kfree(acx); | ||
812 | return ret; | ||
813 | } | ||
814 | |||
815 | int wl1271_acx_frag_threshold(struct wl1271 *wl) | ||
816 | { | ||
817 | struct acx_frag_threshold *acx; | ||
818 | int ret = 0; | ||
819 | |||
820 | wl1271_debug(DEBUG_ACX, "acx frag threshold"); | ||
821 | |||
822 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
823 | |||
824 | if (!acx) { | ||
825 | ret = -ENOMEM; | ||
826 | goto out; | ||
827 | } | ||
828 | |||
829 | acx->frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD; | ||
830 | ret = wl1271_cmd_configure(wl, ACX_FRAG_CFG, acx, sizeof(*acx)); | ||
831 | if (ret < 0) { | ||
832 | wl1271_warning("Setting of frag threshold failed: %d", ret); | ||
833 | goto out; | ||
834 | } | ||
835 | |||
836 | out: | ||
837 | kfree(acx); | ||
838 | return ret; | ||
839 | } | ||
840 | |||
841 | int wl1271_acx_tx_config_options(struct wl1271 *wl) | ||
842 | { | ||
843 | struct acx_tx_config_options *acx; | ||
844 | int ret = 0; | ||
845 | |||
846 | wl1271_debug(DEBUG_ACX, "acx tx config options"); | ||
847 | |||
848 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
849 | |||
850 | if (!acx) { | ||
851 | ret = -ENOMEM; | ||
852 | goto out; | ||
853 | } | ||
854 | |||
855 | acx->tx_compl_timeout = WL1271_ACX_TX_COMPL_TIMEOUT; | ||
856 | acx->tx_compl_threshold = WL1271_ACX_TX_COMPL_THRESHOLD; | ||
857 | ret = wl1271_cmd_configure(wl, ACX_TX_CONFIG_OPT, acx, sizeof(*acx)); | ||
858 | if (ret < 0) { | ||
859 | wl1271_warning("Setting of tx options failed: %d", ret); | ||
860 | goto out; | ||
861 | } | ||
862 | |||
863 | out: | ||
864 | kfree(acx); | ||
865 | return ret; | ||
866 | } | ||
867 | |||
868 | int wl1271_acx_mem_cfg(struct wl1271 *wl) | ||
869 | { | ||
870 | struct wl1271_acx_config_memory *mem_conf; | ||
871 | int ret; | ||
872 | |||
873 | wl1271_debug(DEBUG_ACX, "wl1271 mem cfg"); | ||
874 | |||
875 | mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL); | ||
876 | if (!mem_conf) { | ||
877 | ret = -ENOMEM; | ||
878 | goto out; | ||
879 | } | ||
880 | |||
881 | /* memory config */ | ||
882 | mem_conf->num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS); | ||
883 | mem_conf->rx_mem_block_num = ACX_RX_MEM_BLOCKS; | ||
884 | mem_conf->tx_min_mem_block_num = ACX_TX_MIN_MEM_BLOCKS; | ||
885 | mem_conf->num_ssid_profiles = ACX_NUM_SSID_PROFILES; | ||
886 | mem_conf->total_tx_descriptors = ACX_TX_DESCRIPTORS; | ||
887 | |||
888 | ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf, | ||
889 | sizeof(*mem_conf)); | ||
890 | if (ret < 0) { | ||
891 | wl1271_warning("wl1271 mem config failed: %d", ret); | ||
892 | goto out; | ||
893 | } | ||
894 | |||
895 | out: | ||
896 | kfree(mem_conf); | ||
897 | return ret; | ||
898 | } | ||
899 | |||
900 | int wl1271_acx_init_mem_config(struct wl1271 *wl) | ||
901 | { | ||
902 | int ret; | ||
903 | |||
904 | ret = wl1271_acx_mem_cfg(wl); | ||
905 | if (ret < 0) | ||
906 | return ret; | ||
907 | |||
908 | wl->target_mem_map = kzalloc(sizeof(struct wl1271_acx_mem_map), | ||
909 | GFP_KERNEL); | ||
910 | if (!wl->target_mem_map) { | ||
911 | wl1271_error("couldn't allocate target memory map"); | ||
912 | return -ENOMEM; | ||
913 | } | ||
914 | |||
915 | /* we now ask for the firmware built memory map */ | ||
916 | ret = wl1271_acx_mem_map(wl, (void *)wl->target_mem_map, | ||
917 | sizeof(struct wl1271_acx_mem_map)); | ||
918 | if (ret < 0) { | ||
919 | wl1271_error("couldn't retrieve firmware memory map"); | ||
920 | kfree(wl->target_mem_map); | ||
921 | wl->target_mem_map = NULL; | ||
922 | return ret; | ||
923 | } | ||
924 | |||
925 | /* initialize TX block book keeping */ | ||
926 | wl->tx_blocks_available = wl->target_mem_map->num_tx_mem_blocks; | ||
927 | wl1271_debug(DEBUG_TX, "available tx blocks: %d", | ||
928 | wl->tx_blocks_available); | ||
929 | |||
930 | return 0; | ||
931 | } | ||
932 | |||
933 | int wl1271_acx_init_rx_interrupt(struct wl1271 *wl) | ||
934 | { | ||
935 | struct wl1271_acx_rx_config_opt *rx_conf; | ||
936 | int ret; | ||
937 | |||
938 | wl1271_debug(DEBUG_ACX, "wl1271 rx interrupt config"); | ||
939 | |||
940 | rx_conf = kzalloc(sizeof(*rx_conf), GFP_KERNEL); | ||
941 | if (!rx_conf) { | ||
942 | ret = -ENOMEM; | ||
943 | goto out; | ||
944 | } | ||
945 | |||
946 | rx_conf->threshold = WL1271_RX_INTR_THRESHOLD_DEF; | ||
947 | rx_conf->timeout = WL1271_RX_INTR_TIMEOUT_DEF; | ||
948 | rx_conf->mblk_threshold = USHORT_MAX; /* Disabled */ | ||
949 | rx_conf->queue_type = RX_QUEUE_TYPE_RX_LOW_PRIORITY; | ||
950 | |||
951 | ret = wl1271_cmd_configure(wl, ACX_RX_CONFIG_OPT, rx_conf, | ||
952 | sizeof(*rx_conf)); | ||
953 | if (ret < 0) { | ||
954 | wl1271_warning("wl1271 rx config opt failed: %d", ret); | ||
955 | goto out; | ||
956 | } | ||
957 | |||
958 | out: | ||
959 | kfree(rx_conf); | ||
960 | return ret; | ||
961 | } | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h new file mode 100644 index 000000000000..9068daaf0ddf --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_acx.h | |||
@@ -0,0 +1,1221 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. | ||
5 | * Copyright (C) 2008-2009 Nokia Corporation | ||
6 | * | ||
7 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef __WL1271_ACX_H__ | ||
26 | #define __WL1271_ACX_H__ | ||
27 | |||
28 | #include "wl1271.h" | ||
29 | #include "wl1271_cmd.h" | ||
30 | |||
31 | /************************************************************************* | ||
32 | |||
33 | Host Interrupt Register (WiLink -> Host) | ||
34 | |||
35 | **************************************************************************/ | ||
36 | /* HW Initiated interrupt Watchdog timer expiration */ | ||
37 | #define WL1271_ACX_INTR_WATCHDOG BIT(0) | ||
38 | /* Init sequence is done (masked interrupt, detection through polling only ) */ | ||
39 | #define WL1271_ACX_INTR_INIT_COMPLETE BIT(1) | ||
40 | /* Event was entered to Event MBOX #A*/ | ||
41 | #define WL1271_ACX_INTR_EVENT_A BIT(2) | ||
42 | /* Event was entered to Event MBOX #B*/ | ||
43 | #define WL1271_ACX_INTR_EVENT_B BIT(3) | ||
44 | /* Command processing completion*/ | ||
45 | #define WL1271_ACX_INTR_CMD_COMPLETE BIT(4) | ||
46 | /* Signaling the host on HW wakeup */ | ||
47 | #define WL1271_ACX_INTR_HW_AVAILABLE BIT(5) | ||
48 | /* The MISC bit is used for aggregation of RX, TxComplete and TX rate update */ | ||
49 | #define WL1271_ACX_INTR_DATA BIT(6) | ||
50 | /* Trace meassge on MBOX #A */ | ||
51 | #define WL1271_ACX_INTR_TRACE_A BIT(7) | ||
52 | /* Trace meassge on MBOX #B */ | ||
53 | #define WL1271_ACX_INTR_TRACE_B BIT(8) | ||
54 | |||
55 | #define WL1271_ACX_INTR_ALL 0xFFFFFFFF | ||
56 | #define WL1271_ACX_ALL_EVENTS_VECTOR (WL1271_ACX_INTR_WATCHDOG | \ | ||
57 | WL1271_ACX_INTR_INIT_COMPLETE | \ | ||
58 | WL1271_ACX_INTR_EVENT_A | \ | ||
59 | WL1271_ACX_INTR_EVENT_B | \ | ||
60 | WL1271_ACX_INTR_CMD_COMPLETE | \ | ||
61 | WL1271_ACX_INTR_HW_AVAILABLE | \ | ||
62 | WL1271_ACX_INTR_DATA) | ||
63 | |||
64 | #define WL1271_INTR_MASK (WL1271_ACX_INTR_EVENT_A | \ | ||
65 | WL1271_ACX_INTR_EVENT_B | \ | ||
66 | WL1271_ACX_INTR_DATA) | ||
67 | |||
68 | /* Target's information element */ | ||
69 | struct acx_header { | ||
70 | struct wl1271_cmd_header cmd; | ||
71 | |||
72 | /* acx (or information element) header */ | ||
73 | u16 id; | ||
74 | |||
75 | /* payload length (not including headers */ | ||
76 | u16 len; | ||
77 | }; | ||
78 | |||
79 | struct acx_error_counter { | ||
80 | struct acx_header header; | ||
81 | |||
82 | /* The number of PLCP errors since the last time this */ | ||
83 | /* information element was interrogated. This field is */ | ||
84 | /* automatically cleared when it is interrogated.*/ | ||
85 | u32 PLCP_error; | ||
86 | |||
87 | /* The number of FCS errors since the last time this */ | ||
88 | /* information element was interrogated. This field is */ | ||
89 | /* automatically cleared when it is interrogated.*/ | ||
90 | u32 FCS_error; | ||
91 | |||
92 | /* The number of MPDUs without PLCP header errors received*/ | ||
93 | /* since the last time this information element was interrogated. */ | ||
94 | /* This field is automatically cleared when it is interrogated.*/ | ||
95 | u32 valid_frame; | ||
96 | |||
97 | /* the number of missed sequence numbers in the squentially */ | ||
98 | /* values of frames seq numbers */ | ||
99 | u32 seq_num_miss; | ||
100 | } __attribute__ ((packed)); | ||
101 | |||
102 | struct acx_revision { | ||
103 | struct acx_header header; | ||
104 | |||
105 | /* | ||
106 | * The WiLink firmware version, an ASCII string x.x.x.x, | ||
107 | * that uniquely identifies the current firmware. | ||
108 | * The left most digit is incremented each time a | ||
109 | * significant change is made to the firmware, such as | ||
110 | * code redesign or new platform support. | ||
111 | * The second digit is incremented when major enhancements | ||
112 | * are added or major fixes are made. | ||
113 | * The third digit is incremented for each GA release. | ||
114 | * The fourth digit is incremented for each build. | ||
115 | * The first two digits identify a firmware release version, | ||
116 | * in other words, a unique set of features. | ||
117 | * The first three digits identify a GA release. | ||
118 | */ | ||
119 | char fw_version[20]; | ||
120 | |||
121 | /* | ||
122 | * This 4 byte field specifies the WiLink hardware version. | ||
123 | * bits 0 - 15: Reserved. | ||
124 | * bits 16 - 23: Version ID - The WiLink version ID | ||
125 | * (1 = first spin, 2 = second spin, and so on). | ||
126 | * bits 24 - 31: Chip ID - The WiLink chip ID. | ||
127 | */ | ||
128 | u32 hw_version; | ||
129 | } __attribute__ ((packed)); | ||
130 | |||
131 | enum wl1271_psm_mode { | ||
132 | /* Active mode */ | ||
133 | WL1271_PSM_CAM = 0, | ||
134 | |||
135 | /* Power save mode */ | ||
136 | WL1271_PSM_PS = 1, | ||
137 | |||
138 | /* Extreme low power */ | ||
139 | WL1271_PSM_ELP = 2, | ||
140 | }; | ||
141 | |||
142 | struct acx_sleep_auth { | ||
143 | struct acx_header header; | ||
144 | |||
145 | /* The sleep level authorization of the device. */ | ||
146 | /* 0 - Always active*/ | ||
147 | /* 1 - Power down mode: light / fast sleep*/ | ||
148 | /* 2 - ELP mode: Deep / Max sleep*/ | ||
149 | u8 sleep_auth; | ||
150 | u8 padding[3]; | ||
151 | } __attribute__ ((packed)); | ||
152 | |||
153 | enum { | ||
154 | HOSTIF_PCI_MASTER_HOST_INDIRECT, | ||
155 | HOSTIF_PCI_MASTER_HOST_DIRECT, | ||
156 | HOSTIF_SLAVE, | ||
157 | HOSTIF_PKT_RING, | ||
158 | HOSTIF_DONTCARE = 0xFF | ||
159 | }; | ||
160 | |||
161 | #define DEFAULT_UCAST_PRIORITY 0 | ||
162 | #define DEFAULT_RX_Q_PRIORITY 0 | ||
163 | #define DEFAULT_NUM_STATIONS 1 | ||
164 | #define DEFAULT_RXQ_PRIORITY 0 /* low 0 .. 15 high */ | ||
165 | #define DEFAULT_RXQ_TYPE 0x07 /* All frames, Data/Ctrl/Mgmt */ | ||
166 | #define TRACE_BUFFER_MAX_SIZE 256 | ||
167 | |||
168 | #define DP_RX_PACKET_RING_CHUNK_SIZE 1600 | ||
169 | #define DP_TX_PACKET_RING_CHUNK_SIZE 1600 | ||
170 | #define DP_RX_PACKET_RING_CHUNK_NUM 2 | ||
171 | #define DP_TX_PACKET_RING_CHUNK_NUM 2 | ||
172 | #define DP_TX_COMPLETE_TIME_OUT 20 | ||
173 | #define FW_TX_CMPLT_BLOCK_SIZE 16 | ||
174 | |||
175 | #define TX_MSDU_LIFETIME_MIN 0 | ||
176 | #define TX_MSDU_LIFETIME_MAX 3000 | ||
177 | #define TX_MSDU_LIFETIME_DEF 512 | ||
178 | #define RX_MSDU_LIFETIME_MIN 0 | ||
179 | #define RX_MSDU_LIFETIME_MAX 0xFFFFFFFF | ||
180 | #define RX_MSDU_LIFETIME_DEF 512000 | ||
181 | |||
182 | struct acx_rx_msdu_lifetime { | ||
183 | struct acx_header header; | ||
184 | |||
185 | /* | ||
186 | * The maximum amount of time, in TU, before the | ||
187 | * firmware discards the MSDU. | ||
188 | */ | ||
189 | u32 lifetime; | ||
190 | } __attribute__ ((packed)); | ||
191 | |||
192 | /* | ||
193 | * RX Config Options Table | ||
194 | * Bit Definition | ||
195 | * === ========== | ||
196 | * 31:14 Reserved | ||
197 | * 13 Copy RX Status - when set, write three receive status words | ||
198 | * to top of rx'd MPDUs. | ||
199 | * When cleared, do not write three status words (added rev 1.5) | ||
200 | * 12 Reserved | ||
201 | * 11 RX Complete upon FCS error - when set, give rx complete | ||
202 | * interrupt for FCS errors, after the rx filtering, e.g. unicast | ||
203 | * frames not to us with FCS error will not generate an interrupt. | ||
204 | * 10 SSID Filter Enable - When set, the WiLink discards all beacon, | ||
205 | * probe request, and probe response frames with an SSID that does | ||
206 | * not match the SSID specified by the host in the START/JOIN | ||
207 | * command. | ||
208 | * When clear, the WiLink receives frames with any SSID. | ||
209 | * 9 Broadcast Filter Enable - When set, the WiLink discards all | ||
210 | * broadcast frames. When clear, the WiLink receives all received | ||
211 | * broadcast frames. | ||
212 | * 8:6 Reserved | ||
213 | * 5 BSSID Filter Enable - When set, the WiLink discards any frames | ||
214 | * with a BSSID that does not match the BSSID specified by the | ||
215 | * host. | ||
216 | * When clear, the WiLink receives frames from any BSSID. | ||
217 | * 4 MAC Addr Filter - When set, the WiLink discards any frames | ||
218 | * with a destination address that does not match the MAC address | ||
219 | * of the adaptor. | ||
220 | * When clear, the WiLink receives frames destined to any MAC | ||
221 | * address. | ||
222 | * 3 Promiscuous - When set, the WiLink receives all valid frames | ||
223 | * (i.e., all frames that pass the FCS check). | ||
224 | * When clear, only frames that pass the other filters specified | ||
225 | * are received. | ||
226 | * 2 FCS - When set, the WiLink includes the FCS with the received | ||
227 | * frame. | ||
228 | * When cleared, the FCS is discarded. | ||
229 | * 1 PLCP header - When set, write all data from baseband to frame | ||
230 | * buffer including PHY header. | ||
231 | * 0 Reserved - Always equal to 0. | ||
232 | * | ||
233 | * RX Filter Options Table | ||
234 | * Bit Definition | ||
235 | * === ========== | ||
236 | * 31:12 Reserved - Always equal to 0. | ||
237 | * 11 Association - When set, the WiLink receives all association | ||
238 | * related frames (association request/response, reassocation | ||
239 | * request/response, and disassociation). When clear, these frames | ||
240 | * are discarded. | ||
241 | * 10 Auth/De auth - When set, the WiLink receives all authentication | ||
242 | * and de-authentication frames. When clear, these frames are | ||
243 | * discarded. | ||
244 | * 9 Beacon - When set, the WiLink receives all beacon frames. | ||
245 | * When clear, these frames are discarded. | ||
246 | * 8 Contention Free - When set, the WiLink receives all contention | ||
247 | * free frames. | ||
248 | * When clear, these frames are discarded. | ||
249 | * 7 Control - When set, the WiLink receives all control frames. | ||
250 | * When clear, these frames are discarded. | ||
251 | * 6 Data - When set, the WiLink receives all data frames. | ||
252 | * When clear, these frames are discarded. | ||
253 | * 5 FCS Error - When set, the WiLink receives frames that have FCS | ||
254 | * errors. | ||
255 | * When clear, these frames are discarded. | ||
256 | * 4 Management - When set, the WiLink receives all management | ||
257 | * frames. | ||
258 | * When clear, these frames are discarded. | ||
259 | * 3 Probe Request - When set, the WiLink receives all probe request | ||
260 | * frames. | ||
261 | * When clear, these frames are discarded. | ||
262 | * 2 Probe Response - When set, the WiLink receives all probe | ||
263 | * response frames. | ||
264 | * When clear, these frames are discarded. | ||
265 | * 1 RTS/CTS/ACK - When set, the WiLink receives all RTS, CTS and ACK | ||
266 | * frames. | ||
267 | * When clear, these frames are discarded. | ||
268 | * 0 Rsvd Type/Sub Type - When set, the WiLink receives all frames | ||
269 | * that have reserved frame types and sub types as defined by the | ||
270 | * 802.11 specification. | ||
271 | * When clear, these frames are discarded. | ||
272 | */ | ||
273 | struct acx_rx_config { | ||
274 | struct acx_header header; | ||
275 | |||
276 | u32 config_options; | ||
277 | u32 filter_options; | ||
278 | } __attribute__ ((packed)); | ||
279 | |||
280 | struct acx_packet_detection { | ||
281 | struct acx_header header; | ||
282 | |||
283 | u32 threshold; | ||
284 | } __attribute__ ((packed)); | ||
285 | |||
286 | |||
287 | enum acx_slot_type { | ||
288 | SLOT_TIME_LONG = 0, | ||
289 | SLOT_TIME_SHORT = 1, | ||
290 | DEFAULT_SLOT_TIME = SLOT_TIME_SHORT, | ||
291 | MAX_SLOT_TIMES = 0xFF | ||
292 | }; | ||
293 | |||
294 | #define STATION_WONE_INDEX 0 | ||
295 | |||
296 | struct acx_slot { | ||
297 | struct acx_header header; | ||
298 | |||
299 | u8 wone_index; /* Reserved */ | ||
300 | u8 slot_time; | ||
301 | u8 reserved[6]; | ||
302 | } __attribute__ ((packed)); | ||
303 | |||
304 | |||
305 | #define ADDRESS_GROUP_MAX (8) | ||
306 | #define ADDRESS_GROUP_MAX_LEN (ETH_ALEN * ADDRESS_GROUP_MAX) | ||
307 | |||
308 | struct acx_dot11_grp_addr_tbl { | ||
309 | struct acx_header header; | ||
310 | |||
311 | u8 enabled; | ||
312 | u8 num_groups; | ||
313 | u8 pad[2]; | ||
314 | u8 mac_table[ADDRESS_GROUP_MAX_LEN]; | ||
315 | } __attribute__ ((packed)); | ||
316 | |||
317 | |||
318 | #define RX_TIMEOUT_PS_POLL_MIN 0 | ||
319 | #define RX_TIMEOUT_PS_POLL_MAX (200000) | ||
320 | #define RX_TIMEOUT_PS_POLL_DEF (15) | ||
321 | #define RX_TIMEOUT_UPSD_MIN 0 | ||
322 | #define RX_TIMEOUT_UPSD_MAX (200000) | ||
323 | #define RX_TIMEOUT_UPSD_DEF (15) | ||
324 | |||
325 | struct acx_rx_timeout { | ||
326 | struct acx_header header; | ||
327 | |||
328 | /* | ||
329 | * The longest time the STA will wait to receive | ||
330 | * traffic from the AP after a PS-poll has been | ||
331 | * transmitted. | ||
332 | */ | ||
333 | u16 ps_poll_timeout; | ||
334 | |||
335 | /* | ||
336 | * The longest time the STA will wait to receive | ||
337 | * traffic from the AP after a frame has been sent | ||
338 | * from an UPSD enabled queue. | ||
339 | */ | ||
340 | u16 upsd_timeout; | ||
341 | } __attribute__ ((packed)); | ||
342 | |||
343 | #define RTS_THRESHOLD_MIN 0 | ||
344 | #define RTS_THRESHOLD_MAX 4096 | ||
345 | #define RTS_THRESHOLD_DEF 2347 | ||
346 | |||
347 | struct acx_rts_threshold { | ||
348 | struct acx_header header; | ||
349 | |||
350 | u16 threshold; | ||
351 | u8 pad[2]; | ||
352 | } __attribute__ ((packed)); | ||
353 | |||
354 | struct acx_beacon_filter_option { | ||
355 | struct acx_header header; | ||
356 | |||
357 | u8 enable; | ||
358 | |||
359 | /* | ||
360 | * The number of beacons without the unicast TIM | ||
361 | * bit set that the firmware buffers before | ||
362 | * signaling the host about ready frames. | ||
363 | * When set to 0 and the filter is enabled, beacons | ||
364 | * without the unicast TIM bit set are dropped. | ||
365 | */ | ||
366 | u8 max_num_beacons; | ||
367 | u8 pad[2]; | ||
368 | } __attribute__ ((packed)); | ||
369 | |||
370 | /* | ||
371 | * ACXBeaconFilterEntry (not 221) | ||
372 | * Byte Offset Size (Bytes) Definition | ||
373 | * =========== ============ ========== | ||
374 | * 0 1 IE identifier | ||
375 | * 1 1 Treatment bit mask | ||
376 | * | ||
377 | * ACXBeaconFilterEntry (221) | ||
378 | * Byte Offset Size (Bytes) Definition | ||
379 | * =========== ============ ========== | ||
380 | * 0 1 IE identifier | ||
381 | * 1 1 Treatment bit mask | ||
382 | * 2 3 OUI | ||
383 | * 5 1 Type | ||
384 | * 6 2 Version | ||
385 | * | ||
386 | * | ||
387 | * Treatment bit mask - The information element handling: | ||
388 | * bit 0 - The information element is compared and transferred | ||
389 | * in case of change. | ||
390 | * bit 1 - The information element is transferred to the host | ||
391 | * with each appearance or disappearance. | ||
392 | * Note that both bits can be set at the same time. | ||
393 | */ | ||
394 | #define BEACON_FILTER_TABLE_MAX_IE_NUM (32) | ||
395 | #define BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM (6) | ||
396 | #define BEACON_FILTER_TABLE_IE_ENTRY_SIZE (2) | ||
397 | #define BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE (6) | ||
398 | #define BEACON_FILTER_TABLE_MAX_SIZE ((BEACON_FILTER_TABLE_MAX_IE_NUM * \ | ||
399 | BEACON_FILTER_TABLE_IE_ENTRY_SIZE) + \ | ||
400 | (BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM * \ | ||
401 | BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE)) | ||
402 | |||
403 | struct acx_beacon_filter_ie_table { | ||
404 | struct acx_header header; | ||
405 | |||
406 | u8 num_ie; | ||
407 | u8 table[BEACON_FILTER_TABLE_MAX_SIZE]; | ||
408 | u8 pad[3]; | ||
409 | } __attribute__ ((packed)); | ||
410 | |||
411 | enum { | ||
412 | SG_ENABLE = 0, | ||
413 | SG_DISABLE, | ||
414 | SG_SENSE_NO_ACTIVITY, | ||
415 | SG_SENSE_ACTIVE | ||
416 | }; | ||
417 | |||
418 | struct acx_bt_wlan_coex { | ||
419 | struct acx_header header; | ||
420 | |||
421 | /* | ||
422 | * 0 -> PTA enabled | ||
423 | * 1 -> PTA disabled | ||
424 | * 2 -> sense no active mode, i.e. | ||
425 | * an interrupt is sent upon | ||
426 | * BT activity. | ||
427 | * 3 -> PTA is switched on in response | ||
428 | * to the interrupt sending. | ||
429 | */ | ||
430 | u8 enable; | ||
431 | u8 pad[3]; | ||
432 | } __attribute__ ((packed)); | ||
433 | |||
434 | #define PTA_ANTENNA_TYPE_DEF (0) | ||
435 | #define PTA_BT_HP_MAXTIME_DEF (2000) | ||
436 | #define PTA_WLAN_HP_MAX_TIME_DEF (5000) | ||
437 | #define PTA_SENSE_DISABLE_TIMER_DEF (1350) | ||
438 | #define PTA_PROTECTIVE_RX_TIME_DEF (1500) | ||
439 | #define PTA_PROTECTIVE_TX_TIME_DEF (1500) | ||
440 | #define PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF (3000) | ||
441 | #define PTA_SIGNALING_TYPE_DEF (1) | ||
442 | #define PTA_AFH_LEVERAGE_ON_DEF (0) | ||
443 | #define PTA_NUMBER_QUIET_CYCLE_DEF (0) | ||
444 | #define PTA_MAX_NUM_CTS_DEF (3) | ||
445 | #define PTA_NUMBER_OF_WLAN_PACKETS_DEF (2) | ||
446 | #define PTA_NUMBER_OF_BT_PACKETS_DEF (2) | ||
447 | #define PTA_PROTECTIVE_RX_TIME_FAST_DEF (1500) | ||
448 | #define PTA_PROTECTIVE_TX_TIME_FAST_DEF (3000) | ||
449 | #define PTA_CYCLE_TIME_FAST_DEF (8700) | ||
450 | #define PTA_RX_FOR_AVALANCHE_DEF (5) | ||
451 | #define PTA_ELP_HP_DEF (0) | ||
452 | #define PTA_ANTI_STARVE_PERIOD_DEF (500) | ||
453 | #define PTA_ANTI_STARVE_NUM_CYCLE_DEF (4) | ||
454 | #define PTA_ALLOW_PA_SD_DEF (1) | ||
455 | #define PTA_TIME_BEFORE_BEACON_DEF (6300) | ||
456 | #define PTA_HPDM_MAX_TIME_DEF (1600) | ||
457 | #define PTA_TIME_OUT_NEXT_WLAN_DEF (2550) | ||
458 | #define PTA_AUTO_MODE_NO_CTS_DEF (0) | ||
459 | #define PTA_BT_HP_RESPECTED_DEF (3) | ||
460 | #define PTA_WLAN_RX_MIN_RATE_DEF (24) | ||
461 | #define PTA_ACK_MODE_DEF (1) | ||
462 | |||
463 | struct acx_bt_wlan_coex_param { | ||
464 | struct acx_header header; | ||
465 | |||
466 | /* | ||
467 | * The minimum rate of a received WLAN packet in the STA, | ||
468 | * during protective mode, of which a new BT-HP request | ||
469 | * during this Rx will always be respected and gain the antenna. | ||
470 | */ | ||
471 | u32 min_rate; | ||
472 | |||
473 | /* Max time the BT HP will be respected. */ | ||
474 | u16 bt_hp_max_time; | ||
475 | |||
476 | /* Max time the WLAN HP will be respected. */ | ||
477 | u16 wlan_hp_max_time; | ||
478 | |||
479 | /* | ||
480 | * The time between the last BT activity | ||
481 | * and the moment when the sense mode returns | ||
482 | * to SENSE_INACTIVE. | ||
483 | */ | ||
484 | u16 sense_disable_timer; | ||
485 | |||
486 | /* Time before the next BT HP instance */ | ||
487 | u16 rx_time_bt_hp; | ||
488 | u16 tx_time_bt_hp; | ||
489 | |||
490 | /* range: 10-20000 default: 1500 */ | ||
491 | u16 rx_time_bt_hp_fast; | ||
492 | u16 tx_time_bt_hp_fast; | ||
493 | |||
494 | /* range: 2000-65535 default: 8700 */ | ||
495 | u16 wlan_cycle_fast; | ||
496 | |||
497 | /* range: 0 - 15000 (Msec) default: 1000 */ | ||
498 | u16 bt_anti_starvation_period; | ||
499 | |||
500 | /* range 400-10000(Usec) default: 3000 */ | ||
501 | u16 next_bt_lp_packet; | ||
502 | |||
503 | /* Deafult: worst case for BT DH5 traffic */ | ||
504 | u16 wake_up_beacon; | ||
505 | |||
506 | /* range: 0-50000(Usec) default: 1050 */ | ||
507 | u16 hp_dm_max_guard_time; | ||
508 | |||
509 | /* | ||
510 | * This is to prevent both BT & WLAN antenna | ||
511 | * starvation. | ||
512 | * Range: 100-50000(Usec) default:2550 | ||
513 | */ | ||
514 | u16 next_wlan_packet; | ||
515 | |||
516 | /* 0 -> shared antenna */ | ||
517 | u8 antenna_type; | ||
518 | |||
519 | /* | ||
520 | * 0 -> TI legacy | ||
521 | * 1 -> Palau | ||
522 | */ | ||
523 | u8 signal_type; | ||
524 | |||
525 | /* | ||
526 | * BT AFH status | ||
527 | * 0 -> no AFH | ||
528 | * 1 -> from dedicated GPIO | ||
529 | * 2 -> AFH on (from host) | ||
530 | */ | ||
531 | u8 afh_leverage_on; | ||
532 | |||
533 | /* | ||
534 | * The number of cycles during which no | ||
535 | * TX will be sent after 1 cycle of RX | ||
536 | * transaction in protective mode | ||
537 | */ | ||
538 | u8 quiet_cycle_num; | ||
539 | |||
540 | /* | ||
541 | * The maximum number of CTSs that will | ||
542 | * be sent for receiving RX packet in | ||
543 | * protective mode | ||
544 | */ | ||
545 | u8 max_cts; | ||
546 | |||
547 | /* | ||
548 | * The number of WLAN packets | ||
549 | * transferred in common mode before | ||
550 | * switching to BT. | ||
551 | */ | ||
552 | u8 wlan_packets_num; | ||
553 | |||
554 | /* | ||
555 | * The number of BT packets | ||
556 | * transferred in common mode before | ||
557 | * switching to WLAN. | ||
558 | */ | ||
559 | u8 bt_packets_num; | ||
560 | |||
561 | /* range: 1-255 default: 5 */ | ||
562 | u8 missed_rx_avalanche; | ||
563 | |||
564 | /* range: 0-1 default: 1 */ | ||
565 | u8 wlan_elp_hp; | ||
566 | |||
567 | /* range: 0 - 15 default: 4 */ | ||
568 | u8 bt_anti_starvation_cycles; | ||
569 | |||
570 | u8 ack_mode_dual_ant; | ||
571 | |||
572 | /* | ||
573 | * Allow PA_SD assertion/de-assertion | ||
574 | * during enabled BT activity. | ||
575 | */ | ||
576 | u8 pa_sd_enable; | ||
577 | |||
578 | /* | ||
579 | * Enable/Disable PTA in auto mode: | ||
580 | * Support Both Active & P.S modes | ||
581 | */ | ||
582 | u8 pta_auto_mode_enable; | ||
583 | |||
584 | /* range: 0 - 20 default: 1 */ | ||
585 | u8 bt_hp_respected_num; | ||
586 | } __attribute__ ((packed)); | ||
587 | |||
588 | #define CCA_THRSH_ENABLE_ENERGY_D 0x140A | ||
589 | #define CCA_THRSH_DISABLE_ENERGY_D 0xFFEF | ||
590 | |||
591 | struct acx_energy_detection { | ||
592 | struct acx_header header; | ||
593 | |||
594 | /* The RX Clear Channel Assessment threshold in the PHY */ | ||
595 | u16 rx_cca_threshold; | ||
596 | u8 tx_energy_detection; | ||
597 | u8 pad; | ||
598 | } __attribute__ ((packed)); | ||
599 | |||
600 | #define BCN_RX_TIMEOUT_DEF_VALUE 10000 | ||
601 | #define BROADCAST_RX_TIMEOUT_DEF_VALUE 20000 | ||
602 | #define RX_BROADCAST_IN_PS_DEF_VALUE 1 | ||
603 | #define CONSECUTIVE_PS_POLL_FAILURE_DEF 4 | ||
604 | |||
605 | struct acx_beacon_broadcast { | ||
606 | struct acx_header header; | ||
607 | |||
608 | u16 beacon_rx_timeout; | ||
609 | u16 broadcast_timeout; | ||
610 | |||
611 | /* Enables receiving of broadcast packets in PS mode */ | ||
612 | u8 rx_broadcast_in_ps; | ||
613 | |||
614 | /* Consecutive PS Poll failures before updating the host */ | ||
615 | u8 ps_poll_threshold; | ||
616 | u8 pad[2]; | ||
617 | } __attribute__ ((packed)); | ||
618 | |||
619 | struct acx_event_mask { | ||
620 | struct acx_header header; | ||
621 | |||
622 | u32 event_mask; | ||
623 | u32 high_event_mask; /* Unused */ | ||
624 | } __attribute__ ((packed)); | ||
625 | |||
626 | #define CFG_RX_FCS BIT(2) | ||
627 | #define CFG_RX_ALL_GOOD BIT(3) | ||
628 | #define CFG_UNI_FILTER_EN BIT(4) | ||
629 | #define CFG_BSSID_FILTER_EN BIT(5) | ||
630 | #define CFG_MC_FILTER_EN BIT(6) | ||
631 | #define CFG_MC_ADDR0_EN BIT(7) | ||
632 | #define CFG_MC_ADDR1_EN BIT(8) | ||
633 | #define CFG_BC_REJECT_EN BIT(9) | ||
634 | #define CFG_SSID_FILTER_EN BIT(10) | ||
635 | #define CFG_RX_INT_FCS_ERROR BIT(11) | ||
636 | #define CFG_RX_INT_ENCRYPTED BIT(12) | ||
637 | #define CFG_RX_WR_RX_STATUS BIT(13) | ||
638 | #define CFG_RX_FILTER_NULTI BIT(14) | ||
639 | #define CFG_RX_RESERVE BIT(15) | ||
640 | #define CFG_RX_TIMESTAMP_TSF BIT(16) | ||
641 | |||
642 | #define CFG_RX_RSV_EN BIT(0) | ||
643 | #define CFG_RX_RCTS_ACK BIT(1) | ||
644 | #define CFG_RX_PRSP_EN BIT(2) | ||
645 | #define CFG_RX_PREQ_EN BIT(3) | ||
646 | #define CFG_RX_MGMT_EN BIT(4) | ||
647 | #define CFG_RX_FCS_ERROR BIT(5) | ||
648 | #define CFG_RX_DATA_EN BIT(6) | ||
649 | #define CFG_RX_CTL_EN BIT(7) | ||
650 | #define CFG_RX_CF_EN BIT(8) | ||
651 | #define CFG_RX_BCN_EN BIT(9) | ||
652 | #define CFG_RX_AUTH_EN BIT(10) | ||
653 | #define CFG_RX_ASSOC_EN BIT(11) | ||
654 | |||
655 | #define SCAN_PASSIVE BIT(0) | ||
656 | #define SCAN_5GHZ_BAND BIT(1) | ||
657 | #define SCAN_TRIGGERED BIT(2) | ||
658 | #define SCAN_PRIORITY_HIGH BIT(3) | ||
659 | |||
660 | struct acx_feature_config { | ||
661 | struct acx_header header; | ||
662 | |||
663 | u32 options; | ||
664 | u32 data_flow_options; | ||
665 | } __attribute__ ((packed)); | ||
666 | |||
667 | struct acx_current_tx_power { | ||
668 | struct acx_header header; | ||
669 | |||
670 | u8 current_tx_power; | ||
671 | u8 padding[3]; | ||
672 | } __attribute__ ((packed)); | ||
673 | |||
674 | enum acx_wake_up_event { | ||
675 | WAKE_UP_EVENT_BEACON_BITMAP = 0x01, /* Wake on every Beacon*/ | ||
676 | WAKE_UP_EVENT_DTIM_BITMAP = 0x02, /* Wake on every DTIM*/ | ||
677 | WAKE_UP_EVENT_N_DTIM_BITMAP = 0x04, /* Wake on every Nth DTIM */ | ||
678 | WAKE_UP_EVENT_N_BEACONS_BITMAP = 0x08, /* Wake on every Nth Beacon */ | ||
679 | WAKE_UP_EVENT_BITS_MASK = 0x0F | ||
680 | }; | ||
681 | |||
682 | struct acx_wake_up_condition { | ||
683 | struct acx_header header; | ||
684 | |||
685 | u8 wake_up_event; /* Only one bit can be set */ | ||
686 | u8 listen_interval; | ||
687 | u8 pad[2]; | ||
688 | } __attribute__ ((packed)); | ||
689 | |||
690 | struct acx_aid { | ||
691 | struct acx_header header; | ||
692 | |||
693 | /* | ||
694 | * To be set when associated with an AP. | ||
695 | */ | ||
696 | u16 aid; | ||
697 | u8 pad[2]; | ||
698 | } __attribute__ ((packed)); | ||
699 | |||
700 | enum acx_preamble_type { | ||
701 | ACX_PREAMBLE_LONG = 0, | ||
702 | ACX_PREAMBLE_SHORT = 1 | ||
703 | }; | ||
704 | |||
705 | struct acx_preamble { | ||
706 | struct acx_header header; | ||
707 | |||
708 | /* | ||
709 | * When set, the WiLink transmits the frames with a short preamble and | ||
710 | * when cleared, the WiLink transmits the frames with a long preamble. | ||
711 | */ | ||
712 | u8 preamble; | ||
713 | u8 padding[3]; | ||
714 | } __attribute__ ((packed)); | ||
715 | |||
716 | enum acx_ctsprotect_type { | ||
717 | CTSPROTECT_DISABLE = 0, | ||
718 | CTSPROTECT_ENABLE = 1 | ||
719 | }; | ||
720 | |||
721 | struct acx_ctsprotect { | ||
722 | struct acx_header header; | ||
723 | u8 ctsprotect; | ||
724 | u8 padding[3]; | ||
725 | } __attribute__ ((packed)); | ||
726 | |||
727 | struct acx_tx_statistics { | ||
728 | u32 internal_desc_overflow; | ||
729 | } __attribute__ ((packed)); | ||
730 | |||
731 | struct acx_rx_statistics { | ||
732 | u32 out_of_mem; | ||
733 | u32 hdr_overflow; | ||
734 | u32 hw_stuck; | ||
735 | u32 dropped; | ||
736 | u32 fcs_err; | ||
737 | u32 xfr_hint_trig; | ||
738 | u32 path_reset; | ||
739 | u32 reset_counter; | ||
740 | } __attribute__ ((packed)); | ||
741 | |||
742 | struct acx_dma_statistics { | ||
743 | u32 rx_requested; | ||
744 | u32 rx_errors; | ||
745 | u32 tx_requested; | ||
746 | u32 tx_errors; | ||
747 | } __attribute__ ((packed)); | ||
748 | |||
749 | struct acx_isr_statistics { | ||
750 | /* host command complete */ | ||
751 | u32 cmd_cmplt; | ||
752 | |||
753 | /* fiqisr() */ | ||
754 | u32 fiqs; | ||
755 | |||
756 | /* (INT_STS_ND & INT_TRIG_RX_HEADER) */ | ||
757 | u32 rx_headers; | ||
758 | |||
759 | /* (INT_STS_ND & INT_TRIG_RX_CMPLT) */ | ||
760 | u32 rx_completes; | ||
761 | |||
762 | /* (INT_STS_ND & INT_TRIG_NO_RX_BUF) */ | ||
763 | u32 rx_mem_overflow; | ||
764 | |||
765 | /* (INT_STS_ND & INT_TRIG_S_RX_RDY) */ | ||
766 | u32 rx_rdys; | ||
767 | |||
768 | /* irqisr() */ | ||
769 | u32 irqs; | ||
770 | |||
771 | /* (INT_STS_ND & INT_TRIG_TX_PROC) */ | ||
772 | u32 tx_procs; | ||
773 | |||
774 | /* (INT_STS_ND & INT_TRIG_DECRYPT_DONE) */ | ||
775 | u32 decrypt_done; | ||
776 | |||
777 | /* (INT_STS_ND & INT_TRIG_DMA0) */ | ||
778 | u32 dma0_done; | ||
779 | |||
780 | /* (INT_STS_ND & INT_TRIG_DMA1) */ | ||
781 | u32 dma1_done; | ||
782 | |||
783 | /* (INT_STS_ND & INT_TRIG_TX_EXC_CMPLT) */ | ||
784 | u32 tx_exch_complete; | ||
785 | |||
786 | /* (INT_STS_ND & INT_TRIG_COMMAND) */ | ||
787 | u32 commands; | ||
788 | |||
789 | /* (INT_STS_ND & INT_TRIG_RX_PROC) */ | ||
790 | u32 rx_procs; | ||
791 | |||
792 | /* (INT_STS_ND & INT_TRIG_PM_802) */ | ||
793 | u32 hw_pm_mode_changes; | ||
794 | |||
795 | /* (INT_STS_ND & INT_TRIG_ACKNOWLEDGE) */ | ||
796 | u32 host_acknowledges; | ||
797 | |||
798 | /* (INT_STS_ND & INT_TRIG_PM_PCI) */ | ||
799 | u32 pci_pm; | ||
800 | |||
801 | /* (INT_STS_ND & INT_TRIG_ACM_WAKEUP) */ | ||
802 | u32 wakeups; | ||
803 | |||
804 | /* (INT_STS_ND & INT_TRIG_LOW_RSSI) */ | ||
805 | u32 low_rssi; | ||
806 | } __attribute__ ((packed)); | ||
807 | |||
808 | struct acx_wep_statistics { | ||
809 | /* WEP address keys configured */ | ||
810 | u32 addr_key_count; | ||
811 | |||
812 | /* default keys configured */ | ||
813 | u32 default_key_count; | ||
814 | |||
815 | u32 reserved; | ||
816 | |||
817 | /* number of times that WEP key not found on lookup */ | ||
818 | u32 key_not_found; | ||
819 | |||
820 | /* number of times that WEP key decryption failed */ | ||
821 | u32 decrypt_fail; | ||
822 | |||
823 | /* WEP packets decrypted */ | ||
824 | u32 packets; | ||
825 | |||
826 | /* WEP decrypt interrupts */ | ||
827 | u32 interrupt; | ||
828 | } __attribute__ ((packed)); | ||
829 | |||
830 | #define ACX_MISSED_BEACONS_SPREAD 10 | ||
831 | |||
832 | struct acx_pwr_statistics { | ||
833 | /* the amount of enters into power save mode (both PD & ELP) */ | ||
834 | u32 ps_enter; | ||
835 | |||
836 | /* the amount of enters into ELP mode */ | ||
837 | u32 elp_enter; | ||
838 | |||
839 | /* the amount of missing beacon interrupts to the host */ | ||
840 | u32 missing_bcns; | ||
841 | |||
842 | /* the amount of wake on host-access times */ | ||
843 | u32 wake_on_host; | ||
844 | |||
845 | /* the amount of wake on timer-expire */ | ||
846 | u32 wake_on_timer_exp; | ||
847 | |||
848 | /* the number of packets that were transmitted with PS bit set */ | ||
849 | u32 tx_with_ps; | ||
850 | |||
851 | /* the number of packets that were transmitted with PS bit clear */ | ||
852 | u32 tx_without_ps; | ||
853 | |||
854 | /* the number of received beacons */ | ||
855 | u32 rcvd_beacons; | ||
856 | |||
857 | /* the number of entering into PowerOn (power save off) */ | ||
858 | u32 power_save_off; | ||
859 | |||
860 | /* the number of entries into power save mode */ | ||
861 | u16 enable_ps; | ||
862 | |||
863 | /* | ||
864 | * the number of exits from power save, not including failed PS | ||
865 | * transitions | ||
866 | */ | ||
867 | u16 disable_ps; | ||
868 | |||
869 | /* | ||
870 | * the number of times the TSF counter was adjusted because | ||
871 | * of drift | ||
872 | */ | ||
873 | u32 fix_tsf_ps; | ||
874 | |||
875 | /* Gives statistics about the spread continuous missed beacons. | ||
876 | * The 16 LSB are dedicated for the PS mode. | ||
877 | * The 16 MSB are dedicated for the PS mode. | ||
878 | * cont_miss_bcns_spread[0] - single missed beacon. | ||
879 | * cont_miss_bcns_spread[1] - two continuous missed beacons. | ||
880 | * cont_miss_bcns_spread[2] - three continuous missed beacons. | ||
881 | * ... | ||
882 | * cont_miss_bcns_spread[9] - ten and more continuous missed beacons. | ||
883 | */ | ||
884 | u32 cont_miss_bcns_spread[ACX_MISSED_BEACONS_SPREAD]; | ||
885 | |||
886 | /* the number of beacons in awake mode */ | ||
887 | u32 rcvd_awake_beacons; | ||
888 | } __attribute__ ((packed)); | ||
889 | |||
890 | struct acx_mic_statistics { | ||
891 | u32 rx_pkts; | ||
892 | u32 calc_failure; | ||
893 | } __attribute__ ((packed)); | ||
894 | |||
895 | struct acx_aes_statistics { | ||
896 | u32 encrypt_fail; | ||
897 | u32 decrypt_fail; | ||
898 | u32 encrypt_packets; | ||
899 | u32 decrypt_packets; | ||
900 | u32 encrypt_interrupt; | ||
901 | u32 decrypt_interrupt; | ||
902 | } __attribute__ ((packed)); | ||
903 | |||
904 | struct acx_event_statistics { | ||
905 | u32 heart_beat; | ||
906 | u32 calibration; | ||
907 | u32 rx_mismatch; | ||
908 | u32 rx_mem_empty; | ||
909 | u32 rx_pool; | ||
910 | u32 oom_late; | ||
911 | u32 phy_transmit_error; | ||
912 | u32 tx_stuck; | ||
913 | } __attribute__ ((packed)); | ||
914 | |||
915 | struct acx_ps_statistics { | ||
916 | u32 pspoll_timeouts; | ||
917 | u32 upsd_timeouts; | ||
918 | u32 upsd_max_sptime; | ||
919 | u32 upsd_max_apturn; | ||
920 | u32 pspoll_max_apturn; | ||
921 | u32 pspoll_utilization; | ||
922 | u32 upsd_utilization; | ||
923 | } __attribute__ ((packed)); | ||
924 | |||
925 | struct acx_rxpipe_statistics { | ||
926 | u32 rx_prep_beacon_drop; | ||
927 | u32 descr_host_int_trig_rx_data; | ||
928 | u32 beacon_buffer_thres_host_int_trig_rx_data; | ||
929 | u32 missed_beacon_host_int_trig_rx_data; | ||
930 | u32 tx_xfr_host_int_trig_rx_data; | ||
931 | } __attribute__ ((packed)); | ||
932 | |||
933 | struct acx_statistics { | ||
934 | struct acx_header header; | ||
935 | |||
936 | struct acx_tx_statistics tx; | ||
937 | struct acx_rx_statistics rx; | ||
938 | struct acx_dma_statistics dma; | ||
939 | struct acx_isr_statistics isr; | ||
940 | struct acx_wep_statistics wep; | ||
941 | struct acx_pwr_statistics pwr; | ||
942 | struct acx_aes_statistics aes; | ||
943 | struct acx_mic_statistics mic; | ||
944 | struct acx_event_statistics event; | ||
945 | struct acx_ps_statistics ps; | ||
946 | struct acx_rxpipe_statistics rxpipe; | ||
947 | } __attribute__ ((packed)); | ||
948 | |||
949 | #define ACX_MAX_RATE_CLASSES 8 | ||
950 | #define ACX_RATE_MASK_UNSPECIFIED 0 | ||
951 | #define ACX_RATE_MASK_ALL 0x1eff | ||
952 | #define ACX_RATE_RETRY_LIMIT 10 | ||
953 | |||
954 | struct acx_rate_class { | ||
955 | u32 enabled_rates; | ||
956 | u8 short_retry_limit; | ||
957 | u8 long_retry_limit; | ||
958 | u8 aflags; | ||
959 | u8 reserved; | ||
960 | }; | ||
961 | |||
962 | struct acx_rate_policy { | ||
963 | struct acx_header header; | ||
964 | |||
965 | u32 rate_class_cnt; | ||
966 | struct acx_rate_class rate_class[ACX_MAX_RATE_CLASSES]; | ||
967 | } __attribute__ ((packed)); | ||
968 | |||
969 | #define WL1271_ACX_AC_COUNT 4 | ||
970 | |||
971 | struct acx_ac_cfg { | ||
972 | struct acx_header header; | ||
973 | u8 ac; | ||
974 | u8 cw_min; | ||
975 | u16 cw_max; | ||
976 | u8 aifsn; | ||
977 | u8 reserved; | ||
978 | u16 tx_op_limit; | ||
979 | } __attribute__ ((packed)); | ||
980 | |||
981 | enum wl1271_acx_ac { | ||
982 | WL1271_ACX_AC_BE = 0, | ||
983 | WL1271_ACX_AC_BK = 1, | ||
984 | WL1271_ACX_AC_VI = 2, | ||
985 | WL1271_ACX_AC_VO = 3, | ||
986 | WL1271_ACX_AC_CTS2SELF = 4, | ||
987 | WL1271_ACX_AC_ANY_TID = 0x1F, | ||
988 | WL1271_ACX_AC_INVALID = 0xFF, | ||
989 | }; | ||
990 | |||
991 | enum wl1271_acx_ps_scheme { | ||
992 | WL1271_ACX_PS_SCHEME_LEGACY = 0, | ||
993 | WL1271_ACX_PS_SCHEME_UPSD_TRIGGER = 1, | ||
994 | WL1271_ACX_PS_SCHEME_LEGACY_PSPOLL = 2, | ||
995 | WL1271_ACX_PS_SCHEME_SAPSD = 3, | ||
996 | }; | ||
997 | |||
998 | enum wl1271_acx_ack_policy { | ||
999 | WL1271_ACX_ACK_POLICY_LEGACY = 0, | ||
1000 | WL1271_ACX_ACK_POLICY_NO_ACK = 1, | ||
1001 | WL1271_ACX_ACK_POLICY_BLOCK = 2, | ||
1002 | }; | ||
1003 | |||
1004 | #define WL1271_ACX_TID_COUNT 7 | ||
1005 | |||
1006 | struct acx_tid_config { | ||
1007 | struct acx_header header; | ||
1008 | u8 queue_id; | ||
1009 | u8 channel_type; | ||
1010 | u8 tsid; | ||
1011 | u8 ps_scheme; | ||
1012 | u8 ack_policy; | ||
1013 | u8 padding[3]; | ||
1014 | u32 apsd_conf[2]; | ||
1015 | } __attribute__ ((packed)); | ||
1016 | |||
1017 | struct acx_frag_threshold { | ||
1018 | struct acx_header header; | ||
1019 | u16 frag_threshold; | ||
1020 | u8 padding[2]; | ||
1021 | } __attribute__ ((packed)); | ||
1022 | |||
1023 | #define WL1271_ACX_TX_COMPL_TIMEOUT 5 | ||
1024 | #define WL1271_ACX_TX_COMPL_THRESHOLD 5 | ||
1025 | |||
1026 | struct acx_tx_config_options { | ||
1027 | struct acx_header header; | ||
1028 | u16 tx_compl_timeout; /* msec */ | ||
1029 | u16 tx_compl_threshold; /* number of packets */ | ||
1030 | } __attribute__ ((packed)); | ||
1031 | |||
1032 | #define ACX_RX_MEM_BLOCKS 64 | ||
1033 | #define ACX_TX_MIN_MEM_BLOCKS 64 | ||
1034 | #define ACX_TX_DESCRIPTORS 32 | ||
1035 | #define ACX_NUM_SSID_PROFILES 1 | ||
1036 | |||
1037 | struct wl1271_acx_config_memory { | ||
1038 | struct acx_header header; | ||
1039 | |||
1040 | u8 rx_mem_block_num; | ||
1041 | u8 tx_min_mem_block_num; | ||
1042 | u8 num_stations; | ||
1043 | u8 num_ssid_profiles; | ||
1044 | u32 total_tx_descriptors; | ||
1045 | } __attribute__ ((packed)); | ||
1046 | |||
1047 | struct wl1271_acx_mem_map { | ||
1048 | struct acx_header header; | ||
1049 | |||
1050 | void *code_start; | ||
1051 | void *code_end; | ||
1052 | |||
1053 | void *wep_defkey_start; | ||
1054 | void *wep_defkey_end; | ||
1055 | |||
1056 | void *sta_table_start; | ||
1057 | void *sta_table_end; | ||
1058 | |||
1059 | void *packet_template_start; | ||
1060 | void *packet_template_end; | ||
1061 | |||
1062 | /* Address of the TX result interface (control block) */ | ||
1063 | u32 tx_result; | ||
1064 | u32 tx_result_queue_start; | ||
1065 | |||
1066 | void *queue_memory_start; | ||
1067 | void *queue_memory_end; | ||
1068 | |||
1069 | u32 packet_memory_pool_start; | ||
1070 | u32 packet_memory_pool_end; | ||
1071 | |||
1072 | void *debug_buffer1_start; | ||
1073 | void *debug_buffer1_end; | ||
1074 | |||
1075 | void *debug_buffer2_start; | ||
1076 | void *debug_buffer2_end; | ||
1077 | |||
1078 | /* Number of blocks FW allocated for TX packets */ | ||
1079 | u32 num_tx_mem_blocks; | ||
1080 | |||
1081 | /* Number of blocks FW allocated for RX packets */ | ||
1082 | u32 num_rx_mem_blocks; | ||
1083 | |||
1084 | /* the following 4 fields are valid in SLAVE mode only */ | ||
1085 | u8 *tx_cbuf; | ||
1086 | u8 *rx_cbuf; | ||
1087 | void *rx_ctrl; | ||
1088 | void *tx_ctrl; | ||
1089 | } __attribute__ ((packed)); | ||
1090 | |||
1091 | enum wl1271_acx_rx_queue_type { | ||
1092 | RX_QUEUE_TYPE_RX_LOW_PRIORITY, /* All except the high priority */ | ||
1093 | RX_QUEUE_TYPE_RX_HIGH_PRIORITY, /* Management and voice packets */ | ||
1094 | RX_QUEUE_TYPE_NUM, | ||
1095 | RX_QUEUE_TYPE_MAX = USHORT_MAX | ||
1096 | }; | ||
1097 | |||
1098 | #define WL1271_RX_INTR_THRESHOLD_DEF 0 /* no pacing, send interrupt on | ||
1099 | * every event */ | ||
1100 | #define WL1271_RX_INTR_THRESHOLD_MIN 0 | ||
1101 | #define WL1271_RX_INTR_THRESHOLD_MAX 15 | ||
1102 | |||
1103 | #define WL1271_RX_INTR_TIMEOUT_DEF 5 | ||
1104 | #define WL1271_RX_INTR_TIMEOUT_MIN 1 | ||
1105 | #define WL1271_RX_INTR_TIMEOUT_MAX 100 | ||
1106 | |||
1107 | struct wl1271_acx_rx_config_opt { | ||
1108 | struct acx_header header; | ||
1109 | |||
1110 | u16 mblk_threshold; | ||
1111 | u16 threshold; | ||
1112 | u16 timeout; | ||
1113 | u8 queue_type; | ||
1114 | u8 reserved; | ||
1115 | } __attribute__ ((packed)); | ||
1116 | |||
1117 | enum { | ||
1118 | ACX_WAKE_UP_CONDITIONS = 0x0002, | ||
1119 | ACX_MEM_CFG = 0x0003, | ||
1120 | ACX_SLOT = 0x0004, | ||
1121 | ACX_AC_CFG = 0x0007, | ||
1122 | ACX_MEM_MAP = 0x0008, | ||
1123 | ACX_AID = 0x000A, | ||
1124 | /* ACX_FW_REV is missing in the ref driver, but seems to work */ | ||
1125 | ACX_FW_REV = 0x000D, | ||
1126 | ACX_MEDIUM_USAGE = 0x000F, | ||
1127 | ACX_RX_CFG = 0x0010, | ||
1128 | ACX_TX_QUEUE_CFG = 0x0011, /* FIXME: only used by wl1251 */ | ||
1129 | ACX_STATISTICS = 0x0013, /* Debug API */ | ||
1130 | ACX_PWR_CONSUMPTION_STATISTICS = 0x0014, | ||
1131 | ACX_FEATURE_CFG = 0x0015, | ||
1132 | ACX_TID_CFG = 0x001A, | ||
1133 | ACX_PS_RX_STREAMING = 0x001B, | ||
1134 | ACX_BEACON_FILTER_OPT = 0x001F, | ||
1135 | ACX_NOISE_HIST = 0x0021, | ||
1136 | ACX_HDK_VERSION = 0x0022, /* ??? */ | ||
1137 | ACX_PD_THRESHOLD = 0x0023, | ||
1138 | ACX_TX_CONFIG_OPT = 0x0024, | ||
1139 | ACX_CCA_THRESHOLD = 0x0025, | ||
1140 | ACX_EVENT_MBOX_MASK = 0x0026, | ||
1141 | ACX_CONN_MONIT_PARAMS = 0x002D, | ||
1142 | ACX_CONS_TX_FAILURE = 0x002F, | ||
1143 | ACX_BCN_DTIM_OPTIONS = 0x0031, | ||
1144 | ACX_SG_ENABLE = 0x0032, | ||
1145 | ACX_SG_CFG = 0x0033, | ||
1146 | ACX_BEACON_FILTER_TABLE = 0x0038, | ||
1147 | ACX_ARP_IP_FILTER = 0x0039, | ||
1148 | ACX_ROAMING_STATISTICS_TBL = 0x003B, | ||
1149 | ACX_RATE_POLICY = 0x003D, | ||
1150 | ACX_CTS_PROTECTION = 0x003E, | ||
1151 | ACX_SLEEP_AUTH = 0x003F, | ||
1152 | ACX_PREAMBLE_TYPE = 0x0040, | ||
1153 | ACX_ERROR_CNT = 0x0041, | ||
1154 | ACX_IBSS_FILTER = 0x0044, | ||
1155 | ACX_SERVICE_PERIOD_TIMEOUT = 0x0045, | ||
1156 | ACX_TSF_INFO = 0x0046, | ||
1157 | ACX_CONFIG_PS_WMM = 0x0049, | ||
1158 | ACX_ENABLE_RX_DATA_FILTER = 0x004A, | ||
1159 | ACX_SET_RX_DATA_FILTER = 0x004B, | ||
1160 | ACX_GET_DATA_FILTER_STATISTICS = 0x004C, | ||
1161 | ACX_RX_CONFIG_OPT = 0x004E, | ||
1162 | ACX_FRAG_CFG = 0x004F, | ||
1163 | ACX_BET_ENABLE = 0x0050, | ||
1164 | ACX_RSSI_SNR_TRIGGER = 0x0051, | ||
1165 | ACX_RSSI_SNR_WEIGHTS = 0x0051, | ||
1166 | ACX_KEEP_ALIVE_MODE = 0x0052, | ||
1167 | ACX_SET_KEEP_ALIVE_CONFIG = 0x0054, | ||
1168 | ACX_BA_SESSION_RESPONDER_POLICY = 0x0055, | ||
1169 | ACX_BA_SESSION_INITIATOR_POLICY = 0x0056, | ||
1170 | ACX_PEER_HT_CAP = 0x0057, | ||
1171 | ACX_HT_BSS_OPERATION = 0x0058, | ||
1172 | ACX_COEX_ACTIVITY = 0x0059, | ||
1173 | DOT11_RX_MSDU_LIFE_TIME = 0x1004, | ||
1174 | DOT11_CUR_TX_PWR = 0x100D, | ||
1175 | DOT11_RX_DOT11_MODE = 0x1012, | ||
1176 | DOT11_RTS_THRESHOLD = 0x1013, | ||
1177 | DOT11_GROUP_ADDRESS_TBL = 0x1014, | ||
1178 | |||
1179 | MAX_DOT11_IE = DOT11_GROUP_ADDRESS_TBL, | ||
1180 | |||
1181 | MAX_IE = 0xFFFF | ||
1182 | }; | ||
1183 | |||
1184 | |||
1185 | int wl1271_acx_wake_up_conditions(struct wl1271 *wl, u8 wake_up_event, | ||
1186 | u8 listen_interval); | ||
1187 | int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth); | ||
1188 | int wl1271_acx_fw_version(struct wl1271 *wl, char *buf, size_t len); | ||
1189 | int wl1271_acx_tx_power(struct wl1271 *wl, int power); | ||
1190 | int wl1271_acx_feature_cfg(struct wl1271 *wl); | ||
1191 | int wl1271_acx_mem_map(struct wl1271 *wl, | ||
1192 | struct acx_header *mem_map, size_t len); | ||
1193 | int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl, u32 life_time); | ||
1194 | int wl1271_acx_rx_config(struct wl1271 *wl, u32 config, u32 filter); | ||
1195 | int wl1271_acx_pd_threshold(struct wl1271 *wl); | ||
1196 | int wl1271_acx_slot(struct wl1271 *wl, enum acx_slot_type slot_time); | ||
1197 | int wl1271_acx_group_address_tbl(struct wl1271 *wl); | ||
1198 | int wl1271_acx_service_period_timeout(struct wl1271 *wl); | ||
1199 | int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold); | ||
1200 | int wl1271_acx_beacon_filter_opt(struct wl1271 *wl); | ||
1201 | int wl1271_acx_beacon_filter_table(struct wl1271 *wl); | ||
1202 | int wl1271_acx_sg_enable(struct wl1271 *wl); | ||
1203 | int wl1271_acx_sg_cfg(struct wl1271 *wl); | ||
1204 | int wl1271_acx_cca_threshold(struct wl1271 *wl); | ||
1205 | int wl1271_acx_bcn_dtim_options(struct wl1271 *wl); | ||
1206 | int wl1271_acx_aid(struct wl1271 *wl, u16 aid); | ||
1207 | int wl1271_acx_event_mbox_mask(struct wl1271 *wl, u32 event_mask); | ||
1208 | int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble); | ||
1209 | int wl1271_acx_cts_protect(struct wl1271 *wl, | ||
1210 | enum acx_ctsprotect_type ctsprotect); | ||
1211 | int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats); | ||
1212 | int wl1271_acx_rate_policies(struct wl1271 *wl); | ||
1213 | int wl1271_acx_ac_cfg(struct wl1271 *wl); | ||
1214 | int wl1271_acx_tid_cfg(struct wl1271 *wl); | ||
1215 | int wl1271_acx_frag_threshold(struct wl1271 *wl); | ||
1216 | int wl1271_acx_tx_config_options(struct wl1271 *wl); | ||
1217 | int wl1271_acx_mem_cfg(struct wl1271 *wl); | ||
1218 | int wl1271_acx_init_mem_config(struct wl1271 *wl); | ||
1219 | int wl1271_acx_init_rx_interrupt(struct wl1271 *wl); | ||
1220 | |||
1221 | #endif /* __WL1271_ACX_H__ */ | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.c b/drivers/net/wireless/wl12xx/wl1271_boot.c new file mode 100644 index 000000000000..8228ef474a7e --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_boot.c | |||
@@ -0,0 +1,541 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2008-2009 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/gpio.h> | ||
25 | |||
26 | #include "wl1271_acx.h" | ||
27 | #include "wl1271_reg.h" | ||
28 | #include "wl1271_boot.h" | ||
29 | #include "wl1271_spi.h" | ||
30 | #include "wl1271_event.h" | ||
31 | |||
32 | static struct wl1271_partition_set part_table[PART_TABLE_LEN] = { | ||
33 | [PART_DOWN] = { | ||
34 | .mem = { | ||
35 | .start = 0x00000000, | ||
36 | .size = 0x000177c0 | ||
37 | }, | ||
38 | .reg = { | ||
39 | .start = REGISTERS_BASE, | ||
40 | .size = 0x00008800 | ||
41 | }, | ||
42 | }, | ||
43 | |||
44 | [PART_WORK] = { | ||
45 | .mem = { | ||
46 | .start = 0x00040000, | ||
47 | .size = 0x00014fc0 | ||
48 | }, | ||
49 | .reg = { | ||
50 | .start = REGISTERS_BASE, | ||
51 | .size = 0x0000b000 | ||
52 | }, | ||
53 | }, | ||
54 | |||
55 | [PART_DRPW] = { | ||
56 | .mem = { | ||
57 | .start = 0x00040000, | ||
58 | .size = 0x00014fc0 | ||
59 | }, | ||
60 | .reg = { | ||
61 | .start = DRPW_BASE, | ||
62 | .size = 0x00006000 | ||
63 | } | ||
64 | } | ||
65 | }; | ||
66 | |||
67 | static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag) | ||
68 | { | ||
69 | u32 cpu_ctrl; | ||
70 | |||
71 | /* 10.5.0 run the firmware (I) */ | ||
72 | cpu_ctrl = wl1271_reg_read32(wl, ACX_REG_ECPU_CONTROL); | ||
73 | |||
74 | /* 10.5.1 run the firmware (II) */ | ||
75 | cpu_ctrl |= flag; | ||
76 | wl1271_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl); | ||
77 | } | ||
78 | |||
79 | static void wl1271_boot_fw_version(struct wl1271 *wl) | ||
80 | { | ||
81 | struct wl1271_static_data static_data; | ||
82 | |||
83 | wl1271_spi_mem_read(wl, wl->cmd_box_addr, | ||
84 | &static_data, sizeof(static_data)); | ||
85 | |||
86 | strncpy(wl->chip.fw_ver, static_data.fw_version, | ||
87 | sizeof(wl->chip.fw_ver)); | ||
88 | |||
89 | /* make sure the string is NULL-terminated */ | ||
90 | wl->chip.fw_ver[sizeof(wl->chip.fw_ver) - 1] = '\0'; | ||
91 | } | ||
92 | |||
93 | static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, | ||
94 | size_t fw_data_len, u32 dest) | ||
95 | { | ||
96 | int addr, chunk_num, partition_limit; | ||
97 | u8 *p; | ||
98 | |||
99 | /* whal_FwCtrl_LoadFwImageSm() */ | ||
100 | |||
101 | wl1271_debug(DEBUG_BOOT, "starting firmware upload"); | ||
102 | |||
103 | wl1271_debug(DEBUG_BOOT, "fw_data_len %zd chunk_size %d", | ||
104 | fw_data_len, CHUNK_SIZE); | ||
105 | |||
106 | |||
107 | if ((fw_data_len % 4) != 0) { | ||
108 | wl1271_error("firmware length not multiple of four"); | ||
109 | return -EIO; | ||
110 | } | ||
111 | |||
112 | wl1271_set_partition(wl, dest, | ||
113 | part_table[PART_DOWN].mem.size, | ||
114 | part_table[PART_DOWN].reg.start, | ||
115 | part_table[PART_DOWN].reg.size); | ||
116 | |||
117 | /* 10.1 set partition limit and chunk num */ | ||
118 | chunk_num = 0; | ||
119 | partition_limit = part_table[PART_DOWN].mem.size; | ||
120 | |||
121 | while (chunk_num < fw_data_len / CHUNK_SIZE) { | ||
122 | /* 10.2 update partition, if needed */ | ||
123 | addr = dest + (chunk_num + 2) * CHUNK_SIZE; | ||
124 | if (addr > partition_limit) { | ||
125 | addr = dest + chunk_num * CHUNK_SIZE; | ||
126 | partition_limit = chunk_num * CHUNK_SIZE + | ||
127 | part_table[PART_DOWN].mem.size; | ||
128 | |||
129 | /* FIXME: Over 80 chars! */ | ||
130 | wl1271_set_partition(wl, | ||
131 | addr, | ||
132 | part_table[PART_DOWN].mem.size, | ||
133 | part_table[PART_DOWN].reg.start, | ||
134 | part_table[PART_DOWN].reg.size); | ||
135 | } | ||
136 | |||
137 | /* 10.3 upload the chunk */ | ||
138 | addr = dest + chunk_num * CHUNK_SIZE; | ||
139 | p = buf + chunk_num * CHUNK_SIZE; | ||
140 | wl1271_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x", | ||
141 | p, addr); | ||
142 | wl1271_spi_mem_write(wl, addr, p, CHUNK_SIZE); | ||
143 | |||
144 | chunk_num++; | ||
145 | } | ||
146 | |||
147 | /* 10.4 upload the last chunk */ | ||
148 | addr = dest + chunk_num * CHUNK_SIZE; | ||
149 | p = buf + chunk_num * CHUNK_SIZE; | ||
150 | wl1271_debug(DEBUG_BOOT, "uploading fw last chunk (%zd B) 0x%p to 0x%x", | ||
151 | fw_data_len % CHUNK_SIZE, p, addr); | ||
152 | wl1271_spi_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE); | ||
153 | |||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | static int wl1271_boot_upload_firmware(struct wl1271 *wl) | ||
158 | { | ||
159 | u32 chunks, addr, len; | ||
160 | u8 *fw; | ||
161 | |||
162 | fw = wl->fw; | ||
163 | chunks = be32_to_cpup((u32 *) fw); | ||
164 | fw += sizeof(u32); | ||
165 | |||
166 | wl1271_debug(DEBUG_BOOT, "firmware chunks to be uploaded: %u", chunks); | ||
167 | |||
168 | while (chunks--) { | ||
169 | addr = be32_to_cpup((u32 *) fw); | ||
170 | fw += sizeof(u32); | ||
171 | len = be32_to_cpup((u32 *) fw); | ||
172 | fw += sizeof(u32); | ||
173 | |||
174 | if (len > 300000) { | ||
175 | wl1271_info("firmware chunk too long: %u", len); | ||
176 | return -EINVAL; | ||
177 | } | ||
178 | wl1271_debug(DEBUG_BOOT, "chunk %d addr 0x%x len %u", | ||
179 | chunks, addr, len); | ||
180 | wl1271_boot_upload_firmware_chunk(wl, fw, len, addr); | ||
181 | fw += len; | ||
182 | } | ||
183 | |||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | static int wl1271_boot_upload_nvs(struct wl1271 *wl) | ||
188 | { | ||
189 | size_t nvs_len, burst_len; | ||
190 | int i; | ||
191 | u32 dest_addr, val; | ||
192 | u8 *nvs_ptr, *nvs, *nvs_aligned; | ||
193 | |||
194 | nvs = wl->nvs; | ||
195 | if (nvs == NULL) | ||
196 | return -ENODEV; | ||
197 | |||
198 | nvs_ptr = nvs; | ||
199 | |||
200 | nvs_len = wl->nvs_len; | ||
201 | |||
202 | /* Update the device MAC address into the nvs */ | ||
203 | nvs[11] = wl->mac_addr[0]; | ||
204 | nvs[10] = wl->mac_addr[1]; | ||
205 | nvs[6] = wl->mac_addr[2]; | ||
206 | nvs[5] = wl->mac_addr[3]; | ||
207 | nvs[4] = wl->mac_addr[4]; | ||
208 | nvs[3] = wl->mac_addr[5]; | ||
209 | |||
210 | /* | ||
211 | * Layout before the actual NVS tables: | ||
212 | * 1 byte : burst length. | ||
213 | * 2 bytes: destination address. | ||
214 | * n bytes: data to burst copy. | ||
215 | * | ||
216 | * This is ended by a 0 length, then the NVS tables. | ||
217 | */ | ||
218 | |||
219 | /* FIXME: Do we need to check here whether the LSB is 1? */ | ||
220 | while (nvs_ptr[0]) { | ||
221 | burst_len = nvs_ptr[0]; | ||
222 | dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8)); | ||
223 | |||
224 | /* FIXME: Due to our new wl1271_translate_reg_addr function, | ||
225 | we need to add the REGISTER_BASE to the destination */ | ||
226 | dest_addr += REGISTERS_BASE; | ||
227 | |||
228 | /* We move our pointer to the data */ | ||
229 | nvs_ptr += 3; | ||
230 | |||
231 | for (i = 0; i < burst_len; i++) { | ||
232 | val = (nvs_ptr[0] | (nvs_ptr[1] << 8) | ||
233 | | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); | ||
234 | |||
235 | wl1271_debug(DEBUG_BOOT, | ||
236 | "nvs burst write 0x%x: 0x%x", | ||
237 | dest_addr, val); | ||
238 | wl1271_reg_write32(wl, dest_addr, val); | ||
239 | |||
240 | nvs_ptr += 4; | ||
241 | dest_addr += 4; | ||
242 | } | ||
243 | } | ||
244 | |||
245 | /* | ||
246 | * We've reached the first zero length, the first NVS table | ||
247 | * is 7 bytes further. | ||
248 | */ | ||
249 | nvs_ptr += 7; | ||
250 | nvs_len -= nvs_ptr - nvs; | ||
251 | nvs_len = ALIGN(nvs_len, 4); | ||
252 | |||
253 | /* FIXME: The driver sets the partition here, but this is not needed, | ||
254 | since it sets to the same one as currently in use */ | ||
255 | /* Now we must set the partition correctly */ | ||
256 | wl1271_set_partition(wl, | ||
257 | part_table[PART_WORK].mem.start, | ||
258 | part_table[PART_WORK].mem.size, | ||
259 | part_table[PART_WORK].reg.start, | ||
260 | part_table[PART_WORK].reg.size); | ||
261 | |||
262 | /* Copy the NVS tables to a new block to ensure alignment */ | ||
263 | nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL); | ||
264 | |||
265 | /* And finally we upload the NVS tables */ | ||
266 | /* FIXME: In wl1271, we upload everything at once. | ||
267 | No endianness handling needed here?! The ref driver doesn't do | ||
268 | anything about it at this point */ | ||
269 | wl1271_spi_mem_write(wl, CMD_MBOX_ADDRESS, nvs_aligned, nvs_len); | ||
270 | |||
271 | kfree(nvs_aligned); | ||
272 | return 0; | ||
273 | } | ||
274 | |||
275 | static void wl1271_boot_enable_interrupts(struct wl1271 *wl) | ||
276 | { | ||
277 | enable_irq(wl->irq); | ||
278 | wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, | ||
279 | WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK)); | ||
280 | wl1271_reg_write32(wl, HI_CFG, HI_CFG_DEF_VAL); | ||
281 | } | ||
282 | |||
283 | static int wl1271_boot_soft_reset(struct wl1271 *wl) | ||
284 | { | ||
285 | unsigned long timeout; | ||
286 | u32 boot_data; | ||
287 | |||
288 | /* perform soft reset */ | ||
289 | wl1271_reg_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT); | ||
290 | |||
291 | /* SOFT_RESET is self clearing */ | ||
292 | timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME); | ||
293 | while (1) { | ||
294 | boot_data = wl1271_reg_read32(wl, ACX_REG_SLV_SOFT_RESET); | ||
295 | wl1271_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data); | ||
296 | if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0) | ||
297 | break; | ||
298 | |||
299 | if (time_after(jiffies, timeout)) { | ||
300 | /* 1.2 check pWhalBus->uSelfClearTime if the | ||
301 | * timeout was reached */ | ||
302 | wl1271_error("soft reset timeout"); | ||
303 | return -1; | ||
304 | } | ||
305 | |||
306 | udelay(SOFT_RESET_STALL_TIME); | ||
307 | } | ||
308 | |||
309 | /* disable Rx/Tx */ | ||
310 | wl1271_reg_write32(wl, ENABLE, 0x0); | ||
311 | |||
312 | /* disable auto calibration on start*/ | ||
313 | wl1271_reg_write32(wl, SPARE_A2, 0xffff); | ||
314 | |||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | static int wl1271_boot_run_firmware(struct wl1271 *wl) | ||
319 | { | ||
320 | int loop, ret; | ||
321 | u32 chip_id, interrupt; | ||
322 | |||
323 | wl1271_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT); | ||
324 | |||
325 | chip_id = wl1271_reg_read32(wl, CHIP_ID_B); | ||
326 | |||
327 | wl1271_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id); | ||
328 | |||
329 | if (chip_id != wl->chip.id) { | ||
330 | wl1271_error("chip id doesn't match after firmware boot"); | ||
331 | return -EIO; | ||
332 | } | ||
333 | |||
334 | /* wait for init to complete */ | ||
335 | loop = 0; | ||
336 | while (loop++ < INIT_LOOP) { | ||
337 | udelay(INIT_LOOP_DELAY); | ||
338 | interrupt = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); | ||
339 | |||
340 | if (interrupt == 0xffffffff) { | ||
341 | wl1271_error("error reading hardware complete " | ||
342 | "init indication"); | ||
343 | return -EIO; | ||
344 | } | ||
345 | /* check that ACX_INTR_INIT_COMPLETE is enabled */ | ||
346 | else if (interrupt & WL1271_ACX_INTR_INIT_COMPLETE) { | ||
347 | wl1271_reg_write32(wl, ACX_REG_INTERRUPT_ACK, | ||
348 | WL1271_ACX_INTR_INIT_COMPLETE); | ||
349 | break; | ||
350 | } | ||
351 | } | ||
352 | |||
353 | if (loop >= INIT_LOOP) { | ||
354 | wl1271_error("timeout waiting for the hardware to " | ||
355 | "complete initialization"); | ||
356 | return -EIO; | ||
357 | } | ||
358 | |||
359 | /* get hardware config command mail box */ | ||
360 | wl->cmd_box_addr = wl1271_reg_read32(wl, REG_COMMAND_MAILBOX_PTR); | ||
361 | |||
362 | /* get hardware config event mail box */ | ||
363 | wl->event_box_addr = wl1271_reg_read32(wl, REG_EVENT_MAILBOX_PTR); | ||
364 | |||
365 | /* set the working partition to its "running" mode offset */ | ||
366 | wl1271_set_partition(wl, | ||
367 | part_table[PART_WORK].mem.start, | ||
368 | part_table[PART_WORK].mem.size, | ||
369 | part_table[PART_WORK].reg.start, | ||
370 | part_table[PART_WORK].reg.size); | ||
371 | |||
372 | wl1271_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x", | ||
373 | wl->cmd_box_addr, wl->event_box_addr); | ||
374 | |||
375 | wl1271_boot_fw_version(wl); | ||
376 | |||
377 | /* | ||
378 | * in case of full asynchronous mode the firmware event must be | ||
379 | * ready to receive event from the command mailbox | ||
380 | */ | ||
381 | |||
382 | /* enable gpio interrupts */ | ||
383 | wl1271_boot_enable_interrupts(wl); | ||
384 | |||
385 | /* unmask all mbox events */ | ||
386 | wl->event_mask = 0xffffffff; | ||
387 | |||
388 | ret = wl1271_event_unmask(wl); | ||
389 | if (ret < 0) { | ||
390 | wl1271_error("EVENT mask setting failed"); | ||
391 | return ret; | ||
392 | } | ||
393 | |||
394 | wl1271_event_mbox_config(wl); | ||
395 | |||
396 | /* firmware startup completed */ | ||
397 | return 0; | ||
398 | } | ||
399 | |||
400 | static int wl1271_boot_write_irq_polarity(struct wl1271 *wl) | ||
401 | { | ||
402 | u32 polarity, status, i; | ||
403 | |||
404 | wl1271_reg_write32(wl, OCP_POR_CTR, OCP_REG_POLARITY); | ||
405 | wl1271_reg_write32(wl, OCP_CMD, OCP_CMD_READ); | ||
406 | |||
407 | /* Wait until the command is complete (ie. bit 18 is set) */ | ||
408 | for (i = 0; i < OCP_CMD_LOOP; i++) { | ||
409 | polarity = wl1271_reg_read32(wl, OCP_DATA_READ); | ||
410 | if (polarity & OCP_READY_MASK) | ||
411 | break; | ||
412 | } | ||
413 | if (i == OCP_CMD_LOOP) { | ||
414 | wl1271_error("OCP command timeout!"); | ||
415 | return -EIO; | ||
416 | } | ||
417 | |||
418 | status = polarity & OCP_STATUS_MASK; | ||
419 | if (status != OCP_STATUS_OK) { | ||
420 | wl1271_error("OCP command failed (%d)", status); | ||
421 | return -EIO; | ||
422 | } | ||
423 | |||
424 | /* We use HIGH polarity, so unset the LOW bit */ | ||
425 | polarity &= ~POLARITY_LOW; | ||
426 | |||
427 | wl1271_reg_write32(wl, OCP_POR_CTR, OCP_REG_POLARITY); | ||
428 | wl1271_reg_write32(wl, OCP_DATA_WRITE, polarity); | ||
429 | wl1271_reg_write32(wl, OCP_CMD, OCP_CMD_WRITE); | ||
430 | |||
431 | return 0; | ||
432 | } | ||
433 | |||
434 | int wl1271_boot(struct wl1271 *wl) | ||
435 | { | ||
436 | int ret = 0; | ||
437 | u32 tmp, clk, pause; | ||
438 | |||
439 | if (REF_CLOCK == 0 || REF_CLOCK == 2) | ||
440 | /* ref clk: 19.2/38.4 */ | ||
441 | clk = 0x3; | ||
442 | else if (REF_CLOCK == 1 || REF_CLOCK == 3) | ||
443 | /* ref clk: 26/52 */ | ||
444 | clk = 0x5; | ||
445 | |||
446 | wl1271_reg_write32(wl, PLL_PARAMETERS, clk); | ||
447 | |||
448 | pause = wl1271_reg_read32(wl, PLL_PARAMETERS); | ||
449 | |||
450 | wl1271_debug(DEBUG_BOOT, "pause1 0x%x", pause); | ||
451 | |||
452 | pause &= ~(WU_COUNTER_PAUSE_VAL); /* FIXME: This should probably be | ||
453 | * WU_COUNTER_PAUSE_VAL instead of | ||
454 | * 0x3ff (magic number ). How does | ||
455 | * this work?! */ | ||
456 | pause |= WU_COUNTER_PAUSE_VAL; | ||
457 | wl1271_reg_write32(wl, WU_COUNTER_PAUSE, pause); | ||
458 | |||
459 | /* Continue the ELP wake up sequence */ | ||
460 | wl1271_reg_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL); | ||
461 | udelay(500); | ||
462 | |||
463 | wl1271_set_partition(wl, | ||
464 | part_table[PART_DRPW].mem.start, | ||
465 | part_table[PART_DRPW].mem.size, | ||
466 | part_table[PART_DRPW].reg.start, | ||
467 | part_table[PART_DRPW].reg.size); | ||
468 | |||
469 | /* Read-modify-write DRPW_SCRATCH_START register (see next state) | ||
470 | to be used by DRPw FW. The RTRIM value will be added by the FW | ||
471 | before taking DRPw out of reset */ | ||
472 | |||
473 | wl1271_debug(DEBUG_BOOT, "DRPW_SCRATCH_START %08x", DRPW_SCRATCH_START); | ||
474 | clk = wl1271_reg_read32(wl, DRPW_SCRATCH_START); | ||
475 | |||
476 | wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk); | ||
477 | |||
478 | /* 2 */ | ||
479 | clk |= (REF_CLOCK << 1) << 4; | ||
480 | wl1271_reg_write32(wl, DRPW_SCRATCH_START, clk); | ||
481 | |||
482 | wl1271_set_partition(wl, | ||
483 | part_table[PART_WORK].mem.start, | ||
484 | part_table[PART_WORK].mem.size, | ||
485 | part_table[PART_WORK].reg.start, | ||
486 | part_table[PART_WORK].reg.size); | ||
487 | |||
488 | /* Disable interrupts */ | ||
489 | wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL); | ||
490 | |||
491 | ret = wl1271_boot_soft_reset(wl); | ||
492 | if (ret < 0) | ||
493 | goto out; | ||
494 | |||
495 | /* 2. start processing NVS file */ | ||
496 | ret = wl1271_boot_upload_nvs(wl); | ||
497 | if (ret < 0) | ||
498 | goto out; | ||
499 | |||
500 | /* write firmware's last address (ie. it's length) to | ||
501 | * ACX_EEPROMLESS_IND_REG */ | ||
502 | wl1271_debug(DEBUG_BOOT, "ACX_EEPROMLESS_IND_REG"); | ||
503 | |||
504 | wl1271_reg_write32(wl, ACX_EEPROMLESS_IND_REG, ACX_EEPROMLESS_IND_REG); | ||
505 | |||
506 | tmp = wl1271_reg_read32(wl, CHIP_ID_B); | ||
507 | |||
508 | wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp); | ||
509 | |||
510 | /* 6. read the EEPROM parameters */ | ||
511 | tmp = wl1271_reg_read32(wl, SCR_PAD2); | ||
512 | |||
513 | ret = wl1271_boot_write_irq_polarity(wl); | ||
514 | if (ret < 0) | ||
515 | goto out; | ||
516 | |||
517 | /* FIXME: Need to check whether this is really what we want */ | ||
518 | wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, | ||
519 | WL1271_ACX_ALL_EVENTS_VECTOR); | ||
520 | |||
521 | /* WL1271: The reference driver skips steps 7 to 10 (jumps directly | ||
522 | * to upload_fw) */ | ||
523 | |||
524 | ret = wl1271_boot_upload_firmware(wl); | ||
525 | if (ret < 0) | ||
526 | goto out; | ||
527 | |||
528 | /* 10.5 start firmware */ | ||
529 | ret = wl1271_boot_run_firmware(wl); | ||
530 | if (ret < 0) | ||
531 | goto out; | ||
532 | |||
533 | /* set the wl1271 default filters */ | ||
534 | wl->rx_config = WL1271_DEFAULT_RX_CONFIG; | ||
535 | wl->rx_filter = WL1271_DEFAULT_RX_FILTER; | ||
536 | |||
537 | wl1271_event_mbox_config(wl); | ||
538 | |||
539 | out: | ||
540 | return ret; | ||
541 | } | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.h b/drivers/net/wireless/wl12xx/wl1271_boot.h new file mode 100644 index 000000000000..b0d8fb46a439 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_boot.h | |||
@@ -0,0 +1,72 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2008-2009 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifndef __BOOT_H__ | ||
25 | #define __BOOT_H__ | ||
26 | |||
27 | #include "wl1271.h" | ||
28 | |||
29 | int wl1271_boot(struct wl1271 *wl); | ||
30 | |||
31 | #define WL1271_NO_SUBBANDS 8 | ||
32 | #define WL1271_NO_POWER_LEVELS 4 | ||
33 | #define WL1271_FW_VERSION_MAX_LEN 20 | ||
34 | |||
35 | struct wl1271_static_data { | ||
36 | u8 mac_address[ETH_ALEN]; | ||
37 | u8 padding[2]; | ||
38 | u8 fw_version[WL1271_FW_VERSION_MAX_LEN]; | ||
39 | u32 hw_version; | ||
40 | u8 tx_power_table[WL1271_NO_SUBBANDS][WL1271_NO_POWER_LEVELS]; | ||
41 | }; | ||
42 | |||
43 | /* number of times we try to read the INIT interrupt */ | ||
44 | #define INIT_LOOP 20000 | ||
45 | |||
46 | /* delay between retries */ | ||
47 | #define INIT_LOOP_DELAY 50 | ||
48 | |||
49 | #define REF_CLOCK 2 | ||
50 | #define WU_COUNTER_PAUSE_VAL 0x3FF | ||
51 | #define WELP_ARM_COMMAND_VAL 0x4 | ||
52 | |||
53 | #define OCP_CMD_LOOP 32 | ||
54 | |||
55 | #define OCP_CMD_WRITE 0x1 | ||
56 | #define OCP_CMD_READ 0x2 | ||
57 | |||
58 | #define OCP_READY_MASK BIT(18) | ||
59 | #define OCP_STATUS_MASK (BIT(16) | BIT(17)) | ||
60 | |||
61 | #define OCP_STATUS_NO_RESP 0x00000 | ||
62 | #define OCP_STATUS_OK 0x10000 | ||
63 | #define OCP_STATUS_REQ_FAILED 0x20000 | ||
64 | #define OCP_STATUS_RESP_ERROR 0x30000 | ||
65 | |||
66 | #define OCP_REG_POLARITY 0x30032 | ||
67 | |||
68 | #define CMD_MBOX_ADDRESS 0x407B4 | ||
69 | |||
70 | #define POLARITY_LOW BIT(1) | ||
71 | |||
72 | #endif | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c new file mode 100644 index 000000000000..2a4351ff54dc --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c | |||
@@ -0,0 +1,813 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2009 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/module.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | #include <linux/crc7.h> | ||
27 | #include <linux/spi/spi.h> | ||
28 | #include <linux/etherdevice.h> | ||
29 | |||
30 | #include "wl1271.h" | ||
31 | #include "wl1271_reg.h" | ||
32 | #include "wl1271_spi.h" | ||
33 | #include "wl1271_acx.h" | ||
34 | #include "wl12xx_80211.h" | ||
35 | #include "wl1271_cmd.h" | ||
36 | |||
37 | /* | ||
38 | * send command to firmware | ||
39 | * | ||
40 | * @wl: wl struct | ||
41 | * @id: command id | ||
42 | * @buf: buffer containing the command, must work with dma | ||
43 | * @len: length of the buffer | ||
44 | */ | ||
45 | int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len) | ||
46 | { | ||
47 | struct wl1271_cmd_header *cmd; | ||
48 | unsigned long timeout; | ||
49 | u32 intr; | ||
50 | int ret = 0; | ||
51 | |||
52 | cmd = buf; | ||
53 | cmd->id = id; | ||
54 | cmd->status = 0; | ||
55 | |||
56 | WARN_ON(len % 4 != 0); | ||
57 | |||
58 | wl1271_spi_mem_write(wl, wl->cmd_box_addr, buf, len); | ||
59 | |||
60 | wl1271_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); | ||
61 | |||
62 | timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT); | ||
63 | |||
64 | intr = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); | ||
65 | while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) { | ||
66 | if (time_after(jiffies, timeout)) { | ||
67 | wl1271_error("command complete timeout"); | ||
68 | ret = -ETIMEDOUT; | ||
69 | goto out; | ||
70 | } | ||
71 | |||
72 | msleep(1); | ||
73 | |||
74 | intr = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); | ||
75 | } | ||
76 | |||
77 | wl1271_reg_write32(wl, ACX_REG_INTERRUPT_ACK, | ||
78 | WL1271_ACX_INTR_CMD_COMPLETE); | ||
79 | |||
80 | out: | ||
81 | return ret; | ||
82 | } | ||
83 | |||
84 | int wl1271_cmd_cal_channel_tune(struct wl1271 *wl) | ||
85 | { | ||
86 | struct wl1271_cmd_cal_channel_tune *cmd; | ||
87 | int ret = 0; | ||
88 | |||
89 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
90 | if (!cmd) | ||
91 | return -ENOMEM; | ||
92 | |||
93 | cmd->test.id = TEST_CMD_CHANNEL_TUNE; | ||
94 | |||
95 | cmd->band = WL1271_CHANNEL_TUNE_BAND_2_4; | ||
96 | /* set up any channel, 7 is in the middle of the range */ | ||
97 | cmd->channel = 7; | ||
98 | |||
99 | ret = wl1271_cmd_test(wl, cmd, sizeof(*cmd), 0); | ||
100 | if (ret < 0) | ||
101 | wl1271_warning("TEST_CMD_CHANNEL_TUNE failed"); | ||
102 | |||
103 | kfree(cmd); | ||
104 | return ret; | ||
105 | } | ||
106 | |||
107 | int wl1271_cmd_cal_update_ref_point(struct wl1271 *wl) | ||
108 | { | ||
109 | struct wl1271_cmd_cal_update_ref_point *cmd; | ||
110 | int ret = 0; | ||
111 | |||
112 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
113 | if (!cmd) | ||
114 | return -ENOMEM; | ||
115 | |||
116 | cmd->test.id = TEST_CMD_UPDATE_PD_REFERENCE_POINT; | ||
117 | |||
118 | /* FIXME: still waiting for the correct values */ | ||
119 | cmd->ref_power = 0; | ||
120 | cmd->ref_detector = 0; | ||
121 | |||
122 | cmd->sub_band = WL1271_PD_REFERENCE_POINT_BAND_B_G; | ||
123 | |||
124 | ret = wl1271_cmd_test(wl, cmd, sizeof(*cmd), 0); | ||
125 | if (ret < 0) | ||
126 | wl1271_warning("TEST_CMD_UPDATE_PD_REFERENCE_POINT failed"); | ||
127 | |||
128 | kfree(cmd); | ||
129 | return ret; | ||
130 | } | ||
131 | |||
132 | int wl1271_cmd_cal_p2g(struct wl1271 *wl) | ||
133 | { | ||
134 | struct wl1271_cmd_cal_p2g *cmd; | ||
135 | int ret = 0; | ||
136 | |||
137 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
138 | if (!cmd) | ||
139 | return -ENOMEM; | ||
140 | |||
141 | cmd->test.id = TEST_CMD_P2G_CAL; | ||
142 | |||
143 | cmd->sub_band_mask = WL1271_CAL_P2G_BAND_B_G; | ||
144 | |||
145 | ret = wl1271_cmd_test(wl, cmd, sizeof(*cmd), 0); | ||
146 | if (ret < 0) | ||
147 | wl1271_warning("TEST_CMD_P2G_CAL failed"); | ||
148 | |||
149 | kfree(cmd); | ||
150 | return ret; | ||
151 | } | ||
152 | |||
153 | int wl1271_cmd_cal(struct wl1271 *wl) | ||
154 | { | ||
155 | /* | ||
156 | * FIXME: we must make sure that we're not sleeping when calibration | ||
157 | * is done | ||
158 | */ | ||
159 | int ret; | ||
160 | |||
161 | wl1271_notice("performing tx calibration"); | ||
162 | |||
163 | ret = wl1271_cmd_cal_channel_tune(wl); | ||
164 | if (ret < 0) | ||
165 | return ret; | ||
166 | |||
167 | ret = wl1271_cmd_cal_update_ref_point(wl); | ||
168 | if (ret < 0) | ||
169 | return ret; | ||
170 | |||
171 | ret = wl1271_cmd_cal_p2g(wl); | ||
172 | if (ret < 0) | ||
173 | return ret; | ||
174 | |||
175 | return ret; | ||
176 | } | ||
177 | |||
178 | int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type, u8 dtim_interval, | ||
179 | u16 beacon_interval, u8 wait) | ||
180 | { | ||
181 | static bool do_cal = true; | ||
182 | unsigned long timeout; | ||
183 | struct wl1271_cmd_join *join; | ||
184 | int ret, i; | ||
185 | u8 *bssid; | ||
186 | |||
187 | /* FIXME: remove when we get calibration from the factory */ | ||
188 | if (do_cal) { | ||
189 | ret = wl1271_cmd_cal(wl); | ||
190 | if (ret < 0) | ||
191 | wl1271_warning("couldn't calibrate"); | ||
192 | else | ||
193 | do_cal = false; | ||
194 | } | ||
195 | |||
196 | |||
197 | join = kzalloc(sizeof(*join), GFP_KERNEL); | ||
198 | if (!join) { | ||
199 | ret = -ENOMEM; | ||
200 | goto out; | ||
201 | } | ||
202 | |||
203 | wl1271_debug(DEBUG_CMD, "cmd join"); | ||
204 | |||
205 | /* Reverse order BSSID */ | ||
206 | bssid = (u8 *) &join->bssid_lsb; | ||
207 | for (i = 0; i < ETH_ALEN; i++) | ||
208 | bssid[i] = wl->bssid[ETH_ALEN - i - 1]; | ||
209 | |||
210 | join->rx_config_options = wl->rx_config; | ||
211 | join->rx_filter_options = wl->rx_filter; | ||
212 | |||
213 | join->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS | | ||
214 | RATE_MASK_5_5MBPS | RATE_MASK_11MBPS; | ||
215 | |||
216 | join->beacon_interval = beacon_interval; | ||
217 | join->dtim_interval = dtim_interval; | ||
218 | join->bss_type = bss_type; | ||
219 | join->channel = wl->channel; | ||
220 | join->ssid_len = wl->ssid_len; | ||
221 | memcpy(join->ssid, wl->ssid, wl->ssid_len); | ||
222 | join->ctrl = WL1271_JOIN_CMD_CTRL_TX_FLUSH; | ||
223 | |||
224 | /* increment the session counter */ | ||
225 | wl->session_counter++; | ||
226 | if (wl->session_counter >= SESSION_COUNTER_MAX) | ||
227 | wl->session_counter = 0; | ||
228 | |||
229 | join->ctrl |= wl->session_counter << WL1271_JOIN_CMD_TX_SESSION_OFFSET; | ||
230 | |||
231 | |||
232 | ret = wl1271_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join)); | ||
233 | if (ret < 0) { | ||
234 | wl1271_error("failed to initiate cmd join"); | ||
235 | goto out_free; | ||
236 | } | ||
237 | |||
238 | timeout = msecs_to_jiffies(JOIN_TIMEOUT); | ||
239 | |||
240 | /* | ||
241 | * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to | ||
242 | * simplify locking we just sleep instead, for now | ||
243 | */ | ||
244 | if (wait) | ||
245 | msleep(10); | ||
246 | |||
247 | out_free: | ||
248 | kfree(join); | ||
249 | |||
250 | out: | ||
251 | return ret; | ||
252 | } | ||
253 | |||
254 | /** | ||
255 | * send test command to firmware | ||
256 | * | ||
257 | * @wl: wl struct | ||
258 | * @buf: buffer containing the command, with all headers, must work with dma | ||
259 | * @len: length of the buffer | ||
260 | * @answer: is answer needed | ||
261 | */ | ||
262 | int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer) | ||
263 | { | ||
264 | int ret; | ||
265 | |||
266 | wl1271_debug(DEBUG_CMD, "cmd test"); | ||
267 | |||
268 | ret = wl1271_cmd_send(wl, CMD_TEST, buf, buf_len); | ||
269 | |||
270 | if (ret < 0) { | ||
271 | wl1271_warning("TEST command failed"); | ||
272 | return ret; | ||
273 | } | ||
274 | |||
275 | if (answer) { | ||
276 | struct wl1271_command *cmd_answer; | ||
277 | |||
278 | /* | ||
279 | * The test command got in, we can read the answer. | ||
280 | * The answer would be a wl1271_command, where the | ||
281 | * parameter array contains the actual answer. | ||
282 | */ | ||
283 | wl1271_spi_mem_read(wl, wl->cmd_box_addr, buf, buf_len); | ||
284 | |||
285 | cmd_answer = buf; | ||
286 | |||
287 | if (cmd_answer->header.status != CMD_STATUS_SUCCESS) | ||
288 | wl1271_error("TEST command answer error: %d", | ||
289 | cmd_answer->header.status); | ||
290 | } | ||
291 | |||
292 | return 0; | ||
293 | } | ||
294 | |||
295 | /** | ||
296 | * read acx from firmware | ||
297 | * | ||
298 | * @wl: wl struct | ||
299 | * @id: acx id | ||
300 | * @buf: buffer for the response, including all headers, must work with dma | ||
301 | * @len: lenght of buf | ||
302 | */ | ||
303 | int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len) | ||
304 | { | ||
305 | struct acx_header *acx = buf; | ||
306 | int ret; | ||
307 | |||
308 | wl1271_debug(DEBUG_CMD, "cmd interrogate"); | ||
309 | |||
310 | acx->id = id; | ||
311 | |||
312 | /* payload length, does not include any headers */ | ||
313 | acx->len = len - sizeof(*acx); | ||
314 | |||
315 | ret = wl1271_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx)); | ||
316 | if (ret < 0) { | ||
317 | wl1271_error("INTERROGATE command failed"); | ||
318 | goto out; | ||
319 | } | ||
320 | |||
321 | /* the interrogate command got in, we can read the answer */ | ||
322 | wl1271_spi_mem_read(wl, wl->cmd_box_addr, buf, len); | ||
323 | |||
324 | acx = buf; | ||
325 | if (acx->cmd.status != CMD_STATUS_SUCCESS) | ||
326 | wl1271_error("INTERROGATE command error: %d", | ||
327 | acx->cmd.status); | ||
328 | |||
329 | out: | ||
330 | return ret; | ||
331 | } | ||
332 | |||
333 | /** | ||
334 | * write acx value to firmware | ||
335 | * | ||
336 | * @wl: wl struct | ||
337 | * @id: acx id | ||
338 | * @buf: buffer containing acx, including all headers, must work with dma | ||
339 | * @len: length of buf | ||
340 | */ | ||
341 | int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len) | ||
342 | { | ||
343 | struct acx_header *acx = buf; | ||
344 | int ret; | ||
345 | |||
346 | wl1271_debug(DEBUG_CMD, "cmd configure"); | ||
347 | |||
348 | acx->id = id; | ||
349 | |||
350 | /* payload length, does not include any headers */ | ||
351 | acx->len = len - sizeof(*acx); | ||
352 | |||
353 | ret = wl1271_cmd_send(wl, CMD_CONFIGURE, acx, len); | ||
354 | if (ret < 0) { | ||
355 | wl1271_warning("CONFIGURE command NOK"); | ||
356 | return ret; | ||
357 | } | ||
358 | |||
359 | return 0; | ||
360 | } | ||
361 | |||
362 | int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable) | ||
363 | { | ||
364 | struct cmd_enabledisable_path *cmd; | ||
365 | int ret; | ||
366 | u16 cmd_rx, cmd_tx; | ||
367 | |||
368 | wl1271_debug(DEBUG_CMD, "cmd data path"); | ||
369 | |||
370 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
371 | if (!cmd) { | ||
372 | ret = -ENOMEM; | ||
373 | goto out; | ||
374 | } | ||
375 | |||
376 | cmd->channel = channel; | ||
377 | |||
378 | if (enable) { | ||
379 | cmd_rx = CMD_ENABLE_RX; | ||
380 | cmd_tx = CMD_ENABLE_TX; | ||
381 | } else { | ||
382 | cmd_rx = CMD_DISABLE_RX; | ||
383 | cmd_tx = CMD_DISABLE_TX; | ||
384 | } | ||
385 | |||
386 | ret = wl1271_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd)); | ||
387 | if (ret < 0) { | ||
388 | wl1271_error("rx %s cmd for channel %d failed", | ||
389 | enable ? "start" : "stop", channel); | ||
390 | goto out; | ||
391 | } | ||
392 | |||
393 | wl1271_debug(DEBUG_BOOT, "rx %s cmd channel %d", | ||
394 | enable ? "start" : "stop", channel); | ||
395 | |||
396 | ret = wl1271_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd)); | ||
397 | if (ret < 0) { | ||
398 | wl1271_error("tx %s cmd for channel %d failed", | ||
399 | enable ? "start" : "stop", channel); | ||
400 | return ret; | ||
401 | } | ||
402 | |||
403 | wl1271_debug(DEBUG_BOOT, "tx %s cmd channel %d", | ||
404 | enable ? "start" : "stop", channel); | ||
405 | |||
406 | out: | ||
407 | kfree(cmd); | ||
408 | return ret; | ||
409 | } | ||
410 | |||
411 | int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode) | ||
412 | { | ||
413 | struct wl1271_cmd_ps_params *ps_params = NULL; | ||
414 | int ret = 0; | ||
415 | |||
416 | /* FIXME: this should be in ps.c */ | ||
417 | ret = wl1271_acx_wake_up_conditions(wl, WAKE_UP_EVENT_DTIM_BITMAP, | ||
418 | wl->listen_int); | ||
419 | if (ret < 0) { | ||
420 | wl1271_error("couldn't set wake up conditions"); | ||
421 | goto out; | ||
422 | } | ||
423 | |||
424 | wl1271_debug(DEBUG_CMD, "cmd set ps mode"); | ||
425 | |||
426 | ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL); | ||
427 | if (!ps_params) { | ||
428 | ret = -ENOMEM; | ||
429 | goto out; | ||
430 | } | ||
431 | |||
432 | ps_params->ps_mode = ps_mode; | ||
433 | ps_params->send_null_data = 1; | ||
434 | ps_params->retries = 5; | ||
435 | ps_params->hang_over_period = 128; | ||
436 | ps_params->null_data_rate = 1; /* 1 Mbps */ | ||
437 | |||
438 | ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params, | ||
439 | sizeof(*ps_params)); | ||
440 | if (ret < 0) { | ||
441 | wl1271_error("cmd set_ps_mode failed"); | ||
442 | goto out; | ||
443 | } | ||
444 | |||
445 | out: | ||
446 | kfree(ps_params); | ||
447 | return ret; | ||
448 | } | ||
449 | |||
450 | int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer, | ||
451 | size_t len) | ||
452 | { | ||
453 | struct cmd_read_write_memory *cmd; | ||
454 | int ret = 0; | ||
455 | |||
456 | wl1271_debug(DEBUG_CMD, "cmd read memory"); | ||
457 | |||
458 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
459 | if (!cmd) { | ||
460 | ret = -ENOMEM; | ||
461 | goto out; | ||
462 | } | ||
463 | |||
464 | WARN_ON(len > MAX_READ_SIZE); | ||
465 | len = min_t(size_t, len, MAX_READ_SIZE); | ||
466 | |||
467 | cmd->addr = addr; | ||
468 | cmd->size = len; | ||
469 | |||
470 | ret = wl1271_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd)); | ||
471 | if (ret < 0) { | ||
472 | wl1271_error("read memory command failed: %d", ret); | ||
473 | goto out; | ||
474 | } | ||
475 | |||
476 | /* the read command got in, we can now read the answer */ | ||
477 | wl1271_spi_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd)); | ||
478 | |||
479 | if (cmd->header.status != CMD_STATUS_SUCCESS) | ||
480 | wl1271_error("error in read command result: %d", | ||
481 | cmd->header.status); | ||
482 | |||
483 | memcpy(answer, cmd->value, len); | ||
484 | |||
485 | out: | ||
486 | kfree(cmd); | ||
487 | return ret; | ||
488 | } | ||
489 | |||
490 | int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, | ||
491 | u8 active_scan, u8 high_prio, u8 num_channels, | ||
492 | u8 probe_requests) | ||
493 | { | ||
494 | |||
495 | struct wl1271_cmd_trigger_scan_to *trigger = NULL; | ||
496 | struct wl1271_cmd_scan *params = NULL; | ||
497 | int i, ret; | ||
498 | u16 scan_options = 0; | ||
499 | |||
500 | if (wl->scanning) | ||
501 | return -EINVAL; | ||
502 | |||
503 | params = kzalloc(sizeof(*params), GFP_KERNEL); | ||
504 | if (!params) | ||
505 | return -ENOMEM; | ||
506 | |||
507 | params->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD); | ||
508 | params->params.rx_filter_options = | ||
509 | cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN); | ||
510 | |||
511 | if (!active_scan) | ||
512 | scan_options |= WL1271_SCAN_OPT_PASSIVE; | ||
513 | if (high_prio) | ||
514 | scan_options |= WL1271_SCAN_OPT_PRIORITY_HIGH; | ||
515 | params->params.scan_options = scan_options; | ||
516 | |||
517 | params->params.num_channels = num_channels; | ||
518 | params->params.num_probe_requests = probe_requests; | ||
519 | params->params.tx_rate = cpu_to_le32(RATE_MASK_2MBPS); | ||
520 | params->params.tid_trigger = 0; | ||
521 | params->params.scan_tag = WL1271_SCAN_DEFAULT_TAG; | ||
522 | |||
523 | for (i = 0; i < num_channels; i++) { | ||
524 | params->channels[i].min_duration = | ||
525 | cpu_to_le32(WL1271_SCAN_CHAN_MIN_DURATION); | ||
526 | params->channels[i].max_duration = | ||
527 | cpu_to_le32(WL1271_SCAN_CHAN_MAX_DURATION); | ||
528 | memset(¶ms->channels[i].bssid_lsb, 0xff, 4); | ||
529 | memset(¶ms->channels[i].bssid_msb, 0xff, 2); | ||
530 | params->channels[i].early_termination = 0; | ||
531 | params->channels[i].tx_power_att = WL1271_SCAN_CURRENT_TX_PWR; | ||
532 | params->channels[i].channel = i + 1; | ||
533 | } | ||
534 | |||
535 | if (len && ssid) { | ||
536 | params->params.ssid_len = len; | ||
537 | memcpy(params->params.ssid, ssid, len); | ||
538 | } | ||
539 | |||
540 | ret = wl1271_cmd_build_probe_req(wl, ssid, len); | ||
541 | if (ret < 0) { | ||
542 | wl1271_error("PROBE request template failed"); | ||
543 | goto out; | ||
544 | } | ||
545 | |||
546 | trigger = kzalloc(sizeof(*trigger), GFP_KERNEL); | ||
547 | if (!trigger) { | ||
548 | ret = -ENOMEM; | ||
549 | goto out; | ||
550 | } | ||
551 | |||
552 | /* disable the timeout */ | ||
553 | trigger->timeout = 0; | ||
554 | |||
555 | ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger, | ||
556 | sizeof(*trigger)); | ||
557 | if (ret < 0) { | ||
558 | wl1271_error("trigger scan to failed for hw scan"); | ||
559 | goto out; | ||
560 | } | ||
561 | |||
562 | wl1271_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params)); | ||
563 | |||
564 | wl->scanning = true; | ||
565 | |||
566 | ret = wl1271_cmd_send(wl, CMD_SCAN, params, sizeof(*params)); | ||
567 | if (ret < 0) { | ||
568 | wl1271_error("SCAN failed"); | ||
569 | goto out; | ||
570 | } | ||
571 | |||
572 | wl1271_spi_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params)); | ||
573 | |||
574 | if (params->header.status != CMD_STATUS_SUCCESS) { | ||
575 | wl1271_error("Scan command error: %d", | ||
576 | params->header.status); | ||
577 | wl->scanning = false; | ||
578 | ret = -EIO; | ||
579 | goto out; | ||
580 | } | ||
581 | |||
582 | out: | ||
583 | kfree(params); | ||
584 | return ret; | ||
585 | } | ||
586 | |||
587 | int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, | ||
588 | void *buf, size_t buf_len) | ||
589 | { | ||
590 | struct wl1271_cmd_template_set *cmd; | ||
591 | int ret = 0; | ||
592 | |||
593 | wl1271_debug(DEBUG_CMD, "cmd template_set %d", template_id); | ||
594 | |||
595 | WARN_ON(buf_len > WL1271_CMD_TEMPL_MAX_SIZE); | ||
596 | buf_len = min_t(size_t, buf_len, WL1271_CMD_TEMPL_MAX_SIZE); | ||
597 | |||
598 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
599 | if (!cmd) { | ||
600 | ret = -ENOMEM; | ||
601 | goto out; | ||
602 | } | ||
603 | |||
604 | cmd->len = cpu_to_le16(buf_len); | ||
605 | cmd->template_type = template_id; | ||
606 | cmd->enabled_rates = ACX_RATE_MASK_UNSPECIFIED; | ||
607 | cmd->short_retry_limit = ACX_RATE_RETRY_LIMIT; | ||
608 | cmd->long_retry_limit = ACX_RATE_RETRY_LIMIT; | ||
609 | |||
610 | if (buf) | ||
611 | memcpy(cmd->template_data, buf, buf_len); | ||
612 | |||
613 | ret = wl1271_cmd_send(wl, CMD_SET_TEMPLATE, cmd, sizeof(*cmd)); | ||
614 | if (ret < 0) { | ||
615 | wl1271_warning("cmd set_template failed: %d", ret); | ||
616 | goto out_free; | ||
617 | } | ||
618 | |||
619 | out_free: | ||
620 | kfree(cmd); | ||
621 | |||
622 | out: | ||
623 | return ret; | ||
624 | } | ||
625 | |||
626 | static int wl1271_build_basic_rates(char *rates) | ||
627 | { | ||
628 | u8 index = 0; | ||
629 | |||
630 | rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB; | ||
631 | rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB; | ||
632 | rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB; | ||
633 | rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB; | ||
634 | |||
635 | return index; | ||
636 | } | ||
637 | |||
638 | static int wl1271_build_extended_rates(char *rates) | ||
639 | { | ||
640 | u8 index = 0; | ||
641 | |||
642 | rates[index++] = IEEE80211_OFDM_RATE_6MB; | ||
643 | rates[index++] = IEEE80211_OFDM_RATE_9MB; | ||
644 | rates[index++] = IEEE80211_OFDM_RATE_12MB; | ||
645 | rates[index++] = IEEE80211_OFDM_RATE_18MB; | ||
646 | rates[index++] = IEEE80211_OFDM_RATE_24MB; | ||
647 | rates[index++] = IEEE80211_OFDM_RATE_36MB; | ||
648 | rates[index++] = IEEE80211_OFDM_RATE_48MB; | ||
649 | rates[index++] = IEEE80211_OFDM_RATE_54MB; | ||
650 | |||
651 | return index; | ||
652 | } | ||
653 | |||
654 | int wl1271_cmd_build_null_data(struct wl1271 *wl) | ||
655 | { | ||
656 | struct wl12xx_null_data_template template; | ||
657 | |||
658 | if (!is_zero_ether_addr(wl->bssid)) { | ||
659 | memcpy(template.header.da, wl->bssid, ETH_ALEN); | ||
660 | memcpy(template.header.bssid, wl->bssid, ETH_ALEN); | ||
661 | } else { | ||
662 | memset(template.header.da, 0xff, ETH_ALEN); | ||
663 | memset(template.header.bssid, 0xff, ETH_ALEN); | ||
664 | } | ||
665 | |||
666 | memcpy(template.header.sa, wl->mac_addr, ETH_ALEN); | ||
667 | template.header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA | | ||
668 | IEEE80211_STYPE_NULLFUNC); | ||
669 | |||
670 | return wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, &template, | ||
671 | sizeof(template)); | ||
672 | |||
673 | } | ||
674 | |||
675 | int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid) | ||
676 | { | ||
677 | struct wl12xx_ps_poll_template template; | ||
678 | |||
679 | memcpy(template.bssid, wl->bssid, ETH_ALEN); | ||
680 | memcpy(template.ta, wl->mac_addr, ETH_ALEN); | ||
681 | template.aid = aid; | ||
682 | template.fc = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL); | ||
683 | |||
684 | return wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, &template, | ||
685 | sizeof(template)); | ||
686 | |||
687 | } | ||
688 | |||
689 | int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len) | ||
690 | { | ||
691 | struct wl12xx_probe_req_template template; | ||
692 | struct wl12xx_ie_rates *rates; | ||
693 | char *ptr; | ||
694 | u16 size; | ||
695 | |||
696 | ptr = (char *)&template; | ||
697 | size = sizeof(struct ieee80211_header); | ||
698 | |||
699 | memset(template.header.da, 0xff, ETH_ALEN); | ||
700 | memset(template.header.bssid, 0xff, ETH_ALEN); | ||
701 | memcpy(template.header.sa, wl->mac_addr, ETH_ALEN); | ||
702 | template.header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); | ||
703 | |||
704 | /* IEs */ | ||
705 | /* SSID */ | ||
706 | template.ssid.header.id = WLAN_EID_SSID; | ||
707 | template.ssid.header.len = ssid_len; | ||
708 | if (ssid_len && ssid) | ||
709 | memcpy(template.ssid.ssid, ssid, ssid_len); | ||
710 | size += sizeof(struct wl12xx_ie_header) + ssid_len; | ||
711 | ptr += size; | ||
712 | |||
713 | /* Basic Rates */ | ||
714 | rates = (struct wl12xx_ie_rates *)ptr; | ||
715 | rates->header.id = WLAN_EID_SUPP_RATES; | ||
716 | rates->header.len = wl1271_build_basic_rates(rates->rates); | ||
717 | size += sizeof(struct wl12xx_ie_header) + rates->header.len; | ||
718 | ptr += sizeof(struct wl12xx_ie_header) + rates->header.len; | ||
719 | |||
720 | /* Extended rates */ | ||
721 | rates = (struct wl12xx_ie_rates *)ptr; | ||
722 | rates->header.id = WLAN_EID_EXT_SUPP_RATES; | ||
723 | rates->header.len = wl1271_build_extended_rates(rates->rates); | ||
724 | size += sizeof(struct wl12xx_ie_header) + rates->header.len; | ||
725 | |||
726 | wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size); | ||
727 | |||
728 | return wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, | ||
729 | &template, size); | ||
730 | } | ||
731 | |||
732 | int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id) | ||
733 | { | ||
734 | struct wl1271_cmd_set_keys *cmd; | ||
735 | int ret = 0; | ||
736 | |||
737 | wl1271_debug(DEBUG_CMD, "cmd set_default_wep_key %d", id); | ||
738 | |||
739 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
740 | if (!cmd) { | ||
741 | ret = -ENOMEM; | ||
742 | goto out; | ||
743 | } | ||
744 | |||
745 | cmd->id = id; | ||
746 | cmd->key_action = KEY_SET_ID; | ||
747 | cmd->key_type = KEY_WEP; | ||
748 | |||
749 | ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd)); | ||
750 | if (ret < 0) { | ||
751 | wl1271_warning("cmd set_default_wep_key failed: %d", ret); | ||
752 | goto out; | ||
753 | } | ||
754 | |||
755 | out: | ||
756 | kfree(cmd); | ||
757 | |||
758 | return ret; | ||
759 | } | ||
760 | |||
761 | int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, | ||
762 | u8 key_size, const u8 *key, const u8 *addr) | ||
763 | { | ||
764 | struct wl1271_cmd_set_keys *cmd; | ||
765 | int ret = 0; | ||
766 | |||
767 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
768 | if (!cmd) { | ||
769 | ret = -ENOMEM; | ||
770 | goto out; | ||
771 | } | ||
772 | |||
773 | if (key_type != KEY_WEP) | ||
774 | memcpy(cmd->addr, addr, ETH_ALEN); | ||
775 | |||
776 | cmd->key_action = action; | ||
777 | cmd->key_size = key_size; | ||
778 | cmd->key_type = key_type; | ||
779 | |||
780 | /* we have only one SSID profile */ | ||
781 | cmd->ssid_profile = 0; | ||
782 | |||
783 | cmd->id = id; | ||
784 | |||
785 | /* FIXME: this is from wl1251, needs to be checked */ | ||
786 | if (key_type == KEY_TKIP) { | ||
787 | /* | ||
788 | * We get the key in the following form: | ||
789 | * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes) | ||
790 | * but the target is expecting: | ||
791 | * TKIP - RX MIC - TX MIC | ||
792 | */ | ||
793 | memcpy(cmd->key, key, 16); | ||
794 | memcpy(cmd->key + 16, key + 24, 8); | ||
795 | memcpy(cmd->key + 24, key + 16, 8); | ||
796 | |||
797 | } else { | ||
798 | memcpy(cmd->key, key, key_size); | ||
799 | } | ||
800 | |||
801 | wl1271_dump(DEBUG_CRYPT, "TARGET KEY: ", cmd, sizeof(*cmd)); | ||
802 | |||
803 | ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd)); | ||
804 | if (ret < 0) { | ||
805 | wl1271_warning("could not set keys"); | ||
806 | goto out; | ||
807 | } | ||
808 | |||
809 | out: | ||
810 | kfree(cmd); | ||
811 | |||
812 | return ret; | ||
813 | } | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.h b/drivers/net/wireless/wl12xx/wl1271_cmd.h new file mode 100644 index 000000000000..951a8447a516 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.h | |||
@@ -0,0 +1,464 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. | ||
5 | * Copyright (C) 2009 Nokia Corporation | ||
6 | * | ||
7 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef __WL1271_CMD_H__ | ||
26 | #define __WL1271_CMD_H__ | ||
27 | |||
28 | #include "wl1271.h" | ||
29 | |||
30 | struct acx_header; | ||
31 | |||
32 | int wl1271_cmd_send(struct wl1271 *wl, u16 type, void *buf, size_t buf_len); | ||
33 | int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type, u8 dtim_interval, | ||
34 | u16 beacon_interval, u8 wait); | ||
35 | int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer); | ||
36 | int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len); | ||
37 | int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len); | ||
38 | int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable); | ||
39 | int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode); | ||
40 | int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer, | ||
41 | size_t len); | ||
42 | int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, | ||
43 | u8 active_scan, u8 high_prio, u8 num_channels, | ||
44 | u8 probe_requests); | ||
45 | int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, | ||
46 | void *buf, size_t buf_len); | ||
47 | int wl1271_cmd_build_null_data(struct wl1271 *wl); | ||
48 | int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid); | ||
49 | int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len); | ||
50 | int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id); | ||
51 | int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, | ||
52 | u8 key_size, const u8 *key, const u8 *addr); | ||
53 | |||
54 | enum wl1271_commands { | ||
55 | CMD_INTERROGATE = 1, /*use this to read information elements*/ | ||
56 | CMD_CONFIGURE = 2, /*use this to write information elements*/ | ||
57 | CMD_ENABLE_RX = 3, | ||
58 | CMD_ENABLE_TX = 4, | ||
59 | CMD_DISABLE_RX = 5, | ||
60 | CMD_DISABLE_TX = 6, | ||
61 | CMD_SCAN = 8, | ||
62 | CMD_STOP_SCAN = 9, | ||
63 | CMD_START_JOIN = 11, | ||
64 | CMD_SET_KEYS = 12, | ||
65 | CMD_READ_MEMORY = 13, | ||
66 | CMD_WRITE_MEMORY = 14, | ||
67 | CMD_SET_TEMPLATE = 19, | ||
68 | CMD_TEST = 23, | ||
69 | CMD_NOISE_HIST = 28, | ||
70 | CMD_LNA_CONTROL = 32, | ||
71 | CMD_SET_BCN_MODE = 33, | ||
72 | CMD_MEASUREMENT = 34, | ||
73 | CMD_STOP_MEASUREMENT = 35, | ||
74 | CMD_DISCONNECT = 36, | ||
75 | CMD_SET_PS_MODE = 37, | ||
76 | CMD_CHANNEL_SWITCH = 38, | ||
77 | CMD_STOP_CHANNEL_SWICTH = 39, | ||
78 | CMD_AP_DISCOVERY = 40, | ||
79 | CMD_STOP_AP_DISCOVERY = 41, | ||
80 | CMD_SPS_SCAN = 42, | ||
81 | CMD_STOP_SPS_SCAN = 43, | ||
82 | CMD_HEALTH_CHECK = 45, | ||
83 | CMD_DEBUG = 46, | ||
84 | CMD_TRIGGER_SCAN_TO = 47, | ||
85 | CMD_CONNECTION_SCAN_CFG = 48, | ||
86 | CMD_CONNECTION_SCAN_SSID_CFG = 49, | ||
87 | CMD_START_PERIODIC_SCAN = 50, | ||
88 | CMD_STOP_PERIODIC_SCAN = 51, | ||
89 | CMD_SET_STA_STATE = 52, | ||
90 | |||
91 | NUM_COMMANDS, | ||
92 | MAX_COMMAND_ID = 0xFFFF, | ||
93 | }; | ||
94 | |||
95 | #define MAX_CMD_PARAMS 572 | ||
96 | |||
97 | enum cmd_templ { | ||
98 | CMD_TEMPL_NULL_DATA = 0, | ||
99 | CMD_TEMPL_BEACON, | ||
100 | CMD_TEMPL_CFG_PROBE_REQ_2_4, | ||
101 | CMD_TEMPL_CFG_PROBE_REQ_5, | ||
102 | CMD_TEMPL_PROBE_RESPONSE, | ||
103 | CMD_TEMPL_QOS_NULL_DATA, | ||
104 | CMD_TEMPL_PS_POLL, | ||
105 | CMD_TEMPL_KLV, | ||
106 | CMD_TEMPL_DISCONNECT, | ||
107 | CMD_TEMPL_PROBE_REQ_2_4, /* for firmware internal use only */ | ||
108 | CMD_TEMPL_PROBE_REQ_5, /* for firmware internal use only */ | ||
109 | CMD_TEMPL_BAR, /* for firmware internal use only */ | ||
110 | CMD_TEMPL_CTS, /* | ||
111 | * For CTS-to-self (FastCTS) mechanism | ||
112 | * for BT/WLAN coexistence (SoftGemini). */ | ||
113 | CMD_TEMPL_MAX = 0xff | ||
114 | }; | ||
115 | |||
116 | /* unit ms */ | ||
117 | #define WL1271_COMMAND_TIMEOUT 2000 | ||
118 | #define WL1271_CMD_TEMPL_MAX_SIZE 252 | ||
119 | |||
120 | struct wl1271_cmd_header { | ||
121 | u16 id; | ||
122 | u16 status; | ||
123 | /* payload */ | ||
124 | u8 data[0]; | ||
125 | } __attribute__ ((packed)); | ||
126 | |||
127 | #define WL1271_CMD_MAX_PARAMS 572 | ||
128 | |||
129 | struct wl1271_command { | ||
130 | struct wl1271_cmd_header header; | ||
131 | u8 parameters[WL1271_CMD_MAX_PARAMS]; | ||
132 | } __attribute__ ((packed)); | ||
133 | |||
134 | enum { | ||
135 | CMD_MAILBOX_IDLE = 0, | ||
136 | CMD_STATUS_SUCCESS = 1, | ||
137 | CMD_STATUS_UNKNOWN_CMD = 2, | ||
138 | CMD_STATUS_UNKNOWN_IE = 3, | ||
139 | CMD_STATUS_REJECT_MEAS_SG_ACTIVE = 11, | ||
140 | CMD_STATUS_RX_BUSY = 13, | ||
141 | CMD_STATUS_INVALID_PARAM = 14, | ||
142 | CMD_STATUS_TEMPLATE_TOO_LARGE = 15, | ||
143 | CMD_STATUS_OUT_OF_MEMORY = 16, | ||
144 | CMD_STATUS_STA_TABLE_FULL = 17, | ||
145 | CMD_STATUS_RADIO_ERROR = 18, | ||
146 | CMD_STATUS_WRONG_NESTING = 19, | ||
147 | CMD_STATUS_TIMEOUT = 21, /* Driver internal use.*/ | ||
148 | CMD_STATUS_FW_RESET = 22, /* Driver internal use.*/ | ||
149 | MAX_COMMAND_STATUS = 0xff | ||
150 | }; | ||
151 | |||
152 | |||
153 | /* | ||
154 | * CMD_READ_MEMORY | ||
155 | * | ||
156 | * The host issues this command to read the WiLink device memory/registers. | ||
157 | * | ||
158 | * Note: The Base Band address has special handling (16 bits registers and | ||
159 | * addresses). For more information, see the hardware specification. | ||
160 | */ | ||
161 | /* | ||
162 | * CMD_WRITE_MEMORY | ||
163 | * | ||
164 | * The host issues this command to write the WiLink device memory/registers. | ||
165 | * | ||
166 | * The Base Band address has special handling (16 bits registers and | ||
167 | * addresses). For more information, see the hardware specification. | ||
168 | */ | ||
169 | #define MAX_READ_SIZE 256 | ||
170 | |||
171 | struct cmd_read_write_memory { | ||
172 | struct wl1271_cmd_header header; | ||
173 | |||
174 | /* The address of the memory to read from or write to.*/ | ||
175 | u32 addr; | ||
176 | |||
177 | /* The amount of data in bytes to read from or write to the WiLink | ||
178 | * device.*/ | ||
179 | u32 size; | ||
180 | |||
181 | /* The actual value read from or written to the Wilink. The source | ||
182 | of this field is the Host in WRITE command or the Wilink in READ | ||
183 | command. */ | ||
184 | u8 value[MAX_READ_SIZE]; | ||
185 | }; | ||
186 | |||
187 | #define CMDMBOX_HEADER_LEN 4 | ||
188 | #define CMDMBOX_INFO_ELEM_HEADER_LEN 4 | ||
189 | |||
190 | enum { | ||
191 | BSS_TYPE_IBSS = 0, | ||
192 | BSS_TYPE_STA_BSS = 2, | ||
193 | BSS_TYPE_AP_BSS = 3, | ||
194 | MAX_BSS_TYPE = 0xFF | ||
195 | }; | ||
196 | |||
197 | #define WL1271_JOIN_CMD_CTRL_TX_FLUSH 0x80 /* Firmware flushes all Tx */ | ||
198 | #define WL1271_JOIN_CMD_TX_SESSION_OFFSET 1 | ||
199 | |||
200 | struct wl1271_cmd_join { | ||
201 | struct wl1271_cmd_header header; | ||
202 | |||
203 | u32 bssid_lsb; | ||
204 | u16 bssid_msb; | ||
205 | u16 beacon_interval; /* in TBTTs */ | ||
206 | u32 rx_config_options; | ||
207 | u32 rx_filter_options; | ||
208 | |||
209 | /* | ||
210 | * The target uses this field to determine the rate at | ||
211 | * which to transmit control frame responses (such as | ||
212 | * ACK or CTS frames). | ||
213 | */ | ||
214 | u32 basic_rate_set; | ||
215 | u8 dtim_interval; | ||
216 | /* | ||
217 | * bits 0-2: This bitwise field specifies the type | ||
218 | * of BSS to start or join (BSS_TYPE_*). | ||
219 | * bit 4: Band - The radio band in which to join | ||
220 | * or start. | ||
221 | * 0 - 2.4GHz band | ||
222 | * 1 - 5GHz band | ||
223 | * bits 3, 5-7: Reserved | ||
224 | */ | ||
225 | u8 bss_type; | ||
226 | u8 channel; | ||
227 | u8 ssid_len; | ||
228 | u8 ssid[IW_ESSID_MAX_SIZE]; | ||
229 | u8 ctrl; /* JOIN_CMD_CTRL_* */ | ||
230 | u8 reserved[3]; | ||
231 | } __attribute__ ((packed)); | ||
232 | |||
233 | struct cmd_enabledisable_path { | ||
234 | struct wl1271_cmd_header header; | ||
235 | |||
236 | u8 channel; | ||
237 | u8 padding[3]; | ||
238 | } __attribute__ ((packed)); | ||
239 | |||
240 | struct wl1271_cmd_template_set { | ||
241 | struct wl1271_cmd_header header; | ||
242 | |||
243 | u16 len; | ||
244 | u8 template_type; | ||
245 | u8 index; /* relevant only for KLV_TEMPLATE type */ | ||
246 | u32 enabled_rates; | ||
247 | u8 short_retry_limit; | ||
248 | u8 long_retry_limit; | ||
249 | u8 aflags; | ||
250 | u8 reserved; | ||
251 | u8 template_data[WL1271_CMD_TEMPL_MAX_SIZE]; | ||
252 | } __attribute__ ((packed)); | ||
253 | |||
254 | #define TIM_ELE_ID 5 | ||
255 | #define PARTIAL_VBM_MAX 251 | ||
256 | |||
257 | struct wl1271_tim { | ||
258 | u8 identity; | ||
259 | u8 length; | ||
260 | u8 dtim_count; | ||
261 | u8 dtim_period; | ||
262 | u8 bitmap_ctrl; | ||
263 | u8 pvb_field[PARTIAL_VBM_MAX]; /* Partial Virtual Bitmap */ | ||
264 | } __attribute__ ((packed)); | ||
265 | |||
266 | enum wl1271_cmd_ps_mode { | ||
267 | STATION_ACTIVE_MODE, | ||
268 | STATION_POWER_SAVE_MODE | ||
269 | }; | ||
270 | |||
271 | struct wl1271_cmd_ps_params { | ||
272 | struct wl1271_cmd_header header; | ||
273 | |||
274 | u8 ps_mode; /* STATION_* */ | ||
275 | u8 send_null_data; /* Do we have to send NULL data packet ? */ | ||
276 | u8 retries; /* Number of retires for the initial NULL data packet */ | ||
277 | |||
278 | /* | ||
279 | * TUs during which the target stays awake after switching | ||
280 | * to power save mode. | ||
281 | */ | ||
282 | u8 hang_over_period; | ||
283 | u32 null_data_rate; | ||
284 | } __attribute__ ((packed)); | ||
285 | |||
286 | /* HW encryption keys */ | ||
287 | #define NUM_ACCESS_CATEGORIES_COPY 4 | ||
288 | #define MAX_KEY_SIZE 32 | ||
289 | |||
290 | /* When set, disable HW encryption */ | ||
291 | #define DF_ENCRYPTION_DISABLE 0x01 | ||
292 | /* When set, disable HW decryption */ | ||
293 | #define DF_SNIFF_MODE_ENABLE 0x80 | ||
294 | |||
295 | enum wl1271_cmd_key_action { | ||
296 | KEY_ADD_OR_REPLACE = 1, | ||
297 | KEY_REMOVE = 2, | ||
298 | KEY_SET_ID = 3, | ||
299 | MAX_KEY_ACTION = 0xffff, | ||
300 | }; | ||
301 | |||
302 | enum wl1271_cmd_key_type { | ||
303 | KEY_NONE = 0, | ||
304 | KEY_WEP = 1, | ||
305 | KEY_TKIP = 2, | ||
306 | KEY_AES = 3, | ||
307 | KEY_GEM = 4 | ||
308 | }; | ||
309 | |||
310 | /* FIXME: Add description for key-types */ | ||
311 | |||
312 | struct wl1271_cmd_set_keys { | ||
313 | struct wl1271_cmd_header header; | ||
314 | |||
315 | /* Ignored for default WEP key */ | ||
316 | u8 addr[ETH_ALEN]; | ||
317 | |||
318 | /* key_action_e */ | ||
319 | u16 key_action; | ||
320 | |||
321 | u16 reserved_1; | ||
322 | |||
323 | /* key size in bytes */ | ||
324 | u8 key_size; | ||
325 | |||
326 | /* key_type_e */ | ||
327 | u8 key_type; | ||
328 | u8 ssid_profile; | ||
329 | |||
330 | /* | ||
331 | * TKIP, AES: frame's key id field. | ||
332 | * For WEP default key: key id; | ||
333 | */ | ||
334 | u8 id; | ||
335 | u8 reserved_2[6]; | ||
336 | u8 key[MAX_KEY_SIZE]; | ||
337 | u16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY]; | ||
338 | u32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY]; | ||
339 | } __attribute__ ((packed)); | ||
340 | |||
341 | |||
342 | #define WL1271_SCAN_MAX_CHANNELS 24 | ||
343 | #define WL1271_SCAN_DEFAULT_TAG 1 | ||
344 | #define WL1271_SCAN_CURRENT_TX_PWR 0 | ||
345 | #define WL1271_SCAN_OPT_ACTIVE 0 | ||
346 | #define WL1271_SCAN_OPT_PASSIVE 1 | ||
347 | #define WL1271_SCAN_OPT_PRIORITY_HIGH 4 | ||
348 | #define WL1271_SCAN_CHAN_MIN_DURATION 30000 /* TU */ | ||
349 | #define WL1271_SCAN_CHAN_MAX_DURATION 60000 /* TU */ | ||
350 | |||
351 | struct basic_scan_params { | ||
352 | u32 rx_config_options; | ||
353 | u32 rx_filter_options; | ||
354 | /* Scan option flags (WL1271_SCAN_OPT_*) */ | ||
355 | u16 scan_options; | ||
356 | /* Number of scan channels in the list (maximum 30) */ | ||
357 | u8 num_channels; | ||
358 | /* This field indicates the number of probe requests to send | ||
359 | per channel for an active scan */ | ||
360 | u8 num_probe_requests; | ||
361 | /* Rate bit field for sending the probes */ | ||
362 | u32 tx_rate; | ||
363 | u8 tid_trigger; | ||
364 | u8 ssid_len; | ||
365 | /* in order to align */ | ||
366 | u8 padding1[2]; | ||
367 | u8 ssid[IW_ESSID_MAX_SIZE]; | ||
368 | /* Band to scan */ | ||
369 | u8 band; | ||
370 | u8 use_ssid_list; | ||
371 | u8 scan_tag; | ||
372 | u8 padding2; | ||
373 | } __attribute__ ((packed)); | ||
374 | |||
375 | struct basic_scan_channel_params { | ||
376 | /* Duration in TU to wait for frames on a channel for active scan */ | ||
377 | u32 min_duration; | ||
378 | u32 max_duration; | ||
379 | u32 bssid_lsb; | ||
380 | u16 bssid_msb; | ||
381 | u8 early_termination; | ||
382 | u8 tx_power_att; | ||
383 | u8 channel; | ||
384 | /* FW internal use only! */ | ||
385 | u8 dfs_candidate; | ||
386 | u8 activity_detected; | ||
387 | u8 pad; | ||
388 | } __attribute__ ((packed)); | ||
389 | |||
390 | struct wl1271_cmd_scan { | ||
391 | struct wl1271_cmd_header header; | ||
392 | |||
393 | struct basic_scan_params params; | ||
394 | struct basic_scan_channel_params channels[WL1271_SCAN_MAX_CHANNELS]; | ||
395 | } __attribute__ ((packed)); | ||
396 | |||
397 | struct wl1271_cmd_trigger_scan_to { | ||
398 | struct wl1271_cmd_header header; | ||
399 | |||
400 | u32 timeout; | ||
401 | }; | ||
402 | |||
403 | struct wl1271_cmd_test_header { | ||
404 | u8 id; | ||
405 | u8 padding[3]; | ||
406 | }; | ||
407 | |||
408 | enum wl1271_channel_tune_bands { | ||
409 | WL1271_CHANNEL_TUNE_BAND_2_4, | ||
410 | WL1271_CHANNEL_TUNE_BAND_5, | ||
411 | WL1271_CHANNEL_TUNE_BAND_4_9 | ||
412 | }; | ||
413 | |||
414 | #define WL1271_PD_REFERENCE_POINT_BAND_B_G 0 | ||
415 | |||
416 | #define TEST_CMD_P2G_CAL 0x02 | ||
417 | #define TEST_CMD_CHANNEL_TUNE 0x0d | ||
418 | #define TEST_CMD_UPDATE_PD_REFERENCE_POINT 0x1d | ||
419 | |||
420 | struct wl1271_cmd_cal_channel_tune { | ||
421 | struct wl1271_cmd_header header; | ||
422 | |||
423 | struct wl1271_cmd_test_header test; | ||
424 | |||
425 | u8 band; | ||
426 | u8 channel; | ||
427 | |||
428 | u16 radio_status; | ||
429 | } __attribute__ ((packed)); | ||
430 | |||
431 | struct wl1271_cmd_cal_update_ref_point { | ||
432 | struct wl1271_cmd_header header; | ||
433 | |||
434 | struct wl1271_cmd_test_header test; | ||
435 | |||
436 | s32 ref_power; | ||
437 | s32 ref_detector; | ||
438 | u8 sub_band; | ||
439 | u8 padding[3]; | ||
440 | } __attribute__ ((packed)); | ||
441 | |||
442 | #define MAX_TLV_LENGTH 400 | ||
443 | #define MAX_NVS_VERSION_LENGTH 12 | ||
444 | |||
445 | #define WL1271_CAL_P2G_BAND_B_G BIT(0) | ||
446 | |||
447 | struct wl1271_cmd_cal_p2g { | ||
448 | struct wl1271_cmd_header header; | ||
449 | |||
450 | struct wl1271_cmd_test_header test; | ||
451 | |||
452 | u16 len; | ||
453 | u8 buf[MAX_TLV_LENGTH]; | ||
454 | u8 type; | ||
455 | u8 padding; | ||
456 | |||
457 | s16 radio_status; | ||
458 | u8 nvs_version[MAX_NVS_VERSION_LENGTH]; | ||
459 | |||
460 | u8 sub_band_mask; | ||
461 | u8 padding2; | ||
462 | } __attribute__ ((packed)); | ||
463 | |||
464 | #endif /* __WL1271_CMD_H__ */ | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_debugfs.c b/drivers/net/wireless/wl12xx/wl1271_debugfs.c new file mode 100644 index 000000000000..c1805e5f8964 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_debugfs.c | |||
@@ -0,0 +1,518 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2009 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include "wl1271_debugfs.h" | ||
25 | |||
26 | #include <linux/skbuff.h> | ||
27 | |||
28 | #include "wl1271.h" | ||
29 | #include "wl1271_acx.h" | ||
30 | #include "wl1271_ps.h" | ||
31 | |||
32 | /* ms */ | ||
33 | #define WL1271_DEBUGFS_STATS_LIFETIME 1000 | ||
34 | |||
35 | /* debugfs macros idea from mac80211 */ | ||
36 | |||
37 | #define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...) \ | ||
38 | static ssize_t name## _read(struct file *file, char __user *userbuf, \ | ||
39 | size_t count, loff_t *ppos) \ | ||
40 | { \ | ||
41 | struct wl1271 *wl = file->private_data; \ | ||
42 | char buf[buflen]; \ | ||
43 | int res; \ | ||
44 | \ | ||
45 | res = scnprintf(buf, buflen, fmt "\n", ##value); \ | ||
46 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ | ||
47 | } \ | ||
48 | \ | ||
49 | static const struct file_operations name## _ops = { \ | ||
50 | .read = name## _read, \ | ||
51 | .open = wl1271_open_file_generic, \ | ||
52 | }; | ||
53 | |||
54 | #define DEBUGFS_ADD(name, parent) \ | ||
55 | wl->debugfs.name = debugfs_create_file(#name, 0400, parent, \ | ||
56 | wl, &name## _ops); \ | ||
57 | if (IS_ERR(wl->debugfs.name)) { \ | ||
58 | ret = PTR_ERR(wl->debugfs.name); \ | ||
59 | wl->debugfs.name = NULL; \ | ||
60 | goto out; \ | ||
61 | } | ||
62 | |||
63 | #define DEBUGFS_DEL(name) \ | ||
64 | do { \ | ||
65 | debugfs_remove(wl->debugfs.name); \ | ||
66 | wl->debugfs.name = NULL; \ | ||
67 | } while (0) | ||
68 | |||
69 | #define DEBUGFS_FWSTATS_FILE(sub, name, buflen, fmt) \ | ||
70 | static ssize_t sub## _ ##name## _read(struct file *file, \ | ||
71 | char __user *userbuf, \ | ||
72 | size_t count, loff_t *ppos) \ | ||
73 | { \ | ||
74 | struct wl1271 *wl = file->private_data; \ | ||
75 | char buf[buflen]; \ | ||
76 | int res; \ | ||
77 | \ | ||
78 | wl1271_debugfs_update_stats(wl); \ | ||
79 | \ | ||
80 | res = scnprintf(buf, buflen, fmt "\n", \ | ||
81 | wl->stats.fw_stats->sub.name); \ | ||
82 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ | ||
83 | } \ | ||
84 | \ | ||
85 | static const struct file_operations sub## _ ##name## _ops = { \ | ||
86 | .read = sub## _ ##name## _read, \ | ||
87 | .open = wl1271_open_file_generic, \ | ||
88 | }; | ||
89 | |||
90 | #define DEBUGFS_FWSTATS_ADD(sub, name) \ | ||
91 | DEBUGFS_ADD(sub## _ ##name, wl->debugfs.fw_statistics) | ||
92 | |||
93 | #define DEBUGFS_FWSTATS_DEL(sub, name) \ | ||
94 | DEBUGFS_DEL(sub## _ ##name) | ||
95 | |||
96 | static void wl1271_debugfs_update_stats(struct wl1271 *wl) | ||
97 | { | ||
98 | int ret; | ||
99 | |||
100 | mutex_lock(&wl->mutex); | ||
101 | |||
102 | ret = wl1271_ps_elp_wakeup(wl, false); | ||
103 | if (ret < 0) | ||
104 | goto out; | ||
105 | |||
106 | if (wl->state == WL1271_STATE_ON && | ||
107 | time_after(jiffies, wl->stats.fw_stats_update + | ||
108 | msecs_to_jiffies(WL1271_DEBUGFS_STATS_LIFETIME))) { | ||
109 | wl1271_acx_statistics(wl, wl->stats.fw_stats); | ||
110 | wl->stats.fw_stats_update = jiffies; | ||
111 | } | ||
112 | |||
113 | wl1271_ps_elp_sleep(wl); | ||
114 | |||
115 | out: | ||
116 | mutex_unlock(&wl->mutex); | ||
117 | } | ||
118 | |||
119 | static int wl1271_open_file_generic(struct inode *inode, struct file *file) | ||
120 | { | ||
121 | file->private_data = inode->i_private; | ||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | DEBUGFS_FWSTATS_FILE(tx, internal_desc_overflow, 20, "%u"); | ||
126 | |||
127 | DEBUGFS_FWSTATS_FILE(rx, out_of_mem, 20, "%u"); | ||
128 | DEBUGFS_FWSTATS_FILE(rx, hdr_overflow, 20, "%u"); | ||
129 | DEBUGFS_FWSTATS_FILE(rx, hw_stuck, 20, "%u"); | ||
130 | DEBUGFS_FWSTATS_FILE(rx, dropped, 20, "%u"); | ||
131 | DEBUGFS_FWSTATS_FILE(rx, fcs_err, 20, "%u"); | ||
132 | DEBUGFS_FWSTATS_FILE(rx, xfr_hint_trig, 20, "%u"); | ||
133 | DEBUGFS_FWSTATS_FILE(rx, path_reset, 20, "%u"); | ||
134 | DEBUGFS_FWSTATS_FILE(rx, reset_counter, 20, "%u"); | ||
135 | |||
136 | DEBUGFS_FWSTATS_FILE(dma, rx_requested, 20, "%u"); | ||
137 | DEBUGFS_FWSTATS_FILE(dma, rx_errors, 20, "%u"); | ||
138 | DEBUGFS_FWSTATS_FILE(dma, tx_requested, 20, "%u"); | ||
139 | DEBUGFS_FWSTATS_FILE(dma, tx_errors, 20, "%u"); | ||
140 | |||
141 | DEBUGFS_FWSTATS_FILE(isr, cmd_cmplt, 20, "%u"); | ||
142 | DEBUGFS_FWSTATS_FILE(isr, fiqs, 20, "%u"); | ||
143 | DEBUGFS_FWSTATS_FILE(isr, rx_headers, 20, "%u"); | ||
144 | DEBUGFS_FWSTATS_FILE(isr, rx_mem_overflow, 20, "%u"); | ||
145 | DEBUGFS_FWSTATS_FILE(isr, rx_rdys, 20, "%u"); | ||
146 | DEBUGFS_FWSTATS_FILE(isr, irqs, 20, "%u"); | ||
147 | DEBUGFS_FWSTATS_FILE(isr, tx_procs, 20, "%u"); | ||
148 | DEBUGFS_FWSTATS_FILE(isr, decrypt_done, 20, "%u"); | ||
149 | DEBUGFS_FWSTATS_FILE(isr, dma0_done, 20, "%u"); | ||
150 | DEBUGFS_FWSTATS_FILE(isr, dma1_done, 20, "%u"); | ||
151 | DEBUGFS_FWSTATS_FILE(isr, tx_exch_complete, 20, "%u"); | ||
152 | DEBUGFS_FWSTATS_FILE(isr, commands, 20, "%u"); | ||
153 | DEBUGFS_FWSTATS_FILE(isr, rx_procs, 20, "%u"); | ||
154 | DEBUGFS_FWSTATS_FILE(isr, hw_pm_mode_changes, 20, "%u"); | ||
155 | DEBUGFS_FWSTATS_FILE(isr, host_acknowledges, 20, "%u"); | ||
156 | DEBUGFS_FWSTATS_FILE(isr, pci_pm, 20, "%u"); | ||
157 | DEBUGFS_FWSTATS_FILE(isr, wakeups, 20, "%u"); | ||
158 | DEBUGFS_FWSTATS_FILE(isr, low_rssi, 20, "%u"); | ||
159 | |||
160 | DEBUGFS_FWSTATS_FILE(wep, addr_key_count, 20, "%u"); | ||
161 | DEBUGFS_FWSTATS_FILE(wep, default_key_count, 20, "%u"); | ||
162 | /* skipping wep.reserved */ | ||
163 | DEBUGFS_FWSTATS_FILE(wep, key_not_found, 20, "%u"); | ||
164 | DEBUGFS_FWSTATS_FILE(wep, decrypt_fail, 20, "%u"); | ||
165 | DEBUGFS_FWSTATS_FILE(wep, packets, 20, "%u"); | ||
166 | DEBUGFS_FWSTATS_FILE(wep, interrupt, 20, "%u"); | ||
167 | |||
168 | DEBUGFS_FWSTATS_FILE(pwr, ps_enter, 20, "%u"); | ||
169 | DEBUGFS_FWSTATS_FILE(pwr, elp_enter, 20, "%u"); | ||
170 | DEBUGFS_FWSTATS_FILE(pwr, missing_bcns, 20, "%u"); | ||
171 | DEBUGFS_FWSTATS_FILE(pwr, wake_on_host, 20, "%u"); | ||
172 | DEBUGFS_FWSTATS_FILE(pwr, wake_on_timer_exp, 20, "%u"); | ||
173 | DEBUGFS_FWSTATS_FILE(pwr, tx_with_ps, 20, "%u"); | ||
174 | DEBUGFS_FWSTATS_FILE(pwr, tx_without_ps, 20, "%u"); | ||
175 | DEBUGFS_FWSTATS_FILE(pwr, rcvd_beacons, 20, "%u"); | ||
176 | DEBUGFS_FWSTATS_FILE(pwr, power_save_off, 20, "%u"); | ||
177 | DEBUGFS_FWSTATS_FILE(pwr, enable_ps, 20, "%u"); | ||
178 | DEBUGFS_FWSTATS_FILE(pwr, disable_ps, 20, "%u"); | ||
179 | DEBUGFS_FWSTATS_FILE(pwr, fix_tsf_ps, 20, "%u"); | ||
180 | /* skipping cont_miss_bcns_spread for now */ | ||
181 | DEBUGFS_FWSTATS_FILE(pwr, rcvd_awake_beacons, 20, "%u"); | ||
182 | |||
183 | DEBUGFS_FWSTATS_FILE(mic, rx_pkts, 20, "%u"); | ||
184 | DEBUGFS_FWSTATS_FILE(mic, calc_failure, 20, "%u"); | ||
185 | |||
186 | DEBUGFS_FWSTATS_FILE(aes, encrypt_fail, 20, "%u"); | ||
187 | DEBUGFS_FWSTATS_FILE(aes, decrypt_fail, 20, "%u"); | ||
188 | DEBUGFS_FWSTATS_FILE(aes, encrypt_packets, 20, "%u"); | ||
189 | DEBUGFS_FWSTATS_FILE(aes, decrypt_packets, 20, "%u"); | ||
190 | DEBUGFS_FWSTATS_FILE(aes, encrypt_interrupt, 20, "%u"); | ||
191 | DEBUGFS_FWSTATS_FILE(aes, decrypt_interrupt, 20, "%u"); | ||
192 | |||
193 | DEBUGFS_FWSTATS_FILE(event, heart_beat, 20, "%u"); | ||
194 | DEBUGFS_FWSTATS_FILE(event, calibration, 20, "%u"); | ||
195 | DEBUGFS_FWSTATS_FILE(event, rx_mismatch, 20, "%u"); | ||
196 | DEBUGFS_FWSTATS_FILE(event, rx_mem_empty, 20, "%u"); | ||
197 | DEBUGFS_FWSTATS_FILE(event, rx_pool, 20, "%u"); | ||
198 | DEBUGFS_FWSTATS_FILE(event, oom_late, 20, "%u"); | ||
199 | DEBUGFS_FWSTATS_FILE(event, phy_transmit_error, 20, "%u"); | ||
200 | DEBUGFS_FWSTATS_FILE(event, tx_stuck, 20, "%u"); | ||
201 | |||
202 | DEBUGFS_FWSTATS_FILE(ps, pspoll_timeouts, 20, "%u"); | ||
203 | DEBUGFS_FWSTATS_FILE(ps, upsd_timeouts, 20, "%u"); | ||
204 | DEBUGFS_FWSTATS_FILE(ps, upsd_max_sptime, 20, "%u"); | ||
205 | DEBUGFS_FWSTATS_FILE(ps, upsd_max_apturn, 20, "%u"); | ||
206 | DEBUGFS_FWSTATS_FILE(ps, pspoll_max_apturn, 20, "%u"); | ||
207 | DEBUGFS_FWSTATS_FILE(ps, pspoll_utilization, 20, "%u"); | ||
208 | DEBUGFS_FWSTATS_FILE(ps, upsd_utilization, 20, "%u"); | ||
209 | |||
210 | DEBUGFS_FWSTATS_FILE(rxpipe, rx_prep_beacon_drop, 20, "%u"); | ||
211 | DEBUGFS_FWSTATS_FILE(rxpipe, descr_host_int_trig_rx_data, 20, "%u"); | ||
212 | DEBUGFS_FWSTATS_FILE(rxpipe, beacon_buffer_thres_host_int_trig_rx_data, | ||
213 | 20, "%u"); | ||
214 | DEBUGFS_FWSTATS_FILE(rxpipe, missed_beacon_host_int_trig_rx_data, 20, "%u"); | ||
215 | DEBUGFS_FWSTATS_FILE(rxpipe, tx_xfr_host_int_trig_rx_data, 20, "%u"); | ||
216 | |||
217 | DEBUGFS_READONLY_FILE(retry_count, 20, "%u", wl->stats.retry_count); | ||
218 | DEBUGFS_READONLY_FILE(excessive_retries, 20, "%u", | ||
219 | wl->stats.excessive_retries); | ||
220 | |||
221 | static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf, | ||
222 | size_t count, loff_t *ppos) | ||
223 | { | ||
224 | struct wl1271 *wl = file->private_data; | ||
225 | u32 queue_len; | ||
226 | char buf[20]; | ||
227 | int res; | ||
228 | |||
229 | queue_len = skb_queue_len(&wl->tx_queue); | ||
230 | |||
231 | res = scnprintf(buf, sizeof(buf), "%u\n", queue_len); | ||
232 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); | ||
233 | } | ||
234 | |||
235 | static const struct file_operations tx_queue_len_ops = { | ||
236 | .read = tx_queue_len_read, | ||
237 | .open = wl1271_open_file_generic, | ||
238 | }; | ||
239 | |||
240 | static void wl1271_debugfs_delete_files(struct wl1271 *wl) | ||
241 | { | ||
242 | DEBUGFS_FWSTATS_DEL(tx, internal_desc_overflow); | ||
243 | |||
244 | DEBUGFS_FWSTATS_DEL(rx, out_of_mem); | ||
245 | DEBUGFS_FWSTATS_DEL(rx, hdr_overflow); | ||
246 | DEBUGFS_FWSTATS_DEL(rx, hw_stuck); | ||
247 | DEBUGFS_FWSTATS_DEL(rx, dropped); | ||
248 | DEBUGFS_FWSTATS_DEL(rx, fcs_err); | ||
249 | DEBUGFS_FWSTATS_DEL(rx, xfr_hint_trig); | ||
250 | DEBUGFS_FWSTATS_DEL(rx, path_reset); | ||
251 | DEBUGFS_FWSTATS_DEL(rx, reset_counter); | ||
252 | |||
253 | DEBUGFS_FWSTATS_DEL(dma, rx_requested); | ||
254 | DEBUGFS_FWSTATS_DEL(dma, rx_errors); | ||
255 | DEBUGFS_FWSTATS_DEL(dma, tx_requested); | ||
256 | DEBUGFS_FWSTATS_DEL(dma, tx_errors); | ||
257 | |||
258 | DEBUGFS_FWSTATS_DEL(isr, cmd_cmplt); | ||
259 | DEBUGFS_FWSTATS_DEL(isr, fiqs); | ||
260 | DEBUGFS_FWSTATS_DEL(isr, rx_headers); | ||
261 | DEBUGFS_FWSTATS_DEL(isr, rx_mem_overflow); | ||
262 | DEBUGFS_FWSTATS_DEL(isr, rx_rdys); | ||
263 | DEBUGFS_FWSTATS_DEL(isr, irqs); | ||
264 | DEBUGFS_FWSTATS_DEL(isr, tx_procs); | ||
265 | DEBUGFS_FWSTATS_DEL(isr, decrypt_done); | ||
266 | DEBUGFS_FWSTATS_DEL(isr, dma0_done); | ||
267 | DEBUGFS_FWSTATS_DEL(isr, dma1_done); | ||
268 | DEBUGFS_FWSTATS_DEL(isr, tx_exch_complete); | ||
269 | DEBUGFS_FWSTATS_DEL(isr, commands); | ||
270 | DEBUGFS_FWSTATS_DEL(isr, rx_procs); | ||
271 | DEBUGFS_FWSTATS_DEL(isr, hw_pm_mode_changes); | ||
272 | DEBUGFS_FWSTATS_DEL(isr, host_acknowledges); | ||
273 | DEBUGFS_FWSTATS_DEL(isr, pci_pm); | ||
274 | DEBUGFS_FWSTATS_DEL(isr, wakeups); | ||
275 | DEBUGFS_FWSTATS_DEL(isr, low_rssi); | ||
276 | |||
277 | DEBUGFS_FWSTATS_DEL(wep, addr_key_count); | ||
278 | DEBUGFS_FWSTATS_DEL(wep, default_key_count); | ||
279 | /* skipping wep.reserved */ | ||
280 | DEBUGFS_FWSTATS_DEL(wep, key_not_found); | ||
281 | DEBUGFS_FWSTATS_DEL(wep, decrypt_fail); | ||
282 | DEBUGFS_FWSTATS_DEL(wep, packets); | ||
283 | DEBUGFS_FWSTATS_DEL(wep, interrupt); | ||
284 | |||
285 | DEBUGFS_FWSTATS_DEL(pwr, ps_enter); | ||
286 | DEBUGFS_FWSTATS_DEL(pwr, elp_enter); | ||
287 | DEBUGFS_FWSTATS_DEL(pwr, missing_bcns); | ||
288 | DEBUGFS_FWSTATS_DEL(pwr, wake_on_host); | ||
289 | DEBUGFS_FWSTATS_DEL(pwr, wake_on_timer_exp); | ||
290 | DEBUGFS_FWSTATS_DEL(pwr, tx_with_ps); | ||
291 | DEBUGFS_FWSTATS_DEL(pwr, tx_without_ps); | ||
292 | DEBUGFS_FWSTATS_DEL(pwr, rcvd_beacons); | ||
293 | DEBUGFS_FWSTATS_DEL(pwr, power_save_off); | ||
294 | DEBUGFS_FWSTATS_DEL(pwr, enable_ps); | ||
295 | DEBUGFS_FWSTATS_DEL(pwr, disable_ps); | ||
296 | DEBUGFS_FWSTATS_DEL(pwr, fix_tsf_ps); | ||
297 | /* skipping cont_miss_bcns_spread for now */ | ||
298 | DEBUGFS_FWSTATS_DEL(pwr, rcvd_awake_beacons); | ||
299 | |||
300 | DEBUGFS_FWSTATS_DEL(mic, rx_pkts); | ||
301 | DEBUGFS_FWSTATS_DEL(mic, calc_failure); | ||
302 | |||
303 | DEBUGFS_FWSTATS_DEL(aes, encrypt_fail); | ||
304 | DEBUGFS_FWSTATS_DEL(aes, decrypt_fail); | ||
305 | DEBUGFS_FWSTATS_DEL(aes, encrypt_packets); | ||
306 | DEBUGFS_FWSTATS_DEL(aes, decrypt_packets); | ||
307 | DEBUGFS_FWSTATS_DEL(aes, encrypt_interrupt); | ||
308 | DEBUGFS_FWSTATS_DEL(aes, decrypt_interrupt); | ||
309 | |||
310 | DEBUGFS_FWSTATS_DEL(event, heart_beat); | ||
311 | DEBUGFS_FWSTATS_DEL(event, calibration); | ||
312 | DEBUGFS_FWSTATS_DEL(event, rx_mismatch); | ||
313 | DEBUGFS_FWSTATS_DEL(event, rx_mem_empty); | ||
314 | DEBUGFS_FWSTATS_DEL(event, rx_pool); | ||
315 | DEBUGFS_FWSTATS_DEL(event, oom_late); | ||
316 | DEBUGFS_FWSTATS_DEL(event, phy_transmit_error); | ||
317 | DEBUGFS_FWSTATS_DEL(event, tx_stuck); | ||
318 | |||
319 | DEBUGFS_FWSTATS_DEL(ps, pspoll_timeouts); | ||
320 | DEBUGFS_FWSTATS_DEL(ps, upsd_timeouts); | ||
321 | DEBUGFS_FWSTATS_DEL(ps, upsd_max_sptime); | ||
322 | DEBUGFS_FWSTATS_DEL(ps, upsd_max_apturn); | ||
323 | DEBUGFS_FWSTATS_DEL(ps, pspoll_max_apturn); | ||
324 | DEBUGFS_FWSTATS_DEL(ps, pspoll_utilization); | ||
325 | DEBUGFS_FWSTATS_DEL(ps, upsd_utilization); | ||
326 | |||
327 | DEBUGFS_FWSTATS_DEL(rxpipe, rx_prep_beacon_drop); | ||
328 | DEBUGFS_FWSTATS_DEL(rxpipe, descr_host_int_trig_rx_data); | ||
329 | DEBUGFS_FWSTATS_DEL(rxpipe, beacon_buffer_thres_host_int_trig_rx_data); | ||
330 | DEBUGFS_FWSTATS_DEL(rxpipe, missed_beacon_host_int_trig_rx_data); | ||
331 | DEBUGFS_FWSTATS_DEL(rxpipe, tx_xfr_host_int_trig_rx_data); | ||
332 | |||
333 | DEBUGFS_DEL(tx_queue_len); | ||
334 | DEBUGFS_DEL(retry_count); | ||
335 | DEBUGFS_DEL(excessive_retries); | ||
336 | } | ||
337 | |||
338 | static int wl1271_debugfs_add_files(struct wl1271 *wl) | ||
339 | { | ||
340 | int ret = 0; | ||
341 | |||
342 | DEBUGFS_FWSTATS_ADD(tx, internal_desc_overflow); | ||
343 | |||
344 | DEBUGFS_FWSTATS_ADD(rx, out_of_mem); | ||
345 | DEBUGFS_FWSTATS_ADD(rx, hdr_overflow); | ||
346 | DEBUGFS_FWSTATS_ADD(rx, hw_stuck); | ||
347 | DEBUGFS_FWSTATS_ADD(rx, dropped); | ||
348 | DEBUGFS_FWSTATS_ADD(rx, fcs_err); | ||
349 | DEBUGFS_FWSTATS_ADD(rx, xfr_hint_trig); | ||
350 | DEBUGFS_FWSTATS_ADD(rx, path_reset); | ||
351 | DEBUGFS_FWSTATS_ADD(rx, reset_counter); | ||
352 | |||
353 | DEBUGFS_FWSTATS_ADD(dma, rx_requested); | ||
354 | DEBUGFS_FWSTATS_ADD(dma, rx_errors); | ||
355 | DEBUGFS_FWSTATS_ADD(dma, tx_requested); | ||
356 | DEBUGFS_FWSTATS_ADD(dma, tx_errors); | ||
357 | |||
358 | DEBUGFS_FWSTATS_ADD(isr, cmd_cmplt); | ||
359 | DEBUGFS_FWSTATS_ADD(isr, fiqs); | ||
360 | DEBUGFS_FWSTATS_ADD(isr, rx_headers); | ||
361 | DEBUGFS_FWSTATS_ADD(isr, rx_mem_overflow); | ||
362 | DEBUGFS_FWSTATS_ADD(isr, rx_rdys); | ||
363 | DEBUGFS_FWSTATS_ADD(isr, irqs); | ||
364 | DEBUGFS_FWSTATS_ADD(isr, tx_procs); | ||
365 | DEBUGFS_FWSTATS_ADD(isr, decrypt_done); | ||
366 | DEBUGFS_FWSTATS_ADD(isr, dma0_done); | ||
367 | DEBUGFS_FWSTATS_ADD(isr, dma1_done); | ||
368 | DEBUGFS_FWSTATS_ADD(isr, tx_exch_complete); | ||
369 | DEBUGFS_FWSTATS_ADD(isr, commands); | ||
370 | DEBUGFS_FWSTATS_ADD(isr, rx_procs); | ||
371 | DEBUGFS_FWSTATS_ADD(isr, hw_pm_mode_changes); | ||
372 | DEBUGFS_FWSTATS_ADD(isr, host_acknowledges); | ||
373 | DEBUGFS_FWSTATS_ADD(isr, pci_pm); | ||
374 | DEBUGFS_FWSTATS_ADD(isr, wakeups); | ||
375 | DEBUGFS_FWSTATS_ADD(isr, low_rssi); | ||
376 | |||
377 | DEBUGFS_FWSTATS_ADD(wep, addr_key_count); | ||
378 | DEBUGFS_FWSTATS_ADD(wep, default_key_count); | ||
379 | /* skipping wep.reserved */ | ||
380 | DEBUGFS_FWSTATS_ADD(wep, key_not_found); | ||
381 | DEBUGFS_FWSTATS_ADD(wep, decrypt_fail); | ||
382 | DEBUGFS_FWSTATS_ADD(wep, packets); | ||
383 | DEBUGFS_FWSTATS_ADD(wep, interrupt); | ||
384 | |||
385 | DEBUGFS_FWSTATS_ADD(pwr, ps_enter); | ||
386 | DEBUGFS_FWSTATS_ADD(pwr, elp_enter); | ||
387 | DEBUGFS_FWSTATS_ADD(pwr, missing_bcns); | ||
388 | DEBUGFS_FWSTATS_ADD(pwr, wake_on_host); | ||
389 | DEBUGFS_FWSTATS_ADD(pwr, wake_on_timer_exp); | ||
390 | DEBUGFS_FWSTATS_ADD(pwr, tx_with_ps); | ||
391 | DEBUGFS_FWSTATS_ADD(pwr, tx_without_ps); | ||
392 | DEBUGFS_FWSTATS_ADD(pwr, rcvd_beacons); | ||
393 | DEBUGFS_FWSTATS_ADD(pwr, power_save_off); | ||
394 | DEBUGFS_FWSTATS_ADD(pwr, enable_ps); | ||
395 | DEBUGFS_FWSTATS_ADD(pwr, disable_ps); | ||
396 | DEBUGFS_FWSTATS_ADD(pwr, fix_tsf_ps); | ||
397 | /* skipping cont_miss_bcns_spread for now */ | ||
398 | DEBUGFS_FWSTATS_ADD(pwr, rcvd_awake_beacons); | ||
399 | |||
400 | DEBUGFS_FWSTATS_ADD(mic, rx_pkts); | ||
401 | DEBUGFS_FWSTATS_ADD(mic, calc_failure); | ||
402 | |||
403 | DEBUGFS_FWSTATS_ADD(aes, encrypt_fail); | ||
404 | DEBUGFS_FWSTATS_ADD(aes, decrypt_fail); | ||
405 | DEBUGFS_FWSTATS_ADD(aes, encrypt_packets); | ||
406 | DEBUGFS_FWSTATS_ADD(aes, decrypt_packets); | ||
407 | DEBUGFS_FWSTATS_ADD(aes, encrypt_interrupt); | ||
408 | DEBUGFS_FWSTATS_ADD(aes, decrypt_interrupt); | ||
409 | |||
410 | DEBUGFS_FWSTATS_ADD(event, heart_beat); | ||
411 | DEBUGFS_FWSTATS_ADD(event, calibration); | ||
412 | DEBUGFS_FWSTATS_ADD(event, rx_mismatch); | ||
413 | DEBUGFS_FWSTATS_ADD(event, rx_mem_empty); | ||
414 | DEBUGFS_FWSTATS_ADD(event, rx_pool); | ||
415 | DEBUGFS_FWSTATS_ADD(event, oom_late); | ||
416 | DEBUGFS_FWSTATS_ADD(event, phy_transmit_error); | ||
417 | DEBUGFS_FWSTATS_ADD(event, tx_stuck); | ||
418 | |||
419 | DEBUGFS_FWSTATS_ADD(ps, pspoll_timeouts); | ||
420 | DEBUGFS_FWSTATS_ADD(ps, upsd_timeouts); | ||
421 | DEBUGFS_FWSTATS_ADD(ps, upsd_max_sptime); | ||
422 | DEBUGFS_FWSTATS_ADD(ps, upsd_max_apturn); | ||
423 | DEBUGFS_FWSTATS_ADD(ps, pspoll_max_apturn); | ||
424 | DEBUGFS_FWSTATS_ADD(ps, pspoll_utilization); | ||
425 | DEBUGFS_FWSTATS_ADD(ps, upsd_utilization); | ||
426 | |||
427 | DEBUGFS_FWSTATS_ADD(rxpipe, rx_prep_beacon_drop); | ||
428 | DEBUGFS_FWSTATS_ADD(rxpipe, descr_host_int_trig_rx_data); | ||
429 | DEBUGFS_FWSTATS_ADD(rxpipe, beacon_buffer_thres_host_int_trig_rx_data); | ||
430 | DEBUGFS_FWSTATS_ADD(rxpipe, missed_beacon_host_int_trig_rx_data); | ||
431 | DEBUGFS_FWSTATS_ADD(rxpipe, tx_xfr_host_int_trig_rx_data); | ||
432 | |||
433 | DEBUGFS_ADD(tx_queue_len, wl->debugfs.rootdir); | ||
434 | DEBUGFS_ADD(retry_count, wl->debugfs.rootdir); | ||
435 | DEBUGFS_ADD(excessive_retries, wl->debugfs.rootdir); | ||
436 | |||
437 | out: | ||
438 | if (ret < 0) | ||
439 | wl1271_debugfs_delete_files(wl); | ||
440 | |||
441 | return ret; | ||
442 | } | ||
443 | |||
444 | void wl1271_debugfs_reset(struct wl1271 *wl) | ||
445 | { | ||
446 | memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats)); | ||
447 | wl->stats.retry_count = 0; | ||
448 | wl->stats.excessive_retries = 0; | ||
449 | } | ||
450 | |||
451 | int wl1271_debugfs_init(struct wl1271 *wl) | ||
452 | { | ||
453 | int ret; | ||
454 | |||
455 | wl->debugfs.rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL); | ||
456 | |||
457 | if (IS_ERR(wl->debugfs.rootdir)) { | ||
458 | ret = PTR_ERR(wl->debugfs.rootdir); | ||
459 | wl->debugfs.rootdir = NULL; | ||
460 | goto err; | ||
461 | } | ||
462 | |||
463 | wl->debugfs.fw_statistics = debugfs_create_dir("fw-statistics", | ||
464 | wl->debugfs.rootdir); | ||
465 | |||
466 | if (IS_ERR(wl->debugfs.fw_statistics)) { | ||
467 | ret = PTR_ERR(wl->debugfs.fw_statistics); | ||
468 | wl->debugfs.fw_statistics = NULL; | ||
469 | goto err_root; | ||
470 | } | ||
471 | |||
472 | wl->stats.fw_stats = kzalloc(sizeof(*wl->stats.fw_stats), | ||
473 | GFP_KERNEL); | ||
474 | |||
475 | if (!wl->stats.fw_stats) { | ||
476 | ret = -ENOMEM; | ||
477 | goto err_fw; | ||
478 | } | ||
479 | |||
480 | wl->stats.fw_stats_update = jiffies; | ||
481 | |||
482 | ret = wl1271_debugfs_add_files(wl); | ||
483 | |||
484 | if (ret < 0) | ||
485 | goto err_file; | ||
486 | |||
487 | return 0; | ||
488 | |||
489 | err_file: | ||
490 | kfree(wl->stats.fw_stats); | ||
491 | wl->stats.fw_stats = NULL; | ||
492 | |||
493 | err_fw: | ||
494 | debugfs_remove(wl->debugfs.fw_statistics); | ||
495 | wl->debugfs.fw_statistics = NULL; | ||
496 | |||
497 | err_root: | ||
498 | debugfs_remove(wl->debugfs.rootdir); | ||
499 | wl->debugfs.rootdir = NULL; | ||
500 | |||
501 | err: | ||
502 | return ret; | ||
503 | } | ||
504 | |||
505 | void wl1271_debugfs_exit(struct wl1271 *wl) | ||
506 | { | ||
507 | wl1271_debugfs_delete_files(wl); | ||
508 | |||
509 | kfree(wl->stats.fw_stats); | ||
510 | wl->stats.fw_stats = NULL; | ||
511 | |||
512 | debugfs_remove(wl->debugfs.fw_statistics); | ||
513 | wl->debugfs.fw_statistics = NULL; | ||
514 | |||
515 | debugfs_remove(wl->debugfs.rootdir); | ||
516 | wl->debugfs.rootdir = NULL; | ||
517 | |||
518 | } | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_debugfs.h b/drivers/net/wireless/wl12xx/wl1271_debugfs.h new file mode 100644 index 000000000000..00a45b2669ad --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_debugfs.h | |||
@@ -0,0 +1,33 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2009 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifndef WL1271_DEBUGFS_H | ||
25 | #define WL1271_DEBUGFS_H | ||
26 | |||
27 | #include "wl1271.h" | ||
28 | |||
29 | int wl1271_debugfs_init(struct wl1271 *wl); | ||
30 | void wl1271_debugfs_exit(struct wl1271 *wl); | ||
31 | void wl1271_debugfs_reset(struct wl1271 *wl); | ||
32 | |||
33 | #endif /* WL1271_DEBUGFS_H */ | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_event.c b/drivers/net/wireless/wl12xx/wl1271_event.c new file mode 100644 index 000000000000..f3afd4a6ff33 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_event.c | |||
@@ -0,0 +1,125 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2008-2009 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include "wl1271.h" | ||
25 | #include "wl1271_reg.h" | ||
26 | #include "wl1271_spi.h" | ||
27 | #include "wl1271_event.h" | ||
28 | #include "wl1271_ps.h" | ||
29 | |||
30 | static int wl1271_event_scan_complete(struct wl1271 *wl, | ||
31 | struct event_mailbox *mbox) | ||
32 | { | ||
33 | wl1271_debug(DEBUG_EVENT, "status: 0x%x", | ||
34 | mbox->scheduled_scan_status); | ||
35 | |||
36 | if (wl->scanning) { | ||
37 | mutex_unlock(&wl->mutex); | ||
38 | ieee80211_scan_completed(wl->hw, false); | ||
39 | mutex_lock(&wl->mutex); | ||
40 | wl->scanning = false; | ||
41 | } | ||
42 | |||
43 | return 0; | ||
44 | } | ||
45 | |||
46 | static void wl1271_event_mbox_dump(struct event_mailbox *mbox) | ||
47 | { | ||
48 | wl1271_debug(DEBUG_EVENT, "MBOX DUMP:"); | ||
49 | wl1271_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector); | ||
50 | wl1271_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask); | ||
51 | } | ||
52 | |||
53 | static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) | ||
54 | { | ||
55 | int ret; | ||
56 | u32 vector; | ||
57 | |||
58 | wl1271_event_mbox_dump(mbox); | ||
59 | |||
60 | vector = mbox->events_vector & ~(mbox->events_mask); | ||
61 | wl1271_debug(DEBUG_EVENT, "vector: 0x%x", vector); | ||
62 | |||
63 | if (vector & SCAN_COMPLETE_EVENT_ID) { | ||
64 | ret = wl1271_event_scan_complete(wl, mbox); | ||
65 | if (ret < 0) | ||
66 | return ret; | ||
67 | } | ||
68 | |||
69 | if (vector & BSS_LOSE_EVENT_ID) { | ||
70 | wl1271_debug(DEBUG_EVENT, "BSS_LOSE_EVENT"); | ||
71 | |||
72 | if (wl->psm_requested && wl->psm) { | ||
73 | ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE); | ||
74 | if (ret < 0) | ||
75 | return ret; | ||
76 | } | ||
77 | } | ||
78 | |||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | int wl1271_event_unmask(struct wl1271 *wl) | ||
83 | { | ||
84 | int ret; | ||
85 | |||
86 | ret = wl1271_acx_event_mbox_mask(wl, ~(wl->event_mask)); | ||
87 | if (ret < 0) | ||
88 | return ret; | ||
89 | |||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | void wl1271_event_mbox_config(struct wl1271 *wl) | ||
94 | { | ||
95 | wl->mbox_ptr[0] = wl1271_reg_read32(wl, REG_EVENT_MAILBOX_PTR); | ||
96 | wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox); | ||
97 | |||
98 | wl1271_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x", | ||
99 | wl->mbox_ptr[0], wl->mbox_ptr[1]); | ||
100 | } | ||
101 | |||
102 | int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num) | ||
103 | { | ||
104 | struct event_mailbox mbox; | ||
105 | int ret; | ||
106 | |||
107 | wl1271_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num); | ||
108 | |||
109 | if (mbox_num > 1) | ||
110 | return -EINVAL; | ||
111 | |||
112 | /* first we read the mbox descriptor */ | ||
113 | wl1271_spi_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox, | ||
114 | sizeof(struct event_mailbox)); | ||
115 | |||
116 | /* process the descriptor */ | ||
117 | ret = wl1271_event_process(wl, &mbox); | ||
118 | if (ret < 0) | ||
119 | return ret; | ||
120 | |||
121 | /* then we let the firmware know it can go on...*/ | ||
122 | wl1271_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK); | ||
123 | |||
124 | return 0; | ||
125 | } | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_event.h b/drivers/net/wireless/wl12xx/wl1271_event.h new file mode 100644 index 000000000000..2cdce7c34bf0 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_event.h | |||
@@ -0,0 +1,110 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. | ||
5 | * Copyright (C) 2008-2009 Nokia Corporation | ||
6 | * | ||
7 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef __WL1271_EVENT_H__ | ||
26 | #define __WL1271_EVENT_H__ | ||
27 | |||
28 | /* | ||
29 | * Mbox events | ||
30 | * | ||
31 | * The event mechanism is based on a pair of event buffers (buffers A and | ||
32 | * B) at fixed locations in the target's memory. The host processes one | ||
33 | * buffer while the other buffer continues to collect events. If the host | ||
34 | * is not processing events, an interrupt is issued to signal that a buffer | ||
35 | * is ready. Once the host is done with processing events from one buffer, | ||
36 | * it signals the target (with an ACK interrupt) that the event buffer is | ||
37 | * free. | ||
38 | */ | ||
39 | |||
40 | enum { | ||
41 | MEASUREMENT_START_EVENT_ID = BIT(8), | ||
42 | MEASUREMENT_COMPLETE_EVENT_ID = BIT(9), | ||
43 | SCAN_COMPLETE_EVENT_ID = BIT(10), | ||
44 | SCHEDULED_SCAN_COMPLETE_EVENT_ID = BIT(11), | ||
45 | AP_DISCOVERY_COMPLETE_EVENT_ID = BIT(12), | ||
46 | PS_REPORT_EVENT_ID = BIT(13), | ||
47 | PSPOLL_DELIVERY_FAILURE_EVENT_ID = BIT(14), | ||
48 | DISCONNECT_EVENT_COMPLETE_ID = BIT(15), | ||
49 | JOIN_EVENT_COMPLETE_ID = BIT(16), | ||
50 | CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(17), | ||
51 | BSS_LOSE_EVENT_ID = BIT(18), | ||
52 | REGAINED_BSS_EVENT_ID = BIT(19), | ||
53 | ROAMING_TRIGGER_MAX_TX_RETRY_EVENT_ID = BIT(20), | ||
54 | SOFT_GEMINI_SENSE_EVENT_ID = BIT(22), | ||
55 | SOFT_GEMINI_PREDICTION_EVENT_ID = BIT(23), | ||
56 | SOFT_GEMINI_AVALANCHE_EVENT_ID = BIT(24), | ||
57 | PLT_RX_CALIBRATION_COMPLETE_EVENT_ID = BIT(25), | ||
58 | DBG_EVENT_ID = BIT(26), | ||
59 | HEALTH_CHECK_REPLY_EVENT_ID = BIT(27), | ||
60 | PERIODIC_SCAN_COMPLETE_EVENT_ID = BIT(28), | ||
61 | PERIODIC_SCAN_REPORT_EVENT_ID = BIT(29), | ||
62 | BA_SESSION_TEAR_DOWN_EVENT_ID = BIT(30), | ||
63 | EVENT_MBOX_ALL_EVENT_ID = 0x7fffffff, | ||
64 | }; | ||
65 | |||
66 | struct event_debug_report { | ||
67 | u8 debug_event_id; | ||
68 | u8 num_params; | ||
69 | u16 pad; | ||
70 | u32 report_1; | ||
71 | u32 report_2; | ||
72 | u32 report_3; | ||
73 | } __attribute__ ((packed)); | ||
74 | |||
75 | #define NUM_OF_RSSI_SNR_TRIGGERS 8 | ||
76 | |||
77 | struct event_mailbox { | ||
78 | u32 events_vector; | ||
79 | u32 events_mask; | ||
80 | u32 reserved_1; | ||
81 | u32 reserved_2; | ||
82 | |||
83 | u8 dbg_event_id; | ||
84 | u8 num_relevant_params; | ||
85 | u16 reserved_3; | ||
86 | u32 event_report_p1; | ||
87 | u32 event_report_p2; | ||
88 | u32 event_report_p3; | ||
89 | |||
90 | u8 number_of_scan_results; | ||
91 | u8 scan_tag; | ||
92 | u8 reserved_4[2]; | ||
93 | u32 compl_scheduled_scan_status; | ||
94 | |||
95 | u16 scheduled_scan_attended_channels; | ||
96 | u8 soft_gemini_sense_info; | ||
97 | u8 soft_gemini_protective_info; | ||
98 | s8 rssi_snr_trigger_metric[NUM_OF_RSSI_SNR_TRIGGERS]; | ||
99 | u8 channel_switch_status; | ||
100 | u8 scheduled_scan_status; | ||
101 | u8 ps_status; | ||
102 | |||
103 | u8 reserved_5[29]; | ||
104 | } __attribute__ ((packed)); | ||
105 | |||
106 | int wl1271_event_unmask(struct wl1271 *wl); | ||
107 | void wl1271_event_mbox_config(struct wl1271 *wl); | ||
108 | int wl1271_event_handle(struct wl1271 *wl, u8 mbox); | ||
109 | |||
110 | #endif | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c new file mode 100644 index 000000000000..490df217605a --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_init.c | |||
@@ -0,0 +1,397 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2009 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/module.h> | ||
26 | |||
27 | #include "wl1271_init.h" | ||
28 | #include "wl12xx_80211.h" | ||
29 | #include "wl1271_acx.h" | ||
30 | #include "wl1271_cmd.h" | ||
31 | #include "wl1271_reg.h" | ||
32 | |||
33 | static int wl1271_init_hwenc_config(struct wl1271 *wl) | ||
34 | { | ||
35 | int ret; | ||
36 | |||
37 | ret = wl1271_acx_feature_cfg(wl); | ||
38 | if (ret < 0) { | ||
39 | wl1271_warning("couldn't set feature config"); | ||
40 | return ret; | ||
41 | } | ||
42 | |||
43 | ret = wl1271_cmd_set_default_wep_key(wl, wl->default_key); | ||
44 | if (ret < 0) { | ||
45 | wl1271_warning("couldn't set default key"); | ||
46 | return ret; | ||
47 | } | ||
48 | |||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | static int wl1271_init_templates_config(struct wl1271 *wl) | ||
53 | { | ||
54 | int ret; | ||
55 | |||
56 | /* send empty templates for fw memory reservation */ | ||
57 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL, | ||
58 | sizeof(struct wl12xx_probe_req_template)); | ||
59 | if (ret < 0) | ||
60 | return ret; | ||
61 | |||
62 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, NULL, | ||
63 | sizeof(struct wl12xx_null_data_template)); | ||
64 | if (ret < 0) | ||
65 | return ret; | ||
66 | |||
67 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, NULL, | ||
68 | sizeof(struct wl12xx_ps_poll_template)); | ||
69 | if (ret < 0) | ||
70 | return ret; | ||
71 | |||
72 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, NULL, | ||
73 | sizeof | ||
74 | (struct wl12xx_qos_null_data_template)); | ||
75 | if (ret < 0) | ||
76 | return ret; | ||
77 | |||
78 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE, NULL, | ||
79 | sizeof | ||
80 | (struct wl12xx_probe_resp_template)); | ||
81 | if (ret < 0) | ||
82 | return ret; | ||
83 | |||
84 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON, NULL, | ||
85 | sizeof | ||
86 | (struct wl12xx_beacon_template)); | ||
87 | if (ret < 0) | ||
88 | return ret; | ||
89 | |||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | static int wl1271_init_rx_config(struct wl1271 *wl, u32 config, u32 filter) | ||
94 | { | ||
95 | int ret; | ||
96 | |||
97 | ret = wl1271_acx_rx_msdu_life_time(wl, RX_MSDU_LIFETIME_DEF); | ||
98 | if (ret < 0) | ||
99 | return ret; | ||
100 | |||
101 | ret = wl1271_acx_rx_config(wl, config, filter); | ||
102 | if (ret < 0) | ||
103 | return ret; | ||
104 | |||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | static int wl1271_init_phy_config(struct wl1271 *wl) | ||
109 | { | ||
110 | int ret; | ||
111 | |||
112 | ret = wl1271_acx_pd_threshold(wl); | ||
113 | if (ret < 0) | ||
114 | return ret; | ||
115 | |||
116 | ret = wl1271_acx_slot(wl, DEFAULT_SLOT_TIME); | ||
117 | if (ret < 0) | ||
118 | return ret; | ||
119 | |||
120 | ret = wl1271_acx_group_address_tbl(wl); | ||
121 | if (ret < 0) | ||
122 | return ret; | ||
123 | |||
124 | ret = wl1271_acx_service_period_timeout(wl); | ||
125 | if (ret < 0) | ||
126 | return ret; | ||
127 | |||
128 | ret = wl1271_acx_rts_threshold(wl, RTS_THRESHOLD_DEF); | ||
129 | if (ret < 0) | ||
130 | return ret; | ||
131 | |||
132 | return 0; | ||
133 | } | ||
134 | |||
135 | static int wl1271_init_beacon_filter(struct wl1271 *wl) | ||
136 | { | ||
137 | int ret; | ||
138 | |||
139 | ret = wl1271_acx_beacon_filter_opt(wl); | ||
140 | if (ret < 0) | ||
141 | return ret; | ||
142 | |||
143 | ret = wl1271_acx_beacon_filter_table(wl); | ||
144 | if (ret < 0) | ||
145 | return ret; | ||
146 | |||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | static int wl1271_init_pta(struct wl1271 *wl) | ||
151 | { | ||
152 | int ret; | ||
153 | |||
154 | ret = wl1271_acx_sg_enable(wl); | ||
155 | if (ret < 0) | ||
156 | return ret; | ||
157 | |||
158 | ret = wl1271_acx_sg_cfg(wl); | ||
159 | if (ret < 0) | ||
160 | return ret; | ||
161 | |||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | static int wl1271_init_energy_detection(struct wl1271 *wl) | ||
166 | { | ||
167 | int ret; | ||
168 | |||
169 | ret = wl1271_acx_cca_threshold(wl); | ||
170 | if (ret < 0) | ||
171 | return ret; | ||
172 | |||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | static int wl1271_init_beacon_broadcast(struct wl1271 *wl) | ||
177 | { | ||
178 | int ret; | ||
179 | |||
180 | ret = wl1271_acx_bcn_dtim_options(wl); | ||
181 | if (ret < 0) | ||
182 | return ret; | ||
183 | |||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | static int wl1271_init_general_parms(struct wl1271 *wl) | ||
188 | { | ||
189 | struct wl1271_general_parms *gen_parms; | ||
190 | int ret; | ||
191 | |||
192 | gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL); | ||
193 | if (!gen_parms) | ||
194 | return -ENOMEM; | ||
195 | |||
196 | gen_parms->id = TEST_CMD_INI_FILE_GENERAL_PARAM; | ||
197 | |||
198 | gen_parms->ref_clk = REF_CLK_38_4_E; | ||
199 | /* FIXME: magic numbers */ | ||
200 | gen_parms->settling_time = 5; | ||
201 | gen_parms->clk_valid_on_wakeup = 0; | ||
202 | gen_parms->dc2dcmode = 0; | ||
203 | gen_parms->single_dual_band = 0; | ||
204 | gen_parms->tx_bip_fem_autodetect = 1; | ||
205 | gen_parms->tx_bip_fem_manufacturer = 1; | ||
206 | gen_parms->settings = 1; | ||
207 | |||
208 | ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), 0); | ||
209 | if (ret < 0) { | ||
210 | wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed"); | ||
211 | return ret; | ||
212 | } | ||
213 | |||
214 | kfree(gen_parms); | ||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | static int wl1271_init_radio_parms(struct wl1271 *wl) | ||
219 | { | ||
220 | /* | ||
221 | * FIXME: All these magic numbers should be moved to some place where | ||
222 | * they can be configured (separate file?) | ||
223 | */ | ||
224 | |||
225 | struct wl1271_radio_parms *radio_parms; | ||
226 | int ret; | ||
227 | u8 compensation[] = { 0xec, 0xf6, 0x00, 0x0c, 0x18, 0xf8, 0xfc, 0x00, | ||
228 | 0x08, 0x10, 0xf0, 0xf8, 0x00, 0x0a, 0x14 }; | ||
229 | |||
230 | u8 tx_rate_limits_normal[] = { 0x1e, 0x1f, 0x22, 0x24, 0x28, 0x29 }; | ||
231 | u8 tx_rate_limits_degraded[] = { 0x1b, 0x1c, 0x1e, 0x20, 0x24, 0x25 }; | ||
232 | |||
233 | u8 tx_channel_limits_11b[] = { 0x22, 0x50, 0x50, 0x50, | ||
234 | 0x50, 0x50, 0x50, 0x50, | ||
235 | 0x50, 0x50, 0x22, 0x50, | ||
236 | 0x22, 0x50 }; | ||
237 | |||
238 | u8 tx_channel_limits_ofdm[] = { 0x20, 0x50, 0x50, 0x50, | ||
239 | 0x50, 0x50, 0x50, 0x50, | ||
240 | 0x50, 0x50, 0x20, 0x50, | ||
241 | 0x20, 0x50 }; | ||
242 | |||
243 | u8 tx_pdv_rate_offsets[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; | ||
244 | |||
245 | u8 tx_ibias[] = { 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x27 }; | ||
246 | |||
247 | radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL); | ||
248 | if (!radio_parms) | ||
249 | return -ENOMEM; | ||
250 | |||
251 | radio_parms->id = TEST_CMD_INI_FILE_RADIO_PARAM; | ||
252 | |||
253 | /* Static radio parameters */ | ||
254 | radio_parms->rx_trace_loss = 10; | ||
255 | radio_parms->tx_trace_loss = 10; | ||
256 | memcpy(radio_parms->rx_rssi_and_proc_compens, compensation, | ||
257 | sizeof(compensation)); | ||
258 | |||
259 | /* We don't set the 5GHz -- N/A */ | ||
260 | |||
261 | /* Dynamic radio parameters */ | ||
262 | radio_parms->tx_ref_pd_voltage = cpu_to_le16(0x24e); | ||
263 | radio_parms->tx_ref_power = 0x78; | ||
264 | radio_parms->tx_offset_db = 0x0; | ||
265 | |||
266 | memcpy(radio_parms->tx_rate_limits_normal, tx_rate_limits_normal, | ||
267 | sizeof(tx_rate_limits_normal)); | ||
268 | memcpy(radio_parms->tx_rate_limits_degraded, tx_rate_limits_degraded, | ||
269 | sizeof(tx_rate_limits_degraded)); | ||
270 | |||
271 | memcpy(radio_parms->tx_channel_limits_11b, tx_channel_limits_11b, | ||
272 | sizeof(tx_channel_limits_11b)); | ||
273 | memcpy(radio_parms->tx_channel_limits_ofdm, tx_channel_limits_ofdm, | ||
274 | sizeof(tx_channel_limits_ofdm)); | ||
275 | memcpy(radio_parms->tx_pdv_rate_offsets, tx_pdv_rate_offsets, | ||
276 | sizeof(tx_pdv_rate_offsets)); | ||
277 | memcpy(radio_parms->tx_ibias, tx_ibias, | ||
278 | sizeof(tx_ibias)); | ||
279 | |||
280 | radio_parms->rx_fem_insertion_loss = 0x14; | ||
281 | |||
282 | ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0); | ||
283 | if (ret < 0) | ||
284 | wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed"); | ||
285 | |||
286 | kfree(radio_parms); | ||
287 | return ret; | ||
288 | } | ||
289 | |||
290 | int wl1271_hw_init(struct wl1271 *wl) | ||
291 | { | ||
292 | int ret; | ||
293 | |||
294 | ret = wl1271_init_general_parms(wl); | ||
295 | if (ret < 0) | ||
296 | return ret; | ||
297 | |||
298 | ret = wl1271_init_radio_parms(wl); | ||
299 | if (ret < 0) | ||
300 | return ret; | ||
301 | |||
302 | /* Template settings */ | ||
303 | ret = wl1271_init_templates_config(wl); | ||
304 | if (ret < 0) | ||
305 | return ret; | ||
306 | |||
307 | /* Default memory configuration */ | ||
308 | ret = wl1271_acx_init_mem_config(wl); | ||
309 | if (ret < 0) | ||
310 | return ret; | ||
311 | |||
312 | /* RX config */ | ||
313 | ret = wl1271_init_rx_config(wl, | ||
314 | RX_CFG_PROMISCUOUS | RX_CFG_TSF, | ||
315 | RX_FILTER_OPTION_DEF); | ||
316 | /* RX_CONFIG_OPTION_ANY_DST_ANY_BSS, | ||
317 | RX_FILTER_OPTION_FILTER_ALL); */ | ||
318 | if (ret < 0) | ||
319 | goto out_free_memmap; | ||
320 | |||
321 | /* PHY layer config */ | ||
322 | ret = wl1271_init_phy_config(wl); | ||
323 | if (ret < 0) | ||
324 | goto out_free_memmap; | ||
325 | |||
326 | /* Beacon filtering */ | ||
327 | ret = wl1271_init_beacon_filter(wl); | ||
328 | if (ret < 0) | ||
329 | goto out_free_memmap; | ||
330 | |||
331 | /* Configure TX patch complete interrupt behavior */ | ||
332 | ret = wl1271_acx_tx_config_options(wl); | ||
333 | if (ret < 0) | ||
334 | goto out_free_memmap; | ||
335 | |||
336 | /* RX complete interrupt pacing */ | ||
337 | ret = wl1271_acx_init_rx_interrupt(wl); | ||
338 | if (ret < 0) | ||
339 | goto out_free_memmap; | ||
340 | |||
341 | /* Bluetooth WLAN coexistence */ | ||
342 | ret = wl1271_init_pta(wl); | ||
343 | if (ret < 0) | ||
344 | goto out_free_memmap; | ||
345 | |||
346 | /* Energy detection */ | ||
347 | ret = wl1271_init_energy_detection(wl); | ||
348 | if (ret < 0) | ||
349 | goto out_free_memmap; | ||
350 | |||
351 | /* Beacons and boradcast settings */ | ||
352 | ret = wl1271_init_beacon_broadcast(wl); | ||
353 | if (ret < 0) | ||
354 | goto out_free_memmap; | ||
355 | |||
356 | /* Default fragmentation threshold */ | ||
357 | ret = wl1271_acx_frag_threshold(wl); | ||
358 | if (ret < 0) | ||
359 | goto out_free_memmap; | ||
360 | |||
361 | /* Default TID configuration */ | ||
362 | ret = wl1271_acx_tid_cfg(wl); | ||
363 | if (ret < 0) | ||
364 | goto out_free_memmap; | ||
365 | |||
366 | /* Default AC configuration */ | ||
367 | ret = wl1271_acx_ac_cfg(wl); | ||
368 | if (ret < 0) | ||
369 | goto out_free_memmap; | ||
370 | |||
371 | /* Configure TX rate classes */ | ||
372 | ret = wl1271_acx_rate_policies(wl); | ||
373 | if (ret < 0) | ||
374 | goto out_free_memmap; | ||
375 | |||
376 | /* Enable data path */ | ||
377 | ret = wl1271_cmd_data_path(wl, wl->channel, 1); | ||
378 | if (ret < 0) | ||
379 | goto out_free_memmap; | ||
380 | |||
381 | /* Configure for ELP power saving */ | ||
382 | ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP); | ||
383 | if (ret < 0) | ||
384 | goto out_free_memmap; | ||
385 | |||
386 | /* Configure HW encryption */ | ||
387 | ret = wl1271_init_hwenc_config(wl); | ||
388 | if (ret < 0) | ||
389 | goto out_free_memmap; | ||
390 | |||
391 | return 0; | ||
392 | |||
393 | out_free_memmap: | ||
394 | kfree(wl->target_mem_map); | ||
395 | |||
396 | return ret; | ||
397 | } | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_init.h b/drivers/net/wireless/wl12xx/wl1271_init.h new file mode 100644 index 000000000000..bd8ff0fa2272 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_init.h | |||
@@ -0,0 +1,115 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2009 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifndef __WL1271_INIT_H__ | ||
25 | #define __WL1271_INIT_H__ | ||
26 | |||
27 | #include "wl1271.h" | ||
28 | |||
29 | int wl1271_hw_init_power_auth(struct wl1271 *wl); | ||
30 | int wl1271_hw_init(struct wl1271 *wl); | ||
31 | |||
32 | /* These are not really a TEST_CMD, but the ref driver uses them as such */ | ||
33 | #define TEST_CMD_INI_FILE_RADIO_PARAM 0x19 | ||
34 | #define TEST_CMD_INI_FILE_GENERAL_PARAM 0x1E | ||
35 | |||
36 | struct wl1271_general_parms { | ||
37 | u8 id; | ||
38 | u8 padding[3]; | ||
39 | |||
40 | u8 ref_clk; | ||
41 | u8 settling_time; | ||
42 | u8 clk_valid_on_wakeup; | ||
43 | u8 dc2dcmode; | ||
44 | u8 single_dual_band; | ||
45 | |||
46 | u8 tx_bip_fem_autodetect; | ||
47 | u8 tx_bip_fem_manufacturer; | ||
48 | u8 settings; | ||
49 | } __attribute__ ((packed)); | ||
50 | |||
51 | enum ref_clk_enum { | ||
52 | REF_CLK_19_2_E, | ||
53 | REF_CLK_26_E, | ||
54 | REF_CLK_38_4_E, | ||
55 | REF_CLK_52_E | ||
56 | }; | ||
57 | |||
58 | #define RSSI_AND_PROCESS_COMPENSATION_SIZE 15 | ||
59 | #define NUMBER_OF_SUB_BANDS_5 7 | ||
60 | #define NUMBER_OF_RATE_GROUPS 6 | ||
61 | #define NUMBER_OF_CHANNELS_2_4 14 | ||
62 | #define NUMBER_OF_CHANNELS_5 35 | ||
63 | |||
64 | struct wl1271_radio_parms { | ||
65 | u8 id; | ||
66 | u8 padding[3]; | ||
67 | |||
68 | /* Static radio parameters */ | ||
69 | /* 2.4GHz */ | ||
70 | u8 rx_trace_loss; | ||
71 | u8 tx_trace_loss; | ||
72 | s8 rx_rssi_and_proc_compens[RSSI_AND_PROCESS_COMPENSATION_SIZE]; | ||
73 | |||
74 | /* 5GHz */ | ||
75 | u8 rx_trace_loss_5[NUMBER_OF_SUB_BANDS_5]; | ||
76 | u8 tx_trace_loss_5[NUMBER_OF_SUB_BANDS_5]; | ||
77 | s8 rx_rssi_and_proc_compens_5[RSSI_AND_PROCESS_COMPENSATION_SIZE]; | ||
78 | |||
79 | /* Dynamic radio parameters */ | ||
80 | /* 2.4GHz */ | ||
81 | s16 tx_ref_pd_voltage; | ||
82 | s8 tx_ref_power; | ||
83 | s8 tx_offset_db; | ||
84 | |||
85 | s8 tx_rate_limits_normal[NUMBER_OF_RATE_GROUPS]; | ||
86 | s8 tx_rate_limits_degraded[NUMBER_OF_RATE_GROUPS]; | ||
87 | |||
88 | s8 tx_channel_limits_11b[NUMBER_OF_CHANNELS_2_4]; | ||
89 | s8 tx_channel_limits_ofdm[NUMBER_OF_CHANNELS_2_4]; | ||
90 | s8 tx_pdv_rate_offsets[NUMBER_OF_RATE_GROUPS]; | ||
91 | |||
92 | u8 tx_ibias[NUMBER_OF_RATE_GROUPS]; | ||
93 | u8 rx_fem_insertion_loss; | ||
94 | |||
95 | u8 padding2; | ||
96 | |||
97 | /* 5GHz */ | ||
98 | s16 tx_ref_pd_voltage_5[NUMBER_OF_SUB_BANDS_5]; | ||
99 | s8 tx_ref_power_5[NUMBER_OF_SUB_BANDS_5]; | ||
100 | s8 tx_offset_db_5[NUMBER_OF_SUB_BANDS_5]; | ||
101 | |||
102 | s8 tx_rate_limits_normal_5[NUMBER_OF_RATE_GROUPS]; | ||
103 | s8 tx_rate_limits_degraded_5[NUMBER_OF_RATE_GROUPS]; | ||
104 | |||
105 | s8 tx_channel_limits_ofdm_5[NUMBER_OF_CHANNELS_5]; | ||
106 | s8 tx_pdv_rate_offsets_5[NUMBER_OF_RATE_GROUPS]; | ||
107 | |||
108 | /* FIXME: this is inconsistent with the types for 2.4GHz */ | ||
109 | s8 tx_ibias_5[NUMBER_OF_RATE_GROUPS]; | ||
110 | s8 rx_fem_insertion_loss_5[NUMBER_OF_SUB_BANDS_5]; | ||
111 | |||
112 | u8 padding3[2]; | ||
113 | } __attribute__ ((packed)); | ||
114 | |||
115 | #endif | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c new file mode 100644 index 000000000000..4102d590b798 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_main.c | |||
@@ -0,0 +1,1397 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2008-2009 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/module.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | #include <linux/interrupt.h> | ||
27 | #include <linux/firmware.h> | ||
28 | #include <linux/delay.h> | ||
29 | #include <linux/irq.h> | ||
30 | #include <linux/spi/spi.h> | ||
31 | #include <linux/crc32.h> | ||
32 | #include <linux/etherdevice.h> | ||
33 | #include <linux/spi/wl12xx.h> | ||
34 | |||
35 | #include "wl1271.h" | ||
36 | #include "wl12xx_80211.h" | ||
37 | #include "wl1271_reg.h" | ||
38 | #include "wl1271_spi.h" | ||
39 | #include "wl1271_event.h" | ||
40 | #include "wl1271_tx.h" | ||
41 | #include "wl1271_rx.h" | ||
42 | #include "wl1271_ps.h" | ||
43 | #include "wl1271_init.h" | ||
44 | #include "wl1271_debugfs.h" | ||
45 | #include "wl1271_cmd.h" | ||
46 | #include "wl1271_boot.h" | ||
47 | |||
48 | static int wl1271_plt_init(struct wl1271 *wl) | ||
49 | { | ||
50 | int ret; | ||
51 | |||
52 | ret = wl1271_acx_init_mem_config(wl); | ||
53 | if (ret < 0) | ||
54 | return ret; | ||
55 | |||
56 | ret = wl1271_cmd_data_path(wl, wl->channel, 1); | ||
57 | if (ret < 0) | ||
58 | return ret; | ||
59 | |||
60 | return 0; | ||
61 | } | ||
62 | |||
63 | static void wl1271_disable_interrupts(struct wl1271 *wl) | ||
64 | { | ||
65 | disable_irq(wl->irq); | ||
66 | } | ||
67 | |||
68 | static void wl1271_power_off(struct wl1271 *wl) | ||
69 | { | ||
70 | wl->set_power(false); | ||
71 | } | ||
72 | |||
73 | static void wl1271_power_on(struct wl1271 *wl) | ||
74 | { | ||
75 | wl->set_power(true); | ||
76 | } | ||
77 | |||
78 | static void wl1271_fw_status(struct wl1271 *wl, struct wl1271_fw_status *status) | ||
79 | { | ||
80 | u32 total = 0; | ||
81 | int i; | ||
82 | |||
83 | /* | ||
84 | * FIXME: Reading the FW status directly from the registers seems to | ||
85 | * be the right thing to do, but it doesn't work. And in the | ||
86 | * reference driver, there is a workaround called | ||
87 | * USE_SDIO_24M_WORKAROUND, which reads the status from memory | ||
88 | * instead, so we do the same here. | ||
89 | */ | ||
90 | |||
91 | wl1271_spi_mem_read(wl, STATUS_MEM_ADDRESS, status, sizeof(*status)); | ||
92 | |||
93 | wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, " | ||
94 | "drv_rx_counter = %d, tx_results_counter = %d)", | ||
95 | status->intr, | ||
96 | status->fw_rx_counter, | ||
97 | status->drv_rx_counter, | ||
98 | status->tx_results_counter); | ||
99 | |||
100 | /* update number of available TX blocks */ | ||
101 | for (i = 0; i < NUM_TX_QUEUES; i++) { | ||
102 | u32 cnt = status->tx_released_blks[i] - wl->tx_blocks_freed[i]; | ||
103 | wl->tx_blocks_freed[i] = status->tx_released_blks[i]; | ||
104 | wl->tx_blocks_available += cnt; | ||
105 | total += cnt; | ||
106 | } | ||
107 | |||
108 | /* if more blocks are available now, schedule some tx work */ | ||
109 | if (total && !skb_queue_empty(&wl->tx_queue)) | ||
110 | schedule_work(&wl->tx_work); | ||
111 | |||
112 | /* update the host-chipset time offset */ | ||
113 | wl->time_offset = jiffies_to_usecs(jiffies) - status->fw_localtime; | ||
114 | } | ||
115 | |||
116 | #define WL1271_IRQ_MAX_LOOPS 10 | ||
117 | static void wl1271_irq_work(struct work_struct *work) | ||
118 | { | ||
119 | u32 intr, ctr = WL1271_IRQ_MAX_LOOPS; | ||
120 | int ret; | ||
121 | struct wl1271 *wl = | ||
122 | container_of(work, struct wl1271, irq_work); | ||
123 | |||
124 | mutex_lock(&wl->mutex); | ||
125 | |||
126 | wl1271_debug(DEBUG_IRQ, "IRQ work"); | ||
127 | |||
128 | if (wl->state == WL1271_STATE_OFF) | ||
129 | goto out; | ||
130 | |||
131 | ret = wl1271_ps_elp_wakeup(wl, true); | ||
132 | if (ret < 0) | ||
133 | goto out; | ||
134 | |||
135 | wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL); | ||
136 | |||
137 | intr = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); | ||
138 | if (!intr) { | ||
139 | wl1271_debug(DEBUG_IRQ, "Zero interrupt received."); | ||
140 | goto out_sleep; | ||
141 | } | ||
142 | |||
143 | intr &= WL1271_INTR_MASK; | ||
144 | |||
145 | do { | ||
146 | wl1271_fw_status(wl, wl->fw_status); | ||
147 | |||
148 | |||
149 | if (intr & (WL1271_ACX_INTR_EVENT_A | | ||
150 | WL1271_ACX_INTR_EVENT_B)) { | ||
151 | wl1271_debug(DEBUG_IRQ, | ||
152 | "WL1271_ACX_INTR_EVENT (0x%x)", intr); | ||
153 | if (intr & WL1271_ACX_INTR_EVENT_A) | ||
154 | wl1271_event_handle(wl, 0); | ||
155 | else | ||
156 | wl1271_event_handle(wl, 1); | ||
157 | } | ||
158 | |||
159 | if (intr & WL1271_ACX_INTR_INIT_COMPLETE) | ||
160 | wl1271_debug(DEBUG_IRQ, | ||
161 | "WL1271_ACX_INTR_INIT_COMPLETE"); | ||
162 | |||
163 | if (intr & WL1271_ACX_INTR_HW_AVAILABLE) | ||
164 | wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE"); | ||
165 | |||
166 | if (intr & WL1271_ACX_INTR_DATA) { | ||
167 | u8 tx_res_cnt = wl->fw_status->tx_results_counter - | ||
168 | wl->tx_results_count; | ||
169 | |||
170 | wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA"); | ||
171 | |||
172 | /* check for tx results */ | ||
173 | if (tx_res_cnt) | ||
174 | wl1271_tx_complete(wl, tx_res_cnt); | ||
175 | |||
176 | wl1271_rx(wl, wl->fw_status); | ||
177 | } | ||
178 | |||
179 | intr = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); | ||
180 | intr &= WL1271_INTR_MASK; | ||
181 | } while (intr && --ctr); | ||
182 | |||
183 | out_sleep: | ||
184 | wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, | ||
185 | WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK)); | ||
186 | wl1271_ps_elp_sleep(wl); | ||
187 | |||
188 | out: | ||
189 | mutex_unlock(&wl->mutex); | ||
190 | } | ||
191 | |||
192 | static irqreturn_t wl1271_irq(int irq, void *cookie) | ||
193 | { | ||
194 | struct wl1271 *wl; | ||
195 | unsigned long flags; | ||
196 | |||
197 | wl1271_debug(DEBUG_IRQ, "IRQ"); | ||
198 | |||
199 | wl = cookie; | ||
200 | |||
201 | /* complete the ELP completion */ | ||
202 | spin_lock_irqsave(&wl->wl_lock, flags); | ||
203 | if (wl->elp_compl) { | ||
204 | complete(wl->elp_compl); | ||
205 | wl->elp_compl = NULL; | ||
206 | } | ||
207 | |||
208 | schedule_work(&wl->irq_work); | ||
209 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
210 | |||
211 | return IRQ_HANDLED; | ||
212 | } | ||
213 | |||
214 | static int wl1271_fetch_firmware(struct wl1271 *wl) | ||
215 | { | ||
216 | const struct firmware *fw; | ||
217 | int ret; | ||
218 | |||
219 | ret = request_firmware(&fw, WL1271_FW_NAME, &wl->spi->dev); | ||
220 | |||
221 | if (ret < 0) { | ||
222 | wl1271_error("could not get firmware: %d", ret); | ||
223 | return ret; | ||
224 | } | ||
225 | |||
226 | if (fw->size % 4) { | ||
227 | wl1271_error("firmware size is not multiple of 32 bits: %zu", | ||
228 | fw->size); | ||
229 | ret = -EILSEQ; | ||
230 | goto out; | ||
231 | } | ||
232 | |||
233 | wl->fw_len = fw->size; | ||
234 | wl->fw = kmalloc(wl->fw_len, GFP_KERNEL); | ||
235 | |||
236 | if (!wl->fw) { | ||
237 | wl1271_error("could not allocate memory for the firmware"); | ||
238 | ret = -ENOMEM; | ||
239 | goto out; | ||
240 | } | ||
241 | |||
242 | memcpy(wl->fw, fw->data, wl->fw_len); | ||
243 | |||
244 | ret = 0; | ||
245 | |||
246 | out: | ||
247 | release_firmware(fw); | ||
248 | |||
249 | return ret; | ||
250 | } | ||
251 | |||
252 | static int wl1271_fetch_nvs(struct wl1271 *wl) | ||
253 | { | ||
254 | const struct firmware *fw; | ||
255 | int ret; | ||
256 | |||
257 | ret = request_firmware(&fw, WL1271_NVS_NAME, &wl->spi->dev); | ||
258 | |||
259 | if (ret < 0) { | ||
260 | wl1271_error("could not get nvs file: %d", ret); | ||
261 | return ret; | ||
262 | } | ||
263 | |||
264 | if (fw->size % 4) { | ||
265 | wl1271_error("nvs size is not multiple of 32 bits: %zu", | ||
266 | fw->size); | ||
267 | ret = -EILSEQ; | ||
268 | goto out; | ||
269 | } | ||
270 | |||
271 | wl->nvs_len = fw->size; | ||
272 | wl->nvs = kmalloc(wl->nvs_len, GFP_KERNEL); | ||
273 | |||
274 | if (!wl->nvs) { | ||
275 | wl1271_error("could not allocate memory for the nvs file"); | ||
276 | ret = -ENOMEM; | ||
277 | goto out; | ||
278 | } | ||
279 | |||
280 | memcpy(wl->nvs, fw->data, wl->nvs_len); | ||
281 | |||
282 | ret = 0; | ||
283 | |||
284 | out: | ||
285 | release_firmware(fw); | ||
286 | |||
287 | return ret; | ||
288 | } | ||
289 | |||
290 | static void wl1271_fw_wakeup(struct wl1271 *wl) | ||
291 | { | ||
292 | u32 elp_reg; | ||
293 | |||
294 | elp_reg = ELPCTRL_WAKE_UP; | ||
295 | wl1271_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg); | ||
296 | } | ||
297 | |||
298 | static int wl1271_setup(struct wl1271 *wl) | ||
299 | { | ||
300 | wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL); | ||
301 | if (!wl->fw_status) | ||
302 | return -ENOMEM; | ||
303 | |||
304 | wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL); | ||
305 | if (!wl->tx_res_if) { | ||
306 | kfree(wl->fw_status); | ||
307 | return -ENOMEM; | ||
308 | } | ||
309 | |||
310 | INIT_WORK(&wl->irq_work, wl1271_irq_work); | ||
311 | INIT_WORK(&wl->tx_work, wl1271_tx_work); | ||
312 | return 0; | ||
313 | } | ||
314 | |||
315 | static int wl1271_chip_wakeup(struct wl1271 *wl) | ||
316 | { | ||
317 | int ret = 0; | ||
318 | |||
319 | wl1271_power_on(wl); | ||
320 | msleep(WL1271_POWER_ON_SLEEP); | ||
321 | wl1271_spi_reset(wl); | ||
322 | wl1271_spi_init(wl); | ||
323 | |||
324 | /* We don't need a real memory partition here, because we only want | ||
325 | * to use the registers at this point. */ | ||
326 | wl1271_set_partition(wl, | ||
327 | 0x00000000, | ||
328 | 0x00000000, | ||
329 | REGISTERS_BASE, | ||
330 | REGISTERS_DOWN_SIZE); | ||
331 | |||
332 | /* ELP module wake up */ | ||
333 | wl1271_fw_wakeup(wl); | ||
334 | |||
335 | /* whal_FwCtrl_BootSm() */ | ||
336 | |||
337 | /* 0. read chip id from CHIP_ID */ | ||
338 | wl->chip.id = wl1271_reg_read32(wl, CHIP_ID_B); | ||
339 | |||
340 | /* 1. check if chip id is valid */ | ||
341 | |||
342 | switch (wl->chip.id) { | ||
343 | case CHIP_ID_1271_PG10: | ||
344 | wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete", | ||
345 | wl->chip.id); | ||
346 | |||
347 | ret = wl1271_setup(wl); | ||
348 | if (ret < 0) | ||
349 | goto out; | ||
350 | break; | ||
351 | case CHIP_ID_1271_PG20: | ||
352 | wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)", | ||
353 | wl->chip.id); | ||
354 | |||
355 | ret = wl1271_setup(wl); | ||
356 | if (ret < 0) | ||
357 | goto out; | ||
358 | break; | ||
359 | default: | ||
360 | wl1271_error("unsupported chip id: 0x%x", wl->chip.id); | ||
361 | ret = -ENODEV; | ||
362 | goto out; | ||
363 | } | ||
364 | |||
365 | if (wl->fw == NULL) { | ||
366 | ret = wl1271_fetch_firmware(wl); | ||
367 | if (ret < 0) | ||
368 | goto out; | ||
369 | } | ||
370 | |||
371 | /* No NVS from netlink, try to get it from the filesystem */ | ||
372 | if (wl->nvs == NULL) { | ||
373 | ret = wl1271_fetch_nvs(wl); | ||
374 | if (ret < 0) | ||
375 | goto out; | ||
376 | } | ||
377 | |||
378 | out: | ||
379 | return ret; | ||
380 | } | ||
381 | |||
382 | static void wl1271_filter_work(struct work_struct *work) | ||
383 | { | ||
384 | struct wl1271 *wl = | ||
385 | container_of(work, struct wl1271, filter_work); | ||
386 | int ret; | ||
387 | |||
388 | mutex_lock(&wl->mutex); | ||
389 | |||
390 | if (wl->state == WL1271_STATE_OFF) | ||
391 | goto out; | ||
392 | |||
393 | ret = wl1271_ps_elp_wakeup(wl, false); | ||
394 | if (ret < 0) | ||
395 | goto out; | ||
396 | |||
397 | /* FIXME: replace the magic numbers with proper definitions */ | ||
398 | ret = wl1271_cmd_join(wl, wl->bss_type, 1, 100, 0); | ||
399 | if (ret < 0) | ||
400 | goto out_sleep; | ||
401 | |||
402 | out_sleep: | ||
403 | wl1271_ps_elp_sleep(wl); | ||
404 | |||
405 | out: | ||
406 | mutex_unlock(&wl->mutex); | ||
407 | } | ||
408 | |||
409 | int wl1271_plt_start(struct wl1271 *wl) | ||
410 | { | ||
411 | int ret; | ||
412 | |||
413 | mutex_lock(&wl->mutex); | ||
414 | |||
415 | wl1271_notice("power up"); | ||
416 | |||
417 | if (wl->state != WL1271_STATE_OFF) { | ||
418 | wl1271_error("cannot go into PLT state because not " | ||
419 | "in off state: %d", wl->state); | ||
420 | ret = -EBUSY; | ||
421 | goto out; | ||
422 | } | ||
423 | |||
424 | wl->state = WL1271_STATE_PLT; | ||
425 | |||
426 | ret = wl1271_chip_wakeup(wl); | ||
427 | if (ret < 0) | ||
428 | goto out; | ||
429 | |||
430 | ret = wl1271_boot(wl); | ||
431 | if (ret < 0) | ||
432 | goto out; | ||
433 | |||
434 | wl1271_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver); | ||
435 | |||
436 | ret = wl1271_plt_init(wl); | ||
437 | if (ret < 0) | ||
438 | goto out; | ||
439 | |||
440 | out: | ||
441 | mutex_unlock(&wl->mutex); | ||
442 | |||
443 | return ret; | ||
444 | } | ||
445 | |||
446 | int wl1271_plt_stop(struct wl1271 *wl) | ||
447 | { | ||
448 | int ret = 0; | ||
449 | |||
450 | mutex_lock(&wl->mutex); | ||
451 | |||
452 | wl1271_notice("power down"); | ||
453 | |||
454 | if (wl->state != WL1271_STATE_PLT) { | ||
455 | wl1271_error("cannot power down because not in PLT " | ||
456 | "state: %d", wl->state); | ||
457 | ret = -EBUSY; | ||
458 | goto out; | ||
459 | } | ||
460 | |||
461 | wl1271_disable_interrupts(wl); | ||
462 | wl1271_power_off(wl); | ||
463 | |||
464 | wl->state = WL1271_STATE_OFF; | ||
465 | |||
466 | out: | ||
467 | mutex_unlock(&wl->mutex); | ||
468 | |||
469 | return ret; | ||
470 | } | ||
471 | |||
472 | |||
473 | static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | ||
474 | { | ||
475 | struct wl1271 *wl = hw->priv; | ||
476 | |||
477 | skb_queue_tail(&wl->tx_queue, skb); | ||
478 | |||
479 | /* | ||
480 | * The chip specific setup must run before the first TX packet - | ||
481 | * before that, the tx_work will not be initialized! | ||
482 | */ | ||
483 | |||
484 | schedule_work(&wl->tx_work); | ||
485 | |||
486 | /* | ||
487 | * The workqueue is slow to process the tx_queue and we need stop | ||
488 | * the queue here, otherwise the queue will get too long. | ||
489 | */ | ||
490 | if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_MAX_LENGTH) { | ||
491 | ieee80211_stop_queues(wl->hw); | ||
492 | |||
493 | /* | ||
494 | * FIXME: this is racy, the variable is not properly | ||
495 | * protected. Maybe fix this by removing the stupid | ||
496 | * variable altogether and checking the real queue state? | ||
497 | */ | ||
498 | wl->tx_queue_stopped = true; | ||
499 | } | ||
500 | |||
501 | return NETDEV_TX_OK; | ||
502 | } | ||
503 | |||
504 | static int wl1271_op_start(struct ieee80211_hw *hw) | ||
505 | { | ||
506 | struct wl1271 *wl = hw->priv; | ||
507 | int ret = 0; | ||
508 | |||
509 | wl1271_debug(DEBUG_MAC80211, "mac80211 start"); | ||
510 | |||
511 | mutex_lock(&wl->mutex); | ||
512 | |||
513 | if (wl->state != WL1271_STATE_OFF) { | ||
514 | wl1271_error("cannot start because not in off state: %d", | ||
515 | wl->state); | ||
516 | ret = -EBUSY; | ||
517 | goto out; | ||
518 | } | ||
519 | |||
520 | ret = wl1271_chip_wakeup(wl); | ||
521 | if (ret < 0) | ||
522 | goto out; | ||
523 | |||
524 | ret = wl1271_boot(wl); | ||
525 | if (ret < 0) | ||
526 | goto out; | ||
527 | |||
528 | ret = wl1271_hw_init(wl); | ||
529 | if (ret < 0) | ||
530 | goto out; | ||
531 | |||
532 | wl->state = WL1271_STATE_ON; | ||
533 | |||
534 | wl1271_info("firmware booted (%s)", wl->chip.fw_ver); | ||
535 | |||
536 | out: | ||
537 | if (ret < 0) | ||
538 | wl1271_power_off(wl); | ||
539 | |||
540 | mutex_unlock(&wl->mutex); | ||
541 | |||
542 | return ret; | ||
543 | } | ||
544 | |||
545 | static void wl1271_op_stop(struct ieee80211_hw *hw) | ||
546 | { | ||
547 | struct wl1271 *wl = hw->priv; | ||
548 | int i; | ||
549 | |||
550 | wl1271_info("down"); | ||
551 | |||
552 | wl1271_debug(DEBUG_MAC80211, "mac80211 stop"); | ||
553 | |||
554 | mutex_lock(&wl->mutex); | ||
555 | |||
556 | WARN_ON(wl->state != WL1271_STATE_ON); | ||
557 | |||
558 | if (wl->scanning) { | ||
559 | mutex_unlock(&wl->mutex); | ||
560 | ieee80211_scan_completed(wl->hw, true); | ||
561 | mutex_lock(&wl->mutex); | ||
562 | wl->scanning = false; | ||
563 | } | ||
564 | |||
565 | wl->state = WL1271_STATE_OFF; | ||
566 | |||
567 | wl1271_disable_interrupts(wl); | ||
568 | |||
569 | mutex_unlock(&wl->mutex); | ||
570 | |||
571 | cancel_work_sync(&wl->irq_work); | ||
572 | cancel_work_sync(&wl->tx_work); | ||
573 | cancel_work_sync(&wl->filter_work); | ||
574 | |||
575 | mutex_lock(&wl->mutex); | ||
576 | |||
577 | /* let's notify MAC80211 about the remaining pending TX frames */ | ||
578 | wl1271_tx_flush(wl); | ||
579 | wl1271_power_off(wl); | ||
580 | |||
581 | memset(wl->bssid, 0, ETH_ALEN); | ||
582 | memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1); | ||
583 | wl->ssid_len = 0; | ||
584 | wl->listen_int = 1; | ||
585 | wl->bss_type = MAX_BSS_TYPE; | ||
586 | |||
587 | wl->rx_counter = 0; | ||
588 | wl->elp = false; | ||
589 | wl->psm = 0; | ||
590 | wl->tx_queue_stopped = false; | ||
591 | wl->power_level = WL1271_DEFAULT_POWER_LEVEL; | ||
592 | wl->tx_blocks_available = 0; | ||
593 | wl->tx_results_count = 0; | ||
594 | wl->tx_packets_count = 0; | ||
595 | wl->time_offset = 0; | ||
596 | wl->session_counter = 0; | ||
597 | for (i = 0; i < NUM_TX_QUEUES; i++) | ||
598 | wl->tx_blocks_freed[i] = 0; | ||
599 | |||
600 | wl1271_debugfs_reset(wl); | ||
601 | mutex_unlock(&wl->mutex); | ||
602 | } | ||
603 | |||
604 | static int wl1271_op_add_interface(struct ieee80211_hw *hw, | ||
605 | struct ieee80211_if_init_conf *conf) | ||
606 | { | ||
607 | struct wl1271 *wl = hw->priv; | ||
608 | DECLARE_MAC_BUF(mac); | ||
609 | int ret = 0; | ||
610 | |||
611 | wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %s", | ||
612 | conf->type, print_mac(mac, conf->mac_addr)); | ||
613 | |||
614 | mutex_lock(&wl->mutex); | ||
615 | |||
616 | switch (conf->type) { | ||
617 | case NL80211_IFTYPE_STATION: | ||
618 | wl->bss_type = BSS_TYPE_STA_BSS; | ||
619 | break; | ||
620 | case NL80211_IFTYPE_ADHOC: | ||
621 | wl->bss_type = BSS_TYPE_IBSS; | ||
622 | break; | ||
623 | default: | ||
624 | ret = -EOPNOTSUPP; | ||
625 | goto out; | ||
626 | } | ||
627 | |||
628 | /* FIXME: what if conf->mac_addr changes? */ | ||
629 | |||
630 | out: | ||
631 | mutex_unlock(&wl->mutex); | ||
632 | return ret; | ||
633 | } | ||
634 | |||
635 | static void wl1271_op_remove_interface(struct ieee80211_hw *hw, | ||
636 | struct ieee80211_if_init_conf *conf) | ||
637 | { | ||
638 | wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface"); | ||
639 | } | ||
640 | |||
641 | #if 0 | ||
642 | static int wl1271_op_config_interface(struct ieee80211_hw *hw, | ||
643 | struct ieee80211_vif *vif, | ||
644 | struct ieee80211_if_conf *conf) | ||
645 | { | ||
646 | struct wl1271 *wl = hw->priv; | ||
647 | struct sk_buff *beacon; | ||
648 | DECLARE_MAC_BUF(mac); | ||
649 | int ret; | ||
650 | |||
651 | wl1271_debug(DEBUG_MAC80211, "mac80211 config_interface bssid %s", | ||
652 | print_mac(mac, conf->bssid)); | ||
653 | wl1271_dump_ascii(DEBUG_MAC80211, "ssid: ", conf->ssid, | ||
654 | conf->ssid_len); | ||
655 | |||
656 | mutex_lock(&wl->mutex); | ||
657 | |||
658 | ret = wl1271_ps_elp_wakeup(wl, false); | ||
659 | if (ret < 0) | ||
660 | goto out; | ||
661 | |||
662 | memcpy(wl->bssid, conf->bssid, ETH_ALEN); | ||
663 | |||
664 | ret = wl1271_cmd_build_null_data(wl); | ||
665 | if (ret < 0) | ||
666 | goto out_sleep; | ||
667 | |||
668 | wl->ssid_len = conf->ssid_len; | ||
669 | if (wl->ssid_len) | ||
670 | memcpy(wl->ssid, conf->ssid, wl->ssid_len); | ||
671 | |||
672 | if (wl->bss_type != BSS_TYPE_IBSS) { | ||
673 | /* FIXME: replace the magic numbers with proper definitions */ | ||
674 | ret = wl1271_cmd_join(wl, wl->bss_type, 5, 100, 1); | ||
675 | if (ret < 0) | ||
676 | goto out_sleep; | ||
677 | } | ||
678 | |||
679 | if (conf->changed & IEEE80211_IFCC_BEACON) { | ||
680 | beacon = ieee80211_beacon_get(hw, vif); | ||
681 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON, | ||
682 | beacon->data, beacon->len); | ||
683 | |||
684 | if (ret < 0) { | ||
685 | dev_kfree_skb(beacon); | ||
686 | goto out_sleep; | ||
687 | } | ||
688 | |||
689 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE, | ||
690 | beacon->data, beacon->len); | ||
691 | |||
692 | dev_kfree_skb(beacon); | ||
693 | |||
694 | if (ret < 0) | ||
695 | goto out_sleep; | ||
696 | |||
697 | /* FIXME: replace the magic numbers with proper definitions */ | ||
698 | ret = wl1271_cmd_join(wl, wl->bss_type, 1, 100, 0); | ||
699 | |||
700 | if (ret < 0) | ||
701 | goto out_sleep; | ||
702 | } | ||
703 | |||
704 | out_sleep: | ||
705 | wl1271_ps_elp_sleep(wl); | ||
706 | |||
707 | out: | ||
708 | mutex_unlock(&wl->mutex); | ||
709 | |||
710 | return ret; | ||
711 | } | ||
712 | #endif | ||
713 | |||
714 | static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) | ||
715 | { | ||
716 | struct wl1271 *wl = hw->priv; | ||
717 | struct ieee80211_conf *conf = &hw->conf; | ||
718 | int channel, ret = 0; | ||
719 | |||
720 | channel = ieee80211_frequency_to_channel(conf->channel->center_freq); | ||
721 | |||
722 | wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d", | ||
723 | channel, | ||
724 | conf->flags & IEEE80211_CONF_PS ? "on" : "off", | ||
725 | conf->power_level); | ||
726 | |||
727 | mutex_lock(&wl->mutex); | ||
728 | |||
729 | ret = wl1271_ps_elp_wakeup(wl, false); | ||
730 | if (ret < 0) | ||
731 | goto out; | ||
732 | |||
733 | if (channel != wl->channel) { | ||
734 | u8 old_channel = wl->channel; | ||
735 | wl->channel = channel; | ||
736 | |||
737 | /* FIXME: use beacon interval provided by mac80211 */ | ||
738 | ret = wl1271_cmd_join(wl, wl->bss_type, 1, 100, 0); | ||
739 | if (ret < 0) { | ||
740 | wl->channel = old_channel; | ||
741 | goto out_sleep; | ||
742 | } | ||
743 | } | ||
744 | |||
745 | ret = wl1271_cmd_build_null_data(wl); | ||
746 | if (ret < 0) | ||
747 | goto out_sleep; | ||
748 | |||
749 | if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) { | ||
750 | wl1271_info("psm enabled"); | ||
751 | |||
752 | wl->psm_requested = true; | ||
753 | |||
754 | /* | ||
755 | * We enter PSM only if we're already associated. | ||
756 | * If we're not, we'll enter it when joining an SSID, | ||
757 | * through the bss_info_changed() hook. | ||
758 | */ | ||
759 | ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE); | ||
760 | } else if (!(conf->flags & IEEE80211_CONF_PS) && | ||
761 | wl->psm_requested) { | ||
762 | wl1271_info("psm disabled"); | ||
763 | |||
764 | wl->psm_requested = false; | ||
765 | |||
766 | if (wl->psm) | ||
767 | ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE); | ||
768 | } | ||
769 | |||
770 | if (conf->power_level != wl->power_level) { | ||
771 | ret = wl1271_acx_tx_power(wl, conf->power_level); | ||
772 | if (ret < 0) | ||
773 | goto out; | ||
774 | |||
775 | wl->power_level = conf->power_level; | ||
776 | } | ||
777 | |||
778 | out_sleep: | ||
779 | wl1271_ps_elp_sleep(wl); | ||
780 | |||
781 | out: | ||
782 | mutex_unlock(&wl->mutex); | ||
783 | |||
784 | return ret; | ||
785 | } | ||
786 | |||
787 | #define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \ | ||
788 | FIF_ALLMULTI | \ | ||
789 | FIF_FCSFAIL | \ | ||
790 | FIF_BCN_PRBRESP_PROMISC | \ | ||
791 | FIF_CONTROL | \ | ||
792 | FIF_OTHER_BSS) | ||
793 | |||
794 | static void wl1271_op_configure_filter(struct ieee80211_hw *hw, | ||
795 | unsigned int changed, | ||
796 | unsigned int *total, | ||
797 | int mc_count, | ||
798 | struct dev_addr_list *mc_list) | ||
799 | { | ||
800 | struct wl1271 *wl = hw->priv; | ||
801 | |||
802 | wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter"); | ||
803 | |||
804 | *total &= WL1271_SUPPORTED_FILTERS; | ||
805 | changed &= WL1271_SUPPORTED_FILTERS; | ||
806 | |||
807 | if (changed == 0) | ||
808 | return; | ||
809 | |||
810 | /* FIXME: wl->rx_config and wl->rx_filter are not protected */ | ||
811 | wl->rx_config = WL1271_DEFAULT_RX_CONFIG; | ||
812 | wl->rx_filter = WL1271_DEFAULT_RX_FILTER; | ||
813 | |||
814 | /* | ||
815 | * FIXME: workqueues need to be properly cancelled on stop(), for | ||
816 | * now let's just disable changing the filter settings. They will | ||
817 | * be updated any on config(). | ||
818 | */ | ||
819 | /* schedule_work(&wl->filter_work); */ | ||
820 | } | ||
821 | |||
822 | static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | ||
823 | struct ieee80211_vif *vif, | ||
824 | struct ieee80211_sta *sta, | ||
825 | struct ieee80211_key_conf *key_conf) | ||
826 | { | ||
827 | struct wl1271 *wl = hw->priv; | ||
828 | const u8 *addr; | ||
829 | int ret; | ||
830 | u8 key_type; | ||
831 | |||
832 | static const u8 bcast_addr[ETH_ALEN] = | ||
833 | { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; | ||
834 | |||
835 | wl1271_debug(DEBUG_MAC80211, "mac80211 set key"); | ||
836 | |||
837 | addr = sta ? sta->addr : bcast_addr; | ||
838 | |||
839 | wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd); | ||
840 | wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN); | ||
841 | wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x", | ||
842 | key_conf->alg, key_conf->keyidx, | ||
843 | key_conf->keylen, key_conf->flags); | ||
844 | wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen); | ||
845 | |||
846 | if (is_zero_ether_addr(addr)) { | ||
847 | /* We dont support TX only encryption */ | ||
848 | ret = -EOPNOTSUPP; | ||
849 | goto out; | ||
850 | } | ||
851 | |||
852 | mutex_lock(&wl->mutex); | ||
853 | |||
854 | ret = wl1271_ps_elp_wakeup(wl, false); | ||
855 | if (ret < 0) | ||
856 | goto out_unlock; | ||
857 | |||
858 | switch (key_conf->alg) { | ||
859 | case ALG_WEP: | ||
860 | key_type = KEY_WEP; | ||
861 | |||
862 | key_conf->hw_key_idx = key_conf->keyidx; | ||
863 | break; | ||
864 | case ALG_TKIP: | ||
865 | key_type = KEY_TKIP; | ||
866 | |||
867 | key_conf->hw_key_idx = key_conf->keyidx; | ||
868 | break; | ||
869 | case ALG_CCMP: | ||
870 | key_type = KEY_AES; | ||
871 | |||
872 | key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; | ||
873 | break; | ||
874 | default: | ||
875 | wl1271_error("Unknown key algo 0x%x", key_conf->alg); | ||
876 | |||
877 | ret = -EOPNOTSUPP; | ||
878 | goto out_sleep; | ||
879 | } | ||
880 | |||
881 | switch (cmd) { | ||
882 | case SET_KEY: | ||
883 | ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE, | ||
884 | key_conf->keyidx, key_type, | ||
885 | key_conf->keylen, key_conf->key, | ||
886 | addr); | ||
887 | if (ret < 0) { | ||
888 | wl1271_error("Could not add or replace key"); | ||
889 | goto out_sleep; | ||
890 | } | ||
891 | break; | ||
892 | |||
893 | case DISABLE_KEY: | ||
894 | ret = wl1271_cmd_set_key(wl, KEY_REMOVE, | ||
895 | key_conf->keyidx, key_type, | ||
896 | key_conf->keylen, key_conf->key, | ||
897 | addr); | ||
898 | if (ret < 0) { | ||
899 | wl1271_error("Could not remove key"); | ||
900 | goto out_sleep; | ||
901 | } | ||
902 | break; | ||
903 | |||
904 | default: | ||
905 | wl1271_error("Unsupported key cmd 0x%x", cmd); | ||
906 | ret = -EOPNOTSUPP; | ||
907 | goto out_sleep; | ||
908 | |||
909 | break; | ||
910 | } | ||
911 | |||
912 | out_sleep: | ||
913 | wl1271_ps_elp_sleep(wl); | ||
914 | |||
915 | out_unlock: | ||
916 | mutex_unlock(&wl->mutex); | ||
917 | |||
918 | out: | ||
919 | return ret; | ||
920 | } | ||
921 | |||
922 | static int wl1271_op_hw_scan(struct ieee80211_hw *hw, | ||
923 | struct cfg80211_scan_request *req) | ||
924 | { | ||
925 | struct wl1271 *wl = hw->priv; | ||
926 | int ret; | ||
927 | u8 *ssid = NULL; | ||
928 | size_t ssid_len = 0; | ||
929 | |||
930 | wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan"); | ||
931 | |||
932 | if (req->n_ssids) { | ||
933 | ssid = req->ssids[0].ssid; | ||
934 | ssid_len = req->ssids[0].ssid_len; | ||
935 | } | ||
936 | |||
937 | mutex_lock(&wl->mutex); | ||
938 | |||
939 | ret = wl1271_ps_elp_wakeup(wl, false); | ||
940 | if (ret < 0) | ||
941 | goto out; | ||
942 | |||
943 | ret = wl1271_cmd_scan(hw->priv, ssid, ssid_len, 1, 0, 13, 3); | ||
944 | |||
945 | wl1271_ps_elp_sleep(wl); | ||
946 | |||
947 | out: | ||
948 | mutex_unlock(&wl->mutex); | ||
949 | |||
950 | return ret; | ||
951 | } | ||
952 | |||
953 | static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) | ||
954 | { | ||
955 | struct wl1271 *wl = hw->priv; | ||
956 | int ret; | ||
957 | |||
958 | mutex_lock(&wl->mutex); | ||
959 | |||
960 | ret = wl1271_ps_elp_wakeup(wl, false); | ||
961 | if (ret < 0) | ||
962 | goto out; | ||
963 | |||
964 | ret = wl1271_acx_rts_threshold(wl, (u16) value); | ||
965 | if (ret < 0) | ||
966 | wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret); | ||
967 | |||
968 | wl1271_ps_elp_sleep(wl); | ||
969 | |||
970 | out: | ||
971 | mutex_unlock(&wl->mutex); | ||
972 | |||
973 | return ret; | ||
974 | } | ||
975 | |||
976 | static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, | ||
977 | struct ieee80211_vif *vif, | ||
978 | struct ieee80211_bss_conf *bss_conf, | ||
979 | u32 changed) | ||
980 | { | ||
981 | enum wl1271_cmd_ps_mode mode; | ||
982 | struct wl1271 *wl = hw->priv; | ||
983 | int ret; | ||
984 | |||
985 | wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed"); | ||
986 | |||
987 | mutex_lock(&wl->mutex); | ||
988 | |||
989 | ret = wl1271_ps_elp_wakeup(wl, false); | ||
990 | if (ret < 0) | ||
991 | goto out; | ||
992 | |||
993 | if (changed & BSS_CHANGED_ASSOC) { | ||
994 | if (bss_conf->assoc) { | ||
995 | wl->aid = bss_conf->aid; | ||
996 | |||
997 | ret = wl1271_cmd_build_ps_poll(wl, wl->aid); | ||
998 | if (ret < 0) | ||
999 | goto out_sleep; | ||
1000 | |||
1001 | ret = wl1271_acx_aid(wl, wl->aid); | ||
1002 | if (ret < 0) | ||
1003 | goto out_sleep; | ||
1004 | |||
1005 | /* If we want to go in PSM but we're not there yet */ | ||
1006 | if (wl->psm_requested && !wl->psm) { | ||
1007 | mode = STATION_POWER_SAVE_MODE; | ||
1008 | ret = wl1271_ps_set_mode(wl, mode); | ||
1009 | if (ret < 0) | ||
1010 | goto out_sleep; | ||
1011 | } | ||
1012 | } | ||
1013 | } | ||
1014 | if (changed & BSS_CHANGED_ERP_SLOT) { | ||
1015 | if (bss_conf->use_short_slot) | ||
1016 | ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT); | ||
1017 | else | ||
1018 | ret = wl1271_acx_slot(wl, SLOT_TIME_LONG); | ||
1019 | if (ret < 0) { | ||
1020 | wl1271_warning("Set slot time failed %d", ret); | ||
1021 | goto out_sleep; | ||
1022 | } | ||
1023 | } | ||
1024 | |||
1025 | if (changed & BSS_CHANGED_ERP_PREAMBLE) { | ||
1026 | if (bss_conf->use_short_preamble) | ||
1027 | wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT); | ||
1028 | else | ||
1029 | wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG); | ||
1030 | } | ||
1031 | |||
1032 | if (changed & BSS_CHANGED_ERP_CTS_PROT) { | ||
1033 | if (bss_conf->use_cts_prot) | ||
1034 | ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE); | ||
1035 | else | ||
1036 | ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE); | ||
1037 | if (ret < 0) { | ||
1038 | wl1271_warning("Set ctsprotect failed %d", ret); | ||
1039 | goto out_sleep; | ||
1040 | } | ||
1041 | } | ||
1042 | |||
1043 | out_sleep: | ||
1044 | wl1271_ps_elp_sleep(wl); | ||
1045 | |||
1046 | out: | ||
1047 | mutex_unlock(&wl->mutex); | ||
1048 | } | ||
1049 | |||
1050 | |||
1051 | /* can't be const, mac80211 writes to this */ | ||
1052 | static struct ieee80211_rate wl1271_rates[] = { | ||
1053 | { .bitrate = 10, | ||
1054 | .hw_value = 0x1, | ||
1055 | .hw_value_short = 0x1, }, | ||
1056 | { .bitrate = 20, | ||
1057 | .hw_value = 0x2, | ||
1058 | .hw_value_short = 0x2, | ||
1059 | .flags = IEEE80211_RATE_SHORT_PREAMBLE }, | ||
1060 | { .bitrate = 55, | ||
1061 | .hw_value = 0x4, | ||
1062 | .hw_value_short = 0x4, | ||
1063 | .flags = IEEE80211_RATE_SHORT_PREAMBLE }, | ||
1064 | { .bitrate = 110, | ||
1065 | .hw_value = 0x20, | ||
1066 | .hw_value_short = 0x20, | ||
1067 | .flags = IEEE80211_RATE_SHORT_PREAMBLE }, | ||
1068 | { .bitrate = 60, | ||
1069 | .hw_value = 0x8, | ||
1070 | .hw_value_short = 0x8, }, | ||
1071 | { .bitrate = 90, | ||
1072 | .hw_value = 0x10, | ||
1073 | .hw_value_short = 0x10, }, | ||
1074 | { .bitrate = 120, | ||
1075 | .hw_value = 0x40, | ||
1076 | .hw_value_short = 0x40, }, | ||
1077 | { .bitrate = 180, | ||
1078 | .hw_value = 0x80, | ||
1079 | .hw_value_short = 0x80, }, | ||
1080 | { .bitrate = 240, | ||
1081 | .hw_value = 0x200, | ||
1082 | .hw_value_short = 0x200, }, | ||
1083 | { .bitrate = 360, | ||
1084 | .hw_value = 0x400, | ||
1085 | .hw_value_short = 0x400, }, | ||
1086 | { .bitrate = 480, | ||
1087 | .hw_value = 0x800, | ||
1088 | .hw_value_short = 0x800, }, | ||
1089 | { .bitrate = 540, | ||
1090 | .hw_value = 0x1000, | ||
1091 | .hw_value_short = 0x1000, }, | ||
1092 | }; | ||
1093 | |||
1094 | /* can't be const, mac80211 writes to this */ | ||
1095 | static struct ieee80211_channel wl1271_channels[] = { | ||
1096 | { .hw_value = 1, .center_freq = 2412}, | ||
1097 | { .hw_value = 2, .center_freq = 2417}, | ||
1098 | { .hw_value = 3, .center_freq = 2422}, | ||
1099 | { .hw_value = 4, .center_freq = 2427}, | ||
1100 | { .hw_value = 5, .center_freq = 2432}, | ||
1101 | { .hw_value = 6, .center_freq = 2437}, | ||
1102 | { .hw_value = 7, .center_freq = 2442}, | ||
1103 | { .hw_value = 8, .center_freq = 2447}, | ||
1104 | { .hw_value = 9, .center_freq = 2452}, | ||
1105 | { .hw_value = 10, .center_freq = 2457}, | ||
1106 | { .hw_value = 11, .center_freq = 2462}, | ||
1107 | { .hw_value = 12, .center_freq = 2467}, | ||
1108 | { .hw_value = 13, .center_freq = 2472}, | ||
1109 | }; | ||
1110 | |||
1111 | /* can't be const, mac80211 writes to this */ | ||
1112 | static struct ieee80211_supported_band wl1271_band_2ghz = { | ||
1113 | .channels = wl1271_channels, | ||
1114 | .n_channels = ARRAY_SIZE(wl1271_channels), | ||
1115 | .bitrates = wl1271_rates, | ||
1116 | .n_bitrates = ARRAY_SIZE(wl1271_rates), | ||
1117 | }; | ||
1118 | |||
1119 | static const struct ieee80211_ops wl1271_ops = { | ||
1120 | .start = wl1271_op_start, | ||
1121 | .stop = wl1271_op_stop, | ||
1122 | .add_interface = wl1271_op_add_interface, | ||
1123 | .remove_interface = wl1271_op_remove_interface, | ||
1124 | .config = wl1271_op_config, | ||
1125 | /* .config_interface = wl1271_op_config_interface, */ | ||
1126 | .configure_filter = wl1271_op_configure_filter, | ||
1127 | .tx = wl1271_op_tx, | ||
1128 | .set_key = wl1271_op_set_key, | ||
1129 | .hw_scan = wl1271_op_hw_scan, | ||
1130 | .bss_info_changed = wl1271_op_bss_info_changed, | ||
1131 | .set_rts_threshold = wl1271_op_set_rts_threshold, | ||
1132 | }; | ||
1133 | |||
1134 | static int wl1271_register_hw(struct wl1271 *wl) | ||
1135 | { | ||
1136 | int ret; | ||
1137 | |||
1138 | if (wl->mac80211_registered) | ||
1139 | return 0; | ||
1140 | |||
1141 | SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); | ||
1142 | |||
1143 | ret = ieee80211_register_hw(wl->hw); | ||
1144 | if (ret < 0) { | ||
1145 | wl1271_error("unable to register mac80211 hw: %d", ret); | ||
1146 | return ret; | ||
1147 | } | ||
1148 | |||
1149 | wl->mac80211_registered = true; | ||
1150 | |||
1151 | wl1271_notice("loaded"); | ||
1152 | |||
1153 | return 0; | ||
1154 | } | ||
1155 | |||
1156 | static int wl1271_init_ieee80211(struct wl1271 *wl) | ||
1157 | { | ||
1158 | /* | ||
1159 | * The tx descriptor buffer and the TKIP space. | ||
1160 | * | ||
1161 | * FIXME: add correct 1271 descriptor size | ||
1162 | */ | ||
1163 | wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE; | ||
1164 | |||
1165 | /* unit us */ | ||
1166 | /* FIXME: find a proper value */ | ||
1167 | wl->hw->channel_change_time = 10000; | ||
1168 | |||
1169 | wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | | ||
1170 | IEEE80211_HW_NOISE_DBM; | ||
1171 | |||
1172 | wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); | ||
1173 | wl->hw->wiphy->max_scan_ssids = 1; | ||
1174 | wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz; | ||
1175 | |||
1176 | SET_IEEE80211_DEV(wl->hw, &wl->spi->dev); | ||
1177 | |||
1178 | return 0; | ||
1179 | } | ||
1180 | |||
1181 | static void wl1271_device_release(struct device *dev) | ||
1182 | { | ||
1183 | |||
1184 | } | ||
1185 | |||
1186 | static struct platform_device wl1271_device = { | ||
1187 | .name = "wl1271", | ||
1188 | .id = -1, | ||
1189 | |||
1190 | /* device model insists to have a release function */ | ||
1191 | .dev = { | ||
1192 | .release = wl1271_device_release, | ||
1193 | }, | ||
1194 | }; | ||
1195 | |||
1196 | #define WL1271_DEFAULT_CHANNEL 0 | ||
1197 | static int __devinit wl1271_probe(struct spi_device *spi) | ||
1198 | { | ||
1199 | struct wl12xx_platform_data *pdata; | ||
1200 | struct ieee80211_hw *hw; | ||
1201 | struct wl1271 *wl; | ||
1202 | int ret, i; | ||
1203 | static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf}; | ||
1204 | |||
1205 | pdata = spi->dev.platform_data; | ||
1206 | if (!pdata) { | ||
1207 | wl1271_error("no platform data"); | ||
1208 | return -ENODEV; | ||
1209 | } | ||
1210 | |||
1211 | hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops); | ||
1212 | if (!hw) { | ||
1213 | wl1271_error("could not alloc ieee80211_hw"); | ||
1214 | return -ENOMEM; | ||
1215 | } | ||
1216 | |||
1217 | wl = hw->priv; | ||
1218 | memset(wl, 0, sizeof(*wl)); | ||
1219 | |||
1220 | wl->hw = hw; | ||
1221 | dev_set_drvdata(&spi->dev, wl); | ||
1222 | wl->spi = spi; | ||
1223 | |||
1224 | skb_queue_head_init(&wl->tx_queue); | ||
1225 | |||
1226 | INIT_WORK(&wl->filter_work, wl1271_filter_work); | ||
1227 | wl->channel = WL1271_DEFAULT_CHANNEL; | ||
1228 | wl->scanning = false; | ||
1229 | wl->default_key = 0; | ||
1230 | wl->listen_int = 1; | ||
1231 | wl->rx_counter = 0; | ||
1232 | wl->rx_config = WL1271_DEFAULT_RX_CONFIG; | ||
1233 | wl->rx_filter = WL1271_DEFAULT_RX_FILTER; | ||
1234 | wl->elp = false; | ||
1235 | wl->psm = 0; | ||
1236 | wl->psm_requested = false; | ||
1237 | wl->tx_queue_stopped = false; | ||
1238 | wl->power_level = WL1271_DEFAULT_POWER_LEVEL; | ||
1239 | |||
1240 | /* We use the default power on sleep time until we know which chip | ||
1241 | * we're using */ | ||
1242 | for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) | ||
1243 | wl->tx_frames[i] = NULL; | ||
1244 | |||
1245 | spin_lock_init(&wl->wl_lock); | ||
1246 | |||
1247 | /* | ||
1248 | * In case our MAC address is not correctly set, | ||
1249 | * we use a random but Nokia MAC. | ||
1250 | */ | ||
1251 | memcpy(wl->mac_addr, nokia_oui, 3); | ||
1252 | get_random_bytes(wl->mac_addr + 3, 3); | ||
1253 | |||
1254 | wl->state = WL1271_STATE_OFF; | ||
1255 | mutex_init(&wl->mutex); | ||
1256 | |||
1257 | wl->rx_descriptor = kmalloc(sizeof(*wl->rx_descriptor), GFP_KERNEL); | ||
1258 | if (!wl->rx_descriptor) { | ||
1259 | wl1271_error("could not allocate memory for rx descriptor"); | ||
1260 | ret = -ENOMEM; | ||
1261 | goto out_free; | ||
1262 | } | ||
1263 | |||
1264 | /* This is the only SPI value that we need to set here, the rest | ||
1265 | * comes from the board-peripherals file */ | ||
1266 | spi->bits_per_word = 32; | ||
1267 | |||
1268 | ret = spi_setup(spi); | ||
1269 | if (ret < 0) { | ||
1270 | wl1271_error("spi_setup failed"); | ||
1271 | goto out_free; | ||
1272 | } | ||
1273 | |||
1274 | wl->set_power = pdata->set_power; | ||
1275 | if (!wl->set_power) { | ||
1276 | wl1271_error("set power function missing in platform data"); | ||
1277 | ret = -ENODEV; | ||
1278 | goto out_free; | ||
1279 | } | ||
1280 | |||
1281 | wl->irq = spi->irq; | ||
1282 | if (wl->irq < 0) { | ||
1283 | wl1271_error("irq missing in platform data"); | ||
1284 | ret = -ENODEV; | ||
1285 | goto out_free; | ||
1286 | } | ||
1287 | |||
1288 | ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl); | ||
1289 | if (ret < 0) { | ||
1290 | wl1271_error("request_irq() failed: %d", ret); | ||
1291 | goto out_free; | ||
1292 | } | ||
1293 | |||
1294 | set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); | ||
1295 | |||
1296 | disable_irq(wl->irq); | ||
1297 | |||
1298 | ret = platform_device_register(&wl1271_device); | ||
1299 | if (ret) { | ||
1300 | wl1271_error("couldn't register platform device"); | ||
1301 | goto out_irq; | ||
1302 | } | ||
1303 | dev_set_drvdata(&wl1271_device.dev, wl); | ||
1304 | |||
1305 | ret = wl1271_init_ieee80211(wl); | ||
1306 | if (ret) | ||
1307 | goto out_platform; | ||
1308 | |||
1309 | ret = wl1271_register_hw(wl); | ||
1310 | if (ret) | ||
1311 | goto out_platform; | ||
1312 | |||
1313 | wl1271_debugfs_init(wl); | ||
1314 | |||
1315 | wl1271_notice("initialized"); | ||
1316 | |||
1317 | return 0; | ||
1318 | |||
1319 | out_platform: | ||
1320 | platform_device_unregister(&wl1271_device); | ||
1321 | |||
1322 | out_irq: | ||
1323 | free_irq(wl->irq, wl); | ||
1324 | |||
1325 | out_free: | ||
1326 | kfree(wl->rx_descriptor); | ||
1327 | wl->rx_descriptor = NULL; | ||
1328 | |||
1329 | ieee80211_free_hw(hw); | ||
1330 | |||
1331 | return ret; | ||
1332 | } | ||
1333 | |||
1334 | static int __devexit wl1271_remove(struct spi_device *spi) | ||
1335 | { | ||
1336 | struct wl1271 *wl = dev_get_drvdata(&spi->dev); | ||
1337 | |||
1338 | ieee80211_unregister_hw(wl->hw); | ||
1339 | |||
1340 | wl1271_debugfs_exit(wl); | ||
1341 | platform_device_unregister(&wl1271_device); | ||
1342 | free_irq(wl->irq, wl); | ||
1343 | kfree(wl->target_mem_map); | ||
1344 | kfree(wl->fw); | ||
1345 | wl->fw = NULL; | ||
1346 | kfree(wl->nvs); | ||
1347 | wl->nvs = NULL; | ||
1348 | |||
1349 | kfree(wl->rx_descriptor); | ||
1350 | wl->rx_descriptor = NULL; | ||
1351 | |||
1352 | kfree(wl->fw_status); | ||
1353 | kfree(wl->tx_res_if); | ||
1354 | |||
1355 | ieee80211_free_hw(wl->hw); | ||
1356 | |||
1357 | return 0; | ||
1358 | } | ||
1359 | |||
1360 | |||
1361 | static struct spi_driver wl1271_spi_driver = { | ||
1362 | .driver = { | ||
1363 | .name = "wl1271", | ||
1364 | .bus = &spi_bus_type, | ||
1365 | .owner = THIS_MODULE, | ||
1366 | }, | ||
1367 | |||
1368 | .probe = wl1271_probe, | ||
1369 | .remove = __devexit_p(wl1271_remove), | ||
1370 | }; | ||
1371 | |||
1372 | static int __init wl1271_init(void) | ||
1373 | { | ||
1374 | int ret; | ||
1375 | |||
1376 | ret = spi_register_driver(&wl1271_spi_driver); | ||
1377 | if (ret < 0) { | ||
1378 | wl1271_error("failed to register spi driver: %d", ret); | ||
1379 | goto out; | ||
1380 | } | ||
1381 | |||
1382 | out: | ||
1383 | return ret; | ||
1384 | } | ||
1385 | |||
1386 | static void __exit wl1271_exit(void) | ||
1387 | { | ||
1388 | spi_unregister_driver(&wl1271_spi_driver); | ||
1389 | |||
1390 | wl1271_notice("unloaded"); | ||
1391 | } | ||
1392 | |||
1393 | module_init(wl1271_init); | ||
1394 | module_exit(wl1271_exit); | ||
1395 | |||
1396 | MODULE_LICENSE("GPL"); | ||
1397 | MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>"); | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_ps.c b/drivers/net/wireless/wl12xx/wl1271_ps.c new file mode 100644 index 000000000000..1dc74b0c7736 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_ps.c | |||
@@ -0,0 +1,142 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2008-2009 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include "wl1271_reg.h" | ||
25 | #include "wl1271_ps.h" | ||
26 | #include "wl1271_spi.h" | ||
27 | |||
28 | #define WL1271_WAKEUP_TIMEOUT 500 | ||
29 | |||
30 | /* Routines to toggle sleep mode while in ELP */ | ||
31 | void wl1271_ps_elp_sleep(struct wl1271 *wl) | ||
32 | { | ||
33 | /* | ||
34 | * FIXME: due to a problem in the firmware (causing a firmware | ||
35 | * crash), ELP entry is prevented below. Remove the "true" to | ||
36 | * re-enable ELP entry. | ||
37 | */ | ||
38 | if (true || wl->elp || !wl->psm) | ||
39 | return; | ||
40 | |||
41 | /* | ||
42 | * Go to ELP unless there is work already pending - pending work | ||
43 | * will immediately wakeup the chipset anyway. | ||
44 | */ | ||
45 | if (!work_pending(&wl->irq_work) && !work_pending(&wl->tx_work)) { | ||
46 | wl1271_debug(DEBUG_PSM, "chip to elp"); | ||
47 | wl1271_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP); | ||
48 | wl->elp = true; | ||
49 | } | ||
50 | } | ||
51 | |||
52 | int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake) | ||
53 | { | ||
54 | DECLARE_COMPLETION_ONSTACK(compl); | ||
55 | unsigned long flags; | ||
56 | int ret; | ||
57 | u32 start_time = jiffies; | ||
58 | bool pending = false; | ||
59 | |||
60 | if (!wl->elp) | ||
61 | return 0; | ||
62 | |||
63 | wl1271_debug(DEBUG_PSM, "waking up chip from elp"); | ||
64 | |||
65 | /* | ||
66 | * The spinlock is required here to synchronize both the work and | ||
67 | * the completion variable in one entity. | ||
68 | */ | ||
69 | spin_lock_irqsave(&wl->wl_lock, flags); | ||
70 | if (work_pending(&wl->irq_work) || chip_awake) | ||
71 | pending = true; | ||
72 | else | ||
73 | wl->elp_compl = &compl; | ||
74 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
75 | |||
76 | wl1271_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP); | ||
77 | |||
78 | if (!pending) { | ||
79 | ret = wait_for_completion_timeout( | ||
80 | &compl, msecs_to_jiffies(WL1271_WAKEUP_TIMEOUT)); | ||
81 | if (ret == 0) { | ||
82 | wl1271_error("ELP wakeup timeout!"); | ||
83 | ret = -ETIMEDOUT; | ||
84 | goto err; | ||
85 | } else if (ret < 0) { | ||
86 | wl1271_error("ELP wakeup completion error."); | ||
87 | goto err; | ||
88 | } | ||
89 | } | ||
90 | |||
91 | wl->elp = false; | ||
92 | |||
93 | wl1271_debug(DEBUG_PSM, "wakeup time: %u ms", | ||
94 | jiffies_to_msecs(jiffies - start_time)); | ||
95 | goto out; | ||
96 | |||
97 | err: | ||
98 | spin_lock_irqsave(&wl->wl_lock, flags); | ||
99 | wl->elp_compl = NULL; | ||
100 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
101 | return ret; | ||
102 | |||
103 | out: | ||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode) | ||
108 | { | ||
109 | int ret; | ||
110 | |||
111 | switch (mode) { | ||
112 | case STATION_POWER_SAVE_MODE: | ||
113 | wl1271_debug(DEBUG_PSM, "entering psm"); | ||
114 | ret = wl1271_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE); | ||
115 | if (ret < 0) | ||
116 | return ret; | ||
117 | |||
118 | wl1271_ps_elp_sleep(wl); | ||
119 | if (ret < 0) | ||
120 | return ret; | ||
121 | |||
122 | wl->psm = 1; | ||
123 | break; | ||
124 | case STATION_ACTIVE_MODE: | ||
125 | default: | ||
126 | wl1271_debug(DEBUG_PSM, "leaving psm"); | ||
127 | ret = wl1271_ps_elp_wakeup(wl, false); | ||
128 | if (ret < 0) | ||
129 | return ret; | ||
130 | |||
131 | ret = wl1271_cmd_ps_mode(wl, STATION_ACTIVE_MODE); | ||
132 | if (ret < 0) | ||
133 | return ret; | ||
134 | |||
135 | wl->psm = 0; | ||
136 | break; | ||
137 | } | ||
138 | |||
139 | return ret; | ||
140 | } | ||
141 | |||
142 | |||
diff --git a/drivers/net/wireless/wl12xx/wl1271_ps.h b/drivers/net/wireless/wl12xx/wl1271_ps.h new file mode 100644 index 000000000000..de2bd3c7dc9c --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_ps.h | |||
@@ -0,0 +1,35 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2008-2009 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifndef __WL1271_PS_H__ | ||
25 | #define __WL1271_PS_H__ | ||
26 | |||
27 | #include "wl1271.h" | ||
28 | #include "wl1271_acx.h" | ||
29 | |||
30 | int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode); | ||
31 | void wl1271_ps_elp_sleep(struct wl1271 *wl); | ||
32 | int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake); | ||
33 | |||
34 | |||
35 | #endif /* __WL1271_PS_H__ */ | ||
diff --git a/drivers/net/wireless/wl12xx/reg.h b/drivers/net/wireless/wl12xx/wl1271_reg.h index 2de47cc32b8b..f8ed4a4fc691 100644 --- a/drivers/net/wireless/wl12xx/reg.h +++ b/drivers/net/wireless/wl12xx/wl1271_reg.h | |||
@@ -1,10 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * This file is part of wl12xx | 2 | * This file is part of wl12xx |
3 | * | 3 | * |
4 | * Copyright (c) 1998-2007 Texas Instruments Incorporated | 4 | * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. |
5 | * Copyright (C) 2008 Nokia Corporation | 5 | * Copyright (C) 2009 Nokia Corporation |
6 | * | 6 | * |
7 | * Contact: Kalle Valo <kalle.valo@nokia.com> | 7 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or | 9 | * This program is free software; you can redistribute it and/or |
10 | * modify it under the terms of the GNU General Public License | 10 | * modify it under the terms of the GNU General Public License |
@@ -34,6 +34,7 @@ | |||
34 | #define REGISTERS_WORK_SIZE 0x0000b000 | 34 | #define REGISTERS_WORK_SIZE 0x0000b000 |
35 | 35 | ||
36 | #define HW_ACCESS_ELP_CTRL_REG_ADDR 0x1FFFC | 36 | #define HW_ACCESS_ELP_CTRL_REG_ADDR 0x1FFFC |
37 | #define STATUS_MEM_ADDRESS 0x40400 | ||
37 | 38 | ||
38 | /* ELP register commands */ | 39 | /* ELP register commands */ |
39 | #define ELPCTRL_WAKE_UP 0x1 | 40 | #define ELPCTRL_WAKE_UP 0x1 |
@@ -42,6 +43,25 @@ | |||
42 | /* ELP WLAN_READY bit */ | 43 | /* ELP WLAN_READY bit */ |
43 | #define ELPCTRL_WLAN_READY 0x2 | 44 | #define ELPCTRL_WLAN_READY 0x2 |
44 | 45 | ||
46 | /*=============================================== | ||
47 | Host Software Reset - 32bit RW | ||
48 | ------------------------------------------ | ||
49 | [31:1] Reserved | ||
50 | 0 SOFT_RESET Soft Reset - When this bit is set, | ||
51 | it holds the Wlan hardware in a soft reset state. | ||
52 | This reset disables all MAC and baseband processor | ||
53 | clocks except the CardBus/PCI interface clock. | ||
54 | It also initializes all MAC state machines except | ||
55 | the host interface. It does not reload the | ||
56 | contents of the EEPROM. When this bit is cleared | ||
57 | (not self-clearing), the Wlan hardware | ||
58 | exits the software reset state. | ||
59 | ===============================================*/ | ||
60 | #define ACX_REG_SLV_SOFT_RESET (REGISTERS_BASE + 0x0000) | ||
61 | |||
62 | #define WL1271_SLV_REG_DATA (REGISTERS_BASE + 0x0008) | ||
63 | #define WL1271_SLV_REG_ADATA (REGISTERS_BASE + 0x000c) | ||
64 | #define WL1271_SLV_MEM_DATA (REGISTERS_BASE + 0x0018) | ||
45 | /* | 65 | /* |
46 | * Interrupt registers. | 66 | * Interrupt registers. |
47 | * 64 bit interrupt sources registers ws ced. | 67 | * 64 bit interrupt sources registers ws ced. |
@@ -95,6 +115,9 @@ | |||
95 | #define HOST_MASK_CLR_L (REGISTERS_BASE + 0x0440) | 115 | #define HOST_MASK_CLR_L (REGISTERS_BASE + 0x0440) |
96 | #define HOST_MASK_CLR_H (REGISTERS_BASE + 0x0444) | 116 | #define HOST_MASK_CLR_H (REGISTERS_BASE + 0x0444) |
97 | 117 | ||
118 | #define ACX_REG_INTERRUPT_TRIG (REGISTERS_BASE + 0x0474) | ||
119 | #define ACX_REG_INTERRUPT_TRIG_H (REGISTERS_BASE + 0x0478) | ||
120 | |||
98 | /* Host Interrupts*/ | 121 | /* Host Interrupts*/ |
99 | #define HINT_MASK (REGISTERS_BASE + 0x0494) | 122 | #define HINT_MASK (REGISTERS_BASE + 0x0494) |
100 | #define HINT_MASK_SET (REGISTERS_BASE + 0x0498) | 123 | #define HINT_MASK_SET (REGISTERS_BASE + 0x0498) |
@@ -106,67 +129,6 @@ | |||
106 | #define HINT_ACK (REGISTERS_BASE + 0x04A8) | 129 | #define HINT_ACK (REGISTERS_BASE + 0x04A8) |
107 | #define HINT_TRIG (REGISTERS_BASE + 0x04AC) | 130 | #define HINT_TRIG (REGISTERS_BASE + 0x04AC) |
108 | 131 | ||
109 | /* Device Configuration registers*/ | ||
110 | #define SOR_CFG (REGISTERS_BASE + 0x0800) | ||
111 | #define ECPU_CTRL (REGISTERS_BASE + 0x0804) | ||
112 | #define HI_CFG (REGISTERS_BASE + 0x0808) | ||
113 | #define EE_START (REGISTERS_BASE + 0x080C) | ||
114 | |||
115 | #define CHIP_ID_B (REGISTERS_BASE + 0x5674) | ||
116 | |||
117 | #define CHIP_ID_1251_PG10 (0x7010101) | ||
118 | #define CHIP_ID_1251_PG11 (0x7020101) | ||
119 | #define CHIP_ID_1251_PG12 (0x7030101) | ||
120 | |||
121 | #define ENABLE (REGISTERS_BASE + 0x5450) | ||
122 | |||
123 | /* Power Management registers */ | ||
124 | #define ELP_CFG_MODE (REGISTERS_BASE + 0x5804) | ||
125 | #define ELP_CMD (REGISTERS_BASE + 0x5808) | ||
126 | #define PLL_CAL_TIME (REGISTERS_BASE + 0x5810) | ||
127 | #define CLK_REQ_TIME (REGISTERS_BASE + 0x5814) | ||
128 | #define CLK_BUF_TIME (REGISTERS_BASE + 0x5818) | ||
129 | |||
130 | #define CFG_PLL_SYNC_CNT (REGISTERS_BASE + 0x5820) | ||
131 | |||
132 | /* Scratch Pad registers*/ | ||
133 | #define SCR_PAD0 (REGISTERS_BASE + 0x5608) | ||
134 | #define SCR_PAD1 (REGISTERS_BASE + 0x560C) | ||
135 | #define SCR_PAD2 (REGISTERS_BASE + 0x5610) | ||
136 | #define SCR_PAD3 (REGISTERS_BASE + 0x5614) | ||
137 | #define SCR_PAD4 (REGISTERS_BASE + 0x5618) | ||
138 | #define SCR_PAD4_SET (REGISTERS_BASE + 0x561C) | ||
139 | #define SCR_PAD4_CLR (REGISTERS_BASE + 0x5620) | ||
140 | #define SCR_PAD5 (REGISTERS_BASE + 0x5624) | ||
141 | #define SCR_PAD5_SET (REGISTERS_BASE + 0x5628) | ||
142 | #define SCR_PAD5_CLR (REGISTERS_BASE + 0x562C) | ||
143 | #define SCR_PAD6 (REGISTERS_BASE + 0x5630) | ||
144 | #define SCR_PAD7 (REGISTERS_BASE + 0x5634) | ||
145 | #define SCR_PAD8 (REGISTERS_BASE + 0x5638) | ||
146 | #define SCR_PAD9 (REGISTERS_BASE + 0x563C) | ||
147 | |||
148 | /* Spare registers*/ | ||
149 | #define SPARE_A1 (REGISTERS_BASE + 0x0994) | ||
150 | #define SPARE_A2 (REGISTERS_BASE + 0x0998) | ||
151 | #define SPARE_A3 (REGISTERS_BASE + 0x099C) | ||
152 | #define SPARE_A4 (REGISTERS_BASE + 0x09A0) | ||
153 | #define SPARE_A5 (REGISTERS_BASE + 0x09A4) | ||
154 | #define SPARE_A6 (REGISTERS_BASE + 0x09A8) | ||
155 | #define SPARE_A7 (REGISTERS_BASE + 0x09AC) | ||
156 | #define SPARE_A8 (REGISTERS_BASE + 0x09B0) | ||
157 | #define SPARE_B1 (REGISTERS_BASE + 0x5420) | ||
158 | #define SPARE_B2 (REGISTERS_BASE + 0x5424) | ||
159 | #define SPARE_B3 (REGISTERS_BASE + 0x5428) | ||
160 | #define SPARE_B4 (REGISTERS_BASE + 0x542C) | ||
161 | #define SPARE_B5 (REGISTERS_BASE + 0x5430) | ||
162 | #define SPARE_B6 (REGISTERS_BASE + 0x5434) | ||
163 | #define SPARE_B7 (REGISTERS_BASE + 0x5438) | ||
164 | #define SPARE_B8 (REGISTERS_BASE + 0x543C) | ||
165 | |||
166 | enum wl12xx_acx_int_reg { | ||
167 | ACX_REG_INTERRUPT_TRIG, | ||
168 | ACX_REG_INTERRUPT_TRIG_H, | ||
169 | |||
170 | /*============================================= | 132 | /*============================================= |
171 | Host Interrupt Mask Register - 32bit (RW) | 133 | Host Interrupt Mask Register - 32bit (RW) |
172 | ------------------------------------------ | 134 | ------------------------------------------ |
@@ -195,7 +157,7 @@ enum wl12xx_acx_int_reg { | |||
195 | 21- - | 157 | 21- - |
196 | Default: 0x0001 | 158 | Default: 0x0001 |
197 | *==============================================*/ | 159 | *==============================================*/ |
198 | ACX_REG_INTERRUPT_MASK, | 160 | #define ACX_REG_INTERRUPT_MASK (REGISTERS_BASE + 0x04DC) |
199 | 161 | ||
200 | /*============================================= | 162 | /*============================================= |
201 | Host Interrupt Mask Set 16bit, (Write only) | 163 | Host Interrupt Mask Set 16bit, (Write only) |
@@ -205,7 +167,7 @@ enum wl12xx_acx_int_reg { | |||
205 | without effecting the mask | 167 | without effecting the mask |
206 | state of other bits (0 = no effect). | 168 | state of other bits (0 = no effect). |
207 | ==============================================*/ | 169 | ==============================================*/ |
208 | ACX_REG_HINT_MASK_SET, | 170 | #define ACX_REG_HINT_MASK_SET (REGISTERS_BASE + 0x04E0) |
209 | 171 | ||
210 | /*============================================= | 172 | /*============================================= |
211 | Host Interrupt Mask Clear 16bit,(Write only) | 173 | Host Interrupt Mask Clear 16bit,(Write only) |
@@ -215,7 +177,7 @@ enum wl12xx_acx_int_reg { | |||
215 | without effecting the mask | 177 | without effecting the mask |
216 | state of other bits (0 = no effect). | 178 | state of other bits (0 = no effect). |
217 | =============================================*/ | 179 | =============================================*/ |
218 | ACX_REG_HINT_MASK_CLR, | 180 | #define ACX_REG_HINT_MASK_CLR (REGISTERS_BASE + 0x04E4) |
219 | 181 | ||
220 | /*============================================= | 182 | /*============================================= |
221 | Host Interrupt Status Nondestructive Read | 183 | Host Interrupt Status Nondestructive Read |
@@ -226,7 +188,7 @@ enum wl12xx_acx_int_reg { | |||
226 | Reading this register doesn't | 188 | Reading this register doesn't |
227 | effect its content. | 189 | effect its content. |
228 | =============================================*/ | 190 | =============================================*/ |
229 | ACX_REG_INTERRUPT_NO_CLEAR, | 191 | #define ACX_REG_INTERRUPT_NO_CLEAR (REGISTERS_BASE + 0x04E8) |
230 | 192 | ||
231 | /*============================================= | 193 | /*============================================= |
232 | Host Interrupt Status Clear on Read Register | 194 | Host Interrupt Status Clear on Read Register |
@@ -237,7 +199,7 @@ enum wl12xx_acx_int_reg { | |||
237 | Reading this register clears it, | 199 | Reading this register clears it, |
238 | thus making all interrupts inactive. | 200 | thus making all interrupts inactive. |
239 | ==============================================*/ | 201 | ==============================================*/ |
240 | ACX_REG_INTERRUPT_CLEAR, | 202 | #define ACX_REG_INTERRUPT_CLEAR (REGISTERS_BASE + 0x04F8) |
241 | 203 | ||
242 | /*============================================= | 204 | /*============================================= |
243 | Host Interrupt Acknowledge Register | 205 | Host Interrupt Acknowledge Register |
@@ -249,40 +211,13 @@ enum wl12xx_acx_int_reg { | |||
249 | HINT_STS_ND registers, thus making the | 211 | HINT_STS_ND registers, thus making the |
250 | assotiated interrupt inactive. (0-no effect) | 212 | assotiated interrupt inactive. (0-no effect) |
251 | ==============================================*/ | 213 | ==============================================*/ |
252 | ACX_REG_INTERRUPT_ACK, | 214 | #define ACX_REG_INTERRUPT_ACK (REGISTERS_BASE + 0x04F0) |
253 | 215 | ||
254 | /*=============================================== | 216 | #define RX_DRIVER_DUMMY_WRITE_ADDRESS (REGISTERS_BASE + 0x0534) |
255 | Host Software Reset - 32bit RW | 217 | #define RX_DRIVER_COUNTER_ADDRESS (REGISTERS_BASE + 0x0538) |
256 | ------------------------------------------ | ||
257 | [31:1] Reserved | ||
258 | 0 SOFT_RESET Soft Reset - When this bit is set, | ||
259 | it holds the Wlan hardware in a soft reset state. | ||
260 | This reset disables all MAC and baseband processor | ||
261 | clocks except the CardBus/PCI interface clock. | ||
262 | It also initializes all MAC state machines except | ||
263 | the host interface. It does not reload the | ||
264 | contents of the EEPROM. When this bit is cleared | ||
265 | (not self-clearing), the Wlan hardware | ||
266 | exits the software reset state. | ||
267 | ===============================================*/ | ||
268 | ACX_REG_SLV_SOFT_RESET, | ||
269 | |||
270 | /*=============================================== | ||
271 | EEPROM Burst Read Start - 32bit RW | ||
272 | ------------------------------------------ | ||
273 | [31:1] Reserved | ||
274 | 0 ACX_EE_START - EEPROM Burst Read Start 0 | ||
275 | Setting this bit starts a burst read from | ||
276 | the external EEPROM. | ||
277 | If this bit is set (after reset) before an EEPROM read/write, | ||
278 | the burst read starts at EEPROM address 0. | ||
279 | Otherwise, it starts at the address | ||
280 | following the address of the previous access. | ||
281 | TheWlan hardware hardware clears this bit automatically. | ||
282 | 218 | ||
283 | Default: 0x00000000 | 219 | /* Device Configuration registers*/ |
284 | *================================================*/ | 220 | #define SOR_CFG (REGISTERS_BASE + 0x0800) |
285 | ACX_REG_EE_START, | ||
286 | 221 | ||
287 | /* Embedded ARM CPU Control */ | 222 | /* Embedded ARM CPU Control */ |
288 | 223 | ||
@@ -304,10 +239,89 @@ enum wl12xx_acx_int_reg { | |||
304 | 1 halt eCPU | 239 | 1 halt eCPU |
305 | 0 enable eCPU | 240 | 0 enable eCPU |
306 | ===============================================*/ | 241 | ===============================================*/ |
307 | ACX_REG_ECPU_CONTROL, | 242 | #define ACX_REG_ECPU_CONTROL (REGISTERS_BASE + 0x0804) |
243 | |||
244 | #define HI_CFG (REGISTERS_BASE + 0x0808) | ||
245 | |||
246 | /*=============================================== | ||
247 | EEPROM Burst Read Start - 32bit RW | ||
248 | ------------------------------------------ | ||
249 | [31:1] Reserved | ||
250 | 0 ACX_EE_START - EEPROM Burst Read Start 0 | ||
251 | Setting this bit starts a burst read from | ||
252 | the external EEPROM. | ||
253 | If this bit is set (after reset) before an EEPROM read/write, | ||
254 | the burst read starts at EEPROM address 0. | ||
255 | Otherwise, it starts at the address | ||
256 | following the address of the previous access. | ||
257 | TheWlan hardware hardware clears this bit automatically. | ||
258 | |||
259 | Default: 0x00000000 | ||
260 | *================================================*/ | ||
261 | #define ACX_REG_EE_START (REGISTERS_BASE + 0x080C) | ||
262 | |||
263 | #define OCP_POR_CTR (REGISTERS_BASE + 0x09B4) | ||
264 | #define OCP_DATA_WRITE (REGISTERS_BASE + 0x09B8) | ||
265 | #define OCP_DATA_READ (REGISTERS_BASE + 0x09BC) | ||
266 | #define OCP_CMD (REGISTERS_BASE + 0x09C0) | ||
267 | |||
268 | #define WL1271_HOST_WR_ACCESS (REGISTERS_BASE + 0x09F8) | ||
269 | |||
270 | #define CHIP_ID_B (REGISTERS_BASE + 0x5674) | ||
271 | |||
272 | #define CHIP_ID_1271_PG10 (0x4030101) | ||
273 | #define CHIP_ID_1271_PG20 (0x4030111) | ||
274 | |||
275 | #define ENABLE (REGISTERS_BASE + 0x5450) | ||
276 | |||
277 | /* Power Management registers */ | ||
278 | #define ELP_CFG_MODE (REGISTERS_BASE + 0x5804) | ||
279 | #define ELP_CMD (REGISTERS_BASE + 0x5808) | ||
280 | #define PLL_CAL_TIME (REGISTERS_BASE + 0x5810) | ||
281 | #define CLK_REQ_TIME (REGISTERS_BASE + 0x5814) | ||
282 | #define CLK_BUF_TIME (REGISTERS_BASE + 0x5818) | ||
283 | |||
284 | #define CFG_PLL_SYNC_CNT (REGISTERS_BASE + 0x5820) | ||
285 | |||
286 | /* Scratch Pad registers*/ | ||
287 | #define SCR_PAD0 (REGISTERS_BASE + 0x5608) | ||
288 | #define SCR_PAD1 (REGISTERS_BASE + 0x560C) | ||
289 | #define SCR_PAD2 (REGISTERS_BASE + 0x5610) | ||
290 | #define SCR_PAD3 (REGISTERS_BASE + 0x5614) | ||
291 | #define SCR_PAD4 (REGISTERS_BASE + 0x5618) | ||
292 | #define SCR_PAD4_SET (REGISTERS_BASE + 0x561C) | ||
293 | #define SCR_PAD4_CLR (REGISTERS_BASE + 0x5620) | ||
294 | #define SCR_PAD5 (REGISTERS_BASE + 0x5624) | ||
295 | #define SCR_PAD5_SET (REGISTERS_BASE + 0x5628) | ||
296 | #define SCR_PAD5_CLR (REGISTERS_BASE + 0x562C) | ||
297 | #define SCR_PAD6 (REGISTERS_BASE + 0x5630) | ||
298 | #define SCR_PAD7 (REGISTERS_BASE + 0x5634) | ||
299 | #define SCR_PAD8 (REGISTERS_BASE + 0x5638) | ||
300 | #define SCR_PAD9 (REGISTERS_BASE + 0x563C) | ||
301 | |||
302 | /* Spare registers*/ | ||
303 | #define SPARE_A1 (REGISTERS_BASE + 0x0994) | ||
304 | #define SPARE_A2 (REGISTERS_BASE + 0x0998) | ||
305 | #define SPARE_A3 (REGISTERS_BASE + 0x099C) | ||
306 | #define SPARE_A4 (REGISTERS_BASE + 0x09A0) | ||
307 | #define SPARE_A5 (REGISTERS_BASE + 0x09A4) | ||
308 | #define SPARE_A6 (REGISTERS_BASE + 0x09A8) | ||
309 | #define SPARE_A7 (REGISTERS_BASE + 0x09AC) | ||
310 | #define SPARE_A8 (REGISTERS_BASE + 0x09B0) | ||
311 | #define SPARE_B1 (REGISTERS_BASE + 0x5420) | ||
312 | #define SPARE_B2 (REGISTERS_BASE + 0x5424) | ||
313 | #define SPARE_B3 (REGISTERS_BASE + 0x5428) | ||
314 | #define SPARE_B4 (REGISTERS_BASE + 0x542C) | ||
315 | #define SPARE_B5 (REGISTERS_BASE + 0x5430) | ||
316 | #define SPARE_B6 (REGISTERS_BASE + 0x5434) | ||
317 | #define SPARE_B7 (REGISTERS_BASE + 0x5438) | ||
318 | #define SPARE_B8 (REGISTERS_BASE + 0x543C) | ||
319 | |||
320 | #define PLL_PARAMETERS (REGISTERS_BASE + 0x6040) | ||
321 | #define WU_COUNTER_PAUSE (REGISTERS_BASE + 0x6008) | ||
322 | #define WELP_ARM_COMMAND (REGISTERS_BASE + 0x6100) | ||
323 | #define DRPW_SCRATCH_START (DRPW_BASE + 0x002C) | ||
308 | 324 | ||
309 | ACX_REG_TABLE_LEN | ||
310 | }; | ||
311 | 325 | ||
312 | #define ACX_SLV_SOFT_RESET_BIT BIT(1) | 326 | #define ACX_SLV_SOFT_RESET_BIT BIT(1) |
313 | #define ACX_REG_EEPROM_START_BIT BIT(1) | 327 | #define ACX_REG_EEPROM_START_BIT BIT(1) |
diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.c b/drivers/net/wireless/wl12xx/wl1271_rx.c new file mode 100644 index 000000000000..ad8b6904c5eb --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_rx.c | |||
@@ -0,0 +1,200 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2009 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include "wl1271.h" | ||
25 | #include "wl1271_acx.h" | ||
26 | #include "wl1271_reg.h" | ||
27 | #include "wl1271_rx.h" | ||
28 | #include "wl1271_spi.h" | ||
29 | |||
30 | static u8 wl1271_rx_get_mem_block(struct wl1271_fw_status *status, | ||
31 | u32 drv_rx_counter) | ||
32 | { | ||
33 | return status->rx_pkt_descs[drv_rx_counter] & RX_MEM_BLOCK_MASK; | ||
34 | } | ||
35 | |||
36 | static u32 wl1271_rx_get_buf_size(struct wl1271_fw_status *status, | ||
37 | u32 drv_rx_counter) | ||
38 | { | ||
39 | return (status->rx_pkt_descs[drv_rx_counter] & RX_BUF_SIZE_MASK) >> | ||
40 | RX_BUF_SIZE_SHIFT_DIV; | ||
41 | } | ||
42 | |||
43 | /* The values of this table must match the wl1271_rates[] array */ | ||
44 | static u8 wl1271_rx_rate_to_idx[] = { | ||
45 | /* MCS rates are used only with 11n */ | ||
46 | WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS7 */ | ||
47 | WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS6 */ | ||
48 | WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS5 */ | ||
49 | WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS4 */ | ||
50 | WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS3 */ | ||
51 | WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS2 */ | ||
52 | WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS1 */ | ||
53 | WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS0 */ | ||
54 | |||
55 | 11, /* WL1271_RATE_54 */ | ||
56 | 10, /* WL1271_RATE_48 */ | ||
57 | 9, /* WL1271_RATE_36 */ | ||
58 | 8, /* WL1271_RATE_24 */ | ||
59 | |||
60 | /* TI-specific rate */ | ||
61 | WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_22 */ | ||
62 | |||
63 | 7, /* WL1271_RATE_18 */ | ||
64 | 6, /* WL1271_RATE_12 */ | ||
65 | 3, /* WL1271_RATE_11 */ | ||
66 | 5, /* WL1271_RATE_9 */ | ||
67 | 4, /* WL1271_RATE_6 */ | ||
68 | 2, /* WL1271_RATE_5_5 */ | ||
69 | 1, /* WL1271_RATE_2 */ | ||
70 | 0 /* WL1271_RATE_1 */ | ||
71 | }; | ||
72 | |||
73 | static void wl1271_rx_status(struct wl1271 *wl, | ||
74 | struct wl1271_rx_descriptor *desc, | ||
75 | struct ieee80211_rx_status *status, | ||
76 | u8 beacon) | ||
77 | { | ||
78 | memset(status, 0, sizeof(struct ieee80211_rx_status)); | ||
79 | |||
80 | if ((desc->flags & WL1271_RX_DESC_BAND_MASK) == WL1271_RX_DESC_BAND_BG) | ||
81 | status->band = IEEE80211_BAND_2GHZ; | ||
82 | else | ||
83 | wl1271_warning("unsupported band 0x%x", | ||
84 | desc->flags & WL1271_RX_DESC_BAND_MASK); | ||
85 | |||
86 | /* | ||
87 | * FIXME: Add mactime handling. For IBSS (ad-hoc) we need to get the | ||
88 | * timestamp from the beacon (acx_tsf_info). In BSS mode (infra) we | ||
89 | * only need the mactime for monitor mode. For now the mactime is | ||
90 | * not valid, so RX_FLAG_TSFT should not be set | ||
91 | */ | ||
92 | status->signal = desc->rssi; | ||
93 | |||
94 | /* FIXME: Should this be optimized? */ | ||
95 | status->qual = (desc->rssi - WL1271_RX_MIN_RSSI) * 100 / | ||
96 | (WL1271_RX_MAX_RSSI - WL1271_RX_MIN_RSSI); | ||
97 | status->qual = min(status->qual, 100); | ||
98 | status->qual = max(status->qual, 0); | ||
99 | |||
100 | /* | ||
101 | * FIXME: In wl1251, the SNR should be divided by two. In wl1271 we | ||
102 | * need to divide by two for now, but TI has been discussing about | ||
103 | * changing it. This needs to be rechecked. | ||
104 | */ | ||
105 | status->noise = desc->rssi - (desc->snr >> 1); | ||
106 | |||
107 | status->freq = ieee80211_channel_to_frequency(desc->channel); | ||
108 | |||
109 | if (desc->flags & WL1271_RX_DESC_ENCRYPT_MASK) { | ||
110 | status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED; | ||
111 | |||
112 | if (likely(!(desc->flags & WL1271_RX_DESC_DECRYPT_FAIL))) | ||
113 | status->flag |= RX_FLAG_DECRYPTED; | ||
114 | |||
115 | if (unlikely(desc->flags & WL1271_RX_DESC_MIC_FAIL)) | ||
116 | status->flag |= RX_FLAG_MMIC_ERROR; | ||
117 | } | ||
118 | |||
119 | status->rate_idx = wl1271_rx_rate_to_idx[desc->rate]; | ||
120 | |||
121 | if (status->rate_idx == WL1271_RX_RATE_UNSUPPORTED) | ||
122 | wl1271_warning("unsupported rate"); | ||
123 | } | ||
124 | |||
125 | static void wl1271_rx_handle_data(struct wl1271 *wl, u32 length) | ||
126 | { | ||
127 | struct ieee80211_rx_status rx_status; | ||
128 | struct wl1271_rx_descriptor *desc; | ||
129 | struct sk_buff *skb; | ||
130 | u16 *fc; | ||
131 | u8 *buf; | ||
132 | u8 beacon = 0; | ||
133 | |||
134 | skb = dev_alloc_skb(length); | ||
135 | if (!skb) { | ||
136 | wl1271_error("Couldn't allocate RX frame"); | ||
137 | return; | ||
138 | } | ||
139 | |||
140 | buf = skb_put(skb, length); | ||
141 | wl1271_spi_reg_read(wl, WL1271_SLV_MEM_DATA, buf, length, true); | ||
142 | |||
143 | /* the data read starts with the descriptor */ | ||
144 | desc = (struct wl1271_rx_descriptor *) buf; | ||
145 | |||
146 | /* now we pull the descriptor out of the buffer */ | ||
147 | skb_pull(skb, sizeof(*desc)); | ||
148 | |||
149 | fc = (u16 *)skb->data; | ||
150 | if ((*fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) | ||
151 | beacon = 1; | ||
152 | |||
153 | wl1271_rx_status(wl, desc, &rx_status, beacon); | ||
154 | |||
155 | wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len, | ||
156 | beacon ? "beacon" : ""); | ||
157 | |||
158 | memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); | ||
159 | ieee80211_rx(wl->hw, skb); | ||
160 | } | ||
161 | |||
162 | void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status) | ||
163 | { | ||
164 | struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map; | ||
165 | u32 buf_size; | ||
166 | u32 fw_rx_counter = status->fw_rx_counter & NUM_RX_PKT_DESC_MOD_MASK; | ||
167 | u32 drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK; | ||
168 | u32 mem_block; | ||
169 | |||
170 | while (drv_rx_counter != fw_rx_counter) { | ||
171 | mem_block = wl1271_rx_get_mem_block(status, drv_rx_counter); | ||
172 | buf_size = wl1271_rx_get_buf_size(status, drv_rx_counter); | ||
173 | |||
174 | if (buf_size == 0) { | ||
175 | wl1271_warning("received empty data"); | ||
176 | break; | ||
177 | } | ||
178 | |||
179 | wl->rx_mem_pool_addr.addr = | ||
180 | (mem_block << 8) + wl_mem_map->packet_memory_pool_start; | ||
181 | wl->rx_mem_pool_addr.addr_extra = | ||
182 | wl->rx_mem_pool_addr.addr + 4; | ||
183 | |||
184 | /* Choose the block we want to read */ | ||
185 | wl1271_spi_reg_write(wl, WL1271_SLV_REG_DATA, | ||
186 | &wl->rx_mem_pool_addr, | ||
187 | sizeof(wl->rx_mem_pool_addr), false); | ||
188 | |||
189 | wl1271_rx_handle_data(wl, buf_size); | ||
190 | |||
191 | wl->rx_counter++; | ||
192 | drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK; | ||
193 | } | ||
194 | |||
195 | wl1271_reg_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter); | ||
196 | |||
197 | /* This is a workaround for some problems in the chip */ | ||
198 | wl1271_reg_write32(wl, RX_DRIVER_DUMMY_WRITE_ADDRESS, 0x1); | ||
199 | |||
200 | } | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.h b/drivers/net/wireless/wl12xx/wl1271_rx.h new file mode 100644 index 000000000000..d1ca60e43a25 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_rx.h | |||
@@ -0,0 +1,121 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. | ||
5 | * Copyright (C) 2008-2009 Nokia Corporation | ||
6 | * | ||
7 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef __WL1271_RX_H__ | ||
26 | #define __WL1271_RX_H__ | ||
27 | |||
28 | #include <linux/bitops.h> | ||
29 | |||
30 | #define WL1271_RX_MAX_RSSI -30 | ||
31 | #define WL1271_RX_MIN_RSSI -95 | ||
32 | |||
33 | #define WL1271_RX_ALIGN_TO 4 | ||
34 | #define WL1271_RX_ALIGN(len) (((len) + WL1271_RX_ALIGN_TO - 1) & \ | ||
35 | ~(WL1271_RX_ALIGN_TO - 1)) | ||
36 | |||
37 | #define SHORT_PREAMBLE_BIT BIT(0) | ||
38 | #define OFDM_RATE_BIT BIT(6) | ||
39 | #define PBCC_RATE_BIT BIT(7) | ||
40 | |||
41 | #define PLCP_HEADER_LENGTH 8 | ||
42 | #define RX_DESC_PACKETID_SHIFT 11 | ||
43 | #define RX_MAX_PACKET_ID 3 | ||
44 | |||
45 | #define NUM_RX_PKT_DESC_MOD_MASK 7 | ||
46 | #define WL1271_RX_RATE_UNSUPPORTED 0xFF | ||
47 | |||
48 | #define RX_DESC_VALID_FCS 0x0001 | ||
49 | #define RX_DESC_MATCH_RXADDR1 0x0002 | ||
50 | #define RX_DESC_MCAST 0x0004 | ||
51 | #define RX_DESC_STAINTIM 0x0008 | ||
52 | #define RX_DESC_VIRTUAL_BM 0x0010 | ||
53 | #define RX_DESC_BCAST 0x0020 | ||
54 | #define RX_DESC_MATCH_SSID 0x0040 | ||
55 | #define RX_DESC_MATCH_BSSID 0x0080 | ||
56 | #define RX_DESC_ENCRYPTION_MASK 0x0300 | ||
57 | #define RX_DESC_MEASURMENT 0x0400 | ||
58 | #define RX_DESC_SEQNUM_MASK 0x1800 | ||
59 | #define RX_DESC_MIC_FAIL 0x2000 | ||
60 | #define RX_DESC_DECRYPT_FAIL 0x4000 | ||
61 | |||
62 | /* | ||
63 | * RX Descriptor flags: | ||
64 | * | ||
65 | * Bits 0-1 - band | ||
66 | * Bit 2 - STBC | ||
67 | * Bit 3 - A-MPDU | ||
68 | * Bit 4 - HT | ||
69 | * Bits 5-7 - encryption | ||
70 | */ | ||
71 | #define WL1271_RX_DESC_BAND_MASK 0x03 | ||
72 | #define WL1271_RX_DESC_ENCRYPT_MASK 0xE0 | ||
73 | |||
74 | #define WL1271_RX_DESC_BAND_BG 0x00 | ||
75 | #define WL1271_RX_DESC_BAND_J 0x01 | ||
76 | #define WL1271_RX_DESC_BAND_A 0x02 | ||
77 | |||
78 | #define WL1271_RX_DESC_STBC BIT(2) | ||
79 | #define WL1271_RX_DESC_A_MPDU BIT(3) | ||
80 | #define WL1271_RX_DESC_HT BIT(4) | ||
81 | |||
82 | #define WL1271_RX_DESC_ENCRYPT_WEP 0x20 | ||
83 | #define WL1271_RX_DESC_ENCRYPT_TKIP 0x40 | ||
84 | #define WL1271_RX_DESC_ENCRYPT_AES 0x60 | ||
85 | #define WL1271_RX_DESC_ENCRYPT_GEM 0x80 | ||
86 | |||
87 | /* | ||
88 | * RX Descriptor status | ||
89 | * | ||
90 | * Bits 0-2 - status | ||
91 | * Bits 3-7 - reserved | ||
92 | */ | ||
93 | #define WL1271_RX_DESC_STATUS_MASK 0x07 | ||
94 | |||
95 | #define WL1271_RX_DESC_SUCCESS 0x00 | ||
96 | #define WL1271_RX_DESC_DECRYPT_FAIL 0x01 | ||
97 | #define WL1271_RX_DESC_MIC_FAIL 0x02 | ||
98 | #define WL1271_RX_DESC_DRIVER_RX_Q_FAIL 0x03 | ||
99 | |||
100 | #define RX_MEM_BLOCK_MASK 0xFF | ||
101 | #define RX_BUF_SIZE_MASK 0xFFF00 | ||
102 | #define RX_BUF_SIZE_SHIFT_DIV 6 | ||
103 | |||
104 | struct wl1271_rx_descriptor { | ||
105 | u16 length; | ||
106 | u8 status; | ||
107 | u8 flags; | ||
108 | u8 rate; | ||
109 | u8 channel; | ||
110 | s8 rssi; | ||
111 | u8 snr; | ||
112 | u32 timestamp; | ||
113 | u8 packet_class; | ||
114 | u8 process_id; | ||
115 | u8 pad_len; | ||
116 | u8 reserved; | ||
117 | } __attribute__ ((packed)); | ||
118 | |||
119 | void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status); | ||
120 | |||
121 | #endif | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.c b/drivers/net/wireless/wl12xx/wl1271_spi.c new file mode 100644 index 000000000000..4a12880c16a8 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_spi.c | |||
@@ -0,0 +1,382 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2008-2009 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/module.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | #include <linux/crc7.h> | ||
27 | #include <linux/spi/spi.h> | ||
28 | |||
29 | #include "wl1271.h" | ||
30 | #include "wl12xx_80211.h" | ||
31 | #include "wl1271_spi.h" | ||
32 | |||
33 | static int wl1271_translate_reg_addr(struct wl1271 *wl, int addr) | ||
34 | { | ||
35 | return addr - wl->physical_reg_addr + wl->virtual_reg_addr; | ||
36 | } | ||
37 | |||
38 | static int wl1271_translate_mem_addr(struct wl1271 *wl, int addr) | ||
39 | { | ||
40 | return addr - wl->physical_mem_addr + wl->virtual_mem_addr; | ||
41 | } | ||
42 | |||
43 | |||
44 | void wl1271_spi_reset(struct wl1271 *wl) | ||
45 | { | ||
46 | u8 *cmd; | ||
47 | struct spi_transfer t; | ||
48 | struct spi_message m; | ||
49 | |||
50 | cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); | ||
51 | if (!cmd) { | ||
52 | wl1271_error("could not allocate cmd for spi reset"); | ||
53 | return; | ||
54 | } | ||
55 | |||
56 | memset(&t, 0, sizeof(t)); | ||
57 | spi_message_init(&m); | ||
58 | |||
59 | memset(cmd, 0xff, WSPI_INIT_CMD_LEN); | ||
60 | |||
61 | t.tx_buf = cmd; | ||
62 | t.len = WSPI_INIT_CMD_LEN; | ||
63 | spi_message_add_tail(&t, &m); | ||
64 | |||
65 | spi_sync(wl->spi, &m); | ||
66 | |||
67 | wl1271_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN); | ||
68 | } | ||
69 | |||
70 | void wl1271_spi_init(struct wl1271 *wl) | ||
71 | { | ||
72 | u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd; | ||
73 | struct spi_transfer t; | ||
74 | struct spi_message m; | ||
75 | |||
76 | cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); | ||
77 | if (!cmd) { | ||
78 | wl1271_error("could not allocate cmd for spi init"); | ||
79 | return; | ||
80 | } | ||
81 | |||
82 | memset(crc, 0, sizeof(crc)); | ||
83 | memset(&t, 0, sizeof(t)); | ||
84 | spi_message_init(&m); | ||
85 | |||
86 | /* | ||
87 | * Set WSPI_INIT_COMMAND | ||
88 | * the data is being send from the MSB to LSB | ||
89 | */ | ||
90 | cmd[2] = 0xff; | ||
91 | cmd[3] = 0xff; | ||
92 | cmd[1] = WSPI_INIT_CMD_START | WSPI_INIT_CMD_TX; | ||
93 | cmd[0] = 0; | ||
94 | cmd[7] = 0; | ||
95 | cmd[6] |= HW_ACCESS_WSPI_INIT_CMD_MASK << 3; | ||
96 | cmd[6] |= HW_ACCESS_WSPI_FIXED_BUSY_LEN & WSPI_INIT_CMD_FIXEDBUSY_LEN; | ||
97 | |||
98 | if (HW_ACCESS_WSPI_FIXED_BUSY_LEN == 0) | ||
99 | cmd[5] |= WSPI_INIT_CMD_DIS_FIXEDBUSY; | ||
100 | else | ||
101 | cmd[5] |= WSPI_INIT_CMD_EN_FIXEDBUSY; | ||
102 | |||
103 | cmd[5] |= WSPI_INIT_CMD_IOD | WSPI_INIT_CMD_IP | WSPI_INIT_CMD_CS | ||
104 | | WSPI_INIT_CMD_WSPI | WSPI_INIT_CMD_WS; | ||
105 | |||
106 | crc[0] = cmd[1]; | ||
107 | crc[1] = cmd[0]; | ||
108 | crc[2] = cmd[7]; | ||
109 | crc[3] = cmd[6]; | ||
110 | crc[4] = cmd[5]; | ||
111 | |||
112 | cmd[4] |= crc7(0, crc, WSPI_INIT_CMD_CRC_LEN) << 1; | ||
113 | cmd[4] |= WSPI_INIT_CMD_END; | ||
114 | |||
115 | t.tx_buf = cmd; | ||
116 | t.len = WSPI_INIT_CMD_LEN; | ||
117 | spi_message_add_tail(&t, &m); | ||
118 | |||
119 | spi_sync(wl->spi, &m); | ||
120 | |||
121 | wl1271_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN); | ||
122 | } | ||
123 | |||
124 | /* Set the SPI partitions to access the chip addresses | ||
125 | * | ||
126 | * There are two VIRTUAL (SPI) partitions (the memory partition and the | ||
127 | * registers partition), which are mapped to two different areas of the | ||
128 | * PHYSICAL (hardware) memory. This function also makes other checks to | ||
129 | * ensure that the partitions are not overlapping. In the diagram below, the | ||
130 | * memory partition comes before the register partition, but the opposite is | ||
131 | * also supported. | ||
132 | * | ||
133 | * PHYSICAL address | ||
134 | * space | ||
135 | * | ||
136 | * | | | ||
137 | * ...+----+--> mem_start | ||
138 | * VIRTUAL address ... | | | ||
139 | * space ... | | [PART_0] | ||
140 | * ... | | | ||
141 | * 0x00000000 <--+----+... ...+----+--> mem_start + mem_size | ||
142 | * | | ... | | | ||
143 | * |MEM | ... | | | ||
144 | * | | ... | | | ||
145 | * part_size <--+----+... | | {unused area) | ||
146 | * | | ... | | | ||
147 | * |REG | ... | | | ||
148 | * part_size | | ... | | | ||
149 | * + <--+----+... ...+----+--> reg_start | ||
150 | * reg_size ... | | | ||
151 | * ... | | [PART_1] | ||
152 | * ... | | | ||
153 | * ...+----+--> reg_start + reg_size | ||
154 | * | | | ||
155 | * | ||
156 | */ | ||
157 | int wl1271_set_partition(struct wl1271 *wl, | ||
158 | u32 mem_start, u32 mem_size, | ||
159 | u32 reg_start, u32 reg_size) | ||
160 | { | ||
161 | struct wl1271_partition *partition; | ||
162 | struct spi_transfer t; | ||
163 | struct spi_message m; | ||
164 | size_t len, cmd_len; | ||
165 | u32 *cmd; | ||
166 | int addr; | ||
167 | |||
168 | cmd_len = sizeof(u32) + 2 * sizeof(struct wl1271_partition); | ||
169 | cmd = kzalloc(cmd_len, GFP_KERNEL); | ||
170 | if (!cmd) | ||
171 | return -ENOMEM; | ||
172 | |||
173 | spi_message_init(&m); | ||
174 | memset(&t, 0, sizeof(t)); | ||
175 | |||
176 | partition = (struct wl1271_partition *) (cmd + 1); | ||
177 | addr = HW_ACCESS_PART0_SIZE_ADDR; | ||
178 | len = 2 * sizeof(struct wl1271_partition); | ||
179 | |||
180 | *cmd |= WSPI_CMD_WRITE; | ||
181 | *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; | ||
182 | *cmd |= addr & WSPI_CMD_BYTE_ADDR; | ||
183 | |||
184 | wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", | ||
185 | mem_start, mem_size); | ||
186 | wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", | ||
187 | reg_start, reg_size); | ||
188 | |||
189 | /* Make sure that the two partitions together don't exceed the | ||
190 | * address range */ | ||
191 | if ((mem_size + reg_size) > HW_ACCESS_MEMORY_MAX_RANGE) { | ||
192 | wl1271_debug(DEBUG_SPI, "Total size exceeds maximum virtual" | ||
193 | " address range. Truncating partition[0]."); | ||
194 | mem_size = HW_ACCESS_MEMORY_MAX_RANGE - reg_size; | ||
195 | wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", | ||
196 | mem_start, mem_size); | ||
197 | wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", | ||
198 | reg_start, reg_size); | ||
199 | } | ||
200 | |||
201 | if ((mem_start < reg_start) && | ||
202 | ((mem_start + mem_size) > reg_start)) { | ||
203 | /* Guarantee that the memory partition doesn't overlap the | ||
204 | * registers partition */ | ||
205 | wl1271_debug(DEBUG_SPI, "End of partition[0] is " | ||
206 | "overlapping partition[1]. Adjusted."); | ||
207 | mem_size = reg_start - mem_start; | ||
208 | wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", | ||
209 | mem_start, mem_size); | ||
210 | wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", | ||
211 | reg_start, reg_size); | ||
212 | } else if ((reg_start < mem_start) && | ||
213 | ((reg_start + reg_size) > mem_start)) { | ||
214 | /* Guarantee that the register partition doesn't overlap the | ||
215 | * memory partition */ | ||
216 | wl1271_debug(DEBUG_SPI, "End of partition[1] is" | ||
217 | " overlapping partition[0]. Adjusted."); | ||
218 | reg_size = mem_start - reg_start; | ||
219 | wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", | ||
220 | mem_start, mem_size); | ||
221 | wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", | ||
222 | reg_start, reg_size); | ||
223 | } | ||
224 | |||
225 | partition[0].start = mem_start; | ||
226 | partition[0].size = mem_size; | ||
227 | partition[1].start = reg_start; | ||
228 | partition[1].size = reg_size; | ||
229 | |||
230 | wl->physical_mem_addr = mem_start; | ||
231 | wl->physical_reg_addr = reg_start; | ||
232 | |||
233 | wl->virtual_mem_addr = 0; | ||
234 | wl->virtual_reg_addr = mem_size; | ||
235 | |||
236 | t.tx_buf = cmd; | ||
237 | t.len = cmd_len; | ||
238 | spi_message_add_tail(&t, &m); | ||
239 | |||
240 | spi_sync(wl->spi, &m); | ||
241 | |||
242 | kfree(cmd); | ||
243 | |||
244 | return 0; | ||
245 | } | ||
246 | |||
247 | void wl1271_spi_read(struct wl1271 *wl, int addr, void *buf, | ||
248 | size_t len, bool fixed) | ||
249 | { | ||
250 | struct spi_transfer t[3]; | ||
251 | struct spi_message m; | ||
252 | u8 *busy_buf; | ||
253 | u32 *cmd; | ||
254 | |||
255 | cmd = &wl->buffer_cmd; | ||
256 | busy_buf = wl->buffer_busyword; | ||
257 | |||
258 | *cmd = 0; | ||
259 | *cmd |= WSPI_CMD_READ; | ||
260 | *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; | ||
261 | *cmd |= addr & WSPI_CMD_BYTE_ADDR; | ||
262 | |||
263 | if (fixed) | ||
264 | *cmd |= WSPI_CMD_FIXED; | ||
265 | |||
266 | spi_message_init(&m); | ||
267 | memset(t, 0, sizeof(t)); | ||
268 | |||
269 | t[0].tx_buf = cmd; | ||
270 | t[0].len = 4; | ||
271 | spi_message_add_tail(&t[0], &m); | ||
272 | |||
273 | /* Busy and non busy words read */ | ||
274 | t[1].rx_buf = busy_buf; | ||
275 | t[1].len = WL1271_BUSY_WORD_LEN; | ||
276 | spi_message_add_tail(&t[1], &m); | ||
277 | |||
278 | t[2].rx_buf = buf; | ||
279 | t[2].len = len; | ||
280 | spi_message_add_tail(&t[2], &m); | ||
281 | |||
282 | spi_sync(wl->spi, &m); | ||
283 | |||
284 | /* FIXME: check busy words */ | ||
285 | |||
286 | wl1271_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd)); | ||
287 | wl1271_dump(DEBUG_SPI, "spi_read buf <- ", buf, len); | ||
288 | } | ||
289 | |||
290 | void wl1271_spi_write(struct wl1271 *wl, int addr, void *buf, | ||
291 | size_t len, bool fixed) | ||
292 | { | ||
293 | struct spi_transfer t[2]; | ||
294 | struct spi_message m; | ||
295 | u32 *cmd; | ||
296 | |||
297 | cmd = &wl->buffer_cmd; | ||
298 | |||
299 | *cmd = 0; | ||
300 | *cmd |= WSPI_CMD_WRITE; | ||
301 | *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; | ||
302 | *cmd |= addr & WSPI_CMD_BYTE_ADDR; | ||
303 | |||
304 | if (fixed) | ||
305 | *cmd |= WSPI_CMD_FIXED; | ||
306 | |||
307 | spi_message_init(&m); | ||
308 | memset(t, 0, sizeof(t)); | ||
309 | |||
310 | t[0].tx_buf = cmd; | ||
311 | t[0].len = sizeof(*cmd); | ||
312 | spi_message_add_tail(&t[0], &m); | ||
313 | |||
314 | t[1].tx_buf = buf; | ||
315 | t[1].len = len; | ||
316 | spi_message_add_tail(&t[1], &m); | ||
317 | |||
318 | spi_sync(wl->spi, &m); | ||
319 | |||
320 | wl1271_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); | ||
321 | wl1271_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); | ||
322 | } | ||
323 | |||
324 | void wl1271_spi_mem_read(struct wl1271 *wl, int addr, void *buf, | ||
325 | size_t len) | ||
326 | { | ||
327 | int physical; | ||
328 | |||
329 | physical = wl1271_translate_mem_addr(wl, addr); | ||
330 | |||
331 | wl1271_spi_read(wl, physical, buf, len, false); | ||
332 | } | ||
333 | |||
334 | void wl1271_spi_mem_write(struct wl1271 *wl, int addr, void *buf, | ||
335 | size_t len) | ||
336 | { | ||
337 | int physical; | ||
338 | |||
339 | physical = wl1271_translate_mem_addr(wl, addr); | ||
340 | |||
341 | wl1271_spi_write(wl, physical, buf, len, false); | ||
342 | } | ||
343 | |||
344 | void wl1271_spi_reg_read(struct wl1271 *wl, int addr, void *buf, size_t len, | ||
345 | bool fixed) | ||
346 | { | ||
347 | int physical; | ||
348 | |||
349 | physical = wl1271_translate_reg_addr(wl, addr); | ||
350 | |||
351 | wl1271_spi_read(wl, physical, buf, len, fixed); | ||
352 | } | ||
353 | |||
354 | void wl1271_spi_reg_write(struct wl1271 *wl, int addr, void *buf, size_t len, | ||
355 | bool fixed) | ||
356 | { | ||
357 | int physical; | ||
358 | |||
359 | physical = wl1271_translate_reg_addr(wl, addr); | ||
360 | |||
361 | wl1271_spi_write(wl, physical, buf, len, fixed); | ||
362 | } | ||
363 | |||
364 | u32 wl1271_mem_read32(struct wl1271 *wl, int addr) | ||
365 | { | ||
366 | return wl1271_read32(wl, wl1271_translate_mem_addr(wl, addr)); | ||
367 | } | ||
368 | |||
369 | void wl1271_mem_write32(struct wl1271 *wl, int addr, u32 val) | ||
370 | { | ||
371 | wl1271_write32(wl, wl1271_translate_mem_addr(wl, addr), val); | ||
372 | } | ||
373 | |||
374 | u32 wl1271_reg_read32(struct wl1271 *wl, int addr) | ||
375 | { | ||
376 | return wl1271_read32(wl, wl1271_translate_reg_addr(wl, addr)); | ||
377 | } | ||
378 | |||
379 | void wl1271_reg_write32(struct wl1271 *wl, int addr, u32 val) | ||
380 | { | ||
381 | wl1271_write32(wl, wl1271_translate_reg_addr(wl, addr), val); | ||
382 | } | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.h b/drivers/net/wireless/wl12xx/wl1271_spi.h new file mode 100644 index 000000000000..2c9968458646 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_spi.h | |||
@@ -0,0 +1,113 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. | ||
5 | * Copyright (C) 2008-2009 Nokia Corporation | ||
6 | * | ||
7 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef __WL1271_SPI_H__ | ||
26 | #define __WL1271_SPI_H__ | ||
27 | |||
28 | #include "wl1271_reg.h" | ||
29 | |||
30 | #define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0 | ||
31 | |||
32 | #define HW_ACCESS_PART0_SIZE_ADDR 0x1FFC0 | ||
33 | #define HW_ACCESS_PART0_START_ADDR 0x1FFC4 | ||
34 | #define HW_ACCESS_PART1_SIZE_ADDR 0x1FFC8 | ||
35 | #define HW_ACCESS_PART1_START_ADDR 0x1FFCC | ||
36 | |||
37 | #define HW_ACCESS_REGISTER_SIZE 4 | ||
38 | |||
39 | #define HW_ACCESS_PRAM_MAX_RANGE 0x3c000 | ||
40 | |||
41 | #define WSPI_CMD_READ 0x40000000 | ||
42 | #define WSPI_CMD_WRITE 0x00000000 | ||
43 | #define WSPI_CMD_FIXED 0x20000000 | ||
44 | #define WSPI_CMD_BYTE_LENGTH 0x1FFE0000 | ||
45 | #define WSPI_CMD_BYTE_LENGTH_OFFSET 17 | ||
46 | #define WSPI_CMD_BYTE_ADDR 0x0001FFFF | ||
47 | |||
48 | #define WSPI_INIT_CMD_CRC_LEN 5 | ||
49 | |||
50 | #define WSPI_INIT_CMD_START 0x00 | ||
51 | #define WSPI_INIT_CMD_TX 0x40 | ||
52 | /* the extra bypass bit is sampled by the TNET as '1' */ | ||
53 | #define WSPI_INIT_CMD_BYPASS_BIT 0x80 | ||
54 | #define WSPI_INIT_CMD_FIXEDBUSY_LEN 0x07 | ||
55 | #define WSPI_INIT_CMD_EN_FIXEDBUSY 0x80 | ||
56 | #define WSPI_INIT_CMD_DIS_FIXEDBUSY 0x00 | ||
57 | #define WSPI_INIT_CMD_IOD 0x40 | ||
58 | #define WSPI_INIT_CMD_IP 0x20 | ||
59 | #define WSPI_INIT_CMD_CS 0x10 | ||
60 | #define WSPI_INIT_CMD_WS 0x08 | ||
61 | #define WSPI_INIT_CMD_WSPI 0x01 | ||
62 | #define WSPI_INIT_CMD_END 0x01 | ||
63 | |||
64 | #define WSPI_INIT_CMD_LEN 8 | ||
65 | |||
66 | #define HW_ACCESS_WSPI_FIXED_BUSY_LEN \ | ||
67 | ((WL1271_BUSY_WORD_LEN - 4) / sizeof(u32)) | ||
68 | #define HW_ACCESS_WSPI_INIT_CMD_MASK 0 | ||
69 | |||
70 | |||
71 | /* Raw target IO, address is not translated */ | ||
72 | void wl1271_spi_write(struct wl1271 *wl, int addr, void *buf, | ||
73 | size_t len, bool fixed); | ||
74 | void wl1271_spi_read(struct wl1271 *wl, int addr, void *buf, | ||
75 | size_t len, bool fixed); | ||
76 | |||
77 | /* Memory target IO, address is tranlated to partition 0 */ | ||
78 | void wl1271_spi_mem_read(struct wl1271 *wl, int addr, void *buf, size_t len); | ||
79 | void wl1271_spi_mem_write(struct wl1271 *wl, int addr, void *buf, size_t len); | ||
80 | u32 wl1271_mem_read32(struct wl1271 *wl, int addr); | ||
81 | void wl1271_mem_write32(struct wl1271 *wl, int addr, u32 val); | ||
82 | |||
83 | /* Registers IO */ | ||
84 | void wl1271_spi_reg_read(struct wl1271 *wl, int addr, void *buf, size_t len, | ||
85 | bool fixed); | ||
86 | void wl1271_spi_reg_write(struct wl1271 *wl, int addr, void *buf, size_t len, | ||
87 | bool fixed); | ||
88 | u32 wl1271_reg_read32(struct wl1271 *wl, int addr); | ||
89 | void wl1271_reg_write32(struct wl1271 *wl, int addr, u32 val); | ||
90 | |||
91 | /* INIT and RESET words */ | ||
92 | void wl1271_spi_reset(struct wl1271 *wl); | ||
93 | void wl1271_spi_init(struct wl1271 *wl); | ||
94 | int wl1271_set_partition(struct wl1271 *wl, | ||
95 | u32 part_start, u32 part_size, | ||
96 | u32 reg_start, u32 reg_size); | ||
97 | |||
98 | static inline u32 wl1271_read32(struct wl1271 *wl, int addr) | ||
99 | { | ||
100 | wl1271_spi_read(wl, addr, &wl->buffer_32, | ||
101 | sizeof(wl->buffer_32), false); | ||
102 | |||
103 | return wl->buffer_32; | ||
104 | } | ||
105 | |||
106 | static inline void wl1271_write32(struct wl1271 *wl, int addr, u32 val) | ||
107 | { | ||
108 | wl->buffer_32 = val; | ||
109 | wl1271_spi_write(wl, addr, &wl->buffer_32, | ||
110 | sizeof(wl->buffer_32), false); | ||
111 | } | ||
112 | |||
113 | #endif /* __WL1271_SPI_H__ */ | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c new file mode 100644 index 000000000000..ff221258b941 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_tx.c | |||
@@ -0,0 +1,378 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2009 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/module.h> | ||
26 | |||
27 | #include "wl1271.h" | ||
28 | #include "wl1271_spi.h" | ||
29 | #include "wl1271_reg.h" | ||
30 | #include "wl1271_ps.h" | ||
31 | #include "wl1271_tx.h" | ||
32 | |||
33 | static int wl1271_tx_id(struct wl1271 *wl, struct sk_buff *skb) | ||
34 | { | ||
35 | int i; | ||
36 | |||
37 | for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) | ||
38 | if (wl->tx_frames[i] == NULL) { | ||
39 | wl->tx_frames[i] = skb; | ||
40 | return i; | ||
41 | } | ||
42 | |||
43 | return -EBUSY; | ||
44 | } | ||
45 | |||
46 | static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra) | ||
47 | { | ||
48 | struct wl1271_tx_hw_descr *desc; | ||
49 | u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra; | ||
50 | u32 total_blocks, excluded; | ||
51 | int id, ret = -EBUSY; | ||
52 | |||
53 | /* allocate free identifier for the packet */ | ||
54 | id = wl1271_tx_id(wl, skb); | ||
55 | if (id < 0) | ||
56 | return id; | ||
57 | |||
58 | /* approximate the number of blocks required for this packet | ||
59 | in the firmware */ | ||
60 | /* FIXME: try to figure out what is done here and make it cleaner */ | ||
61 | total_blocks = (skb->len) >> TX_HW_BLOCK_SHIFT_DIV; | ||
62 | excluded = (total_blocks << 2) + (skb->len & 0xff) + 34; | ||
63 | total_blocks += (excluded > 252) ? 2 : 1; | ||
64 | total_blocks += TX_HW_BLOCK_SPARE; | ||
65 | |||
66 | if (total_blocks <= wl->tx_blocks_available) { | ||
67 | desc = (struct wl1271_tx_hw_descr *)skb_push( | ||
68 | skb, total_len - skb->len); | ||
69 | |||
70 | desc->extra_mem_blocks = TX_HW_BLOCK_SPARE; | ||
71 | desc->total_mem_blocks = total_blocks; | ||
72 | desc->id = id; | ||
73 | |||
74 | wl->tx_blocks_available -= total_blocks; | ||
75 | |||
76 | ret = 0; | ||
77 | |||
78 | wl1271_debug(DEBUG_TX, | ||
79 | "tx_allocate: size: %d, blocks: %d, id: %d", | ||
80 | total_len, total_blocks, id); | ||
81 | } else | ||
82 | wl->tx_frames[id] = NULL; | ||
83 | |||
84 | return ret; | ||
85 | } | ||
86 | |||
87 | static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, | ||
88 | u32 extra, struct ieee80211_tx_info *control) | ||
89 | { | ||
90 | struct wl1271_tx_hw_descr *desc; | ||
91 | int pad; | ||
92 | |||
93 | desc = (struct wl1271_tx_hw_descr *) skb->data; | ||
94 | |||
95 | /* configure packet life time */ | ||
96 | desc->start_time = jiffies_to_usecs(jiffies) - wl->time_offset; | ||
97 | desc->life_time = TX_HW_MGMT_PKT_LIFETIME_TU; | ||
98 | |||
99 | /* configure the tx attributes */ | ||
100 | desc->tx_attr = wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER; | ||
101 | /* FIXME: do we know the packet priority? can we identify mgmt | ||
102 | packets, and use max prio for them at least? */ | ||
103 | desc->tid = 0; | ||
104 | desc->aid = TX_HW_DEFAULT_AID; | ||
105 | desc->reserved = 0; | ||
106 | |||
107 | /* align the length (and store in terms of words) */ | ||
108 | pad = WL1271_TX_ALIGN(skb->len); | ||
109 | desc->length = pad >> 2; | ||
110 | |||
111 | /* calculate number of padding bytes */ | ||
112 | pad = pad - skb->len; | ||
113 | desc->tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD; | ||
114 | |||
115 | wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d", pad); | ||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | static int wl1271_tx_send_packet(struct wl1271 *wl, struct sk_buff *skb, | ||
120 | struct ieee80211_tx_info *control) | ||
121 | { | ||
122 | |||
123 | struct wl1271_tx_hw_descr *desc; | ||
124 | int len; | ||
125 | |||
126 | /* FIXME: This is a workaround for getting non-aligned packets. | ||
127 | This happens at least with EAPOL packets from the user space. | ||
128 | Our DMA requires packets to be aligned on a 4-byte boundary. | ||
129 | */ | ||
130 | if (unlikely((long)skb->data & 0x03)) { | ||
131 | int offset = (4 - (long)skb->data) & 0x03; | ||
132 | wl1271_debug(DEBUG_TX, "skb offset %d", offset); | ||
133 | |||
134 | /* check whether the current skb can be used */ | ||
135 | if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) { | ||
136 | unsigned char *src = skb->data; | ||
137 | |||
138 | /* align the buffer on a 4-byte boundary */ | ||
139 | skb_reserve(skb, offset); | ||
140 | memmove(skb->data, src, skb->len); | ||
141 | } else { | ||
142 | wl1271_info("No handler, fixme!"); | ||
143 | return -EINVAL; | ||
144 | } | ||
145 | } | ||
146 | |||
147 | len = WL1271_TX_ALIGN(skb->len); | ||
148 | |||
149 | /* perform a fixed address block write with the packet */ | ||
150 | wl1271_spi_reg_write(wl, WL1271_SLV_MEM_DATA, skb->data, len, true); | ||
151 | |||
152 | /* write packet new counter into the write access register */ | ||
153 | wl->tx_packets_count++; | ||
154 | wl1271_reg_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count); | ||
155 | |||
156 | desc = (struct wl1271_tx_hw_descr *) skb->data; | ||
157 | wl1271_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u (%u words)", | ||
158 | desc->id, skb, len, desc->length); | ||
159 | |||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | /* caller must hold wl->mutex */ | ||
164 | static int wl1271_tx_frame(struct wl1271 *wl, struct sk_buff *skb) | ||
165 | { | ||
166 | struct ieee80211_tx_info *info; | ||
167 | u32 extra = 0; | ||
168 | int ret = 0; | ||
169 | u8 idx; | ||
170 | |||
171 | if (!skb) | ||
172 | return -EINVAL; | ||
173 | |||
174 | info = IEEE80211_SKB_CB(skb); | ||
175 | |||
176 | if (info->control.hw_key && | ||
177 | info->control.hw_key->alg == ALG_TKIP) | ||
178 | extra = WL1271_TKIP_IV_SPACE; | ||
179 | |||
180 | if (info->control.hw_key) { | ||
181 | idx = info->control.hw_key->hw_key_idx; | ||
182 | |||
183 | /* FIXME: do we have to do this if we're not using WEP? */ | ||
184 | if (unlikely(wl->default_key != idx)) { | ||
185 | ret = wl1271_cmd_set_default_wep_key(wl, idx); | ||
186 | if (ret < 0) | ||
187 | return ret; | ||
188 | } | ||
189 | } | ||
190 | |||
191 | ret = wl1271_tx_allocate(wl, skb, extra); | ||
192 | if (ret < 0) | ||
193 | return ret; | ||
194 | |||
195 | ret = wl1271_tx_fill_hdr(wl, skb, extra, info); | ||
196 | if (ret < 0) | ||
197 | return ret; | ||
198 | |||
199 | ret = wl1271_tx_send_packet(wl, skb, info); | ||
200 | if (ret < 0) | ||
201 | return ret; | ||
202 | |||
203 | return ret; | ||
204 | } | ||
205 | |||
206 | void wl1271_tx_work(struct work_struct *work) | ||
207 | { | ||
208 | struct wl1271 *wl = container_of(work, struct wl1271, tx_work); | ||
209 | struct sk_buff *skb; | ||
210 | bool woken_up = false; | ||
211 | int ret; | ||
212 | |||
213 | mutex_lock(&wl->mutex); | ||
214 | |||
215 | if (unlikely(wl->state == WL1271_STATE_OFF)) | ||
216 | goto out; | ||
217 | |||
218 | while ((skb = skb_dequeue(&wl->tx_queue))) { | ||
219 | if (!woken_up) { | ||
220 | ret = wl1271_ps_elp_wakeup(wl, false); | ||
221 | if (ret < 0) | ||
222 | goto out; | ||
223 | woken_up = true; | ||
224 | } | ||
225 | |||
226 | ret = wl1271_tx_frame(wl, skb); | ||
227 | if (ret == -EBUSY) { | ||
228 | /* firmware buffer is full, stop queues */ | ||
229 | wl1271_debug(DEBUG_TX, "tx_work: fw buffer full, " | ||
230 | "stop queues"); | ||
231 | ieee80211_stop_queues(wl->hw); | ||
232 | wl->tx_queue_stopped = true; | ||
233 | skb_queue_head(&wl->tx_queue, skb); | ||
234 | goto out; | ||
235 | } else if (ret < 0) { | ||
236 | dev_kfree_skb(skb); | ||
237 | goto out; | ||
238 | } else if (wl->tx_queue_stopped) { | ||
239 | /* firmware buffer has space, restart queues */ | ||
240 | wl1271_debug(DEBUG_TX, | ||
241 | "complete_packet: waking queues"); | ||
242 | ieee80211_wake_queues(wl->hw); | ||
243 | wl->tx_queue_stopped = false; | ||
244 | } | ||
245 | } | ||
246 | |||
247 | out: | ||
248 | if (woken_up) | ||
249 | wl1271_ps_elp_sleep(wl); | ||
250 | |||
251 | mutex_unlock(&wl->mutex); | ||
252 | } | ||
253 | |||
254 | static void wl1271_tx_complete_packet(struct wl1271 *wl, | ||
255 | struct wl1271_tx_hw_res_descr *result) | ||
256 | { | ||
257 | |||
258 | struct ieee80211_tx_info *info; | ||
259 | struct sk_buff *skb; | ||
260 | u32 header_len; | ||
261 | int id = result->id; | ||
262 | |||
263 | /* check for id legality */ | ||
264 | if (id >= TX_HW_RESULT_QUEUE_LEN || wl->tx_frames[id] == NULL) { | ||
265 | wl1271_warning("TX result illegal id: %d", id); | ||
266 | return; | ||
267 | } | ||
268 | |||
269 | skb = wl->tx_frames[id]; | ||
270 | info = IEEE80211_SKB_CB(skb); | ||
271 | |||
272 | /* update packet status */ | ||
273 | if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { | ||
274 | if (result->status == TX_SUCCESS) | ||
275 | info->flags |= IEEE80211_TX_STAT_ACK; | ||
276 | if (result->status & TX_RETRY_EXCEEDED) { | ||
277 | /* FIXME */ | ||
278 | /* info->status.excessive_retries = 1; */ | ||
279 | wl->stats.excessive_retries++; | ||
280 | } | ||
281 | } | ||
282 | |||
283 | /* FIXME */ | ||
284 | /* info->status.retry_count = result->ack_failures; */ | ||
285 | wl->stats.retry_count += result->ack_failures; | ||
286 | |||
287 | /* get header len */ | ||
288 | if (info->control.hw_key && | ||
289 | info->control.hw_key->alg == ALG_TKIP) | ||
290 | header_len = WL1271_TKIP_IV_SPACE + | ||
291 | sizeof(struct wl1271_tx_hw_descr); | ||
292 | else | ||
293 | header_len = sizeof(struct wl1271_tx_hw_descr); | ||
294 | |||
295 | wl1271_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x" | ||
296 | " status 0x%x", | ||
297 | result->id, skb, result->ack_failures, | ||
298 | result->rate_class_index, result->status); | ||
299 | |||
300 | /* remove private header from packet */ | ||
301 | skb_pull(skb, header_len); | ||
302 | |||
303 | /* return the packet to the stack */ | ||
304 | ieee80211_tx_status(wl->hw, skb); | ||
305 | wl->tx_frames[result->id] = NULL; | ||
306 | } | ||
307 | |||
308 | /* Called upon reception of a TX complete interrupt */ | ||
309 | void wl1271_tx_complete(struct wl1271 *wl, u32 count) | ||
310 | { | ||
311 | struct wl1271_acx_mem_map *memmap = | ||
312 | (struct wl1271_acx_mem_map *)wl->target_mem_map; | ||
313 | u32 i; | ||
314 | |||
315 | wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count); | ||
316 | |||
317 | /* read the tx results from the chipset */ | ||
318 | wl1271_spi_mem_read(wl, memmap->tx_result, | ||
319 | wl->tx_res_if, sizeof(*wl->tx_res_if)); | ||
320 | |||
321 | /* verify that the result buffer is not getting overrun */ | ||
322 | if (count > TX_HW_RESULT_QUEUE_LEN) { | ||
323 | wl1271_warning("TX result overflow from chipset: %d", count); | ||
324 | count = TX_HW_RESULT_QUEUE_LEN; | ||
325 | } | ||
326 | |||
327 | /* process the results */ | ||
328 | for (i = 0; i < count; i++) { | ||
329 | struct wl1271_tx_hw_res_descr *result; | ||
330 | u8 offset = wl->tx_results_count & TX_HW_RESULT_QUEUE_LEN_MASK; | ||
331 | |||
332 | /* process the packet */ | ||
333 | result = &(wl->tx_res_if->tx_results_queue[offset]); | ||
334 | wl1271_tx_complete_packet(wl, result); | ||
335 | |||
336 | wl->tx_results_count++; | ||
337 | } | ||
338 | |||
339 | /* write host counter to chipset (to ack) */ | ||
340 | wl1271_mem_write32(wl, memmap->tx_result + | ||
341 | offsetof(struct wl1271_tx_hw_res_if, | ||
342 | tx_result_host_counter), | ||
343 | wl->tx_res_if->tx_result_fw_counter); | ||
344 | } | ||
345 | |||
346 | /* caller must hold wl->mutex */ | ||
347 | void wl1271_tx_flush(struct wl1271 *wl) | ||
348 | { | ||
349 | int i; | ||
350 | struct sk_buff *skb; | ||
351 | struct ieee80211_tx_info *info; | ||
352 | |||
353 | /* TX failure */ | ||
354 | /* control->flags = 0; FIXME */ | ||
355 | |||
356 | while ((skb = skb_dequeue(&wl->tx_queue))) { | ||
357 | info = IEEE80211_SKB_CB(skb); | ||
358 | |||
359 | wl1271_debug(DEBUG_TX, "flushing skb 0x%p", skb); | ||
360 | |||
361 | if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) | ||
362 | continue; | ||
363 | |||
364 | ieee80211_tx_status(wl->hw, skb); | ||
365 | } | ||
366 | |||
367 | for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) | ||
368 | if (wl->tx_frames[i] != NULL) { | ||
369 | skb = wl->tx_frames[i]; | ||
370 | info = IEEE80211_SKB_CB(skb); | ||
371 | |||
372 | if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) | ||
373 | continue; | ||
374 | |||
375 | ieee80211_tx_status(wl->hw, skb); | ||
376 | wl->tx_frames[i] = NULL; | ||
377 | } | ||
378 | } | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.h b/drivers/net/wireless/wl12xx/wl1271_tx.h new file mode 100644 index 000000000000..4a614067ddba --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_tx.h | |||
@@ -0,0 +1,130 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. | ||
5 | * Copyright (C) 2009 Nokia Corporation | ||
6 | * | ||
7 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef __WL1271_TX_H__ | ||
26 | #define __WL1271_TX_H__ | ||
27 | |||
28 | #define TX_HW_BLOCK_SPARE 2 | ||
29 | #define TX_HW_BLOCK_SHIFT_DIV 8 | ||
30 | |||
31 | #define TX_HW_MGMT_PKT_LIFETIME_TU 2000 | ||
32 | /* The chipset reference driver states, that the "aid" value 1 | ||
33 | * is for infra-BSS, but is still always used */ | ||
34 | #define TX_HW_DEFAULT_AID 1 | ||
35 | |||
36 | #define TX_HW_ATTR_SAVE_RETRIES BIT(0) | ||
37 | #define TX_HW_ATTR_HEADER_PAD BIT(1) | ||
38 | #define TX_HW_ATTR_SESSION_COUNTER (BIT(2) | BIT(3) | BIT(4)) | ||
39 | #define TX_HW_ATTR_RATE_POLICY (BIT(5) | BIT(6) | BIT(7) | \ | ||
40 | BIT(8) | BIT(9)) | ||
41 | #define TX_HW_ATTR_LAST_WORD_PAD (BIT(10) | BIT(11)) | ||
42 | #define TX_HW_ATTR_TX_CMPLT_REQ BIT(12) | ||
43 | |||
44 | #define TX_HW_ATTR_OFST_SAVE_RETRIES 0 | ||
45 | #define TX_HW_ATTR_OFST_HEADER_PAD 1 | ||
46 | #define TX_HW_ATTR_OFST_SESSION_COUNTER 2 | ||
47 | #define TX_HW_ATTR_OFST_RATE_POLICY 5 | ||
48 | #define TX_HW_ATTR_OFST_LAST_WORD_PAD 10 | ||
49 | #define TX_HW_ATTR_OFST_TX_CMPLT_REQ 12 | ||
50 | |||
51 | #define TX_HW_RESULT_QUEUE_LEN 16 | ||
52 | #define TX_HW_RESULT_QUEUE_LEN_MASK 0xf | ||
53 | |||
54 | #define WL1271_TX_ALIGN_TO 4 | ||
55 | #define WL1271_TX_ALIGN(len) (((len) + WL1271_TX_ALIGN_TO - 1) & \ | ||
56 | ~(WL1271_TX_ALIGN_TO - 1)) | ||
57 | #define WL1271_TKIP_IV_SPACE 4 | ||
58 | |||
59 | struct wl1271_tx_hw_descr { | ||
60 | /* Length of packet in words, including descriptor+header+data */ | ||
61 | u16 length; | ||
62 | /* Number of extra memory blocks to allocate for this packet in | ||
63 | addition to the number of blocks derived from the packet length */ | ||
64 | u8 extra_mem_blocks; | ||
65 | /* Total number of memory blocks allocated by the host for this packet. | ||
66 | Must be equal or greater than the actual blocks number allocated by | ||
67 | HW!! */ | ||
68 | u8 total_mem_blocks; | ||
69 | /* Device time (in us) when the packet arrived to the driver */ | ||
70 | u32 start_time; | ||
71 | /* Max delay in TUs until transmission. The last device time the | ||
72 | packet can be transmitted is: startTime+(1024*LifeTime) */ | ||
73 | u16 life_time; | ||
74 | /* Bitwise fields - see TX_ATTR... definitions above. */ | ||
75 | u16 tx_attr; | ||
76 | /* Packet identifier used also in the Tx-Result. */ | ||
77 | u8 id; | ||
78 | /* The packet TID value (as User-Priority) */ | ||
79 | u8 tid; | ||
80 | /* Identifier of the remote STA in IBSS, 1 in infra-BSS */ | ||
81 | u8 aid; | ||
82 | u8 reserved; | ||
83 | } __attribute__ ((packed)); | ||
84 | |||
85 | enum wl1271_tx_hw_res_status { | ||
86 | TX_SUCCESS = 0, | ||
87 | TX_HW_ERROR = 1, | ||
88 | TX_DISABLED = 2, | ||
89 | TX_RETRY_EXCEEDED = 3, | ||
90 | TX_TIMEOUT = 4, | ||
91 | TX_KEY_NOT_FOUND = 5, | ||
92 | TX_PEER_NOT_FOUND = 6, | ||
93 | TX_SESSION_MISMATCH = 7 | ||
94 | }; | ||
95 | |||
96 | struct wl1271_tx_hw_res_descr { | ||
97 | /* Packet Identifier - same value used in the Tx descriptor.*/ | ||
98 | u8 id; | ||
99 | /* The status of the transmission, indicating success or one of | ||
100 | several possible reasons for failure. */ | ||
101 | u8 status; | ||
102 | /* Total air access duration including all retrys and overheads.*/ | ||
103 | u16 medium_usage; | ||
104 | /* The time passed from host xfer to Tx-complete.*/ | ||
105 | u32 fw_handling_time; | ||
106 | /* Total media delay | ||
107 | (from 1st EDCA AIFS counter until TX Complete). */ | ||
108 | u32 medium_delay; | ||
109 | /* LS-byte of last TKIP seq-num (saved per AC for recovery). */ | ||
110 | u8 lsb_security_sequence_number; | ||
111 | /* Retry count - number of transmissions without successful ACK.*/ | ||
112 | u8 ack_failures; | ||
113 | /* The rate that succeeded getting ACK | ||
114 | (Valid only if status=SUCCESS). */ | ||
115 | u8 rate_class_index; | ||
116 | /* for 4-byte alignment. */ | ||
117 | u8 spare; | ||
118 | } __attribute__ ((packed)); | ||
119 | |||
120 | struct wl1271_tx_hw_res_if { | ||
121 | u32 tx_result_fw_counter; | ||
122 | u32 tx_result_host_counter; | ||
123 | struct wl1271_tx_hw_res_descr tx_results_queue[TX_HW_RESULT_QUEUE_LEN]; | ||
124 | } __attribute__ ((packed)); | ||
125 | |||
126 | void wl1271_tx_work(struct work_struct *work); | ||
127 | void wl1271_tx_complete(struct wl1271 *wl, u32 count); | ||
128 | void wl1271_tx_flush(struct wl1271 *wl); | ||
129 | |||
130 | #endif | ||