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

boot.c (13541B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * This file is part of wl1271
      4 *
      5 * Copyright (C) 2008-2010 Nokia Corporation
      6 *
      7 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
      8 */
      9
     10#include <linux/slab.h>
     11#include <linux/export.h>
     12
     13#include "debug.h"
     14#include "acx.h"
     15#include "boot.h"
     16#include "io.h"
     17#include "event.h"
     18#include "rx.h"
     19#include "hw_ops.h"
     20
     21static int wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag)
     22{
     23	u32 cpu_ctrl;
     24	int ret;
     25
     26	/* 10.5.0 run the firmware (I) */
     27	ret = wlcore_read_reg(wl, REG_ECPU_CONTROL, &cpu_ctrl);
     28	if (ret < 0)
     29		goto out;
     30
     31	/* 10.5.1 run the firmware (II) */
     32	cpu_ctrl |= flag;
     33	ret = wlcore_write_reg(wl, REG_ECPU_CONTROL, cpu_ctrl);
     34
     35out:
     36	return ret;
     37}
     38
     39static int wlcore_boot_parse_fw_ver(struct wl1271 *wl,
     40				    struct wl1271_static_data *static_data)
     41{
     42	int ret;
     43
     44	strncpy(wl->chip.fw_ver_str, static_data->fw_version,
     45		sizeof(wl->chip.fw_ver_str));
     46
     47	/* make sure the string is NULL-terminated */
     48	wl->chip.fw_ver_str[sizeof(wl->chip.fw_ver_str) - 1] = '\0';
     49
     50	ret = sscanf(wl->chip.fw_ver_str + 4, "%u.%u.%u.%u.%u",
     51		     &wl->chip.fw_ver[0], &wl->chip.fw_ver[1],
     52		     &wl->chip.fw_ver[2], &wl->chip.fw_ver[3],
     53		     &wl->chip.fw_ver[4]);
     54
     55	if (ret != 5) {
     56		wl1271_warning("fw version incorrect value");
     57		memset(wl->chip.fw_ver, 0, sizeof(wl->chip.fw_ver));
     58		ret = -EINVAL;
     59		goto out;
     60	}
     61
     62	ret = wlcore_identify_fw(wl);
     63	if (ret < 0)
     64		goto out;
     65out:
     66	return ret;
     67}
     68
     69static int wlcore_validate_fw_ver(struct wl1271 *wl)
     70{
     71	unsigned int *fw_ver = wl->chip.fw_ver;
     72	unsigned int *min_ver = (wl->fw_type == WL12XX_FW_TYPE_MULTI) ?
     73		wl->min_mr_fw_ver : wl->min_sr_fw_ver;
     74	char min_fw_str[32] = "";
     75	int off = 0;
     76	int i;
     77
     78	/* the chip must be exactly equal */
     79	if ((min_ver[FW_VER_CHIP] != WLCORE_FW_VER_IGNORE) &&
     80	    (min_ver[FW_VER_CHIP] != fw_ver[FW_VER_CHIP]))
     81		goto fail;
     82
     83	/* the firmware type must be equal */
     84	if ((min_ver[FW_VER_IF_TYPE] != WLCORE_FW_VER_IGNORE) &&
     85	    (min_ver[FW_VER_IF_TYPE] != fw_ver[FW_VER_IF_TYPE]))
     86		goto fail;
     87
     88	/* the project number must be equal */
     89	if ((min_ver[FW_VER_SUBTYPE] != WLCORE_FW_VER_IGNORE) &&
     90	    (min_ver[FW_VER_SUBTYPE] != fw_ver[FW_VER_SUBTYPE]))
     91		goto fail;
     92
     93	/* the API version must be greater or equal */
     94	if ((min_ver[FW_VER_MAJOR] != WLCORE_FW_VER_IGNORE) &&
     95		 (min_ver[FW_VER_MAJOR] > fw_ver[FW_VER_MAJOR]))
     96		goto fail;
     97
     98	/* if the API version is equal... */
     99	if (((min_ver[FW_VER_MAJOR] == WLCORE_FW_VER_IGNORE) ||
    100	     (min_ver[FW_VER_MAJOR] == fw_ver[FW_VER_MAJOR])) &&
    101	    /* ...the minor must be greater or equal */
    102	    ((min_ver[FW_VER_MINOR] != WLCORE_FW_VER_IGNORE) &&
    103	     (min_ver[FW_VER_MINOR] > fw_ver[FW_VER_MINOR])))
    104		goto fail;
    105
    106	return 0;
    107
    108fail:
    109	for (i = 0; i < NUM_FW_VER && off < sizeof(min_fw_str); i++)
    110		if (min_ver[i] == WLCORE_FW_VER_IGNORE)
    111			off += snprintf(min_fw_str + off,
    112					sizeof(min_fw_str) - off,
    113					"*.");
    114		else
    115			off += snprintf(min_fw_str + off,
    116					sizeof(min_fw_str) - off,
    117					"%u.", min_ver[i]);
    118
    119	wl1271_error("Your WiFi FW version (%u.%u.%u.%u.%u) is invalid.\n"
    120		     "Please use at least FW %s\n"
    121		     "You can get the latest firmwares at:\n"
    122		     "git://git.ti.com/wilink8-wlan/wl18xx_fw.git",
    123		     fw_ver[FW_VER_CHIP], fw_ver[FW_VER_IF_TYPE],
    124		     fw_ver[FW_VER_MAJOR], fw_ver[FW_VER_SUBTYPE],
    125		     fw_ver[FW_VER_MINOR], min_fw_str);
    126	return -EINVAL;
    127}
    128
    129static int wlcore_boot_static_data(struct wl1271 *wl)
    130{
    131	struct wl1271_static_data *static_data;
    132	size_t len = sizeof(*static_data) + wl->static_data_priv_len;
    133	int ret;
    134
    135	static_data = kmalloc(len, GFP_KERNEL);
    136	if (!static_data) {
    137		ret = -ENOMEM;
    138		goto out;
    139	}
    140
    141	ret = wlcore_read(wl, wl->cmd_box_addr, static_data, len, false);
    142	if (ret < 0)
    143		goto out_free;
    144
    145	ret = wlcore_boot_parse_fw_ver(wl, static_data);
    146	if (ret < 0)
    147		goto out_free;
    148
    149	ret = wlcore_validate_fw_ver(wl);
    150	if (ret < 0)
    151		goto out_free;
    152
    153	ret = wlcore_handle_static_data(wl, static_data);
    154	if (ret < 0)
    155		goto out_free;
    156
    157out_free:
    158	kfree(static_data);
    159out:
    160	return ret;
    161}
    162
    163static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
    164					     size_t fw_data_len, u32 dest)
    165{
    166	struct wlcore_partition_set partition;
    167	int addr, chunk_num, partition_limit;
    168	u8 *p, *chunk;
    169	int ret;
    170
    171	/* whal_FwCtrl_LoadFwImageSm() */
    172
    173	wl1271_debug(DEBUG_BOOT, "starting firmware upload");
    174
    175	wl1271_debug(DEBUG_BOOT, "fw_data_len %zd chunk_size %d",
    176		     fw_data_len, CHUNK_SIZE);
    177
    178	if ((fw_data_len % 4) != 0) {
    179		wl1271_error("firmware length not multiple of four");
    180		return -EIO;
    181	}
    182
    183	chunk = kmalloc(CHUNK_SIZE, GFP_KERNEL);
    184	if (!chunk) {
    185		wl1271_error("allocation for firmware upload chunk failed");
    186		return -ENOMEM;
    187	}
    188
    189	memcpy(&partition, &wl->ptable[PART_DOWN], sizeof(partition));
    190	partition.mem.start = dest;
    191	ret = wlcore_set_partition(wl, &partition);
    192	if (ret < 0)
    193		goto out;
    194
    195	/* 10.1 set partition limit and chunk num */
    196	chunk_num = 0;
    197	partition_limit = wl->ptable[PART_DOWN].mem.size;
    198
    199	while (chunk_num < fw_data_len / CHUNK_SIZE) {
    200		/* 10.2 update partition, if needed */
    201		addr = dest + (chunk_num + 2) * CHUNK_SIZE;
    202		if (addr > partition_limit) {
    203			addr = dest + chunk_num * CHUNK_SIZE;
    204			partition_limit = chunk_num * CHUNK_SIZE +
    205				wl->ptable[PART_DOWN].mem.size;
    206			partition.mem.start = addr;
    207			ret = wlcore_set_partition(wl, &partition);
    208			if (ret < 0)
    209				goto out;
    210		}
    211
    212		/* 10.3 upload the chunk */
    213		addr = dest + chunk_num * CHUNK_SIZE;
    214		p = buf + chunk_num * CHUNK_SIZE;
    215		memcpy(chunk, p, CHUNK_SIZE);
    216		wl1271_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x",
    217			     p, addr);
    218		ret = wlcore_write(wl, addr, chunk, CHUNK_SIZE, false);
    219		if (ret < 0)
    220			goto out;
    221
    222		chunk_num++;
    223	}
    224
    225	/* 10.4 upload the last chunk */
    226	addr = dest + chunk_num * CHUNK_SIZE;
    227	p = buf + chunk_num * CHUNK_SIZE;
    228	memcpy(chunk, p, fw_data_len % CHUNK_SIZE);
    229	wl1271_debug(DEBUG_BOOT, "uploading fw last chunk (%zd B) 0x%p to 0x%x",
    230		     fw_data_len % CHUNK_SIZE, p, addr);
    231	ret = wlcore_write(wl, addr, chunk, fw_data_len % CHUNK_SIZE, false);
    232
    233out:
    234	kfree(chunk);
    235	return ret;
    236}
    237
    238int wlcore_boot_upload_firmware(struct wl1271 *wl)
    239{
    240	u32 chunks, addr, len;
    241	int ret = 0;
    242	u8 *fw;
    243
    244	fw = wl->fw;
    245	chunks = be32_to_cpup((__be32 *) fw);
    246	fw += sizeof(u32);
    247
    248	wl1271_debug(DEBUG_BOOT, "firmware chunks to be uploaded: %u", chunks);
    249
    250	while (chunks--) {
    251		addr = be32_to_cpup((__be32 *) fw);
    252		fw += sizeof(u32);
    253		len = be32_to_cpup((__be32 *) fw);
    254		fw += sizeof(u32);
    255
    256		if (len > 300000) {
    257			wl1271_info("firmware chunk too long: %u", len);
    258			return -EINVAL;
    259		}
    260		wl1271_debug(DEBUG_BOOT, "chunk %d addr 0x%x len %u",
    261			     chunks, addr, len);
    262		ret = wl1271_boot_upload_firmware_chunk(wl, fw, len, addr);
    263		if (ret != 0)
    264			break;
    265		fw += len;
    266	}
    267
    268	return ret;
    269}
    270EXPORT_SYMBOL_GPL(wlcore_boot_upload_firmware);
    271
    272int wlcore_boot_upload_nvs(struct wl1271 *wl)
    273{
    274	struct platform_device *pdev = wl->pdev;
    275	struct wlcore_platdev_data *pdev_data = dev_get_platdata(&pdev->dev);
    276	const char *nvs_name = "unknown";
    277	size_t nvs_len, burst_len;
    278	int i;
    279	u32 dest_addr, val;
    280	u8 *nvs_ptr, *nvs_aligned;
    281	int ret;
    282
    283	if (wl->nvs == NULL) {
    284		wl1271_error("NVS file is needed during boot");
    285		return -ENODEV;
    286	}
    287
    288	if (pdev_data && pdev_data->family)
    289		nvs_name = pdev_data->family->nvs_name;
    290
    291	if (wl->quirks & WLCORE_QUIRK_LEGACY_NVS) {
    292		struct wl1271_nvs_file *nvs =
    293			(struct wl1271_nvs_file *)wl->nvs;
    294		/*
    295		 * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz
    296		 * band configurations) can be removed when those NVS files stop
    297		 * floating around.
    298		 */
    299		if (wl->nvs_len == sizeof(struct wl1271_nvs_file) ||
    300		    wl->nvs_len == WL1271_INI_LEGACY_NVS_FILE_SIZE) {
    301			if (nvs->general_params.dual_mode_select)
    302				wl->enable_11a = true;
    303		}
    304
    305		if (wl->nvs_len != sizeof(struct wl1271_nvs_file) &&
    306		    (wl->nvs_len != WL1271_INI_LEGACY_NVS_FILE_SIZE ||
    307		     wl->enable_11a)) {
    308			wl1271_error("%s size is not as expected: %zu != %zu",
    309				     nvs_name, wl->nvs_len,
    310				     sizeof(struct wl1271_nvs_file));
    311			kfree(wl->nvs);
    312			wl->nvs = NULL;
    313			wl->nvs_len = 0;
    314			return -EILSEQ;
    315		}
    316
    317		/* only the first part of the NVS needs to be uploaded */
    318		nvs_len = sizeof(nvs->nvs);
    319		nvs_ptr = (u8 *) nvs->nvs;
    320	} else {
    321		struct wl128x_nvs_file *nvs = (struct wl128x_nvs_file *)wl->nvs;
    322
    323		if (wl->nvs_len == sizeof(struct wl128x_nvs_file)) {
    324			if (nvs->general_params.dual_mode_select)
    325				wl->enable_11a = true;
    326		} else {
    327			wl1271_error("%s size is not as expected: %zu != %zu",
    328				     nvs_name, wl->nvs_len,
    329				     sizeof(struct wl128x_nvs_file));
    330			kfree(wl->nvs);
    331			wl->nvs = NULL;
    332			wl->nvs_len = 0;
    333			return -EILSEQ;
    334		}
    335
    336		/* only the first part of the NVS needs to be uploaded */
    337		nvs_len = sizeof(nvs->nvs);
    338		nvs_ptr = (u8 *)nvs->nvs;
    339	}
    340
    341	/* update current MAC address to NVS */
    342	nvs_ptr[11] = wl->addresses[0].addr[0];
    343	nvs_ptr[10] = wl->addresses[0].addr[1];
    344	nvs_ptr[6] = wl->addresses[0].addr[2];
    345	nvs_ptr[5] = wl->addresses[0].addr[3];
    346	nvs_ptr[4] = wl->addresses[0].addr[4];
    347	nvs_ptr[3] = wl->addresses[0].addr[5];
    348
    349	/*
    350	 * Layout before the actual NVS tables:
    351	 * 1 byte : burst length.
    352	 * 2 bytes: destination address.
    353	 * n bytes: data to burst copy.
    354	 *
    355	 * This is ended by a 0 length, then the NVS tables.
    356	 */
    357
    358	/* FIXME: Do we need to check here whether the LSB is 1? */
    359	while (nvs_ptr[0]) {
    360		burst_len = nvs_ptr[0];
    361		dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8));
    362
    363		/*
    364		 * Due to our new wl1271_translate_reg_addr function,
    365		 * we need to add the register partition start address
    366		 * to the destination
    367		 */
    368		dest_addr += wl->curr_part.reg.start;
    369
    370		/* We move our pointer to the data */
    371		nvs_ptr += 3;
    372
    373		for (i = 0; i < burst_len; i++) {
    374			if (nvs_ptr + 3 >= (u8 *) wl->nvs + nvs_len)
    375				goto out_badnvs;
    376
    377			val = (nvs_ptr[0] | (nvs_ptr[1] << 8)
    378			       | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24));
    379
    380			wl1271_debug(DEBUG_BOOT,
    381				     "nvs burst write 0x%x: 0x%x",
    382				     dest_addr, val);
    383			ret = wlcore_write32(wl, dest_addr, val);
    384			if (ret < 0)
    385				return ret;
    386
    387			nvs_ptr += 4;
    388			dest_addr += 4;
    389		}
    390
    391		if (nvs_ptr >= (u8 *) wl->nvs + nvs_len)
    392			goto out_badnvs;
    393	}
    394
    395	/*
    396	 * We've reached the first zero length, the first NVS table
    397	 * is located at an aligned offset which is at least 7 bytes further.
    398	 * NOTE: The wl->nvs->nvs element must be first, in order to
    399	 * simplify the casting, we assume it is at the beginning of
    400	 * the wl->nvs structure.
    401	 */
    402	nvs_ptr = (u8 *)wl->nvs +
    403			ALIGN(nvs_ptr - (u8 *)wl->nvs + 7, 4);
    404
    405	if (nvs_ptr >= (u8 *) wl->nvs + nvs_len)
    406		goto out_badnvs;
    407
    408	nvs_len -= nvs_ptr - (u8 *)wl->nvs;
    409
    410	/* Now we must set the partition correctly */
    411	ret = wlcore_set_partition(wl, &wl->ptable[PART_WORK]);
    412	if (ret < 0)
    413		return ret;
    414
    415	/* Copy the NVS tables to a new block to ensure alignment */
    416	nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL);
    417	if (!nvs_aligned)
    418		return -ENOMEM;
    419
    420	/* And finally we upload the NVS tables */
    421	ret = wlcore_write_data(wl, REG_CMD_MBOX_ADDRESS, nvs_aligned, nvs_len,
    422				false);
    423
    424	kfree(nvs_aligned);
    425	return ret;
    426
    427out_badnvs:
    428	wl1271_error("nvs data is malformed");
    429	return -EILSEQ;
    430}
    431EXPORT_SYMBOL_GPL(wlcore_boot_upload_nvs);
    432
    433int wlcore_boot_run_firmware(struct wl1271 *wl)
    434{
    435	int loop, ret;
    436	u32 chip_id, intr;
    437
    438	/* Make sure we have the boot partition */
    439	ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
    440	if (ret < 0)
    441		return ret;
    442
    443	ret = wl1271_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT);
    444	if (ret < 0)
    445		return ret;
    446
    447	ret = wlcore_read_reg(wl, REG_CHIP_ID_B, &chip_id);
    448	if (ret < 0)
    449		return ret;
    450
    451	wl1271_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id);
    452
    453	if (chip_id != wl->chip.id) {
    454		wl1271_error("chip id doesn't match after firmware boot");
    455		return -EIO;
    456	}
    457
    458	/* wait for init to complete */
    459	loop = 0;
    460	while (loop++ < INIT_LOOP) {
    461		udelay(INIT_LOOP_DELAY);
    462		ret = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR, &intr);
    463		if (ret < 0)
    464			return ret;
    465
    466		if (intr == 0xffffffff) {
    467			wl1271_error("error reading hardware complete "
    468				     "init indication");
    469			return -EIO;
    470		}
    471		/* check that ACX_INTR_INIT_COMPLETE is enabled */
    472		else if (intr & WL1271_ACX_INTR_INIT_COMPLETE) {
    473			ret = wlcore_write_reg(wl, REG_INTERRUPT_ACK,
    474					       WL1271_ACX_INTR_INIT_COMPLETE);
    475			if (ret < 0)
    476				return ret;
    477			break;
    478		}
    479	}
    480
    481	if (loop > INIT_LOOP) {
    482		wl1271_error("timeout waiting for the hardware to "
    483			     "complete initialization");
    484		return -EIO;
    485	}
    486
    487	/* get hardware config command mail box */
    488	ret = wlcore_read_reg(wl, REG_COMMAND_MAILBOX_PTR, &wl->cmd_box_addr);
    489	if (ret < 0)
    490		return ret;
    491
    492	wl1271_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x", wl->cmd_box_addr);
    493
    494	/* get hardware config event mail box */
    495	ret = wlcore_read_reg(wl, REG_EVENT_MAILBOX_PTR, &wl->mbox_ptr[0]);
    496	if (ret < 0)
    497		return ret;
    498
    499	wl->mbox_ptr[1] = wl->mbox_ptr[0] + wl->mbox_size;
    500
    501	wl1271_debug(DEBUG_MAILBOX, "MBOX ptrs: 0x%x 0x%x",
    502		     wl->mbox_ptr[0], wl->mbox_ptr[1]);
    503
    504	ret = wlcore_boot_static_data(wl);
    505	if (ret < 0) {
    506		wl1271_error("error getting static data");
    507		return ret;
    508	}
    509
    510	/*
    511	 * in case of full asynchronous mode the firmware event must be
    512	 * ready to receive event from the command mailbox
    513	 */
    514
    515	/* unmask required mbox events  */
    516	ret = wl1271_event_unmask(wl);
    517	if (ret < 0) {
    518		wl1271_error("EVENT mask setting failed");
    519		return ret;
    520	}
    521
    522	/* set the working partition to its "running" mode offset */
    523	ret = wlcore_set_partition(wl, &wl->ptable[PART_WORK]);
    524
    525	/* firmware startup completed */
    526	return ret;
    527}
    528EXPORT_SYMBOL_GPL(wlcore_boot_run_firmware);