aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShahar Levi <shahar_levi@ti.com>2011-03-06 09:32:08 -0500
committerLuciano Coelho <coelho@ti.com>2011-04-19 09:19:47 -0400
commit48a61477bdc04896bd96d259388a0c42a7019943 (patch)
treed36c7638d2405a63db333713a5c7897d736011a5
parent5aa42346bba2e385674eb1dd4019dfce4c2ef771 (diff)
wl12xx: 1281/1283 support - Add acx commands
New acx command that sets: Rx fifo enable reduced bus transactions in RX path. Tx bus transactions padding to SDIO block size that improve preference in Tx and essential for working with SDIO HS (48Mhz). The max SDIO block size is 256 when working with Tx bus transactions padding to SDIO block. Add new ops to SDIO & SPI that handles the win size change in case of transactions padding (relevant only for SDIO). [Fix endianess issues; simplify sdio-specific block_size handling; minor changes in comments; use "aligned_len" in one calculation instead of "pad" to avoid confusion -- Luca] Signed-off-by: Shahar Levi <shahar_levi@ti.com> Reviewed-by: Luciano Coelho <coelho@ti.com> Signed-off-by: Luciano Coelho <coelho@ti.com>
-rw-r--r--drivers/net/wireless/wl12xx/acx.c26
-rw-r--r--drivers/net/wireless/wl12xx/acx.h11
-rw-r--r--drivers/net/wireless/wl12xx/init.c27
-rw-r--r--drivers/net/wireless/wl12xx/init.h1
-rw-r--r--drivers/net/wireless/wl12xx/io.c10
-rw-r--r--drivers/net/wireless/wl12xx/io.h1
-rw-r--r--drivers/net/wireless/wl12xx/main.c7
-rw-r--r--drivers/net/wireless/wl12xx/tx.c64
-rw-r--r--drivers/net/wireless/wl12xx/tx.h46
-rw-r--r--drivers/net/wireless/wl12xx/wl12xx.h3
10 files changed, 168 insertions, 28 deletions
diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c
index a3db755ceeda..50676b36ad26 100644
--- a/drivers/net/wireless/wl12xx/acx.c
+++ b/drivers/net/wireless/wl12xx/acx.c
@@ -1019,6 +1019,32 @@ out:
1019 return ret; 1019 return ret;
1020} 1020}
1021 1021
1022int wl1271_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap)
1023{
1024 struct wl1271_acx_host_config_bitmap *bitmap_conf;
1025 int ret;
1026
1027 bitmap_conf = kzalloc(sizeof(*bitmap_conf), GFP_KERNEL);
1028 if (!bitmap_conf) {
1029 ret = -ENOMEM;
1030 goto out;
1031 }
1032
1033 bitmap_conf->host_cfg_bitmap = cpu_to_le32(host_cfg_bitmap);
1034
1035 ret = wl1271_cmd_configure(wl, ACX_HOST_IF_CFG_BITMAP,
1036 bitmap_conf, sizeof(*bitmap_conf));
1037 if (ret < 0) {
1038 wl1271_warning("wl1271 bitmap config opt failed: %d", ret);
1039 goto out;
1040 }
1041
1042out:
1043 kfree(bitmap_conf);
1044
1045 return ret;
1046}
1047
1022int wl1271_acx_init_mem_config(struct wl1271 *wl) 1048int wl1271_acx_init_mem_config(struct wl1271 *wl)
1023{ 1049{
1024 int ret; 1050 int ret;
diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h
index dd19b01d807b..0a40caeab2a2 100644
--- a/drivers/net/wireless/wl12xx/acx.h
+++ b/drivers/net/wireless/wl12xx/acx.h
@@ -939,6 +939,16 @@ struct wl1271_acx_keep_alive_config {
939 u8 padding; 939 u8 padding;
940} __packed; 940} __packed;
941 941
942#define HOST_IF_CFG_RX_FIFO_ENABLE BIT(0)
943#define HOST_IF_CFG_TX_EXTRA_BLKS_SWAP BIT(1)
944#define HOST_IF_CFG_TX_PAD_TO_SDIO_BLK BIT(3)
945
946struct wl1271_acx_host_config_bitmap {
947 struct acx_header header;
948
949 __le32 host_cfg_bitmap;
950} __packed;
951
942enum { 952enum {
943 WL1271_ACX_TRIG_TYPE_LEVEL = 0, 953 WL1271_ACX_TRIG_TYPE_LEVEL = 0,
944 WL1271_ACX_TRIG_TYPE_EDGE, 954 WL1271_ACX_TRIG_TYPE_EDGE,
@@ -1275,6 +1285,7 @@ int wl1271_acx_tx_config_options(struct wl1271 *wl);
1275int wl1271_acx_ap_mem_cfg(struct wl1271 *wl); 1285int wl1271_acx_ap_mem_cfg(struct wl1271 *wl);
1276int wl1271_acx_sta_mem_cfg(struct wl1271 *wl); 1286int wl1271_acx_sta_mem_cfg(struct wl1271 *wl);
1277int wl1271_acx_init_mem_config(struct wl1271 *wl); 1287int wl1271_acx_init_mem_config(struct wl1271 *wl);
1288int wl1271_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap);
1278int wl1271_acx_init_rx_interrupt(struct wl1271 *wl); 1289int wl1271_acx_init_rx_interrupt(struct wl1271 *wl);
1279int wl1271_acx_smart_reflex(struct wl1271 *wl); 1290int wl1271_acx_smart_reflex(struct wl1271 *wl);
1280int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable); 1291int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable);
diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c
index 6072fe457135..34c41084bcf1 100644
--- a/drivers/net/wireless/wl12xx/init.c
+++ b/drivers/net/wireless/wl12xx/init.c
@@ -31,6 +31,7 @@
31#include "cmd.h" 31#include "cmd.h"
32#include "reg.h" 32#include "reg.h"
33#include "tx.h" 33#include "tx.h"
34#include "io.h"
34 35
35int wl1271_sta_init_templates_config(struct wl1271 *wl) 36int wl1271_sta_init_templates_config(struct wl1271 *wl)
36{ 37{
@@ -504,6 +505,27 @@ static int wl1271_set_ba_policies(struct wl1271 *wl)
504 return ret; 505 return ret;
505} 506}
506 507
508int wl1271_chip_specific_init(struct wl1271 *wl)
509{
510 int ret = 0;
511
512 if (wl->chip.id == CHIP_ID_1283_PG20) {
513 u32 host_cfg_bitmap = HOST_IF_CFG_RX_FIFO_ENABLE;
514
515 if (wl1271_set_block_size(wl))
516 /* Enable SDIO padding */
517 host_cfg_bitmap |= HOST_IF_CFG_TX_PAD_TO_SDIO_BLK;
518
519 /* Must be before wl1271_acx_init_mem_config() */
520 ret = wl1271_acx_host_if_cfg_bitmap(wl, host_cfg_bitmap);
521 if (ret < 0)
522 goto out;
523 }
524out:
525 return ret;
526}
527
528
507int wl1271_hw_init(struct wl1271 *wl) 529int wl1271_hw_init(struct wl1271 *wl)
508{ 530{
509 struct conf_tx_ac_category *conf_ac; 531 struct conf_tx_ac_category *conf_ac;
@@ -519,6 +541,11 @@ int wl1271_hw_init(struct wl1271 *wl)
519 if (ret < 0) 541 if (ret < 0)
520 return ret; 542 return ret;
521 543
544 /* Chip-specific init */
545 ret = wl1271_chip_specific_init(wl);
546 if (ret < 0)
547 return ret;
548
522 /* Mode specific init */ 549 /* Mode specific init */
523 if (is_ap) 550 if (is_ap)
524 ret = wl1271_ap_hw_init(wl); 551 ret = wl1271_ap_hw_init(wl);
diff --git a/drivers/net/wireless/wl12xx/init.h b/drivers/net/wireless/wl12xx/init.h
index 3a8bd3f426d2..4975270a91ab 100644
--- a/drivers/net/wireless/wl12xx/init.h
+++ b/drivers/net/wireless/wl12xx/init.h
@@ -31,6 +31,7 @@ int wl1271_sta_init_templates_config(struct wl1271 *wl);
31int wl1271_init_phy_config(struct wl1271 *wl); 31int wl1271_init_phy_config(struct wl1271 *wl);
32int wl1271_init_pta(struct wl1271 *wl); 32int wl1271_init_pta(struct wl1271 *wl);
33int wl1271_init_energy_detection(struct wl1271 *wl); 33int wl1271_init_energy_detection(struct wl1271 *wl);
34int wl1271_chip_specific_init(struct wl1271 *wl);
34int wl1271_hw_init(struct wl1271 *wl); 35int wl1271_hw_init(struct wl1271 *wl);
35 36
36#endif 37#endif
diff --git a/drivers/net/wireless/wl12xx/io.c b/drivers/net/wireless/wl12xx/io.c
index d557f73e7c19..aa40c98e8fd3 100644
--- a/drivers/net/wireless/wl12xx/io.c
+++ b/drivers/net/wireless/wl12xx/io.c
@@ -43,6 +43,16 @@
43#define OCP_STATUS_REQ_FAILED 0x20000 43#define OCP_STATUS_REQ_FAILED 0x20000
44#define OCP_STATUS_RESP_ERROR 0x30000 44#define OCP_STATUS_RESP_ERROR 0x30000
45 45
46bool wl1271_set_block_size(struct wl1271 *wl)
47{
48 if (wl->if_ops->set_block_size) {
49 wl->if_ops->set_block_size(wl);
50 return true;
51 }
52
53 return false;
54}
55
46void wl1271_disable_interrupts(struct wl1271 *wl) 56void wl1271_disable_interrupts(struct wl1271 *wl)
47{ 57{
48 wl->if_ops->disable_irq(wl); 58 wl->if_ops->disable_irq(wl);
diff --git a/drivers/net/wireless/wl12xx/io.h b/drivers/net/wireless/wl12xx/io.h
index c1aac8292089..84454f6d8169 100644
--- a/drivers/net/wireless/wl12xx/io.h
+++ b/drivers/net/wireless/wl12xx/io.h
@@ -169,5 +169,6 @@ int wl1271_init_ieee80211(struct wl1271 *wl);
169struct ieee80211_hw *wl1271_alloc_hw(void); 169struct ieee80211_hw *wl1271_alloc_hw(void);
170int wl1271_free_hw(struct wl1271 *wl); 170int wl1271_free_hw(struct wl1271 *wl);
171irqreturn_t wl1271_irq(int irq, void *data); 171irqreturn_t wl1271_irq(int irq, void *data);
172bool wl1271_set_block_size(struct wl1271 *wl);
172 173
173#endif 174#endif
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index b0c49352b56f..f24906f54a71 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -450,6 +450,11 @@ static int wl1271_plt_init(struct wl1271 *wl)
450 if (ret < 0) 450 if (ret < 0)
451 return ret; 451 return ret;
452 452
453 /* Chip-specific initializations */
454 ret = wl1271_chip_specific_init(wl);
455 if (ret < 0)
456 return ret;
457
453 ret = wl1271_sta_init_templates_config(wl); 458 ret = wl1271_sta_init_templates_config(wl);
454 if (ret < 0) 459 if (ret < 0)
455 return ret; 460 return ret;
@@ -1335,6 +1340,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl)
1335 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map)); 1340 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
1336 wl->ap_fw_ps_map = 0; 1341 wl->ap_fw_ps_map = 0;
1337 wl->ap_ps_map = 0; 1342 wl->ap_ps_map = 0;
1343 wl->block_size = 0;
1338 1344
1339 for (i = 0; i < NUM_TX_QUEUES; i++) 1345 for (i = 0; i < NUM_TX_QUEUES; i++)
1340 wl->tx_blocks_freed[i] = 0; 1346 wl->tx_blocks_freed[i] = 0;
@@ -3458,6 +3464,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
3458 wl->ap_ps_map = 0; 3464 wl->ap_ps_map = 0;
3459 wl->ap_fw_ps_map = 0; 3465 wl->ap_fw_ps_map = 0;
3460 wl->quirks = 0; 3466 wl->quirks = 0;
3467 wl->block_size = 0;
3461 3468
3462 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map)); 3469 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
3463 for (i = 0; i < ACX_TX_DESCRIPTORS; i++) 3470 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index 5e9ef7d53e7e..e296f0a5fe27 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -132,6 +132,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
132{ 132{
133 struct wl1271_tx_hw_descr *desc; 133 struct wl1271_tx_hw_descr *desc;
134 u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra; 134 u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra;
135 u32 len;
135 u32 total_blocks; 136 u32 total_blocks;
136 int id, ret = -EBUSY; 137 int id, ret = -EBUSY;
137 138
@@ -145,14 +146,20 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
145 146
146 /* approximate the number of blocks required for this packet 147 /* approximate the number of blocks required for this packet
147 in the firmware */ 148 in the firmware */
148 total_blocks = total_len + TX_HW_BLOCK_SIZE - 1; 149 if (wl->block_size)
149 total_blocks = total_blocks / TX_HW_BLOCK_SIZE + TX_HW_BLOCK_SPARE; 150 len = ALIGN(total_len, wl->block_size);
151 else
152 len = total_len;
153
154 total_blocks = (len + TX_HW_BLOCK_SIZE - 1) / TX_HW_BLOCK_SIZE +
155 TX_HW_BLOCK_SPARE;
156
150 if (total_blocks <= wl->tx_blocks_available) { 157 if (total_blocks <= wl->tx_blocks_available) {
151 desc = (struct wl1271_tx_hw_descr *)skb_push( 158 desc = (struct wl1271_tx_hw_descr *)skb_push(
152 skb, total_len - skb->len); 159 skb, total_len - skb->len);
153 160
154 desc->extra_mem_blocks = TX_HW_BLOCK_SPARE; 161 desc->wl127x_mem.extra_blocks = TX_HW_BLOCK_SPARE;
155 desc->total_mem_blocks = total_blocks; 162 desc->wl127x_mem.total_mem_blocks = total_blocks;
156 desc->id = id; 163 desc->id = id;
157 164
158 wl->tx_blocks_available -= total_blocks; 165 wl->tx_blocks_available -= total_blocks;
@@ -178,7 +185,7 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
178{ 185{
179 struct timespec ts; 186 struct timespec ts;
180 struct wl1271_tx_hw_descr *desc; 187 struct wl1271_tx_hw_descr *desc;
181 int pad, ac, rate_idx; 188 int aligned_len, ac, rate_idx;
182 s64 hosttime; 189 s64 hosttime;
183 u16 tx_attr; 190 u16 tx_attr;
184 191
@@ -237,20 +244,32 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
237 tx_attr |= rate_idx << TX_HW_ATTR_OFST_RATE_POLICY; 244 tx_attr |= rate_idx << TX_HW_ATTR_OFST_RATE_POLICY;
238 desc->reserved = 0; 245 desc->reserved = 0;
239 246
240 /* align the length (and store in terms of words) */ 247 if (wl->block_size) {
241 pad = ALIGN(skb->len, WL1271_TX_ALIGN_TO); 248 aligned_len = ALIGN(skb->len, wl->block_size);
242 desc->length = cpu_to_le16(pad >> 2); 249
250 desc->wl128x_mem.extra_bytes = aligned_len - skb->len;
251 desc->length = cpu_to_le16(aligned_len >> 2);
252 } else {
253 int pad;
254
255 /* align the length (and store in terms of words) */
256 aligned_len = ALIGN(skb->len, WL1271_TX_ALIGN_TO);
257 desc->length = cpu_to_le16(aligned_len >> 2);
258
259 /* calculate number of padding bytes */
260 pad = aligned_len - skb->len;
261 tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD;
243 262
244 /* calculate number of padding bytes */ 263 wl1271_debug(DEBUG_TX, "tx_fill_hdr: padding: %d", pad);
245 pad = pad - skb->len; 264 }
246 tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD;
247 265
248 desc->tx_attr = cpu_to_le16(tx_attr); 266 desc->tx_attr = cpu_to_le16(tx_attr);
249 267
250 wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d hlid: %d " 268 wl1271_debug(DEBUG_TX, "tx_fill_hdr: hlid: %d tx_attr: 0x%x "
251 "tx_attr: 0x%x len: %d life: %d mem: %d", pad, desc->hlid, 269 "len: %d life: %d mem: %d",
252 le16_to_cpu(desc->tx_attr), le16_to_cpu(desc->length), 270 desc->hlid, le16_to_cpu(desc->tx_attr),
253 le16_to_cpu(desc->life_time), desc->total_mem_blocks); 271 le16_to_cpu(desc->length), le16_to_cpu(desc->life_time),
272 desc->wl127x_mem.total_mem_blocks);
254} 273}
255 274
256/* caller must hold wl->mutex */ 275/* caller must hold wl->mutex */
@@ -305,11 +324,18 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
305 wl1271_tx_fill_hdr(wl, skb, extra, info, hlid); 324 wl1271_tx_fill_hdr(wl, skb, extra, info, hlid);
306 325
307 /* 326 /*
308 * The length of each packet is stored in terms of words. Thus, we must 327 * The length of each packet is stored in terms of
309 * pad the skb data to make sure its length is aligned. 328 * words. Thus, we must pad the skb data to make sure its
310 * The number of padding bytes is computed and set in wl1271_tx_fill_hdr 329 * length is aligned. The number of padding bytes is computed
330 * and set in wl1271_tx_fill_hdr.
331 * In special cases, we want to align to a specific block size
332 * (eg. for wl128x with SDIO we align to 256).
311 */ 333 */
312 total_len = ALIGN(skb->len, WL1271_TX_ALIGN_TO); 334 if (wl->block_size)
335 total_len = ALIGN(skb->len, wl->block_size);
336 else
337 total_len = ALIGN(skb->len, WL1271_TX_ALIGN_TO);
338
313 memcpy(wl->aggr_buf + buf_offset, skb->data, skb->len); 339 memcpy(wl->aggr_buf + buf_offset, skb->data, skb->len);
314 memset(wl->aggr_buf + buf_offset + skb->len, 0, total_len - skb->len); 340 memset(wl->aggr_buf + buf_offset + skb->len, 0, total_len - skb->len);
315 341
diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h
index 02f07fa66e82..e31317717ab2 100644
--- a/drivers/net/wireless/wl12xx/tx.h
+++ b/drivers/net/wireless/wl12xx/tx.h
@@ -55,20 +55,48 @@
55#define WL1271_TX_ALIGN_TO 4 55#define WL1271_TX_ALIGN_TO 4
56#define WL1271_TKIP_IV_SPACE 4 56#define WL1271_TKIP_IV_SPACE 4
57 57
58struct wl127x_tx_mem {
59 /*
60 * Number of extra memory blocks to allocate for this packet
61 * in addition to the number of blocks derived from the packet
62 * length.
63 */
64 u8 extra_blocks;
65 /*
66 * Total number of memory blocks allocated by the host for
67 * this packet. Must be equal or greater than the actual
68 * blocks number allocated by HW.
69 */
70 u8 total_mem_blocks;
71} __packed;
72
73struct wl128x_tx_mem {
74 /*
75 * Total number of memory blocks allocated by the host for
76 * this packet.
77 */
78 u8 total_mem_blocks;
79 /*
80 * Number of extra bytes, at the end of the frame. the host
81 * uses this padding to complete each frame to integer number
82 * of SDIO blocks.
83 */
84 u8 extra_bytes;
85} __packed;
86
58struct wl1271_tx_hw_descr { 87struct wl1271_tx_hw_descr {
59 /* Length of packet in words, including descriptor+header+data */ 88 /* Length of packet in words, including descriptor+header+data */
60 __le16 length; 89 __le16 length;
61 /* Number of extra memory blocks to allocate for this packet in 90 union {
62 addition to the number of blocks derived from the packet length */ 91 struct wl127x_tx_mem wl127x_mem;
63 u8 extra_mem_blocks; 92 struct wl128x_tx_mem wl128x_mem;
64 /* Total number of memory blocks allocated by the host for this packet. 93 } __packed;
65 Must be equal or greater than the actual blocks number allocated by
66 HW!! */
67 u8 total_mem_blocks;
68 /* Device time (in us) when the packet arrived to the driver */ 94 /* Device time (in us) when the packet arrived to the driver */
69 __le32 start_time; 95 __le32 start_time;
70 /* Max delay in TUs until transmission. The last device time the 96 /*
71 packet can be transmitted is: startTime+(1024*LifeTime) */ 97 * Max delay in TUs until transmission. The last device time the
98 * packet can be transmitted is: start_time + (1024 * life_time)
99 */
72 __le16 life_time; 100 __le16 life_time;
73 /* Bitwise fields - see TX_ATTR... definitions above. */ 101 /* Bitwise fields - see TX_ATTR... definitions above. */
74 __le16 tx_attr; 102 __le16 tx_attr;
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index a2e899d4e1aa..959b338d0af4 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -303,6 +303,7 @@ struct wl1271_if_operations {
303 struct device* (*dev)(struct wl1271 *wl); 303 struct device* (*dev)(struct wl1271 *wl);
304 void (*enable_irq)(struct wl1271 *wl); 304 void (*enable_irq)(struct wl1271 *wl);
305 void (*disable_irq)(struct wl1271 *wl); 305 void (*disable_irq)(struct wl1271 *wl);
306 void (*set_block_size) (struct wl1271 *wl);
306}; 307};
307 308
308#define MAX_NUM_KEYS 14 309#define MAX_NUM_KEYS 14
@@ -533,6 +534,8 @@ struct wl1271 {
533 bool ba_support; 534 bool ba_support;
534 u8 ba_rx_bitmap; 535 u8 ba_rx_bitmap;
535 536
537 u32 block_size;
538
536 /* 539 /*
537 * AP-mode - links indexed by HLID. The global and broadcast links 540 * AP-mode - links indexed by HLID. The global and broadcast links
538 * are always active. 541 * are always active.