blob: d564a9fa33c6fed9456ee0f5cb11fbadc45edf31 [file] [log] [blame]
/****************************************************************************
*
* Copyright (c) 2014 - 2016 Samsung Electronics Co., Ltd. All rights reserved
*
****************************************************************************/
#include <linux/types.h>
#include "debug.h"
#include "dev.h"
#include "sap.h"
#include "sap_dbg.h"
#include "hip.h"
#define SUPPORTED_OLD_VERSION 0
static int sap_dbg_version_supported(u16 version);
static int sap_dbg_rx_handler(struct slsi_dev *sdev, struct sk_buff *skb);
static struct sap_api sap_dbg = {
.sap_class = SAP_DBG,
.sap_version_supported = sap_dbg_version_supported,
.sap_handler = sap_dbg_rx_handler,
.sap_versions = { FAPI_DEBUG_SAP_VERSION, SUPPORTED_OLD_VERSION },
};
static int sap_dbg_version_supported(u16 version)
{
unsigned int major = SAP_MAJOR(version);
unsigned int minor = SAP_MINOR(version);
u8 i = 0;
SLSI_INFO_NODEV("Reported version: %d.%d\n", major, minor);
for (i = 0; i < SAP_MAX_VER; i++)
if (SAP_MAJOR(sap_dbg.sap_versions[i]) == major)
return 0;
SLSI_ERR_NODEV("Version %d.%d Not supported\n", major, minor);
return -EINVAL;
}
static void slsi_rx_debug(struct slsi_dev *sdev, struct net_device *dev, struct sk_buff *skb)
{
u16 id = fapi_get_u16(skb, id);
SLSI_UNUSED_PARAMETER(dev);
switch (id) {
case DEBUG_FAULT_IND:
SLSI_WARN(sdev, "WF_FW_INFO: |cpu %s|id 0x%04X|arg 0x%08X|count %d|timestamp %10u|\n",
((fapi_get_u16(skb, u.debug_fault_ind.cpu) == 0x8000) ? "MAC" :
(fapi_get_u16(skb, u.debug_fault_ind.cpu) == 0x4000) ? "PHY" : "???"),
fapi_get_u16(skb, u.debug_fault_ind.faultid),
fapi_get_u32(skb, u.debug_fault_ind.arg),
fapi_get_u16(skb, u.debug_fault_ind.count),
fapi_get_u32(skb, u.debug_fault_ind.timestamp));
break;
case DEBUG_WORD12IND:
atomic_inc(&sdev->debug_inds);
SLSI_DBG1(sdev, SLSI_FW_TEST, "FW DEBUG(id:%d, subid:%d, vif:%d, time:%u) %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X\n",
fapi_get_u16(skb, u.debug_word12_ind.module_id),
fapi_get_u16(skb, u.debug_word12_ind.module_sub_id),
fapi_get_vif(skb),
fapi_get_u32(skb, u.debug_word12_ind.timestamp),
fapi_get_u16(skb, u.debug_word12_ind.debug_words[0]),
fapi_get_u16(skb, u.debug_word12_ind.debug_words[1]),
fapi_get_u16(skb, u.debug_word12_ind.debug_words[2]),
fapi_get_u16(skb, u.debug_word12_ind.debug_words[3]),
fapi_get_u16(skb, u.debug_word12_ind.debug_words[4]),
fapi_get_u16(skb, u.debug_word12_ind.debug_words[5]),
fapi_get_u16(skb, u.debug_word12_ind.debug_words[6]),
fapi_get_u16(skb, u.debug_word12_ind.debug_words[7]),
fapi_get_u16(skb, u.debug_word12_ind.debug_words[8]),
fapi_get_u16(skb, u.debug_word12_ind.debug_words[9]),
fapi_get_u16(skb, u.debug_word12_ind.debug_words[10]),
fapi_get_u16(skb, u.debug_word12_ind.debug_words[11]));
break;
default:
SLSI_DBG1(sdev, SLSI_MLME, "Unhandled Debug Ind: 0x%.4x\n", id);
break;
}
slsi_kfree_skb(skb);
}
static int slsi_rx_dbg_sap(struct slsi_dev *sdev, struct sk_buff *skb)
{
u16 id = fapi_get_u16(skb, id);
u16 vif = fapi_get_vif(skb);
struct net_device *dev;
switch (id) {
case DEBUG_FAULT_IND:
case DEBUG_WORD12IND:
case DEBUG_GENERIC_IND:
slsi_rx_debug(sdev, NULL, skb);
break;
case DEBUG_PKT_SINK_REPORT_IND:
{
rcu_read_lock();
dev = slsi_get_netdev_rcu(sdev, vif);
if (!dev) {
rcu_read_unlock();
slsi_kfree_skb(skb);
break;
}
slsi_rx_sink_report(sdev, dev, skb);
rcu_read_unlock();
break;
}
case DEBUG_PKT_GEN_REPORT_IND:
{
rcu_read_lock();
dev = slsi_get_netdev_rcu(sdev, vif);
if (!dev) {
rcu_read_unlock();
slsi_kfree_skb(skb);
break;
}
slsi_rx_gen_report(sdev, dev, skb);
rcu_read_unlock();
break;
}
default:
slsi_kfree_skb(skb);
SLSI_ERR(sdev, "Unhandled Ind: 0x%.4x\n", id);
break;
}
return 0;
}
void slsi_rx_dbg_sap_work(struct work_struct *work)
{
struct slsi_skb_work *w = container_of(work, struct slsi_skb_work, work);
struct slsi_dev *sdev = w->sdev;
struct sk_buff *skb = slsi_skb_work_dequeue(w);
slsi_wakelock(&sdev->wlan_wl);
while (skb) {
slsi_debug_frame(sdev, NULL, skb, "RX");
slsi_rx_dbg_sap(sdev, skb);
skb = slsi_skb_work_dequeue(w);
}
slsi_wakeunlock(&sdev->wlan_wl);
}
static int sap_dbg_rx_handler(struct slsi_dev *sdev, struct sk_buff *skb)
{
/* DEBUG SAP has a generic confirm. Theoretically, that
* can mean upper layer code can block on the confirm.
*/
if (slsi_rx_blocking_signals(sdev, skb) == 0)
return 0;
slsi_skb_work_enqueue(&sdev->rx_dbg_sap, skb);
return 0;
}
int sap_dbg_init(void)
{
SLSI_INFO_NODEV("Registering SAP\n");
slsi_hip_sap_register(&sap_dbg);
return 0;
}
int sap_dbg_deinit(void)
{
SLSI_INFO_NODEV("Unregistering SAP\n");
slsi_hip_sap_unregister(&sap_dbg);
return 0;
}