drivers/nvmem/stm32-bsec-optee-ta.c

Source file repositories/reference/linux-study-clean/drivers/nvmem/stm32-bsec-optee-ta.c

File Facts

System
Linux kernel
Corpus path
drivers/nvmem/stm32-bsec-optee-ta.c
Extension
.c
Size
7637 bytes
Lines
299
Domain
Driver Families
Bucket
drivers/nvmem
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (IS_ERR(shm_buf)) {
			ret = PTR_ERR(shm_buf);
			pr_err("tee_shm_get_va failed for transmit (%d)\n", ret);
		} else {
			/* read data from 32 bits aligned buffer */
			memcpy(buf, &shm_buf[offset % 4], bytes);
		}
	}

	tee_shm_free(shm);

out_tee_session:
	stm32_bsec_ta_close_session(ctx, session_id);

	return ret;
}

/* stm32_bsec_optee_ta_write() - nvmem write access using PTA client driver */
int stm32_bsec_optee_ta_write(struct tee_context *ctx, unsigned int lower,
			      unsigned int offset, void *buf, size_t bytes)
{	struct tee_shm *shm;
	struct tee_ioctl_invoke_arg arg;
	struct tee_param param[2];
	u8 *shm_buf;
	int ret;
	u32 session_id;

	ret = stm32_bsec_ta_open_session(ctx, &session_id);
	if (ret)
		return ret;

	/* Allow only writing complete 32-bits aligned words */
	if ((bytes % 4) || (offset % 4))
		return -EINVAL;

	memset(&arg, 0, sizeof(arg));
	memset(&param, 0, sizeof(param));

	arg.func = PTA_BSEC_WRITE_MEM;
	arg.session = session_id;
	arg.num_params = 2;

	param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT;
	param[0].u.value.a = offset;
	param[0].u.value.b = FUSE_ACCESS;

	shm = tee_shm_alloc_kernel_buf(ctx, bytes);
	if (IS_ERR(shm)) {
		ret = PTR_ERR(shm);
		goto out_tee_session;
	}

	param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT;
	param[1].u.memref.shm = shm;
	param[1].u.memref.size = bytes;

	shm_buf = tee_shm_get_va(shm, 0);
	if (IS_ERR(shm_buf)) {
		ret = PTR_ERR(shm_buf);
		pr_err("tee_shm_get_va failed for transmit (%d)\n", ret);
		tee_shm_free(shm);

		goto out_tee_session;
	}

	memcpy(shm_buf, buf, bytes);

	ret = tee_client_invoke_func(ctx, &arg, param);
	if (ret < 0 || arg.ret != 0) {
		pr_err("TA_BSEC invoke failed TEE err:%#x, ret:%#x\n", arg.ret, ret);
		if (!ret)
			ret = -EIO;
	}
	pr_debug("Write OTPs %d to %zu, ret=%d\n", offset / 4, (offset + bytes) / 4, ret);

	/* Lock the upper OTPs with ECC protection, word programming only */
	if (!ret && ((offset + bytes) >= (lower * 4))) {
		u32 start, nb_lock;
		u32 *lock = (u32 *)shm_buf;
		int i;

		/*
		 * don't lock the lower OTPs, no ECC protection and incremental
		 * bit programming, a second write is allowed
		 */
		start = max_t(u32, offset, lower * 4);
		nb_lock = (offset + bytes - start) / 4;

		param[0].u.value.a = start;
		param[0].u.value.b = LOCK_ACCESS;

Annotation

Implementation Notes