lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <3a3a3e2c-2156-40bb-9233-fc2e6320eaa6@tuxon.dev>
Date: Sun, 14 Sep 2025 18:42:43 +0300
From: Claudiu Beznea <claudiu.beznea@...on.dev>
To: Varshini Rajendran <varshini.rajendran@...rochip.com>,
 eugen.hristev@...aro.org, jic23@...nel.org, dlechner@...libre.com,
 nuno.sa@...log.com, andy@...nel.org, robh@...nel.org, krzk+dt@...nel.org,
 conor+dt@...nel.org, nicolas.ferre@...rochip.com,
 alexandre.belloni@...tlin.com, srini@...nel.org, linux-iio@...r.kernel.org,
 devicetree@...r.kernel.org, linux-arm-kernel@...ts.infradead.org,
 linux-kernel@...r.kernel.org
Subject: Re: [PATCH 02/15] nvmem: microchip-otpc: rework to access packets
 based on tag

Hi, Varshini,

On 8/4/25 13:02, Varshini Rajendran wrote:
> Rework the driver to change the packet access technique based on the TAG
> instead of the currently in use "id".
> 
> Since there is no way of knowing the OTP memory mapping in advance or the
> changes it can go through with time, the id based approach is not reliable.
> Accessing the packets based on the associated tags is a fail-proof
> approach. This method is aided by adding a table of contents to store the
> payload information which makes it easier to traverse through the OTP
> memory and read the data of the intended packet. The stride of the nvmem
> device is adjusted to 1 to support the TAG being treated as an offset.
> The only reliable way to recognize a packet without being aware of the
> flashed contents of the OTP memory is the TAG of the packet.
> 
> Signed-off-by: Varshini Rajendran <varshini.rajendran@...rochip.com>
> ---
>  drivers/nvmem/microchip-otpc.c | 130 +++++++++++++++++++++++++--------
>  1 file changed, 101 insertions(+), 29 deletions(-)
> 
> diff --git a/drivers/nvmem/microchip-otpc.c b/drivers/nvmem/microchip-otpc.c
> index df979e8549fd..e922c882af72 100644
> --- a/drivers/nvmem/microchip-otpc.c
> +++ b/drivers/nvmem/microchip-otpc.c
> @@ -18,16 +18,27 @@
>  #define MCHP_OTPC_CR_READ		BIT(6)
>  #define MCHP_OTPC_MR			(0x4)
>  #define MCHP_OTPC_MR_ADDR		GENMASK(31, 16)
> +#define MCHP_OTPC_MR_EMUL		BIT(7)
>  #define MCHP_OTPC_AR			(0x8)
>  #define MCHP_OTPC_SR			(0xc)
>  #define MCHP_OTPC_SR_READ		BIT(6)
>  #define MCHP_OTPC_HR			(0x20)
>  #define MCHP_OTPC_HR_SIZE		GENMASK(15, 8)
> +#define MCHP_OTPC_HR_PACKET_TYPE	GENMASK(2, 0)
>  #define MCHP_OTPC_DR			(0x24)
>  
>  #define MCHP_OTPC_NAME			"mchp-otpc"
>  #define MCHP_OTPC_SIZE			(11 * 1024)
>  
> +enum packet_type {
> +	PACKET_TYPE_REGULAR = 1,
> +	PACKET_TYPE_KEY	= 2,
> +	PACKET_TYPE_BOOT_CONFIG = 3,
> +	PACKET_TYPE_SECURE_BOOT_CONFIG = 4,
> +	PACKET_TYPE_HARDWARE_CONFIG = 5,
> +	PACKET_TYPE_CUSTOM = 6,

You can drop unused packet types.

> +};
> +
>  /**
>   * struct mchp_otpc - OTPC private data structure
>   * @base: base address
> @@ -42,6 +53,25 @@ struct mchp_otpc {
>  	u32 npackets;
>  };
>  
> +/**
> + * struct mchp_otpc_payload_info - OTP packet's payload information
> + *				retrieved from the packet's header
> + * @id: driver assigned packet ID
> + * @packet_offset: offset address of the packet to be written in the
> + *			register OTPC_MR.ADDR to access the packet
> + * @payload_length: length of the packet's payload
> + * @packet_type: type of the packet
> + * @packet_tag: TAG corresponding to the packet. Applicable for most
> + *		of the regular packets
> + */
> +struct mchp_otpc_payload_info {
> +	u32 id;
> +	u32 packet_offset;

Can you keep packet specific members in struct mchp_otpc_packet?

> +	u32 payload_length;
> +	u32 packet_type;
> +	u32 packet_tag;

Will this technique limit the number of packets that can be in memory? I
think this is not an issue with the current devices? What about the upcomming?

> +};
> +
>  /**
>   * struct mchp_otpc_packet - OTPC packet data structure
>   * @list: list head
> @@ -50,20 +80,16 @@ struct mchp_otpc {
>   */
>  struct mchp_otpc_packet {
>  	struct list_head list;
> -	u32 id;
> -	u32 offset;
> +	struct mchp_otpc_payload_info payload_info;

Warning: ../drivers/nvmem/microchip-otpc.c:83 struct member 'payload_info'
not described in 'mchp_otpc_packet'

>  };
>  
> -static struct mchp_otpc_packet *mchp_otpc_id_to_packet(struct mchp_otpc *otpc,
> -						       u32 id)
> +static struct mchp_otpc_packet *mchp_otpc_tag_to_packet(struct mchp_otpc *otpc,
> +							u32 tag)
>  {
>  	struct mchp_otpc_packet *packet;
>  
> -	if (id >= otpc->npackets)
> -		return NULL;
> -
>  	list_for_each_entry(packet, &otpc->packets, list) {
> -		if (packet->id == id)
> +		if (packet->payload_info.packet_tag == tag)
>  			return packet;
>  	}
>  
> @@ -140,8 +166,27 @@ static int mchp_otpc_prepare_read(struct mchp_otpc *otpc,
>   * offset returned by hardware.
>   *
>   * For this, the read function will return the first requested bytes in the
> - * packet. The user will have to be aware of the memory footprint before doing
> - * the read request.
> + * packet. The user won't have to be aware of the memory footprint before doing
> + * the read request since it is abstracted and taken care by this driver.
> + *
> + * There is no way of knowing the Mapping of the OTP memory table in advance. In
> + * this read function the offset requested is treated as the identifier string
> + * i.e., Packet TAG, to acquire the payload with reliability. The packet Tag
> + * is the only way to recognize a packet without being aware of the flashed
> + * OTP memory map table.
> + */
> +
> +/**
> + * mchp_otpc_read() - Read the OTP packets and fill the buffer based on the TAG
> + *		      of the packet treated as the offset.
> + * @priv: Pointer to device structure.
> + * @off: offset of the OTP packet to be read. In this case, the TAG of the
> + *	 corresponding packet.
> + * @val: Pointer to data buffer
> + * @bytes: length of the buffer
> + *
> + * A value of zero will be returned on success, a negative errno will be
> + * returned in error cases.
>   */
>  static int mchp_otpc_read(void *priv, unsigned int off, void *val,
>  			  size_t bytes)
> @@ -154,30 +199,23 @@ static int mchp_otpc_read(void *priv, unsigned int off, void *val,
>  	int ret, payload_size;
>  
>  	/*
> -	 * We reach this point with off being multiple of stride = 4 to
> -	 * be able to cross the subsystem. Inside the driver we use continuous
> -	 * unsigned integer numbers for packet id, thus divide off by 4
> -	 * before passing it to mchp_otpc_id_to_packet().
> +	 * From this point the packet tag received as the offset has to be translated
> +	 * into the actual packet. For this we traverse the table of contents stored
> +	 * in a list "packet" and look for the tag.
>  	 */
> -	packet = mchp_otpc_id_to_packet(otpc, off / 4);
> +
> +	packet = mchp_otpc_tag_to_packet(otpc, off);
>  	if (!packet)
>  		return -EINVAL;

If one would want to read the full content of the memory will this function
return first time offset will not corresond to a valid packet?

> -	offset = packet->offset;
> +	offset = packet->payload_info.packet_offset;
>  
> -	while (len < bytes) {
> +	if (len < bytes) {

The approach now is that a single packet can be read at a moment, right? Is
this intended?

>  		ret = mchp_otpc_prepare_read(otpc, offset);
>  		if (ret)
>  			return ret;
>  
> -		/* Read and save header content. */
> -		*buf++ = readl_relaxed(otpc->base + MCHP_OTPC_HR);
> -		len += sizeof(*buf);
> -		offset++;
> -		if (len >= bytes)
> -			break;
> -

Dropping this will not return the header content anymore. Is this intended?

>  		/* Read and save payload content. */
> -		payload_size = FIELD_GET(MCHP_OTPC_HR_SIZE, *(buf - 1));
> +		payload_size = packet->payload_info.payload_length;
>  		writel_relaxed(0UL, otpc->base + MCHP_OTPC_AR);
>  		do {
>  			*buf++ = readl_relaxed(otpc->base + MCHP_OTPC_DR);
> @@ -190,6 +228,20 @@ static int mchp_otpc_read(void *priv, unsigned int off, void *val,
>  	return 0;
>  }
>  
> +static int mchp_otpc_read_packet_tag(struct mchp_otpc *otpc, unsigned int offset, unsigned int *val)

This exceeed 100 chars.

> +{
> +	int ret;
> +
> +	ret = mchp_otpc_prepare_read(otpc, offset);
> +	if (ret)
> +		return ret;
> +
> +	writel_relaxed(0UL, otpc->base + MCHP_OTPC_AR);
> +	*val = readl_relaxed(otpc->base + MCHP_OTPC_DR);
> +
> +	return 0;
> +}
> +
>  static int mchp_otpc_init_packets_list(struct mchp_otpc *otpc, u32 *size)
>  {
>  	struct mchp_otpc_packet *packet;
> @@ -213,8 +265,15 @@ static int mchp_otpc_init_packets_list(struct mchp_otpc *otpc, u32 *size)
>  		if (!packet)
>  			return -ENOMEM;
>  
> -		packet->id = id++;
> -		packet->offset = word_pos;
> +		packet->payload_info.id = id++;
> +		packet->payload_info.packet_offset = word_pos;
> +		packet->payload_info.payload_length = payload_size;
> +		packet->payload_info.packet_type = FIELD_GET(MCHP_OTPC_HR_PACKET_TYPE, word);
> +
> +		if (packet->payload_info.packet_type == PACKET_TYPE_REGULAR)
> +			ret = mchp_otpc_read_packet_tag(otpc, packet->payload_info.packet_offset,
> +							&packet->payload_info.packet_tag);
> +
>  		INIT_LIST_HEAD(&packet->list);
>  		list_add_tail(&packet->list, &otpc->packets);
>  
> @@ -236,7 +295,7 @@ static struct nvmem_config mchp_nvmem_config = {
>  	.type = NVMEM_TYPE_OTP,
>  	.read_only = true,
>  	.word_size = 4,
> -	.stride = 4,
> +	.stride = 1,
>  	.reg_read = mchp_otpc_read,
>  };
>  
> @@ -244,8 +303,9 @@ static int mchp_otpc_probe(struct platform_device *pdev)
>  {
>  	struct nvmem_device *nvmem;
>  	struct mchp_otpc *otpc;
> -	u32 size;
> +	u32 size, tmp;
>  	int ret;
> +	bool emul_enable;
>  
>  	otpc = devm_kzalloc(&pdev->dev, sizeof(*otpc), GFP_KERNEL);
>  	if (!otpc)
> @@ -256,10 +316,22 @@ static int mchp_otpc_probe(struct platform_device *pdev)
>  		return PTR_ERR(otpc->base);
>  
>  	otpc->dev = &pdev->dev;
> +
> +	tmp = readl_relaxed(otpc->base + MCHP_OTPC_MR);
> +	emul_enable = tmp & MCHP_OTPC_MR_EMUL;
> +	if (emul_enable)
> +		dev_info(otpc->dev, "Emulation mode enabled\n");

Can you update the commit with the meaning of these?

> +
>  	ret = mchp_otpc_init_packets_list(otpc, &size);
>  	if (ret)
>  		return ret;
>  
> +	if (size == 0) {
> +		dev_err(otpc->dev, "Cannot access OTP memory !\n");

Space before !

> +		if (!emul_enable)
> +			dev_err(otpc->dev, "Boot packet not configured & Emulation mode not enabled !\n");

Do you still want to register the driver in case size == 0?

Thank you,
Claudiu

> +	}
> +
>  	mchp_nvmem_config.dev = otpc->dev;
>  	mchp_nvmem_config.add_legacy_fixed_of_cells = true;
>  	mchp_nvmem_config.size = size;


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ