/**************************************************************************** * * Copyright (c) 2014 - 2018 Samsung Electronics Co., Ltd. All rights reserved * ****************************************************************************/ #include #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_DBG4(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; } 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(); 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(); kfree_skb(skb); break; } slsi_rx_gen_report(sdev, dev, skb); rcu_read_unlock(); break; } default: 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_wake_lock(&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_wake_unlock(&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; }