spi-topcliff-pch: add recovery processing in case wait-event timeout
[zen-stable.git] / drivers / misc / iwmc3200top / log.c
bloba36a55a49cac7855eaaa597acab0d0c380ed1e41
1 /*
2 * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
3 * drivers/misc/iwmc3200top/log.c
5 * Copyright (C) 2009 Intel Corporation. All rights reserved.
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License version
9 * 2 as published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 * 02110-1301, USA.
22 * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
23 * -
27 #include <linux/kernel.h>
28 #include <linux/mmc/sdio_func.h>
29 #include <linux/slab.h>
30 #include <linux/ctype.h>
31 #include "fw-msg.h"
32 #include "iwmc3200top.h"
33 #include "log.h"
35 /* Maximal hexadecimal string size of the FW memdump message */
36 #define LOG_MSG_SIZE_MAX 12400
38 /* iwmct_logdefs is a global used by log macros */
39 u8 iwmct_logdefs[LOG_SRC_MAX];
40 static u8 iwmct_fw_logdefs[FW_LOG_SRC_MAX];
43 static int _log_set_log_filter(u8 *logdefs, int size, u8 src, u8 logmask)
45 int i;
47 if (src < size)
48 logdefs[src] = logmask;
49 else if (src == LOG_SRC_ALL)
50 for (i = 0; i < size; i++)
51 logdefs[i] = logmask;
52 else
53 return -1;
55 return 0;
59 int iwmct_log_set_filter(u8 src, u8 logmask)
61 return _log_set_log_filter(iwmct_logdefs, LOG_SRC_MAX, src, logmask);
65 int iwmct_log_set_fw_filter(u8 src, u8 logmask)
67 return _log_set_log_filter(iwmct_fw_logdefs,
68 FW_LOG_SRC_MAX, src, logmask);
72 static int log_msg_format_hex(char *str, int slen, u8 *ibuf,
73 int ilen, char *pref)
75 int pos = 0;
76 int i;
77 int len;
79 for (pos = 0, i = 0; pos < slen - 2 && pref[i] != '\0'; i++, pos++)
80 str[pos] = pref[i];
82 for (i = 0; pos < slen - 2 && i < ilen; pos += len, i++)
83 len = snprintf(&str[pos], slen - pos - 1, " %2.2X", ibuf[i]);
85 if (i < ilen)
86 return -1;
88 return 0;
91 /* NOTE: This function is not thread safe.
92 Currently it's called only from sdio rx worker - no race there
94 void iwmct_log_top_message(struct iwmct_priv *priv, u8 *buf, int len)
96 struct top_msg *msg;
97 static char logbuf[LOG_MSG_SIZE_MAX];
99 msg = (struct top_msg *)buf;
101 if (len < sizeof(msg->hdr) + sizeof(msg->u.log.log_hdr)) {
102 LOG_ERROR(priv, FW_MSG, "Log message from TOP "
103 "is too short %d (expected %zd)\n",
104 len, sizeof(msg->hdr) + sizeof(msg->u.log.log_hdr));
105 return;
108 if (!(iwmct_fw_logdefs[msg->u.log.log_hdr.logsource] &
109 BIT(msg->u.log.log_hdr.severity)) ||
110 !(iwmct_logdefs[LOG_SRC_FW_MSG] & BIT(msg->u.log.log_hdr.severity)))
111 return;
113 switch (msg->hdr.category) {
114 case COMM_CATEGORY_TESTABILITY:
115 if (!(iwmct_logdefs[LOG_SRC_TST] &
116 BIT(msg->u.log.log_hdr.severity)))
117 return;
118 if (log_msg_format_hex(logbuf, LOG_MSG_SIZE_MAX, buf,
119 le16_to_cpu(msg->hdr.length) +
120 sizeof(msg->hdr), "<TST>"))
121 LOG_WARNING(priv, TST,
122 "TOP TST message is too long, truncating...");
123 LOG_WARNING(priv, TST, "%s\n", logbuf);
124 break;
125 case COMM_CATEGORY_DEBUG:
126 if (msg->hdr.opcode == OP_DBG_ZSTR_MSG)
127 LOG_INFO(priv, FW_MSG, "%s %s", "<DBG>",
128 ((u8 *)msg) + sizeof(msg->hdr)
129 + sizeof(msg->u.log.log_hdr));
130 else {
131 if (log_msg_format_hex(logbuf, LOG_MSG_SIZE_MAX, buf,
132 le16_to_cpu(msg->hdr.length)
133 + sizeof(msg->hdr),
134 "<DBG>"))
135 LOG_WARNING(priv, FW_MSG,
136 "TOP DBG message is too long,"
137 "truncating...");
138 LOG_WARNING(priv, FW_MSG, "%s\n", logbuf);
140 break;
141 default:
142 break;
146 static int _log_get_filter_str(u8 *logdefs, int logdefsz, char *buf, int size)
148 int i, pos, len;
149 for (i = 0, pos = 0; (pos < size-1) && (i < logdefsz); i++) {
150 len = snprintf(&buf[pos], size - pos - 1, "0x%02X%02X,",
151 i, logdefs[i]);
152 pos += len;
154 buf[pos-1] = '\n';
155 buf[pos] = '\0';
157 if (i < logdefsz)
158 return -1;
159 return 0;
162 int log_get_filter_str(char *buf, int size)
164 return _log_get_filter_str(iwmct_logdefs, LOG_SRC_MAX, buf, size);
167 int log_get_fw_filter_str(char *buf, int size)
169 return _log_get_filter_str(iwmct_fw_logdefs, FW_LOG_SRC_MAX, buf, size);
172 #define HEXADECIMAL_RADIX 16
173 #define LOG_SRC_FORMAT 7 /* log level is in format of "0xXXXX," */
175 ssize_t show_iwmct_log_level(struct device *d,
176 struct device_attribute *attr, char *buf)
178 struct iwmct_priv *priv = dev_get_drvdata(d);
179 char *str_buf;
180 int buf_size;
181 ssize_t ret;
183 buf_size = (LOG_SRC_FORMAT * LOG_SRC_MAX) + 1;
184 str_buf = kzalloc(buf_size, GFP_KERNEL);
185 if (!str_buf) {
186 LOG_ERROR(priv, DEBUGFS,
187 "failed to allocate %d bytes\n", buf_size);
188 ret = -ENOMEM;
189 goto exit;
192 if (log_get_filter_str(str_buf, buf_size) < 0) {
193 ret = -EINVAL;
194 goto exit;
197 ret = sprintf(buf, "%s", str_buf);
199 exit:
200 kfree(str_buf);
201 return ret;
204 ssize_t store_iwmct_log_level(struct device *d,
205 struct device_attribute *attr,
206 const char *buf, size_t count)
208 struct iwmct_priv *priv = dev_get_drvdata(d);
209 char *token, *str_buf = NULL;
210 long val;
211 ssize_t ret = count;
212 u8 src, mask;
214 if (!count)
215 goto exit;
217 str_buf = kzalloc(count, GFP_KERNEL);
218 if (!str_buf) {
219 LOG_ERROR(priv, DEBUGFS,
220 "failed to allocate %zd bytes\n", count);
221 ret = -ENOMEM;
222 goto exit;
225 memcpy(str_buf, buf, count);
227 while ((token = strsep(&str_buf, ",")) != NULL) {
228 while (isspace(*token))
229 ++token;
230 if (strict_strtol(token, HEXADECIMAL_RADIX, &val)) {
231 LOG_ERROR(priv, DEBUGFS,
232 "failed to convert string to long %s\n",
233 token);
234 ret = -EINVAL;
235 goto exit;
238 mask = val & 0xFF;
239 src = (val & 0XFF00) >> 8;
240 iwmct_log_set_filter(src, mask);
243 exit:
244 kfree(str_buf);
245 return ret;
248 ssize_t show_iwmct_log_level_fw(struct device *d,
249 struct device_attribute *attr, char *buf)
251 struct iwmct_priv *priv = dev_get_drvdata(d);
252 char *str_buf;
253 int buf_size;
254 ssize_t ret;
256 buf_size = (LOG_SRC_FORMAT * FW_LOG_SRC_MAX) + 2;
258 str_buf = kzalloc(buf_size, GFP_KERNEL);
259 if (!str_buf) {
260 LOG_ERROR(priv, DEBUGFS,
261 "failed to allocate %d bytes\n", buf_size);
262 ret = -ENOMEM;
263 goto exit;
266 if (log_get_fw_filter_str(str_buf, buf_size) < 0) {
267 ret = -EINVAL;
268 goto exit;
271 ret = sprintf(buf, "%s", str_buf);
273 exit:
274 kfree(str_buf);
275 return ret;
278 ssize_t store_iwmct_log_level_fw(struct device *d,
279 struct device_attribute *attr,
280 const char *buf, size_t count)
282 struct iwmct_priv *priv = dev_get_drvdata(d);
283 struct top_msg cmd;
284 char *token, *str_buf = NULL;
285 ssize_t ret = count;
286 u16 cmdlen = 0;
287 int i;
288 long val;
289 u8 src, mask;
291 if (!count)
292 goto exit;
294 str_buf = kzalloc(count, GFP_KERNEL);
295 if (!str_buf) {
296 LOG_ERROR(priv, DEBUGFS,
297 "failed to allocate %zd bytes\n", count);
298 ret = -ENOMEM;
299 goto exit;
302 memcpy(str_buf, buf, count);
304 cmd.hdr.type = COMM_TYPE_H2D;
305 cmd.hdr.category = COMM_CATEGORY_DEBUG;
306 cmd.hdr.opcode = CMD_DBG_LOG_LEVEL;
308 for (i = 0; ((token = strsep(&str_buf, ",")) != NULL) &&
309 (i < FW_LOG_SRC_MAX); i++) {
311 while (isspace(*token))
312 ++token;
314 if (strict_strtol(token, HEXADECIMAL_RADIX, &val)) {
315 LOG_ERROR(priv, DEBUGFS,
316 "failed to convert string to long %s\n",
317 token);
318 ret = -EINVAL;
319 goto exit;
322 mask = val & 0xFF; /* LSB */
323 src = (val & 0XFF00) >> 8; /* 2nd least significant byte. */
324 iwmct_log_set_fw_filter(src, mask);
326 cmd.u.logdefs[i].logsource = src;
327 cmd.u.logdefs[i].sevmask = mask;
330 cmd.hdr.length = cpu_to_le16(i * sizeof(cmd.u.logdefs[0]));
331 cmdlen = (i * sizeof(cmd.u.logdefs[0]) + sizeof(cmd.hdr));
333 ret = iwmct_send_hcmd(priv, (u8 *)&cmd, cmdlen);
334 if (ret) {
335 LOG_ERROR(priv, DEBUGFS,
336 "Failed to send %d bytes of fwcmd, ret=%zd\n",
337 cmdlen, ret);
338 goto exit;
339 } else
340 LOG_INFO(priv, DEBUGFS, "fwcmd sent (%d bytes)\n", cmdlen);
342 ret = count;
344 exit:
345 kfree(str_buf);
346 return ret;