diff options
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/bmi.c | 191 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/hif-ops.h | 10 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/hif.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/sdio.c | 162 |
4 files changed, 190 insertions, 175 deletions
diff --git a/drivers/net/wireless/ath/ath6kl/bmi.c b/drivers/net/wireless/ath/ath6kl/bmi.c index a962fe4c6b7e..12f5b57d2dc2 100644 --- a/drivers/net/wireless/ath/ath6kl/bmi.c +++ b/drivers/net/wireless/ath/ath6kl/bmi.c | |||
@@ -19,165 +19,6 @@ | |||
19 | #include "target.h" | 19 | #include "target.h" |
20 | #include "debug.h" | 20 | #include "debug.h" |
21 | 21 | ||
22 | static int ath6kl_get_bmi_cmd_credits(struct ath6kl *ar) | ||
23 | { | ||
24 | u32 addr; | ||
25 | unsigned long timeout; | ||
26 | int ret; | ||
27 | |||
28 | ar->bmi.cmd_credits = 0; | ||
29 | |||
30 | /* Read the counter register to get the command credits */ | ||
31 | addr = COUNT_DEC_ADDRESS + (HTC_MAILBOX_NUM_MAX + ENDPOINT1) * 4; | ||
32 | |||
33 | timeout = jiffies + msecs_to_jiffies(BMI_COMMUNICATION_TIMEOUT); | ||
34 | while (time_before(jiffies, timeout) && !ar->bmi.cmd_credits) { | ||
35 | |||
36 | /* | ||
37 | * Hit the credit counter with a 4-byte access, the first byte | ||
38 | * read will hit the counter and cause a decrement, while the | ||
39 | * remaining 3 bytes has no effect. The rationale behind this | ||
40 | * is to make all HIF accesses 4-byte aligned. | ||
41 | */ | ||
42 | ret = hif_read_write_sync(ar, addr, | ||
43 | (u8 *)&ar->bmi.cmd_credits, 4, | ||
44 | HIF_RD_SYNC_BYTE_INC); | ||
45 | if (ret) { | ||
46 | ath6kl_err("Unable to decrement the command credit count register: %d\n", | ||
47 | ret); | ||
48 | return ret; | ||
49 | } | ||
50 | |||
51 | /* The counter is only 8 bits. | ||
52 | * Ignore anything in the upper 3 bytes | ||
53 | */ | ||
54 | ar->bmi.cmd_credits &= 0xFF; | ||
55 | } | ||
56 | |||
57 | if (!ar->bmi.cmd_credits) { | ||
58 | ath6kl_err("bmi communication timeout\n"); | ||
59 | return -ETIMEDOUT; | ||
60 | } | ||
61 | |||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | static int ath6kl_bmi_get_rx_lkahd(struct ath6kl *ar) | ||
66 | { | ||
67 | unsigned long timeout; | ||
68 | u32 rx_word = 0; | ||
69 | int ret = 0; | ||
70 | |||
71 | timeout = jiffies + msecs_to_jiffies(BMI_COMMUNICATION_TIMEOUT); | ||
72 | while (time_before(jiffies, timeout) && !rx_word) { | ||
73 | ret = hif_read_write_sync(ar, RX_LOOKAHEAD_VALID_ADDRESS, | ||
74 | (u8 *)&rx_word, sizeof(rx_word), | ||
75 | HIF_RD_SYNC_BYTE_INC); | ||
76 | if (ret) { | ||
77 | ath6kl_err("unable to read RX_LOOKAHEAD_VALID\n"); | ||
78 | return ret; | ||
79 | } | ||
80 | |||
81 | /* all we really want is one bit */ | ||
82 | rx_word &= (1 << ENDPOINT1); | ||
83 | } | ||
84 | |||
85 | if (!rx_word) { | ||
86 | ath6kl_err("bmi_recv_buf FIFO empty\n"); | ||
87 | return -EINVAL; | ||
88 | } | ||
89 | |||
90 | return ret; | ||
91 | } | ||
92 | |||
93 | static int ath6kl_bmi_send_buf(struct ath6kl *ar, u8 *buf, u32 len) | ||
94 | { | ||
95 | int ret; | ||
96 | u32 addr; | ||
97 | |||
98 | ret = ath6kl_get_bmi_cmd_credits(ar); | ||
99 | if (ret) | ||
100 | return ret; | ||
101 | |||
102 | addr = ar->mbox_info.htc_addr; | ||
103 | |||
104 | ret = hif_read_write_sync(ar, addr, buf, len, | ||
105 | HIF_WR_SYNC_BYTE_INC); | ||
106 | if (ret) | ||
107 | ath6kl_err("unable to send the bmi data to the device\n"); | ||
108 | |||
109 | return ret; | ||
110 | } | ||
111 | |||
112 | static int ath6kl_bmi_recv_buf(struct ath6kl *ar, u8 *buf, u32 len) | ||
113 | { | ||
114 | int ret; | ||
115 | u32 addr; | ||
116 | |||
117 | /* | ||
118 | * During normal bootup, small reads may be required. | ||
119 | * Rather than issue an HIF Read and then wait as the Target | ||
120 | * adds successive bytes to the FIFO, we wait here until | ||
121 | * we know that response data is available. | ||
122 | * | ||
123 | * This allows us to cleanly timeout on an unexpected | ||
124 | * Target failure rather than risk problems at the HIF level. | ||
125 | * In particular, this avoids SDIO timeouts and possibly garbage | ||
126 | * data on some host controllers. And on an interconnect | ||
127 | * such as Compact Flash (as well as some SDIO masters) which | ||
128 | * does not provide any indication on data timeout, it avoids | ||
129 | * a potential hang or garbage response. | ||
130 | * | ||
131 | * Synchronization is more difficult for reads larger than the | ||
132 | * size of the MBOX FIFO (128B), because the Target is unable | ||
133 | * to push the 129th byte of data until AFTER the Host posts an | ||
134 | * HIF Read and removes some FIFO data. So for large reads the | ||
135 | * Host proceeds to post an HIF Read BEFORE all the data is | ||
136 | * actually available to read. Fortunately, large BMI reads do | ||
137 | * not occur in practice -- they're supported for debug/development. | ||
138 | * | ||
139 | * So Host/Target BMI synchronization is divided into these cases: | ||
140 | * CASE 1: length < 4 | ||
141 | * Should not happen | ||
142 | * | ||
143 | * CASE 2: 4 <= length <= 128 | ||
144 | * Wait for first 4 bytes to be in FIFO | ||
145 | * If CONSERVATIVE_BMI_READ is enabled, also wait for | ||
146 | * a BMI command credit, which indicates that the ENTIRE | ||
147 | * response is available in the the FIFO | ||
148 | * | ||
149 | * CASE 3: length > 128 | ||
150 | * Wait for the first 4 bytes to be in FIFO | ||
151 | * | ||
152 | * For most uses, a small timeout should be sufficient and we will | ||
153 | * usually see a response quickly; but there may be some unusual | ||
154 | * (debug) cases of BMI_EXECUTE where we want an larger timeout. | ||
155 | * For now, we use an unbounded busy loop while waiting for | ||
156 | * BMI_EXECUTE. | ||
157 | * | ||
158 | * If BMI_EXECUTE ever needs to support longer-latency execution, | ||
159 | * especially in production, this code needs to be enhanced to sleep | ||
160 | * and yield. Also note that BMI_COMMUNICATION_TIMEOUT is currently | ||
161 | * a function of Host processor speed. | ||
162 | */ | ||
163 | if (len >= 4) { /* NB: Currently, always true */ | ||
164 | ret = ath6kl_bmi_get_rx_lkahd(ar); | ||
165 | if (ret) | ||
166 | return ret; | ||
167 | } | ||
168 | |||
169 | addr = ar->mbox_info.htc_addr; | ||
170 | ret = hif_read_write_sync(ar, addr, buf, len, | ||
171 | HIF_RD_SYNC_BYTE_INC); | ||
172 | if (ret) { | ||
173 | ath6kl_err("Unable to read the bmi data from the device: %d\n", | ||
174 | ret); | ||
175 | return ret; | ||
176 | } | ||
177 | |||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | int ath6kl_bmi_done(struct ath6kl *ar) | 22 | int ath6kl_bmi_done(struct ath6kl *ar) |
182 | { | 23 | { |
183 | int ret; | 24 | int ret; |
@@ -190,7 +31,7 @@ int ath6kl_bmi_done(struct ath6kl *ar) | |||
190 | 31 | ||
191 | ar->bmi.done_sent = true; | 32 | ar->bmi.done_sent = true; |
192 | 33 | ||
193 | ret = ath6kl_bmi_send_buf(ar, (u8 *)&cid, sizeof(cid)); | 34 | ret = ath6kl_hif_bmi_write(ar, (u8 *)&cid, sizeof(cid)); |
194 | if (ret) { | 35 | if (ret) { |
195 | ath6kl_err("Unable to send bmi done: %d\n", ret); | 36 | ath6kl_err("Unable to send bmi done: %d\n", ret); |
196 | return ret; | 37 | return ret; |
@@ -210,13 +51,13 @@ int ath6kl_bmi_get_target_info(struct ath6kl *ar, | |||
210 | return -EACCES; | 51 | return -EACCES; |
211 | } | 52 | } |
212 | 53 | ||
213 | ret = ath6kl_bmi_send_buf(ar, (u8 *)&cid, sizeof(cid)); | 54 | ret = ath6kl_hif_bmi_write(ar, (u8 *)&cid, sizeof(cid)); |
214 | if (ret) { | 55 | if (ret) { |
215 | ath6kl_err("Unable to send get target info: %d\n", ret); | 56 | ath6kl_err("Unable to send get target info: %d\n", ret); |
216 | return ret; | 57 | return ret; |
217 | } | 58 | } |
218 | 59 | ||
219 | ret = ath6kl_bmi_recv_buf(ar, (u8 *)&targ_info->version, | 60 | ret = ath6kl_hif_bmi_read(ar, (u8 *)&targ_info->version, |
220 | sizeof(targ_info->version)); | 61 | sizeof(targ_info->version)); |
221 | if (ret) { | 62 | if (ret) { |
222 | ath6kl_err("Unable to recv target info: %d\n", ret); | 63 | ath6kl_err("Unable to recv target info: %d\n", ret); |
@@ -225,7 +66,7 @@ int ath6kl_bmi_get_target_info(struct ath6kl *ar, | |||
225 | 66 | ||
226 | if (le32_to_cpu(targ_info->version) == TARGET_VERSION_SENTINAL) { | 67 | if (le32_to_cpu(targ_info->version) == TARGET_VERSION_SENTINAL) { |
227 | /* Determine how many bytes are in the Target's targ_info */ | 68 | /* Determine how many bytes are in the Target's targ_info */ |
228 | ret = ath6kl_bmi_recv_buf(ar, | 69 | ret = ath6kl_hif_bmi_read(ar, |
229 | (u8 *)&targ_info->byte_count, | 70 | (u8 *)&targ_info->byte_count, |
230 | sizeof(targ_info->byte_count)); | 71 | sizeof(targ_info->byte_count)); |
231 | if (ret) { | 72 | if (ret) { |
@@ -244,7 +85,7 @@ int ath6kl_bmi_get_target_info(struct ath6kl *ar, | |||
244 | } | 85 | } |
245 | 86 | ||
246 | /* Read the remainder of the targ_info */ | 87 | /* Read the remainder of the targ_info */ |
247 | ret = ath6kl_bmi_recv_buf(ar, | 88 | ret = ath6kl_hif_bmi_read(ar, |
248 | ((u8 *)targ_info) + | 89 | ((u8 *)targ_info) + |
249 | sizeof(targ_info->byte_count), | 90 | sizeof(targ_info->byte_count), |
250 | sizeof(*targ_info) - | 91 | sizeof(*targ_info) - |
@@ -300,13 +141,13 @@ int ath6kl_bmi_read(struct ath6kl *ar, u32 addr, u8 *buf, u32 len) | |||
300 | memcpy(&(ar->bmi.cmd_buf[offset]), &rx_len, sizeof(rx_len)); | 141 | memcpy(&(ar->bmi.cmd_buf[offset]), &rx_len, sizeof(rx_len)); |
301 | offset += sizeof(len); | 142 | offset += sizeof(len); |
302 | 143 | ||
303 | ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset); | 144 | ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset); |
304 | if (ret) { | 145 | if (ret) { |
305 | ath6kl_err("Unable to write to the device: %d\n", | 146 | ath6kl_err("Unable to write to the device: %d\n", |
306 | ret); | 147 | ret); |
307 | return ret; | 148 | return ret; |
308 | } | 149 | } |
309 | ret = ath6kl_bmi_recv_buf(ar, ar->bmi.cmd_buf, rx_len); | 150 | ret = ath6kl_hif_bmi_read(ar, ar->bmi.cmd_buf, rx_len); |
310 | if (ret) { | 151 | if (ret) { |
311 | ath6kl_err("Unable to read from the device: %d\n", | 152 | ath6kl_err("Unable to read from the device: %d\n", |
312 | ret); | 153 | ret); |
@@ -371,7 +212,7 @@ int ath6kl_bmi_write(struct ath6kl *ar, u32 addr, u8 *buf, u32 len) | |||
371 | memcpy(&(ar->bmi.cmd_buf[offset]), src, tx_len); | 212 | memcpy(&(ar->bmi.cmd_buf[offset]), src, tx_len); |
372 | offset += tx_len; | 213 | offset += tx_len; |
373 | 214 | ||
374 | ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset); | 215 | ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset); |
375 | if (ret) { | 216 | if (ret) { |
376 | ath6kl_err("Unable to write to the device: %d\n", | 217 | ath6kl_err("Unable to write to the device: %d\n", |
377 | ret); | 218 | ret); |
@@ -413,13 +254,13 @@ int ath6kl_bmi_execute(struct ath6kl *ar, u32 addr, u32 *param) | |||
413 | memcpy(&(ar->bmi.cmd_buf[offset]), param, sizeof(*param)); | 254 | memcpy(&(ar->bmi.cmd_buf[offset]), param, sizeof(*param)); |
414 | offset += sizeof(*param); | 255 | offset += sizeof(*param); |
415 | 256 | ||
416 | ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset); | 257 | ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset); |
417 | if (ret) { | 258 | if (ret) { |
418 | ath6kl_err("Unable to write to the device: %d\n", ret); | 259 | ath6kl_err("Unable to write to the device: %d\n", ret); |
419 | return ret; | 260 | return ret; |
420 | } | 261 | } |
421 | 262 | ||
422 | ret = ath6kl_bmi_recv_buf(ar, ar->bmi.cmd_buf, sizeof(*param)); | 263 | ret = ath6kl_hif_bmi_read(ar, ar->bmi.cmd_buf, sizeof(*param)); |
423 | if (ret) { | 264 | if (ret) { |
424 | ath6kl_err("Unable to read from the device: %d\n", ret); | 265 | ath6kl_err("Unable to read from the device: %d\n", ret); |
425 | return ret; | 266 | return ret; |
@@ -457,7 +298,7 @@ int ath6kl_bmi_set_app_start(struct ath6kl *ar, u32 addr) | |||
457 | memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr)); | 298 | memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr)); |
458 | offset += sizeof(addr); | 299 | offset += sizeof(addr); |
459 | 300 | ||
460 | ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset); | 301 | ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset); |
461 | if (ret) { | 302 | if (ret) { |
462 | ath6kl_err("Unable to write to the device: %d\n", ret); | 303 | ath6kl_err("Unable to write to the device: %d\n", ret); |
463 | return ret; | 304 | return ret; |
@@ -493,13 +334,13 @@ int ath6kl_bmi_reg_read(struct ath6kl *ar, u32 addr, u32 *param) | |||
493 | memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr)); | 334 | memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr)); |
494 | offset += sizeof(addr); | 335 | offset += sizeof(addr); |
495 | 336 | ||
496 | ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset); | 337 | ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset); |
497 | if (ret) { | 338 | if (ret) { |
498 | ath6kl_err("Unable to write to the device: %d\n", ret); | 339 | ath6kl_err("Unable to write to the device: %d\n", ret); |
499 | return ret; | 340 | return ret; |
500 | } | 341 | } |
501 | 342 | ||
502 | ret = ath6kl_bmi_recv_buf(ar, ar->bmi.cmd_buf, sizeof(*param)); | 343 | ret = ath6kl_hif_bmi_read(ar, ar->bmi.cmd_buf, sizeof(*param)); |
503 | if (ret) { | 344 | if (ret) { |
504 | ath6kl_err("Unable to read from the device: %d\n", ret); | 345 | ath6kl_err("Unable to read from the device: %d\n", ret); |
505 | return ret; | 346 | return ret; |
@@ -540,7 +381,7 @@ int ath6kl_bmi_reg_write(struct ath6kl *ar, u32 addr, u32 param) | |||
540 | memcpy(&(ar->bmi.cmd_buf[offset]), ¶m, sizeof(param)); | 381 | memcpy(&(ar->bmi.cmd_buf[offset]), ¶m, sizeof(param)); |
541 | offset += sizeof(param); | 382 | offset += sizeof(param); |
542 | 383 | ||
543 | ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset); | 384 | ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset); |
544 | if (ret) { | 385 | if (ret) { |
545 | ath6kl_err("Unable to write to the device: %d\n", ret); | 386 | ath6kl_err("Unable to write to the device: %d\n", ret); |
546 | return ret; | 387 | return ret; |
@@ -587,7 +428,7 @@ int ath6kl_bmi_lz_data(struct ath6kl *ar, u8 *buf, u32 len) | |||
587 | tx_len); | 428 | tx_len); |
588 | offset += tx_len; | 429 | offset += tx_len; |
589 | 430 | ||
590 | ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset); | 431 | ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset); |
591 | if (ret) { | 432 | if (ret) { |
592 | ath6kl_err("Unable to write to the device: %d\n", | 433 | ath6kl_err("Unable to write to the device: %d\n", |
593 | ret); | 434 | ret); |
@@ -629,7 +470,7 @@ int ath6kl_bmi_lz_stream_start(struct ath6kl *ar, u32 addr) | |||
629 | memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr)); | 470 | memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr)); |
630 | offset += sizeof(addr); | 471 | offset += sizeof(addr); |
631 | 472 | ||
632 | ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset); | 473 | ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset); |
633 | if (ret) { | 474 | if (ret) { |
634 | ath6kl_err("Unable to start LZ stream to the device: %d\n", | 475 | ath6kl_err("Unable to start LZ stream to the device: %d\n", |
635 | ret); | 476 | ret); |
diff --git a/drivers/net/wireless/ath/ath6kl/hif-ops.h b/drivers/net/wireless/ath/ath6kl/hif-ops.h index eed22870448b..0c4c602464b7 100644 --- a/drivers/net/wireless/ath/ath6kl/hif-ops.h +++ b/drivers/net/wireless/ath/ath6kl/hif-ops.h | |||
@@ -91,6 +91,16 @@ static inline int ath6kl_hif_suspend(struct ath6kl *ar, | |||
91 | return ar->hif_ops->suspend(ar, wow); | 91 | return ar->hif_ops->suspend(ar, wow); |
92 | } | 92 | } |
93 | 93 | ||
94 | static inline int ath6kl_hif_bmi_read(struct ath6kl *ar, u8 *buf, u32 len) | ||
95 | { | ||
96 | return ar->hif_ops->bmi_read(ar, buf, len); | ||
97 | } | ||
98 | |||
99 | static inline int ath6kl_hif_bmi_write(struct ath6kl *ar, u8 *buf, u32 len) | ||
100 | { | ||
101 | return ar->hif_ops->bmi_write(ar, buf, len); | ||
102 | } | ||
103 | |||
94 | static inline int ath6kl_hif_resume(struct ath6kl *ar) | 104 | static inline int ath6kl_hif_resume(struct ath6kl *ar) |
95 | { | 105 | { |
96 | ath6kl_dbg(ATH6KL_DBG_HIF, "hif resume\n"); | 106 | ath6kl_dbg(ATH6KL_DBG_HIF, "hif resume\n"); |
diff --git a/drivers/net/wireless/ath/ath6kl/hif.h b/drivers/net/wireless/ath/ath6kl/hif.h index f2dc3bcdae4a..42004e9069b6 100644 --- a/drivers/net/wireless/ath/ath6kl/hif.h +++ b/drivers/net/wireless/ath/ath6kl/hif.h | |||
@@ -244,6 +244,8 @@ struct ath6kl_hif_ops { | |||
244 | void (*cleanup_scatter)(struct ath6kl *ar); | 244 | void (*cleanup_scatter)(struct ath6kl *ar); |
245 | int (*suspend)(struct ath6kl *ar, struct cfg80211_wowlan *wow); | 245 | int (*suspend)(struct ath6kl *ar, struct cfg80211_wowlan *wow); |
246 | int (*resume)(struct ath6kl *ar); | 246 | int (*resume)(struct ath6kl *ar); |
247 | int (*bmi_read)(struct ath6kl *ar, u8 *buf, u32 len); | ||
248 | int (*bmi_write)(struct ath6kl *ar, u8 *buf, u32 len); | ||
247 | int (*power_on)(struct ath6kl *ar); | 249 | int (*power_on)(struct ath6kl *ar); |
248 | int (*power_off)(struct ath6kl *ar); | 250 | int (*power_off)(struct ath6kl *ar); |
249 | void (*stop)(struct ath6kl *ar); | 251 | void (*stop)(struct ath6kl *ar); |
diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c index beb5f9bf26af..080be036a27e 100644 --- a/drivers/net/wireless/ath/ath6kl/sdio.c +++ b/drivers/net/wireless/ath/ath6kl/sdio.c | |||
@@ -845,6 +845,166 @@ static int ath6kl_sdio_resume(struct ath6kl *ar) | |||
845 | return 0; | 845 | return 0; |
846 | } | 846 | } |
847 | 847 | ||
848 | static int ath6kl_sdio_bmi_credits(struct ath6kl *ar) | ||
849 | { | ||
850 | u32 addr; | ||
851 | unsigned long timeout; | ||
852 | int ret; | ||
853 | |||
854 | ar->bmi.cmd_credits = 0; | ||
855 | |||
856 | /* Read the counter register to get the command credits */ | ||
857 | addr = COUNT_DEC_ADDRESS + (HTC_MAILBOX_NUM_MAX + ENDPOINT1) * 4; | ||
858 | |||
859 | timeout = jiffies + msecs_to_jiffies(BMI_COMMUNICATION_TIMEOUT); | ||
860 | while (time_before(jiffies, timeout) && !ar->bmi.cmd_credits) { | ||
861 | |||
862 | /* | ||
863 | * Hit the credit counter with a 4-byte access, the first byte | ||
864 | * read will hit the counter and cause a decrement, while the | ||
865 | * remaining 3 bytes has no effect. The rationale behind this | ||
866 | * is to make all HIF accesses 4-byte aligned. | ||
867 | */ | ||
868 | ret = ath6kl_sdio_read_write_sync(ar, addr, | ||
869 | (u8 *)&ar->bmi.cmd_credits, 4, | ||
870 | HIF_RD_SYNC_BYTE_INC); | ||
871 | if (ret) { | ||
872 | ath6kl_err("Unable to decrement the command credit " | ||
873 | "count register: %d\n", ret); | ||
874 | return ret; | ||
875 | } | ||
876 | |||
877 | /* The counter is only 8 bits. | ||
878 | * Ignore anything in the upper 3 bytes | ||
879 | */ | ||
880 | ar->bmi.cmd_credits &= 0xFF; | ||
881 | } | ||
882 | |||
883 | if (!ar->bmi.cmd_credits) { | ||
884 | ath6kl_err("bmi communication timeout\n"); | ||
885 | return -ETIMEDOUT; | ||
886 | } | ||
887 | |||
888 | return 0; | ||
889 | } | ||
890 | |||
891 | static int ath6kl_bmi_get_rx_lkahd(struct ath6kl *ar) | ||
892 | { | ||
893 | unsigned long timeout; | ||
894 | u32 rx_word = 0; | ||
895 | int ret = 0; | ||
896 | |||
897 | timeout = jiffies + msecs_to_jiffies(BMI_COMMUNICATION_TIMEOUT); | ||
898 | while ((time_before(jiffies, timeout)) && !rx_word) { | ||
899 | ret = ath6kl_sdio_read_write_sync(ar, | ||
900 | RX_LOOKAHEAD_VALID_ADDRESS, | ||
901 | (u8 *)&rx_word, sizeof(rx_word), | ||
902 | HIF_RD_SYNC_BYTE_INC); | ||
903 | if (ret) { | ||
904 | ath6kl_err("unable to read RX_LOOKAHEAD_VALID\n"); | ||
905 | return ret; | ||
906 | } | ||
907 | |||
908 | /* all we really want is one bit */ | ||
909 | rx_word &= (1 << ENDPOINT1); | ||
910 | } | ||
911 | |||
912 | if (!rx_word) { | ||
913 | ath6kl_err("bmi_recv_buf FIFO empty\n"); | ||
914 | return -EINVAL; | ||
915 | } | ||
916 | |||
917 | return ret; | ||
918 | } | ||
919 | |||
920 | static int ath6kl_sdio_bmi_write(struct ath6kl *ar, u8 *buf, u32 len) | ||
921 | { | ||
922 | int ret; | ||
923 | u32 addr; | ||
924 | |||
925 | ret = ath6kl_sdio_bmi_credits(ar); | ||
926 | if (ret) | ||
927 | return ret; | ||
928 | |||
929 | addr = ar->mbox_info.htc_addr; | ||
930 | |||
931 | ret = ath6kl_sdio_read_write_sync(ar, addr, buf, len, | ||
932 | HIF_WR_SYNC_BYTE_INC); | ||
933 | if (ret) | ||
934 | ath6kl_err("unable to send the bmi data to the device\n"); | ||
935 | |||
936 | return ret; | ||
937 | } | ||
938 | |||
939 | static int ath6kl_sdio_bmi_read(struct ath6kl *ar, u8 *buf, u32 len) | ||
940 | { | ||
941 | int ret; | ||
942 | u32 addr; | ||
943 | |||
944 | /* | ||
945 | * During normal bootup, small reads may be required. | ||
946 | * Rather than issue an HIF Read and then wait as the Target | ||
947 | * adds successive bytes to the FIFO, we wait here until | ||
948 | * we know that response data is available. | ||
949 | * | ||
950 | * This allows us to cleanly timeout on an unexpected | ||
951 | * Target failure rather than risk problems at the HIF level. | ||
952 | * In particular, this avoids SDIO timeouts and possibly garbage | ||
953 | * data on some host controllers. And on an interconnect | ||
954 | * such as Compact Flash (as well as some SDIO masters) which | ||
955 | * does not provide any indication on data timeout, it avoids | ||
956 | * a potential hang or garbage response. | ||
957 | * | ||
958 | * Synchronization is more difficult for reads larger than the | ||
959 | * size of the MBOX FIFO (128B), because the Target is unable | ||
960 | * to push the 129th byte of data until AFTER the Host posts an | ||
961 | * HIF Read and removes some FIFO data. So for large reads the | ||
962 | * Host proceeds to post an HIF Read BEFORE all the data is | ||
963 | * actually available to read. Fortunately, large BMI reads do | ||
964 | * not occur in practice -- they're supported for debug/development. | ||
965 | * | ||
966 | * So Host/Target BMI synchronization is divided into these cases: | ||
967 | * CASE 1: length < 4 | ||
968 | * Should not happen | ||
969 | * | ||
970 | * CASE 2: 4 <= length <= 128 | ||
971 | * Wait for first 4 bytes to be in FIFO | ||
972 | * If CONSERVATIVE_BMI_READ is enabled, also wait for | ||
973 | * a BMI command credit, which indicates that the ENTIRE | ||
974 | * response is available in the the FIFO | ||
975 | * | ||
976 | * CASE 3: length > 128 | ||
977 | * Wait for the first 4 bytes to be in FIFO | ||
978 | * | ||
979 | * For most uses, a small timeout should be sufficient and we will | ||
980 | * usually see a response quickly; but there may be some unusual | ||
981 | * (debug) cases of BMI_EXECUTE where we want an larger timeout. | ||
982 | * For now, we use an unbounded busy loop while waiting for | ||
983 | * BMI_EXECUTE. | ||
984 | * | ||
985 | * If BMI_EXECUTE ever needs to support longer-latency execution, | ||
986 | * especially in production, this code needs to be enhanced to sleep | ||
987 | * and yield. Also note that BMI_COMMUNICATION_TIMEOUT is currently | ||
988 | * a function of Host processor speed. | ||
989 | */ | ||
990 | if (len >= 4) { /* NB: Currently, always true */ | ||
991 | ret = ath6kl_bmi_get_rx_lkahd(ar); | ||
992 | if (ret) | ||
993 | return ret; | ||
994 | } | ||
995 | |||
996 | addr = ar->mbox_info.htc_addr; | ||
997 | ret = ath6kl_sdio_read_write_sync(ar, addr, buf, len, | ||
998 | HIF_RD_SYNC_BYTE_INC); | ||
999 | if (ret) { | ||
1000 | ath6kl_err("Unable to read the bmi data from the device: %d\n", | ||
1001 | ret); | ||
1002 | return ret; | ||
1003 | } | ||
1004 | |||
1005 | return 0; | ||
1006 | } | ||
1007 | |||
848 | static void ath6kl_sdio_stop(struct ath6kl *ar) | 1008 | static void ath6kl_sdio_stop(struct ath6kl *ar) |
849 | { | 1009 | { |
850 | struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); | 1010 | struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); |
@@ -889,6 +1049,8 @@ static const struct ath6kl_hif_ops ath6kl_sdio_ops = { | |||
889 | .cleanup_scatter = ath6kl_sdio_cleanup_scatter, | 1049 | .cleanup_scatter = ath6kl_sdio_cleanup_scatter, |
890 | .suspend = ath6kl_sdio_suspend, | 1050 | .suspend = ath6kl_sdio_suspend, |
891 | .resume = ath6kl_sdio_resume, | 1051 | .resume = ath6kl_sdio_resume, |
1052 | .bmi_read = ath6kl_sdio_bmi_read, | ||
1053 | .bmi_write = ath6kl_sdio_bmi_write, | ||
892 | .power_on = ath6kl_sdio_power_on, | 1054 | .power_on = ath6kl_sdio_power_on, |
893 | .power_off = ath6kl_sdio_power_off, | 1055 | .power_off = ath6kl_sdio_power_off, |
894 | .stop = ath6kl_sdio_stop, | 1056 | .stop = ath6kl_sdio_stop, |