• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/drivers/misc/iwmc3200top/
1/*
2 * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
3 * drivers/misc/iwmc3200top/log.c
4 *
5 * Copyright (C) 2009 Intel Corporation. All rights reserved.
6 *
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.
10 *
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.
15 *
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.
20 *
21 *
22 * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
23 *  -
24 *
25 */
26
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"
34
35/* Maximal hexadecimal string size of the FW memdump message */
36#define LOG_MSG_SIZE_MAX		12400
37
38/* iwmct_logdefs is a global used by log macros */
39u8 iwmct_logdefs[LOG_SRC_MAX];
40static u8 iwmct_fw_logdefs[FW_LOG_SRC_MAX];
41
42
43static int _log_set_log_filter(u8 *logdefs, int size, u8 src, u8 logmask)
44{
45	int i;
46
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;
54
55	return 0;
56}
57
58
59int iwmct_log_set_filter(u8 src, u8 logmask)
60{
61	return _log_set_log_filter(iwmct_logdefs, LOG_SRC_MAX, src, logmask);
62}
63
64
65int iwmct_log_set_fw_filter(u8 src, u8 logmask)
66{
67	return _log_set_log_filter(iwmct_fw_logdefs,
68				   FW_LOG_SRC_MAX, src, logmask);
69}
70
71
72static int log_msg_format_hex(char *str, int slen, u8 *ibuf,
73			      int ilen, char *pref)
74{
75	int pos = 0;
76	int i;
77	int len;
78
79	for (pos = 0, i = 0; pos < slen - 2 && pref[i] != '\0'; i++, pos++)
80		str[pos] = pref[i];
81
82	for (i = 0; pos < slen - 2 && i < ilen; pos += len, i++)
83		len = snprintf(&str[pos], slen - pos - 1, " %2.2X", ibuf[i]);
84
85	if (i < ilen)
86		return -1;
87
88	return 0;
89}
90
91/*	NOTE: This function is not thread safe.
92	Currently it's called only from sdio rx worker - no race there
93*/
94void iwmct_log_top_message(struct iwmct_priv *priv, u8 *buf, int len)
95{
96	struct top_msg *msg;
97	static char logbuf[LOG_MSG_SIZE_MAX];
98
99	msg = (struct top_msg *)buf;
100
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;
106	}
107
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;
112
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);
139		}
140		break;
141	default:
142		break;
143	}
144}
145
146static int _log_get_filter_str(u8 *logdefs, int logdefsz, char *buf, int size)
147{
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;
153	}
154	buf[pos-1] = '\n';
155	buf[pos] = '\0';
156
157	if (i < logdefsz)
158		return -1;
159	return 0;
160}
161
162int log_get_filter_str(char *buf, int size)
163{
164	return _log_get_filter_str(iwmct_logdefs, LOG_SRC_MAX, buf, size);
165}
166
167int log_get_fw_filter_str(char *buf, int size)
168{
169	return _log_get_filter_str(iwmct_fw_logdefs, FW_LOG_SRC_MAX, buf, size);
170}
171
172#define HEXADECIMAL_RADIX	16
173#define LOG_SRC_FORMAT		7 /* log level is in format of "0xXXXX," */
174
175ssize_t show_iwmct_log_level(struct device *d,
176				struct device_attribute *attr, char *buf)
177{
178	struct iwmct_priv *priv = dev_get_drvdata(d);
179	char *str_buf;
180	int buf_size;
181	ssize_t ret;
182
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;
190	}
191
192	if (log_get_filter_str(str_buf, buf_size) < 0) {
193		ret = -EINVAL;
194		goto exit;
195	}
196
197	ret = sprintf(buf, "%s", str_buf);
198
199exit:
200	kfree(str_buf);
201	return ret;
202}
203
204ssize_t store_iwmct_log_level(struct device *d,
205			struct device_attribute *attr,
206			const char *buf, size_t count)
207{
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;
213
214	if (!count)
215		goto exit;
216
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;
223	}
224
225	memcpy(str_buf, buf, count);
226
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;
236		}
237
238		mask  = val & 0xFF;
239		src = (val & 0XFF00) >> 8;
240		iwmct_log_set_filter(src, mask);
241	}
242
243exit:
244	kfree(str_buf);
245	return ret;
246}
247
248ssize_t show_iwmct_log_level_fw(struct device *d,
249			struct device_attribute *attr, char *buf)
250{
251	struct iwmct_priv *priv = dev_get_drvdata(d);
252	char *str_buf;
253	int buf_size;
254	ssize_t ret;
255
256	buf_size = (LOG_SRC_FORMAT * FW_LOG_SRC_MAX) + 2;
257
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;
264	}
265
266	if (log_get_fw_filter_str(str_buf, buf_size) < 0) {
267		ret = -EINVAL;
268		goto exit;
269	}
270
271	ret = sprintf(buf, "%s", str_buf);
272
273exit:
274	kfree(str_buf);
275	return ret;
276}
277
278ssize_t store_iwmct_log_level_fw(struct device *d,
279			struct device_attribute *attr,
280			const char *buf, size_t count)
281{
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;
290
291	if (!count)
292		goto exit;
293
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;
300	}
301
302	memcpy(str_buf, buf, count);
303
304	cmd.hdr.type = COMM_TYPE_H2D;
305	cmd.hdr.category = COMM_CATEGORY_DEBUG;
306	cmd.hdr.opcode = CMD_DBG_LOG_LEVEL;
307
308	for (i = 0; ((token = strsep(&str_buf, ",")) != NULL) &&
309		     (i < FW_LOG_SRC_MAX); i++) {
310
311		while (isspace(*token))
312			++token;
313
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;
320		}
321
322		mask  = val & 0xFF; /* LSB */
323		src = (val & 0XFF00) >> 8; /* 2nd least significant byte. */
324		iwmct_log_set_fw_filter(src, mask);
325
326		cmd.u.logdefs[i].logsource = src;
327		cmd.u.logdefs[i].sevmask = mask;
328	}
329
330	cmd.hdr.length = cpu_to_le16(i * sizeof(cmd.u.logdefs[0]));
331	cmdlen = (i * sizeof(cmd.u.logdefs[0]) + sizeof(cmd.hdr));
332
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);
341
342	ret = count;
343
344exit:
345	kfree(str_buf);
346	return ret;
347}
348