cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

testmode.c (11120B)


      1// SPDX-License-Identifier: ISC
      2/*
      3 * Copyright (c) 2014-2017 Qualcomm Atheros, Inc.
      4 */
      5
      6#include "testmode.h"
      7
      8#include <net/netlink.h>
      9#include <linux/firmware.h>
     10
     11#include "debug.h"
     12#include "wmi.h"
     13#include "hif.h"
     14#include "hw.h"
     15#include "core.h"
     16
     17#include "testmode_i.h"
     18
     19static const struct nla_policy ath10k_tm_policy[ATH10K_TM_ATTR_MAX + 1] = {
     20	[ATH10K_TM_ATTR_CMD]		= { .type = NLA_U32 },
     21	[ATH10K_TM_ATTR_DATA]		= { .type = NLA_BINARY,
     22					    .len = ATH10K_TM_DATA_MAX_LEN },
     23	[ATH10K_TM_ATTR_WMI_CMDID]	= { .type = NLA_U32 },
     24	[ATH10K_TM_ATTR_VERSION_MAJOR]	= { .type = NLA_U32 },
     25	[ATH10K_TM_ATTR_VERSION_MINOR]	= { .type = NLA_U32 },
     26};
     27
     28/* Returns true if callee consumes the skb and the skb should be discarded.
     29 * Returns false if skb is not used. Does not sleep.
     30 */
     31bool ath10k_tm_event_wmi(struct ath10k *ar, u32 cmd_id, struct sk_buff *skb)
     32{
     33	struct sk_buff *nl_skb;
     34	bool consumed;
     35	int ret;
     36
     37	ath10k_dbg(ar, ATH10K_DBG_TESTMODE,
     38		   "testmode event wmi cmd_id %d skb %pK skb->len %d\n",
     39		   cmd_id, skb, skb->len);
     40
     41	ath10k_dbg_dump(ar, ATH10K_DBG_TESTMODE, NULL, "", skb->data, skb->len);
     42
     43	spin_lock_bh(&ar->data_lock);
     44
     45	if (!ar->testmode.utf_monitor) {
     46		consumed = false;
     47		goto out;
     48	}
     49
     50	/* Only testmode.c should be handling events from utf firmware,
     51	 * otherwise all sort of problems will arise as mac80211 operations
     52	 * are not initialised.
     53	 */
     54	consumed = true;
     55
     56	nl_skb = cfg80211_testmode_alloc_event_skb(ar->hw->wiphy,
     57						   2 * sizeof(u32) + skb->len,
     58						   GFP_ATOMIC);
     59	if (!nl_skb) {
     60		ath10k_warn(ar,
     61			    "failed to allocate skb for testmode wmi event\n");
     62		goto out;
     63	}
     64
     65	ret = nla_put_u32(nl_skb, ATH10K_TM_ATTR_CMD, ATH10K_TM_CMD_WMI);
     66	if (ret) {
     67		ath10k_warn(ar,
     68			    "failed to put testmode wmi event cmd attribute: %d\n",
     69			    ret);
     70		kfree_skb(nl_skb);
     71		goto out;
     72	}
     73
     74	ret = nla_put_u32(nl_skb, ATH10K_TM_ATTR_WMI_CMDID, cmd_id);
     75	if (ret) {
     76		ath10k_warn(ar,
     77			    "failed to put testmode wmi event cmd_id: %d\n",
     78			    ret);
     79		kfree_skb(nl_skb);
     80		goto out;
     81	}
     82
     83	ret = nla_put(nl_skb, ATH10K_TM_ATTR_DATA, skb->len, skb->data);
     84	if (ret) {
     85		ath10k_warn(ar,
     86			    "failed to copy skb to testmode wmi event: %d\n",
     87			    ret);
     88		kfree_skb(nl_skb);
     89		goto out;
     90	}
     91
     92	cfg80211_testmode_event(nl_skb, GFP_ATOMIC);
     93
     94out:
     95	spin_unlock_bh(&ar->data_lock);
     96
     97	return consumed;
     98}
     99
    100static int ath10k_tm_cmd_get_version(struct ath10k *ar, struct nlattr *tb[])
    101{
    102	struct sk_buff *skb;
    103	int ret;
    104
    105	ath10k_dbg(ar, ATH10K_DBG_TESTMODE,
    106		   "testmode cmd get version_major %d version_minor %d\n",
    107		   ATH10K_TESTMODE_VERSION_MAJOR,
    108		   ATH10K_TESTMODE_VERSION_MINOR);
    109
    110	skb = cfg80211_testmode_alloc_reply_skb(ar->hw->wiphy,
    111						nla_total_size(sizeof(u32)));
    112	if (!skb)
    113		return -ENOMEM;
    114
    115	ret = nla_put_u32(skb, ATH10K_TM_ATTR_VERSION_MAJOR,
    116			  ATH10K_TESTMODE_VERSION_MAJOR);
    117	if (ret) {
    118		kfree_skb(skb);
    119		return ret;
    120	}
    121
    122	ret = nla_put_u32(skb, ATH10K_TM_ATTR_VERSION_MINOR,
    123			  ATH10K_TESTMODE_VERSION_MINOR);
    124	if (ret) {
    125		kfree_skb(skb);
    126		return ret;
    127	}
    128
    129	ret = nla_put_u32(skb, ATH10K_TM_ATTR_WMI_OP_VERSION,
    130			  ar->normal_mode_fw.fw_file.wmi_op_version);
    131	if (ret) {
    132		kfree_skb(skb);
    133		return ret;
    134	}
    135
    136	return cfg80211_testmode_reply(skb);
    137}
    138
    139static int ath10k_tm_fetch_utf_firmware_api_1(struct ath10k *ar,
    140					      struct ath10k_fw_file *fw_file)
    141{
    142	char filename[100];
    143	int ret;
    144
    145	snprintf(filename, sizeof(filename), "%s/%s",
    146		 ar->hw_params.fw.dir, ATH10K_FW_UTF_FILE);
    147
    148	/* load utf firmware image */
    149	ret = firmware_request_nowarn(&fw_file->firmware, filename, ar->dev);
    150	ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode fw request '%s': %d\n",
    151		   filename, ret);
    152
    153	if (ret) {
    154		ath10k_warn(ar, "failed to retrieve utf firmware '%s': %d\n",
    155			    filename, ret);
    156		return ret;
    157	}
    158
    159	/* We didn't find FW UTF API 1 ("utf.bin") does not advertise
    160	 * firmware features. Do an ugly hack where we force the firmware
    161	 * features to match with 10.1 branch so that wmi.c will use the
    162	 * correct WMI interface.
    163	 */
    164
    165	fw_file->wmi_op_version = ATH10K_FW_WMI_OP_VERSION_10_1;
    166	fw_file->htt_op_version = ATH10K_FW_HTT_OP_VERSION_10_1;
    167	fw_file->firmware_data = fw_file->firmware->data;
    168	fw_file->firmware_len = fw_file->firmware->size;
    169
    170	return 0;
    171}
    172
    173static int ath10k_tm_fetch_firmware(struct ath10k *ar)
    174{
    175	struct ath10k_fw_components *utf_mode_fw;
    176	int ret;
    177	char fw_name[100];
    178	int fw_api2 = 2;
    179
    180	switch (ar->hif.bus) {
    181	case ATH10K_BUS_SDIO:
    182	case ATH10K_BUS_USB:
    183		scnprintf(fw_name, sizeof(fw_name), "%s-%s-%d.bin",
    184			  ATH10K_FW_UTF_FILE_BASE, ath10k_bus_str(ar->hif.bus),
    185			  fw_api2);
    186		break;
    187	default:
    188		scnprintf(fw_name, sizeof(fw_name), "%s-%d.bin",
    189			  ATH10K_FW_UTF_FILE_BASE, fw_api2);
    190		break;
    191	}
    192
    193	ret = ath10k_core_fetch_firmware_api_n(ar, fw_name,
    194					       &ar->testmode.utf_mode_fw.fw_file);
    195	if (ret == 0) {
    196		ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode using fw utf api 2");
    197		goto out;
    198	}
    199
    200	ret = ath10k_tm_fetch_utf_firmware_api_1(ar, &ar->testmode.utf_mode_fw.fw_file);
    201	if (ret) {
    202		ath10k_err(ar, "failed to fetch utf firmware binary: %d", ret);
    203		return ret;
    204	}
    205
    206	ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode using utf api 1");
    207
    208out:
    209	utf_mode_fw = &ar->testmode.utf_mode_fw;
    210
    211	/* Use the same board data file as the normal firmware uses (but
    212	 * it's still "owned" by normal_mode_fw so we shouldn't free it.
    213	 */
    214	utf_mode_fw->board_data = ar->normal_mode_fw.board_data;
    215	utf_mode_fw->board_len = ar->normal_mode_fw.board_len;
    216
    217	if (!utf_mode_fw->fw_file.otp_data) {
    218		ath10k_info(ar, "utf.bin didn't contain otp binary, taking it from the normal mode firmware");
    219		utf_mode_fw->fw_file.otp_data = ar->normal_mode_fw.fw_file.otp_data;
    220		utf_mode_fw->fw_file.otp_len = ar->normal_mode_fw.fw_file.otp_len;
    221	}
    222
    223	return 0;
    224}
    225
    226static int ath10k_tm_cmd_utf_start(struct ath10k *ar, struct nlattr *tb[])
    227{
    228	const char *ver;
    229	int ret;
    230
    231	ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode cmd utf start\n");
    232
    233	mutex_lock(&ar->conf_mutex);
    234
    235	if (ar->state == ATH10K_STATE_UTF) {
    236		ret = -EALREADY;
    237		goto err;
    238	}
    239
    240	/* start utf only when the driver is not in use  */
    241	if (ar->state != ATH10K_STATE_OFF) {
    242		ret = -EBUSY;
    243		goto err;
    244	}
    245
    246	if (WARN_ON(ar->testmode.utf_mode_fw.fw_file.firmware != NULL)) {
    247		/* utf image is already downloaded, it shouldn't be */
    248		ret = -EEXIST;
    249		goto err;
    250	}
    251
    252	ret = ath10k_tm_fetch_firmware(ar);
    253	if (ret) {
    254		ath10k_err(ar, "failed to fetch UTF firmware: %d", ret);
    255		goto err;
    256	}
    257
    258	if (ar->testmode.utf_mode_fw.fw_file.codeswap_data &&
    259	    ar->testmode.utf_mode_fw.fw_file.codeswap_len) {
    260		ret = ath10k_swap_code_seg_init(ar,
    261						&ar->testmode.utf_mode_fw.fw_file);
    262		if (ret) {
    263			ath10k_warn(ar,
    264				    "failed to init utf code swap segment: %d\n",
    265				    ret);
    266			goto err_release_utf_mode_fw;
    267		}
    268	}
    269
    270	spin_lock_bh(&ar->data_lock);
    271	ar->testmode.utf_monitor = true;
    272	spin_unlock_bh(&ar->data_lock);
    273
    274	ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode wmi version %d\n",
    275		   ar->testmode.utf_mode_fw.fw_file.wmi_op_version);
    276
    277	ret = ath10k_hif_power_up(ar, ATH10K_FIRMWARE_MODE_UTF);
    278	if (ret) {
    279		ath10k_err(ar, "failed to power up hif (testmode): %d\n", ret);
    280		ar->state = ATH10K_STATE_OFF;
    281		goto err_release_utf_mode_fw;
    282	}
    283
    284	ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_UTF,
    285				&ar->testmode.utf_mode_fw);
    286	if (ret) {
    287		ath10k_err(ar, "failed to start core (testmode): %d\n", ret);
    288		ar->state = ATH10K_STATE_OFF;
    289		goto err_power_down;
    290	}
    291
    292	ar->state = ATH10K_STATE_UTF;
    293
    294	if (strlen(ar->testmode.utf_mode_fw.fw_file.fw_version) > 0)
    295		ver = ar->testmode.utf_mode_fw.fw_file.fw_version;
    296	else
    297		ver = "API 1";
    298
    299	ath10k_info(ar, "UTF firmware %s started\n", ver);
    300
    301	mutex_unlock(&ar->conf_mutex);
    302
    303	return 0;
    304
    305err_power_down:
    306	ath10k_hif_power_down(ar);
    307
    308err_release_utf_mode_fw:
    309	if (ar->testmode.utf_mode_fw.fw_file.codeswap_data &&
    310	    ar->testmode.utf_mode_fw.fw_file.codeswap_len)
    311		ath10k_swap_code_seg_release(ar,
    312					     &ar->testmode.utf_mode_fw.fw_file);
    313
    314	release_firmware(ar->testmode.utf_mode_fw.fw_file.firmware);
    315	ar->testmode.utf_mode_fw.fw_file.firmware = NULL;
    316
    317err:
    318	mutex_unlock(&ar->conf_mutex);
    319
    320	return ret;
    321}
    322
    323static void __ath10k_tm_cmd_utf_stop(struct ath10k *ar)
    324{
    325	lockdep_assert_held(&ar->conf_mutex);
    326
    327	ath10k_core_stop(ar);
    328	ath10k_hif_power_down(ar);
    329
    330	spin_lock_bh(&ar->data_lock);
    331
    332	ar->testmode.utf_monitor = false;
    333
    334	spin_unlock_bh(&ar->data_lock);
    335
    336	if (ar->testmode.utf_mode_fw.fw_file.codeswap_data &&
    337	    ar->testmode.utf_mode_fw.fw_file.codeswap_len)
    338		ath10k_swap_code_seg_release(ar,
    339					     &ar->testmode.utf_mode_fw.fw_file);
    340
    341	release_firmware(ar->testmode.utf_mode_fw.fw_file.firmware);
    342	ar->testmode.utf_mode_fw.fw_file.firmware = NULL;
    343
    344	ar->state = ATH10K_STATE_OFF;
    345}
    346
    347static int ath10k_tm_cmd_utf_stop(struct ath10k *ar, struct nlattr *tb[])
    348{
    349	int ret;
    350
    351	ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode cmd utf stop\n");
    352
    353	mutex_lock(&ar->conf_mutex);
    354
    355	if (ar->state != ATH10K_STATE_UTF) {
    356		ret = -ENETDOWN;
    357		goto out;
    358	}
    359
    360	__ath10k_tm_cmd_utf_stop(ar);
    361
    362	ret = 0;
    363
    364	ath10k_info(ar, "UTF firmware stopped\n");
    365
    366out:
    367	mutex_unlock(&ar->conf_mutex);
    368	return ret;
    369}
    370
    371static int ath10k_tm_cmd_wmi(struct ath10k *ar, struct nlattr *tb[])
    372{
    373	struct sk_buff *skb;
    374	int ret, buf_len;
    375	u32 cmd_id;
    376	void *buf;
    377
    378	mutex_lock(&ar->conf_mutex);
    379
    380	if (ar->state != ATH10K_STATE_UTF) {
    381		ret = -ENETDOWN;
    382		goto out;
    383	}
    384
    385	if (!tb[ATH10K_TM_ATTR_DATA]) {
    386		ret = -EINVAL;
    387		goto out;
    388	}
    389
    390	if (!tb[ATH10K_TM_ATTR_WMI_CMDID]) {
    391		ret = -EINVAL;
    392		goto out;
    393	}
    394
    395	buf = nla_data(tb[ATH10K_TM_ATTR_DATA]);
    396	buf_len = nla_len(tb[ATH10K_TM_ATTR_DATA]);
    397	cmd_id = nla_get_u32(tb[ATH10K_TM_ATTR_WMI_CMDID]);
    398
    399	ath10k_dbg(ar, ATH10K_DBG_TESTMODE,
    400		   "testmode cmd wmi cmd_id %d buf %pK buf_len %d\n",
    401		   cmd_id, buf, buf_len);
    402
    403	ath10k_dbg_dump(ar, ATH10K_DBG_TESTMODE, NULL, "", buf, buf_len);
    404
    405	skb = ath10k_wmi_alloc_skb(ar, buf_len);
    406	if (!skb) {
    407		ret = -ENOMEM;
    408		goto out;
    409	}
    410
    411	memcpy(skb->data, buf, buf_len);
    412
    413	ret = ath10k_wmi_cmd_send(ar, skb, cmd_id);
    414	if (ret) {
    415		ath10k_warn(ar, "failed to transmit wmi command (testmode): %d\n",
    416			    ret);
    417		goto out;
    418	}
    419
    420	ret = 0;
    421
    422out:
    423	mutex_unlock(&ar->conf_mutex);
    424	return ret;
    425}
    426
    427int ath10k_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
    428		  void *data, int len)
    429{
    430	struct ath10k *ar = hw->priv;
    431	struct nlattr *tb[ATH10K_TM_ATTR_MAX + 1];
    432	int ret;
    433
    434	ret = nla_parse_deprecated(tb, ATH10K_TM_ATTR_MAX, data, len,
    435				   ath10k_tm_policy, NULL);
    436	if (ret)
    437		return ret;
    438
    439	if (!tb[ATH10K_TM_ATTR_CMD])
    440		return -EINVAL;
    441
    442	switch (nla_get_u32(tb[ATH10K_TM_ATTR_CMD])) {
    443	case ATH10K_TM_CMD_GET_VERSION:
    444		return ath10k_tm_cmd_get_version(ar, tb);
    445	case ATH10K_TM_CMD_UTF_START:
    446		return ath10k_tm_cmd_utf_start(ar, tb);
    447	case ATH10K_TM_CMD_UTF_STOP:
    448		return ath10k_tm_cmd_utf_stop(ar, tb);
    449	case ATH10K_TM_CMD_WMI:
    450		return ath10k_tm_cmd_wmi(ar, tb);
    451	default:
    452		return -EOPNOTSUPP;
    453	}
    454}
    455
    456void ath10k_testmode_destroy(struct ath10k *ar)
    457{
    458	mutex_lock(&ar->conf_mutex);
    459
    460	if (ar->state != ATH10K_STATE_UTF) {
    461		/* utf firmware is not running, nothing to do */
    462		goto out;
    463	}
    464
    465	__ath10k_tm_cmd_utf_stop(ar);
    466
    467out:
    468	mutex_unlock(&ar->conf_mutex);
    469}