ath10k: rename hif callback
[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 int ath10k_bmi_done(struct ath10k *ar)
24 {
25         struct bmi_cmd cmd;
26         u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.done);
27         int ret;
28
29         if (ar->bmi.done_sent) {
30                 ath10k_dbg(ATH10K_DBG_CORE, "%s skipped\n", __func__);
31                 return 0;
32         }
33
34         ar->bmi.done_sent = true;
35         cmd.id = __cpu_to_le32(BMI_DONE);
36
37         ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL);
38         if (ret) {
39                 ath10k_warn("unable to write to the device: %d\n", ret);
40                 return ret;
41         }
42
43         ath10k_dbg(ATH10K_DBG_CORE, "BMI done\n");
44         return 0;
45 }
46
47 int ath10k_bmi_get_target_info(struct ath10k *ar,
48                                struct bmi_target_info *target_info)
49 {
50         struct bmi_cmd cmd;
51         union bmi_resp resp;
52         u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.get_target_info);
53         u32 resplen = sizeof(resp.get_target_info);
54         int ret;
55
56         if (ar->bmi.done_sent) {
57                 ath10k_warn("BMI Get Target Info Command disallowed\n");
58                 return -EBUSY;
59         }
60
61         cmd.id = __cpu_to_le32(BMI_GET_TARGET_INFO);
62
63         ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &resplen);
64         if (ret) {
65                 ath10k_warn("unable to get target info from device\n");
66                 return ret;
67         }
68
69         if (resplen < sizeof(resp.get_target_info)) {
70                 ath10k_warn("invalid get_target_info response length (%d)\n",
71                             resplen);
72                 return -EIO;
73         }
74
75         target_info->version = __le32_to_cpu(resp.get_target_info.version);
76         target_info->type    = __le32_to_cpu(resp.get_target_info.type);
77         return 0;
78 }
79
80 int ath10k_bmi_read_memory(struct ath10k *ar,
81                            u32 address, void *buffer, u32 length)
82 {
83         struct bmi_cmd cmd;
84         union bmi_resp resp;
85         u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.read_mem);
86         u32 rxlen;
87         int ret;
88
89         if (ar->bmi.done_sent) {
90                 ath10k_warn("command disallowed\n");
91                 return -EBUSY;
92         }
93
94         ath10k_dbg(ATH10K_DBG_CORE,
95                    "%s: (device: 0x%p, address: 0x%x, length: %d)\n",
96                    __func__, ar, address, length);
97
98         while (length) {
99                 rxlen = min_t(u32, length, BMI_MAX_DATA_SIZE);
100
101                 cmd.id            = __cpu_to_le32(BMI_READ_MEMORY);
102                 cmd.read_mem.addr = __cpu_to_le32(address);
103                 cmd.read_mem.len  = __cpu_to_le32(rxlen);
104
105                 ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen,
106                                                   &resp, &rxlen);
107                 if (ret) {
108                         ath10k_warn("unable to read from the device (%d)\n",
109                                     ret);
110                         return ret;
111                 }
112
113                 memcpy(buffer, resp.read_mem.payload, rxlen);
114                 address += rxlen;
115                 buffer  += rxlen;
116                 length  -= rxlen;
117         }
118
119         return 0;
120 }
121
122 int ath10k_bmi_write_memory(struct ath10k *ar,
123                             u32 address, const void *buffer, u32 length)
124 {
125         struct bmi_cmd cmd;
126         u32 hdrlen = sizeof(cmd.id) + sizeof(cmd.write_mem);
127         u32 txlen;
128         int ret;
129
130         if (ar->bmi.done_sent) {
131                 ath10k_warn("command disallowed\n");
132                 return -EBUSY;
133         }
134
135         ath10k_dbg(ATH10K_DBG_CORE,
136                    "%s: (device: 0x%p, address: 0x%x, length: %d)\n",
137                    __func__, ar, address, length);
138
139         while (length) {
140                 txlen = min(length, BMI_MAX_DATA_SIZE - hdrlen);
141
142                 /* copy before roundup to avoid reading beyond buffer*/
143                 memcpy(cmd.write_mem.payload, buffer, txlen);
144                 txlen = roundup(txlen, 4);
145
146                 cmd.id             = __cpu_to_le32(BMI_WRITE_MEMORY);
147                 cmd.write_mem.addr = __cpu_to_le32(address);
148                 cmd.write_mem.len  = __cpu_to_le32(txlen);
149
150                 ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, hdrlen + txlen,
151                                                   NULL, NULL);
152                 if (ret) {
153                         ath10k_warn("unable to write to the device (%d)\n",
154                                     ret);
155                         return ret;
156                 }
157
158                 /* fixup roundup() so `length` zeroes out for last chunk */
159                 txlen = min(txlen, length);
160
161                 address += txlen;
162                 buffer  += txlen;
163                 length  -= txlen;
164         }
165
166         return 0;
167 }
168
169 int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 *param)
170 {
171         struct bmi_cmd cmd;
172         union bmi_resp resp;
173         u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.execute);
174         u32 resplen = sizeof(resp.execute);
175         int ret;
176
177         if (ar->bmi.done_sent) {
178                 ath10k_warn("command disallowed\n");
179                 return -EBUSY;
180         }
181
182         ath10k_dbg(ATH10K_DBG_CORE,
183                    "%s: (device: 0x%p, address: 0x%x, param: %d)\n",
184                    __func__, ar, address, *param);
185
186         cmd.id            = __cpu_to_le32(BMI_EXECUTE);
187         cmd.execute.addr  = __cpu_to_le32(address);
188         cmd.execute.param = __cpu_to_le32(*param);
189
190         ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &resplen);
191         if (ret) {
192                 ath10k_warn("unable to read from the device\n");
193                 return ret;
194         }
195
196         if (resplen < sizeof(resp.execute)) {
197                 ath10k_warn("invalid execute response length (%d)\n",
198                             resplen);
199                 return ret;
200         }
201
202         *param = __le32_to_cpu(resp.execute.result);
203         return 0;
204 }
205
206 int ath10k_bmi_lz_data(struct ath10k *ar, const void *buffer, u32 length)
207 {
208         struct bmi_cmd cmd;
209         u32 hdrlen = sizeof(cmd.id) + sizeof(cmd.lz_data);
210         u32 txlen;
211         int ret;
212
213         if (ar->bmi.done_sent) {
214                 ath10k_warn("command disallowed\n");
215                 return -EBUSY;
216         }
217
218         while (length) {
219                 txlen = min(length, BMI_MAX_DATA_SIZE - hdrlen);
220
221                 WARN_ON_ONCE(txlen & 3);
222
223                 cmd.id          = __cpu_to_le32(BMI_LZ_DATA);
224                 cmd.lz_data.len = __cpu_to_le32(txlen);
225                 memcpy(cmd.lz_data.payload, buffer, txlen);
226
227                 ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, hdrlen + txlen,
228                                                   NULL, NULL);
229                 if (ret) {
230                         ath10k_warn("unable to write to the device\n");
231                         return ret;
232                 }
233
234                 buffer += txlen;
235                 length -= txlen;
236         }
237
238         return 0;
239 }
240
241 int ath10k_bmi_lz_stream_start(struct ath10k *ar, u32 address)
242 {
243         struct bmi_cmd cmd;
244         u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.lz_start);
245         int ret;
246
247         if (ar->bmi.done_sent) {
248                 ath10k_warn("command disallowed\n");
249                 return -EBUSY;
250         }
251
252         cmd.id            = __cpu_to_le32(BMI_LZ_STREAM_START);
253         cmd.lz_start.addr = __cpu_to_le32(address);
254
255         ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL);
256         if (ret) {
257                 ath10k_warn("unable to Start LZ Stream to the device\n");
258                 return ret;
259         }
260
261         return 0;
262 }
263
264 int ath10k_bmi_fast_download(struct ath10k *ar,
265                              u32 address, const void *buffer, u32 length)
266 {
267         u8 trailer[4] = {};
268         u32 head_len = rounddown(length, 4);
269         u32 trailer_len = length - head_len;
270         int ret;
271
272         ret = ath10k_bmi_lz_stream_start(ar, address);
273         if (ret)
274                 return ret;
275
276         /* copy the last word into a zero padded buffer */
277         if (trailer_len > 0)
278                 memcpy(trailer, buffer + head_len, trailer_len);
279
280         ret = ath10k_bmi_lz_data(ar, buffer, head_len);
281         if (ret)
282                 return ret;
283
284         if (trailer_len > 0)
285                 ret = ath10k_bmi_lz_data(ar, trailer, 4);
286
287         if (ret != 0)
288                 return ret;
289
290         /*
291          * Close compressed stream and open a new (fake) one.
292          * This serves mainly to flush Target caches.
293          */
294         ret = ath10k_bmi_lz_stream_start(ar, 0x00);
295
296         return ret;
297 }