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