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
22 * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
27 #include <linux/kernel.h>
28 #include <linux/mmc/sdio_func.h>
29 #include <linux/slab.h>
30 #include <linux/ctype.h>
32 #include "iwmc3200top.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
)
48 logdefs
[src
] = logmask
;
49 else if (src
== LOG_SRC_ALL
)
50 for (i
= 0; i
< size
; i
++)
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
,
79 for (pos
= 0, i
= 0; pos
< slen
- 2 && pref
[i
] != '\0'; i
++, pos
++)
82 for (i
= 0; pos
< slen
- 2 && i
< ilen
; pos
+= len
, i
++)
83 len
= snprintf(&str
[pos
], slen
- pos
- 1, " %2.2X", ibuf
[i
]);
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
)
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
));
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
)))
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
)))
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
);
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
));
131 if (log_msg_format_hex(logbuf
, LOG_MSG_SIZE_MAX
, buf
,
132 le16_to_cpu(msg
->hdr
.length
)
135 LOG_WARNING(priv
, FW_MSG
,
136 "TOP DBG message is too long,"
138 LOG_WARNING(priv
, FW_MSG
, "%s\n", logbuf
);
146 static int _log_get_filter_str(u8
*logdefs
, int logdefsz
, char *buf
, int size
)
149 for (i
= 0, pos
= 0; (pos
< size
-1) && (i
< logdefsz
); i
++) {
150 len
= snprintf(&buf
[pos
], size
- pos
- 1, "0x%02X%02X,",
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
);
183 buf_size
= (LOG_SRC_FORMAT
* LOG_SRC_MAX
) + 1;
184 str_buf
= kzalloc(buf_size
, GFP_KERNEL
);
186 LOG_ERROR(priv
, DEBUGFS
,
187 "failed to allocate %d bytes\n", buf_size
);
192 if (log_get_filter_str(str_buf
, buf_size
) < 0) {
197 ret
= sprintf(buf
, "%s", str_buf
);
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
;
217 str_buf
= kzalloc(count
, GFP_KERNEL
);
219 LOG_ERROR(priv
, DEBUGFS
,
220 "failed to allocate %zd bytes\n", count
);
225 memcpy(str_buf
, buf
, count
);
227 while ((token
= strsep(&str_buf
, ",")) != NULL
) {
228 while (isspace(*token
))
230 if (strict_strtol(token
, HEXADECIMAL_RADIX
, &val
)) {
231 LOG_ERROR(priv
, DEBUGFS
,
232 "failed to convert string to long %s\n",
239 src
= (val
& 0XFF00) >> 8;
240 iwmct_log_set_filter(src
, mask
);
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
);
256 buf_size
= (LOG_SRC_FORMAT
* FW_LOG_SRC_MAX
) + 2;
258 str_buf
= kzalloc(buf_size
, GFP_KERNEL
);
260 LOG_ERROR(priv
, DEBUGFS
,
261 "failed to allocate %d bytes\n", buf_size
);
266 if (log_get_fw_filter_str(str_buf
, buf_size
) < 0) {
271 ret
= sprintf(buf
, "%s", str_buf
);
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
);
284 char *token
, *str_buf
= NULL
;
294 str_buf
= kzalloc(count
, GFP_KERNEL
);
296 LOG_ERROR(priv
, DEBUGFS
,
297 "failed to allocate %zd bytes\n", count
);
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
))
314 if (strict_strtol(token
, HEXADECIMAL_RADIX
, &val
)) {
315 LOG_ERROR(priv
, DEBUGFS
,
316 "failed to convert string to long %s\n",
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
);
335 LOG_ERROR(priv
, DEBUGFS
,
336 "Failed to send %d bytes of fwcmd, ret=%zd\n",
340 LOG_INFO(priv
, DEBUGFS
, "fwcmd sent (%d bytes)\n", cmdlen
);