ath10k: add BMI log level
[cascardo/linux.git] / drivers / net / wireless / ath / ath10k / bmi.c
1 /*
2  * Copyright (c) 2005-2011 Atheros Communications Inc.
3  * Copyright (c) 2011-2013 Qualcomm Atheros, Inc.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 #include "bmi.h"
19 #include "hif.h"
20 #include "debug.h"
21 #include "htc.h"
22
23 void ath10k_bmi_start(struct ath10k *ar)
24 {
25         ath10k_dbg(ATH10K_DBG_BMI, "bmi start\n");
26
27         ar->bmi.done_sent = false;
28 }
29
30 int ath10k_bmi_done(struct ath10k *ar)
31 {
32         struct bmi_cmd cmd;
33         u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.done);
34         int ret;
35
36         ath10k_dbg(ATH10K_DBG_BMI, "bmi done\n");
37
38         if (ar->bmi.done_sent) {
39                 ath10k_dbg(ATH10K_DBG_BMI, "bmi skipped\n");
40                 return 0;
41         }
42
43         ar->bmi.done_sent = true;
44         cmd.id = __cpu_to_le32(BMI_DONE);
45
46         ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL);
47         if (ret) {
48                 ath10k_warn("unable to write to the device: %d\n", ret);
49                 return ret;
50         }
51
52         return 0;
53 }
54
55 int ath10k_bmi_get_target_info(struct ath10k *ar,
56                                struct bmi_target_info *target_info)
57 {
58         struct bmi_cmd cmd;
59         union bmi_resp resp;
60         u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.get_target_info);
61         u32 resplen = sizeof(resp.get_target_info);
62         int ret;
63
64         ath10k_dbg(ATH10K_DBG_BMI, "bmi get target info\n");
65
66         if (ar->bmi.done_sent) {
67                 ath10k_warn("BMI Get Target Info Command disallowed\n");
68                 return -EBUSY;
69         }
70
71         cmd.id = __cpu_to_le32(BMI_GET_TARGET_INFO);
72
73         ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &resplen);
74         if (ret) {
75                 ath10k_warn("unable to get target info from device\n");
76                 return ret;
77         }
78
79         if (resplen < sizeof(resp.get_target_info)) {
80                 ath10k_warn("invalid get_target_info response length (%d)\n",
81                             resplen);
82                 return -EIO;
83         }
84
85         target_info->version = __le32_to_cpu(resp.get_target_info.version);
86         target_info->type    = __le32_to_cpu(resp.get_target_info.type);
87
88         return 0;
89 }
90
91 int ath10k_bmi_read_memory(struct ath10k *ar,
92                            u32 address, void *buffer, u32 length)
93 {
94         struct bmi_cmd cmd;
95         union bmi_resp resp;
96         u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.read_mem);
97         u32 rxlen;
98         int ret;
99
100         ath10k_dbg(ATH10K_DBG_BMI, "bmi read address 0x%x length %d\n",
101                    address, length);
102
103         if (ar->bmi.done_sent) {
104                 ath10k_warn("command disallowed\n");
105                 return -EBUSY;
106         }
107
108         while (length) {
109                 rxlen = min_t(u32, length, BMI_MAX_DATA_SIZE);
110
111                 cmd.id            = __cpu_to_le32(BMI_READ_MEMORY);
112                 cmd.read_mem.addr = __cpu_to_le32(address);
113                 cmd.read_mem.len  = __cpu_to_le32(rxlen);
114
115                 ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen,
116                                                   &resp, &rxlen);
117                 if (ret) {
118                         ath10k_warn("unable to read from the device (%d)\n",
119                                     ret);
120                         return ret;
121                 }
122
123                 memcpy(buffer, resp.read_mem.payload, rxlen);
124                 address += rxlen;
125                 buffer  += rxlen;
126                 length  -= rxlen;
127         }
128
129         return 0;
130 }
131
132 int ath10k_bmi_write_memory(struct ath10k *ar,
133                             u32 address, const void *buffer, u32 length)
134 {
135         struct bmi_cmd cmd;
136         u32 hdrlen = sizeof(cmd.id) + sizeof(cmd.write_mem);
137         u32 txlen;
138         int ret;
139
140         ath10k_dbg(ATH10K_DBG_BMI, "bmi write address 0x%x length %d\n",
141                    address, length);
142
143         if (ar->bmi.done_sent) {
144                 ath10k_warn("command disallowed\n");
145                 return -EBUSY;
146         }
147
148         while (length) {
149                 txlen = min(length, BMI_MAX_DATA_SIZE - hdrlen);
150
151                 /* copy before roundup to avoid reading beyond buffer*/
152                 memcpy(cmd.write_mem.payload, buffer, txlen);
153                 txlen = roundup(txlen, 4);
154
155                 cmd.id             = __cpu_to_le32(BMI_WRITE_MEMORY);
156                 cmd.write_mem.addr = __cpu_to_le32(address);
157                 cmd.write_mem.len  = __cpu_to_le32(txlen);
158
159                 ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, hdrlen + txlen,
160                                                   NULL, NULL);
161                 if (ret) {
162                         ath10k_warn("unable to write to the device (%d)\n",
163                                     ret);
164                         return ret;
165                 }
166
167                 /* fixup roundup() so `length` zeroes out for last chunk */
168                 txlen = min(txlen, length);
169
170                 address += txlen;
171                 buffer  += txlen;
172                 length  -= txlen;
173         }
174
175         return 0;
176 }
177
178 int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 *param)
179 {
180         struct bmi_cmd cmd;
181         union bmi_resp resp;
182         u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.execute);
183         u32 resplen = sizeof(resp.execute);
184         int ret;
185
186         ath10k_dbg(ATH10K_DBG_BMI, "bmi execute address 0x%x param 0x%x\n",
187                    address, *param);
188
189         if (ar->bmi.done_sent) {
190                 ath10k_warn("command disallowed\n");
191                 return -EBUSY;
192         }
193
194         cmd.id            = __cpu_to_le32(BMI_EXECUTE);
195         cmd.execute.addr  = __cpu_to_le32(address);
196         cmd.execute.param = __cpu_to_le32(*param);
197
198         ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &resplen);
199         if (ret) {
200                 ath10k_warn("unable to read from the device\n");
201                 return ret;
202         }
203
204         if (resplen < sizeof(resp.execute)) {
205                 ath10k_warn("invalid execute response length (%d)\n",
206                             resplen);
207                 return ret;
208         }
209
210         *param = __le32_to_cpu(resp.execute.result);
211         return 0;
212 }
213
214 int ath10k_bmi_lz_data(struct ath10k *ar, const void *buffer, u32 length)
215 {
216         struct bmi_cmd cmd;
217         u32 hdrlen = sizeof(cmd.id) + sizeof(cmd.lz_data);
218         u32 txlen;
219         int ret;
220
221         ath10k_dbg(ATH10K_DBG_BMI, "bmi lz data buffer 0x%p length %d\n",
222                    buffer, length);
223
224         if (ar->bmi.done_sent) {
225                 ath10k_warn("command disallowed\n");
226                 return -EBUSY;
227         }
228
229         while (length) {
230                 txlen = min(length, BMI_MAX_DATA_SIZE - hdrlen);
231
232                 WARN_ON_ONCE(txlen & 3);
233
234                 cmd.id          = __cpu_to_le32(BMI_LZ_DATA);
235                 cmd.lz_data.len = __cpu_to_le32(txlen);
236                 memcpy(cmd.lz_data.payload, buffer, txlen);
237
238                 ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, hdrlen + txlen,
239                                                   NULL, NULL);
240                 if (ret) {
241                         ath10k_warn("unable to write to the device\n");
242                         return ret;
243                 }
244
245                 buffer += txlen;
246                 length -= txlen;
247         }
248
249         return 0;
250 }
251
252 int ath10k_bmi_lz_stream_start(struct ath10k *ar, u32 address)
253 {
254         struct bmi_cmd cmd;
255         u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.lz_start);
256         int ret;
257
258         ath10k_dbg(ATH10K_DBG_BMI, "bmi lz stream start address 0x%x\n",
259                    address);
260
261         if (ar->bmi.done_sent) {
262                 ath10k_warn("command disallowed\n");
263                 return -EBUSY;
264         }
265
266         cmd.id            = __cpu_to_le32(BMI_LZ_STREAM_START);
267         cmd.lz_start.addr = __cpu_to_le32(address);
268
269         ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL);
270         if (ret) {
271                 ath10k_warn("unable to Start LZ Stream to the device\n");
272                 return ret;
273         }
274
275         return 0;
276 }
277
278 int ath10k_bmi_fast_download(struct ath10k *ar,
279                              u32 address, const void *buffer, u32 length)
280 {
281         u8 trailer[4] = {};
282         u32 head_len = rounddown(length, 4);
283         u32 trailer_len = length - head_len;
284         int ret;
285
286         ath10k_dbg(ATH10K_DBG_BMI,
287                    "bmi fast download address 0x%x buffer 0x%p length %d\n",
288                    address, buffer, length);
289
290         ret = ath10k_bmi_lz_stream_start(ar, address);
291         if (ret)
292                 return ret;
293
294         /* copy the last word into a zero padded buffer */
295         if (trailer_len > 0)
296                 memcpy(trailer, buffer + head_len, trailer_len);
297
298         ret = ath10k_bmi_lz_data(ar, buffer, head_len);
299         if (ret)
300                 return ret;
301
302         if (trailer_len > 0)
303                 ret = ath10k_bmi_lz_data(ar, trailer, 4);
304
305         if (ret != 0)
306                 return ret;
307
308         /*
309          * Close compressed stream and open a new (fake) one.
310          * This serves mainly to flush Target caches.
311          */
312         ret = ath10k_bmi_lz_stream_start(ar, 0x00);
313
314         return ret;
315 }