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

bmi.c (12345B)


      1// SPDX-License-Identifier: ISC
      2/*
      3 * Copyright (c) 2005-2011 Atheros Communications Inc.
      4 * Copyright (c) 2011-2014,2016-2017 Qualcomm Atheros, Inc.
      5 */
      6
      7#include "bmi.h"
      8#include "hif.h"
      9#include "debug.h"
     10#include "htc.h"
     11#include "hw.h"
     12
     13void ath10k_bmi_start(struct ath10k *ar)
     14{
     15	ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi start\n");
     16
     17	ar->bmi.done_sent = false;
     18}
     19EXPORT_SYMBOL(ath10k_bmi_start);
     20
     21int ath10k_bmi_done(struct ath10k *ar)
     22{
     23	struct bmi_cmd cmd;
     24	u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.done);
     25	int ret;
     26
     27	ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi done\n");
     28
     29	if (ar->bmi.done_sent) {
     30		ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi skipped\n");
     31		return 0;
     32	}
     33
     34	ar->bmi.done_sent = true;
     35	cmd.id = __cpu_to_le32(BMI_DONE);
     36
     37	ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL);
     38	if (ret) {
     39		ath10k_warn(ar, "unable to write to the device: %d\n", ret);
     40		return ret;
     41	}
     42
     43	return 0;
     44}
     45
     46int ath10k_bmi_get_target_info(struct ath10k *ar,
     47			       struct bmi_target_info *target_info)
     48{
     49	struct bmi_cmd cmd;
     50	union bmi_resp resp;
     51	u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.get_target_info);
     52	u32 resplen = sizeof(resp.get_target_info);
     53	int ret;
     54
     55	ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi get target info\n");
     56
     57	if (ar->bmi.done_sent) {
     58		ath10k_warn(ar, "BMI Get Target Info Command disallowed\n");
     59		return -EBUSY;
     60	}
     61
     62	cmd.id = __cpu_to_le32(BMI_GET_TARGET_INFO);
     63
     64	ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &resplen);
     65	if (ret) {
     66		ath10k_warn(ar, "unable to get target info from device\n");
     67		return ret;
     68	}
     69
     70	if (resplen < sizeof(resp.get_target_info)) {
     71		ath10k_warn(ar, "invalid get_target_info response length (%d)\n",
     72			    resplen);
     73		return -EIO;
     74	}
     75
     76	target_info->version = __le32_to_cpu(resp.get_target_info.version);
     77	target_info->type    = __le32_to_cpu(resp.get_target_info.type);
     78
     79	return 0;
     80}
     81
     82#define TARGET_VERSION_SENTINAL 0xffffffffu
     83
     84int ath10k_bmi_get_target_info_sdio(struct ath10k *ar,
     85				    struct bmi_target_info *target_info)
     86{
     87	struct bmi_cmd cmd;
     88	union bmi_resp resp;
     89	u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.get_target_info);
     90	u32 resplen, ver_len;
     91	__le32 tmp;
     92	int ret;
     93
     94	ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi get target info SDIO\n");
     95
     96	if (ar->bmi.done_sent) {
     97		ath10k_warn(ar, "BMI Get Target Info Command disallowed\n");
     98		return -EBUSY;
     99	}
    100
    101	cmd.id = __cpu_to_le32(BMI_GET_TARGET_INFO);
    102
    103	/* Step 1: Read 4 bytes of the target info and check if it is
    104	 * the special sentinal version word or the first word in the
    105	 * version response.
    106	 */
    107	resplen = sizeof(u32);
    108	ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &tmp, &resplen);
    109	if (ret) {
    110		ath10k_warn(ar, "unable to read from device\n");
    111		return ret;
    112	}
    113
    114	/* Some SDIO boards have a special sentinal byte before the real
    115	 * version response.
    116	 */
    117	if (__le32_to_cpu(tmp) == TARGET_VERSION_SENTINAL) {
    118		/* Step 1b: Read the version length */
    119		resplen = sizeof(u32);
    120		ret = ath10k_hif_exchange_bmi_msg(ar, NULL, 0, &tmp,
    121						  &resplen);
    122		if (ret) {
    123			ath10k_warn(ar, "unable to read from device\n");
    124			return ret;
    125		}
    126	}
    127
    128	ver_len = __le32_to_cpu(tmp);
    129
    130	/* Step 2: Check the target info length */
    131	if (ver_len != sizeof(resp.get_target_info)) {
    132		ath10k_warn(ar, "Unexpected target info len: %u. Expected: %zu\n",
    133			    ver_len, sizeof(resp.get_target_info));
    134		return -EINVAL;
    135	}
    136
    137	/* Step 3: Read the rest of the version response */
    138	resplen = sizeof(resp.get_target_info) - sizeof(u32);
    139	ret = ath10k_hif_exchange_bmi_msg(ar, NULL, 0,
    140					  &resp.get_target_info.version,
    141					  &resplen);
    142	if (ret) {
    143		ath10k_warn(ar, "unable to read from device\n");
    144		return ret;
    145	}
    146
    147	target_info->version = __le32_to_cpu(resp.get_target_info.version);
    148	target_info->type    = __le32_to_cpu(resp.get_target_info.type);
    149
    150	return 0;
    151}
    152
    153int ath10k_bmi_read_memory(struct ath10k *ar,
    154			   u32 address, void *buffer, u32 length)
    155{
    156	struct bmi_cmd cmd;
    157	union bmi_resp resp;
    158	u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.read_mem);
    159	u32 rxlen;
    160	int ret;
    161
    162	ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi read address 0x%x length %d\n",
    163		   address, length);
    164
    165	if (ar->bmi.done_sent) {
    166		ath10k_warn(ar, "command disallowed\n");
    167		return -EBUSY;
    168	}
    169
    170	while (length) {
    171		rxlen = min_t(u32, length, BMI_MAX_DATA_SIZE);
    172
    173		cmd.id            = __cpu_to_le32(BMI_READ_MEMORY);
    174		cmd.read_mem.addr = __cpu_to_le32(address);
    175		cmd.read_mem.len  = __cpu_to_le32(rxlen);
    176
    177		ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen,
    178						  &resp, &rxlen);
    179		if (ret) {
    180			ath10k_warn(ar, "unable to read from the device (%d)\n",
    181				    ret);
    182			return ret;
    183		}
    184
    185		memcpy(buffer, resp.read_mem.payload, rxlen);
    186		address += rxlen;
    187		buffer  += rxlen;
    188		length  -= rxlen;
    189	}
    190
    191	return 0;
    192}
    193EXPORT_SYMBOL(ath10k_bmi_read_memory);
    194
    195int ath10k_bmi_write_soc_reg(struct ath10k *ar, u32 address, u32 reg_val)
    196{
    197	struct bmi_cmd cmd;
    198	u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.write_soc_reg);
    199	int ret;
    200
    201	ath10k_dbg(ar, ATH10K_DBG_BMI,
    202		   "bmi write soc register 0x%08x val 0x%08x\n",
    203		   address, reg_val);
    204
    205	if (ar->bmi.done_sent) {
    206		ath10k_warn(ar, "bmi write soc register command in progress\n");
    207		return -EBUSY;
    208	}
    209
    210	cmd.id = __cpu_to_le32(BMI_WRITE_SOC_REGISTER);
    211	cmd.write_soc_reg.addr = __cpu_to_le32(address);
    212	cmd.write_soc_reg.value = __cpu_to_le32(reg_val);
    213
    214	ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL);
    215	if (ret) {
    216		ath10k_warn(ar, "Unable to write soc register to device: %d\n",
    217			    ret);
    218		return ret;
    219	}
    220
    221	return 0;
    222}
    223
    224int ath10k_bmi_read_soc_reg(struct ath10k *ar, u32 address, u32 *reg_val)
    225{
    226	struct bmi_cmd cmd;
    227	union bmi_resp resp;
    228	u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.read_soc_reg);
    229	u32 resplen = sizeof(resp.read_soc_reg);
    230	int ret;
    231
    232	ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi read soc register 0x%08x\n",
    233		   address);
    234
    235	if (ar->bmi.done_sent) {
    236		ath10k_warn(ar, "bmi read soc register command in progress\n");
    237		return -EBUSY;
    238	}
    239
    240	cmd.id = __cpu_to_le32(BMI_READ_SOC_REGISTER);
    241	cmd.read_soc_reg.addr = __cpu_to_le32(address);
    242
    243	ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &resplen);
    244	if (ret) {
    245		ath10k_warn(ar, "Unable to read soc register from device: %d\n",
    246			    ret);
    247		return ret;
    248	}
    249
    250	*reg_val = __le32_to_cpu(resp.read_soc_reg.value);
    251
    252	ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi read soc register value 0x%08x\n",
    253		   *reg_val);
    254
    255	return 0;
    256}
    257
    258int ath10k_bmi_write_memory(struct ath10k *ar,
    259			    u32 address, const void *buffer, u32 length)
    260{
    261	struct bmi_cmd cmd;
    262	u32 hdrlen = sizeof(cmd.id) + sizeof(cmd.write_mem);
    263	u32 txlen;
    264	int ret;
    265
    266	ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi write address 0x%x length %d\n",
    267		   address, length);
    268
    269	if (ar->bmi.done_sent) {
    270		ath10k_warn(ar, "command disallowed\n");
    271		return -EBUSY;
    272	}
    273
    274	while (length) {
    275		txlen = min(length, BMI_MAX_DATA_SIZE - hdrlen);
    276
    277		/* copy before roundup to avoid reading beyond buffer*/
    278		memcpy(cmd.write_mem.payload, buffer, txlen);
    279		txlen = roundup(txlen, 4);
    280
    281		cmd.id             = __cpu_to_le32(BMI_WRITE_MEMORY);
    282		cmd.write_mem.addr = __cpu_to_le32(address);
    283		cmd.write_mem.len  = __cpu_to_le32(txlen);
    284
    285		ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, hdrlen + txlen,
    286						  NULL, NULL);
    287		if (ret) {
    288			ath10k_warn(ar, "unable to write to the device (%d)\n",
    289				    ret);
    290			return ret;
    291		}
    292
    293		/* fixup roundup() so `length` zeroes out for last chunk */
    294		txlen = min(txlen, length);
    295
    296		address += txlen;
    297		buffer  += txlen;
    298		length  -= txlen;
    299	}
    300
    301	return 0;
    302}
    303
    304int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 param, u32 *result)
    305{
    306	struct bmi_cmd cmd;
    307	union bmi_resp resp;
    308	u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.execute);
    309	u32 resplen = sizeof(resp.execute);
    310	int ret;
    311
    312	ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi execute address 0x%x param 0x%x\n",
    313		   address, param);
    314
    315	if (ar->bmi.done_sent) {
    316		ath10k_warn(ar, "command disallowed\n");
    317		return -EBUSY;
    318	}
    319
    320	cmd.id            = __cpu_to_le32(BMI_EXECUTE);
    321	cmd.execute.addr  = __cpu_to_le32(address);
    322	cmd.execute.param = __cpu_to_le32(param);
    323
    324	ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &resplen);
    325	if (ret) {
    326		ath10k_warn(ar, "unable to read from the device\n");
    327		return ret;
    328	}
    329
    330	if (resplen < sizeof(resp.execute)) {
    331		ath10k_warn(ar, "invalid execute response length (%d)\n",
    332			    resplen);
    333		return -EIO;
    334	}
    335
    336	*result = __le32_to_cpu(resp.execute.result);
    337
    338	ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi execute result 0x%x\n", *result);
    339
    340	return 0;
    341}
    342
    343static int ath10k_bmi_lz_data_large(struct ath10k *ar, const void *buffer, u32 length)
    344{
    345	struct bmi_cmd *cmd;
    346	u32 hdrlen = sizeof(cmd->id) + sizeof(cmd->lz_data);
    347	u32 txlen;
    348	int ret;
    349	size_t buf_len;
    350
    351	ath10k_dbg(ar, ATH10K_DBG_BMI, "large bmi lz data buffer 0x%pK length %d\n",
    352		   buffer, length);
    353
    354	if (ar->bmi.done_sent) {
    355		ath10k_warn(ar, "command disallowed\n");
    356		return -EBUSY;
    357	}
    358
    359	buf_len = sizeof(*cmd) + BMI_MAX_LARGE_DATA_SIZE - BMI_MAX_DATA_SIZE;
    360	cmd = kzalloc(buf_len, GFP_KERNEL);
    361	if (!cmd)
    362		return -ENOMEM;
    363
    364	while (length) {
    365		txlen = min(length, BMI_MAX_LARGE_DATA_SIZE - hdrlen);
    366
    367		WARN_ON_ONCE(txlen & 3);
    368
    369		cmd->id          = __cpu_to_le32(BMI_LZ_DATA);
    370		cmd->lz_data.len = __cpu_to_le32(txlen);
    371		memcpy(cmd->lz_data.payload, buffer, txlen);
    372
    373		ret = ath10k_hif_exchange_bmi_msg(ar, cmd, hdrlen + txlen,
    374						  NULL, NULL);
    375		if (ret) {
    376			ath10k_warn(ar, "unable to write to the device\n");
    377			kfree(cmd);
    378			return ret;
    379		}
    380
    381		buffer += txlen;
    382		length -= txlen;
    383	}
    384
    385	kfree(cmd);
    386
    387	return 0;
    388}
    389
    390int ath10k_bmi_lz_data(struct ath10k *ar, const void *buffer, u32 length)
    391{
    392	struct bmi_cmd cmd;
    393	u32 hdrlen = sizeof(cmd.id) + sizeof(cmd.lz_data);
    394	u32 txlen;
    395	int ret;
    396
    397	ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi lz data buffer 0x%pK length %d\n",
    398		   buffer, length);
    399
    400	if (ar->bmi.done_sent) {
    401		ath10k_warn(ar, "command disallowed\n");
    402		return -EBUSY;
    403	}
    404
    405	while (length) {
    406		txlen = min(length, BMI_MAX_DATA_SIZE - hdrlen);
    407
    408		WARN_ON_ONCE(txlen & 3);
    409
    410		cmd.id          = __cpu_to_le32(BMI_LZ_DATA);
    411		cmd.lz_data.len = __cpu_to_le32(txlen);
    412		memcpy(cmd.lz_data.payload, buffer, txlen);
    413
    414		ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, hdrlen + txlen,
    415						  NULL, NULL);
    416		if (ret) {
    417			ath10k_warn(ar, "unable to write to the device\n");
    418			return ret;
    419		}
    420
    421		buffer += txlen;
    422		length -= txlen;
    423	}
    424
    425	return 0;
    426}
    427
    428int ath10k_bmi_lz_stream_start(struct ath10k *ar, u32 address)
    429{
    430	struct bmi_cmd cmd;
    431	u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.lz_start);
    432	int ret;
    433
    434	ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi lz stream start address 0x%x\n",
    435		   address);
    436
    437	if (ar->bmi.done_sent) {
    438		ath10k_warn(ar, "command disallowed\n");
    439		return -EBUSY;
    440	}
    441
    442	cmd.id            = __cpu_to_le32(BMI_LZ_STREAM_START);
    443	cmd.lz_start.addr = __cpu_to_le32(address);
    444
    445	ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL);
    446	if (ret) {
    447		ath10k_warn(ar, "unable to Start LZ Stream to the device\n");
    448		return ret;
    449	}
    450
    451	return 0;
    452}
    453
    454int ath10k_bmi_fast_download(struct ath10k *ar,
    455			     u32 address, const void *buffer, u32 length)
    456{
    457	u8 trailer[4] = {};
    458	u32 head_len = rounddown(length, 4);
    459	u32 trailer_len = length - head_len;
    460	int ret;
    461
    462	ath10k_dbg(ar, ATH10K_DBG_BMI,
    463		   "bmi fast download address 0x%x buffer 0x%pK length %d\n",
    464		   address, buffer, length);
    465
    466	ret = ath10k_bmi_lz_stream_start(ar, address);
    467	if (ret)
    468		return ret;
    469
    470	/* copy the last word into a zero padded buffer */
    471	if (trailer_len > 0)
    472		memcpy(trailer, buffer + head_len, trailer_len);
    473
    474	if (ar->hw_params.bmi_large_size_download)
    475		ret = ath10k_bmi_lz_data_large(ar, buffer, head_len);
    476	else
    477		ret = ath10k_bmi_lz_data(ar, buffer, head_len);
    478
    479	if (ret)
    480		return ret;
    481
    482	if (trailer_len > 0)
    483		ret = ath10k_bmi_lz_data(ar, trailer, 4);
    484
    485	if (ret != 0)
    486		return ret;
    487
    488	/*
    489	 * Close compressed stream and open a new (fake) one.
    490	 * This serves mainly to flush Target caches.
    491	 */
    492	ret = ath10k_bmi_lz_stream_start(ar, 0x00);
    493
    494	return ret;
    495}
    496
    497int ath10k_bmi_set_start(struct ath10k *ar, u32 address)
    498{
    499	struct bmi_cmd cmd;
    500	u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.set_app_start);
    501	int ret;
    502
    503	if (ar->bmi.done_sent) {
    504		ath10k_warn(ar, "bmi set start command disallowed\n");
    505		return -EBUSY;
    506	}
    507
    508	cmd.id = __cpu_to_le32(BMI_SET_APP_START);
    509	cmd.set_app_start.addr = __cpu_to_le32(address);
    510
    511	ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL);
    512	if (ret) {
    513		ath10k_warn(ar, "unable to set start to the device:%d\n", ret);
    514		return ret;
    515	}
    516
    517	return 0;
    518}