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 for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <c0445eff-4ee4-5cdf-6e5b-bcdf2504c4c5@linux.intel.com>
Date: Tue, 12 Aug 2025 13:52:04 +0300 (EEST)
From: Ilpo Järvinen <ilpo.jarvinen@...ux.intel.com>
To: Ron Li <xiangrongl@...dia.com>
cc: Hans de Goede <hdegoede@...hat.com>, vadimp@...dia.com, 
    alok.a.tiwari@...cle.com, kblaiech@...dia.com, davthompson@...dia.com, 
    platform-driver-x86@...r.kernel.org, LKML <linux-kernel@...r.kernel.org>
Subject: Re: [PATCH v2 1/4] platform/mellanox/mlxbf_pka: Add mlxbf_pka driver
 for BlueField DPU

On Mon, 11 Aug 2025, Ron Li wrote:

> Add the mlxbf_pka driver to support the BlueField DPU Public Key
> Acceleration (PKA) hardware. The PKA provides a simple, complete
> framework for crypto public key hardware offload. It supports direct
> access to the public key hardware resources from the user space, and
> makes available several arithmetic operations: some basic operations
> (e.g., addition and multiplication), some complex operations (e.g.,
> modular exponentiation and modular inversion), and high-level
> operations such as RSA, Diffie-Hellman, Elliptic Curve Cryptography,
> and the Federal Digital Signature Algorithm (DSA as documented in
> FIPS-186) public-private key systems.
> 
> The PKA driver initializes the PKA hardware interface and implements
> file operations so that user space libraries can bypass the kernel and
> have direct access to a specific set of device registers. The Arm cores
> interface to the PKA hardware through rings and a 64KB memory known as
> Window RAM. There are multiple PKA devices on the BlueField SoC. In
> general, each PKA device has 4 rings, 1 window RAM and 1 True Random
> Number Generator (TRNG). Thus, the driver has been designed to probe
> each PKA and each individual ring inside a given PKA. It also registers
> the TRNG to feed the kernel entropy (i.e., /dev/hwrng). To implement
> such design, the driver creates individual device files for each ring
> and TRNG module. The ring device files are identified using their ids,
> i.e., /dev/mlxbf_pka/<ring_id>.
> 
> The main driver logic such as probe() and remove() are implemented in
> mlxbf_pka_drv.c. The PKA ring device operations are also implemented in
> this source file, such as open(), release() and mmap().
> 
> The mlxbf_pka_dev.c source file implements functions to operate the
> underlying PKA hardware, such as TRNG operation, PKA hardware I/O
> access, PKA memory resource operation, etc.
> 
> The PKA driver is a lightweight driver that implements file operations
> and map memory regions of the PKA hardware to user space drivers and
> libraries. There is no in-kernel crypto support. Therefore, the PKA
> driver is included under drivers/platform/mellanox.
> 
> Testing
> 
> - Successful build of kernel for ARM64.
> 
> - Tested ARM64 build on several Mellanox BlueField 2 and 3 SoC boards
> that include the PKA hardware. The testing includes the validation of
> the PKA hardware execution, random number generation and public key
> acceleration performance.
> 
> Reviewed-by: David Thompson <davthompson@...dia.com>
> Reviewed-by: Khalil Blaiech <kblaiech@...dia.com>
> Signed-off-by: Ron Li <xiangrongl@...dia.com>

> diff --git a/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_dev.c b/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_dev.c
> new file mode 100644
> index 000000000000..3048e7436509
> --- /dev/null
> +++ b/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_dev.c
> @@ -0,0 +1,1941 @@
> +// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause
> +// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION. All rights reserved.
> +
> +#include <linux/bitfield.h>
> +#include <linux/compiler.h>
> +#include <linux/delay.h>
> +#include <linux/device.h>
> +#include <linux/io.h>
> +#include <linux/iopoll.h>
> +#include <linux/ioport.h>
> +#include <linux/kernel.h>
> +#include <linux/math.h>
> +#include <linux/slab.h>
> +#include <linux/string.h>
> +#include <linux/time.h>
> +#include <linux/timex.h>
> +#include <linux/types.h>
> +
> +#include "mlxbf_pka_dev.h"
> +
> +#define MASTER_CONTROLLER_OUT_OF_RESET 0
> +
> +/* Personalization string "NVIDIA-MELLANOX-BLUEFIELD-TRUE_RANDOM_NUMBER_GEN". */
> +static u32 mlxbf_pka_trng_drbg_ps_str[] = {
> +	0x4e564944, 0x49412d4d, 0x454c4c41, 0x4e4f582d,
> +	0x424c5545, 0x4649454c, 0x442d5452, 0x55455f52,
> +	0x414e444f, 0x4d5f4e55, 0x4d424552, 0x5f47454e
> +};
> +
> +/* Personalization string for DRBG test. */
> +static u32 mlxbf_pka_trng_drbg_test_ps_str[] = {
> +	0x64299d83, 0xc34d7098, 0x5bd1f51d, 0xddccfdc1,
> +	0xdd0455b7, 0x166279e5, 0x0974cb1b, 0x2f2cd100,
> +	0x59a5060a, 0xca79940d, 0xd4e29a40, 0x56b7b779
> +};
> +
> +/* First Entropy string for DRBG test. */
> +static u32 mlxbf_pka_trng_drbg_test_etpy_str1[] = {
> +	0xaa6bbcab, 0xef45e339, 0x136ca1e7, 0xbce1c881,
> +	0x9fa37b09, 0x63b53667, 0xb36e0053, 0xa202ed81,
> +	0x4650d90d, 0x8eed6127, 0x666f2402, 0x0dfd3af9
> +};
> +
> +/* Second Entropy string for DRBG test. */
> +static u32 mlxbf_pka_trng_drbg_test_etpy_str2[] = {
> +	0x35c1b7a1, 0x0154c52b, 0xd5777390, 0x226a4fdb,
> +	0x5f16080d, 0x06b68369, 0xd0c93d00, 0x3336e27f,
> +	0x1abf2c37, 0xe6ab006c, 0xa4adc6e1, 0x8e1907a2
> +};
> +
> +/* Known answer for DRBG test. */
> +static u32 mlxbf_pka_trng_drbg_test_output[] = {
> +	0xb663b9f1, 0x24943e13, 0x80f7dce5, 0xaba1a16f
> +};
> +
> +/* Known answer for poker test. */
> +static u64 poker_test_exp_cnt[] = {
> +	0x20f42bf4, 0xaf415f4, 0xf4f4fff4, 0xfff4f4f4
> +};
> +
> +struct mlxbf_pka_dev_gbl_config_t mlxbf_pka_gbl_config;
> +
> +/* Global PKA shim resource info table. */
> +static struct mlxbf_pka_dev_gbl_shim_res_info_t mlxbf_pka_gbl_res_tbl[MLXBF_PKA_MAX_NUM_IO_BLOCKS];
> +
> +/* Start a PKA device timer. */
> +static inline u64 mlxbf_pka_dev_timer_start_msec(u32 msec)
> +{
> +	u64 cur_time = get_cycles();
> +
> +	return (cur_time + (mlxbf_pka_early_cpu_speed() * msec) / MSEC_PER_SEC);

Again, please remove the unnecessary parenthesis.

> +}
> +
> +/* Test a PKA device timer for completion. */
> +static inline bool mlxbf_pka_dev_timer_done(u64 timer)
> +{
> +	return (get_cycles() >= timer);
> +}
> +
> +/* Return register base address. */
> +static inline u64 mlxbf_pka_dev_get_register_base(u64 base, u64 reg_addr)
> +{
> +	return (base + reg_addr) & PAGE_MASK;
> +}
> +
> +/* Return register offset. */
> +static inline u64 mlxbf_pka_dev_get_register_offset(u64 base, u64 reg_addr)
> +{
> +	return (base + reg_addr) & ~PAGE_MASK;
> +}
> +
> +/* Return word offset within io memory. */
> +static inline u64 mlxbf_pka_dev_get_word_offset(u64 mem_base, u64 word_addr, u64 mem_size)
> +{
> +	return (mem_base + word_addr) & (mem_size - 1);
> +}
> +
> +static inline u64 mlxbf_pka_dev_io_read(void __iomem *mem_ptr, u64 mem_off)
> +{
> +	return readq_relaxed(mem_ptr + mem_off);
> +}
> +
> +static inline void mlxbf_pka_dev_io_write(void __iomem *mem_ptr, u64 mem_off, u64 value)
> +{
> +	writeq_relaxed(value, mem_ptr + mem_off);
> +}
> +
> +/*
> + * Mapping PKA Ring address into Window RAM address.
> + * It converts the ring address, either physical address or virtual address, to
> + * valid address into the Window RAM. This is done assuming the Window RAM base,

Where does this "assume" them? Perhaps it should be rephrased?

> + * size and mask. Here, base is the actual physical address of the Window RAM,
> + * with the help of mask it is reduced to Window RAM offset within that PKA
> + * block. Further, with the help of addr and size, we arrive at the Window RAM
> + * offset address for a PKA Ring within the given Window RAM.
> + */
> +static inline u64 mlxbf_pka_ring_mem_addr(u64 base, u64 mask, u64 addr, u64 size)

Could these input variables match better to the comment above the 
function. As per the comment above, my guess is: win_base, win_mask, 
ring_addr, ring_size?

> +{
> +	return ((base) & (mask)) |
> +	       (FIELD_GET(MLXBF_PKA_WINDOW_RAM_RING_ADDR_MASK, addr) |

> +	       (FIELD_GET(MLXBF_PKA_WINDOW_RAM_RING_SIZE_MASK, (addr) & ~((size) - 1)) >>
> +		MLXBF_PKA_WINDOW_RAM_RING_SIZE_SHIFT));

This doesn't look correct conversion, FIELD_GET() will downshift the 
value. I now realize MLXBF_PKA_WINDOW_RAM_RING_SIZE_SHIFT isn't what I 
expected it to be based on its name. I expected it to be the shift value 
for the lowest bit in MLXBF_PKA_WINDOW_RAM_RING_SIZE_MASK (0xF0000), ie., 
16).

This function might actually need BOTH FIELD_GET() and FIELD_PREP().

FIELD_GET() extracts a field from input downshifting it, FIELD_PREP(), on 
the other hand prepares fields in output by upshifting them.

So to me it looks here you have fields in "addr" you want to extract 
(RING ADDR & SIZE). Then, you construct some output by chaining |, each is 
probably a field in some well-defined format not explicitly defined here.
Or can those fields actually overlap (the output field sizes are not 
constant/fixed)? If the field size in the output are not fixed, then 
FIELD_PREP() shouldn't be used for such fields.

TBH, even if you have the long comment above the function, I couldn't 
figure out what this function does and have to guesswork many details.

> +}
> +
> +/* Add the resource to the global resource table. */
> +static int mlxbf_pka_dev_add_resource(struct mlxbf_pka_dev_res_t *res_ptr, u32 shim_idx)
> +{
> +	u8 res_cnt;
> +
> +	res_cnt = mlxbf_pka_gbl_res_tbl[shim_idx].res_cnt;
> +	if (res_cnt >= MLXBF_PKA_DEV_SHIM_RES_CNT)
> +		return -ENOMEM;
> +
> +	mlxbf_pka_gbl_res_tbl[shim_idx].res_tbl[res_cnt] = res_ptr;
> +	mlxbf_pka_gbl_res_tbl[shim_idx].res_cnt++;
> +
> +	return 0;
> +}
> +
> +/* Remove the resource from the global resource table. */
> +static int mlxbf_pka_dev_put_resource(struct mlxbf_pka_dev_res_t *res, u32 shim_idx)
> +{
> +	struct mlxbf_pka_dev_res_t *res_ptr;
> +	u8 res_idx;
> +
> +	for (res_idx = 0; res_idx < MLXBF_PKA_DEV_SHIM_RES_CNT; res_idx++) {
> +		res_ptr = mlxbf_pka_gbl_res_tbl[shim_idx].res_tbl[res_idx];
> +		if (res_ptr && !strcmp(res_ptr->name, res->name)) {

This logic isn't reversed?

> +			mlxbf_pka_gbl_res_tbl[shim_idx].res_tbl[res_idx] = NULL;
> +			mlxbf_pka_gbl_res_tbl[shim_idx].res_cnt--;
> +			break;
> +		}
> +	}
> +
> +	/*
> +	 * Check whether the resource shares the same memory map; If so, the memory
> +	 * map shouldn't be released.
> +	 */
> +	for (res_idx = 0; res_idx < MLXBF_PKA_DEV_SHIM_RES_CNT; res_idx++) {
> +		res_ptr = mlxbf_pka_gbl_res_tbl[shim_idx].res_tbl[res_idx];
> +		if (res_ptr && res_ptr->base == res->base)
> +			return -EBUSY;
> +	}
> +
> +	return 0;
> +}
> +
> +static void __iomem *mlxbf_pka_dev_get_resource_ioaddr(u64 res_base, u32 shim_idx)
> +{
> +	struct mlxbf_pka_dev_res_t *res_ptr;
> +	u8 res_cnt, res_idx;
> +
> +	res_cnt = mlxbf_pka_gbl_res_tbl[shim_idx].res_cnt;
> +	if (!res_cnt)
> +		return NULL;
> +
> +	for (res_idx = 0; res_idx < res_cnt; res_idx++) {
> +		res_ptr = mlxbf_pka_gbl_res_tbl[shim_idx].res_tbl[res_idx];
> +		if (res_ptr->base == res_base)
> +			return res_ptr->ioaddr;
> +	}
> +
> +	return NULL;
> +}
> +
> +/* Set PKA device resource config and map io memory if needed. */
> +static int mlxbf_pka_dev_set_resource_config(struct device *dev,
> +					     struct mlxbf_pka_dev_shim_s *shim,
> +					     struct mlxbf_pka_dev_res_t *res_ptr,
> +					     u64 res_base,
> +					     u64 res_size,
> +					     u64 res_type,
> +					     char *res_name)
> +{
> +	if (res_ptr->status == MLXBF_PKA_DEV_RES_STATUS_MAPPED)
> +		return -EPERM;
> +
> +	switch (res_type) {
> +	case MLXBF_PKA_DEV_RES_TYPE_REG:
> +		res_ptr->base = res_base;
> +		break;
> +	case MLXBF_PKA_DEV_RES_TYPE_MEM:
> +		res_ptr->base = shim->mem_res.eip154_base + res_base;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	res_ptr->size = res_size;
> +	res_ptr->type = res_type;
> +	res_ptr->name = res_name;
> +	res_ptr->status = MLXBF_PKA_DEV_RES_STATUS_UNMAPPED;
> +	res_ptr->ioaddr = mlxbf_pka_dev_get_resource_ioaddr(res_ptr->base, shim->shim_id);
> +	if (!res_ptr->ioaddr) {
> +		if (!devm_request_mem_region(dev, res_ptr->base, res_ptr->size, res_ptr->name)) {
> +			dev_err(dev, "failed to get io memory region\n");
> +			return -EPERM;
> +		}
> +
> +		res_ptr->ioaddr = devm_ioremap(dev, res_ptr->base, res_ptr->size);
> +		if (!res_ptr->ioaddr) {
> +			dev_err(dev, "unable to map io memory into CPU space\n");
> +			return -ENOMEM;
> +		}
> +	}
> +
> +	res_ptr->status = MLXBF_PKA_DEV_RES_STATUS_MAPPED;
> +
> +	if (!res_ptr->ioaddr || mlxbf_pka_dev_add_resource(res_ptr, shim->shim_id)) {
> +		dev_err(dev, "unable to map io memory\n");
> +		return -ENOMEM;
> +	}
> +
> +	return 0;
> +}
> +
> +/* Unset PKA device resource config - unmap io memory if needed. */
> +static void mlxbf_pka_dev_unset_resource_config(struct mlxbf_pka_dev_shim_s *shim,
> +						struct mlxbf_pka_dev_res_t *res_ptr)
> +{
> +	if (res_ptr->status != MLXBF_PKA_DEV_RES_STATUS_MAPPED)
> +		return;
> +
> +	if (!res_ptr->ioaddr)
> +		return;
> +
> +	if (-EBUSY == mlxbf_pka_dev_put_resource(res_ptr, shim->shim_id))
> +		return;
> +
> +	pr_debug("mlxbf_pka: PKA device resource released\n");

dev_dbg(), remove the manual prefix.

> +	res_ptr->status = MLXBF_PKA_DEV_RES_STATUS_UNMAPPED;
> +}
> +
> +int mlxbf_pka_dev_clear_ring_counters(struct mlxbf_pka_dev_ring_t *ring)
> +{
> +	struct mlxbf_pka_dev_res_t *master_seq_ctrl_ptr;
> +	u64 master_reg_base, master_reg_off;
> +	struct mlxbf_pka_dev_shim_s *shim;
> +	void __iomem *master_reg_ptr;
> +
> +	shim = ring->shim;
> +	master_seq_ctrl_ptr = &shim->resources.master_seq_ctrl;
> +	master_reg_base = master_seq_ctrl_ptr->base;
> +	master_reg_ptr = master_seq_ctrl_ptr->ioaddr;
> +	master_reg_off = mlxbf_pka_dev_get_register_offset(master_reg_base,
> +							   MLXBF_PKA_MASTER_SEQ_CTRL_ADDR);
> +
> +	/* Push the EIP-154 master controller into reset. */
> +	mlxbf_pka_dev_io_write(master_reg_ptr, master_reg_off, MLXBF_PKA_MASTER_SEQ_CTRL_RESET);
> +
> +	/* Clear counters. */
> +	mlxbf_pka_dev_io_write(master_reg_ptr, master_reg_off,
> +			       MLXBF_PKA_MASTER_SEQ_CTRL_CLEAR_COUNTERS);
> +
> +	/* Take the EIP-154 master controller out of reset. */
> +	mlxbf_pka_dev_io_write(master_reg_ptr, master_reg_off, MASTER_CONTROLLER_OUT_OF_RESET);
> +
> +	return 0;
> +}
> +
> +/*
> + * Initialize ring. Set ring parameters and configure ring resources. It returns
> + * 0 on success, a negative error code on failure.
> + */
> +static int mlxbf_pka_dev_init_ring(struct device *dev,
> +				   struct mlxbf_pka_dev_ring_t *ring,
> +				   u32 ring_id,
> +				   struct mlxbf_pka_dev_shim_s *shim)
> +{
> +	struct mlxbf_pka_dev_res_t *ring_window_ram_ptr;
> +	struct mlxbf_pka_dev_res_t *ring_info_words_ptr;
> +	struct mlxbf_pka_dev_res_t *ring_counters_ptr;
> +	u8 window_ram_split;
> +	u32 ring_words_off;
> +	u32 ring_cntrs_off;
> +	u32 ring_mem_base;
> +	u32 ring_mem_off;
> +	u32 shim_ring_id;
> +
> +	if (ring->status != MLXBF_PKA_DEV_RING_STATUS_UNDEFINED) {
> +		dev_err(dev, "PKA ring must be undefined\n");
> +		return -EPERM;
> +	}
> +
> +	if (ring_id > MLXBF_PKA_MAX_NUM_RINGS - 1) {
> +		dev_err(dev, "invalid ring identifier\n");
> +		return -EINVAL;
> +	}
> +
> +	ring->ring_id = ring_id;
> +	ring->shim = shim;
> +	ring->resources_num = MLXBF_PKA_MAX_NUM_RING_RESOURCES;
> +	shim_ring_id = ring_id % MLXBF_PKA_MAX_NUM_IO_BLOCK_RINGS;
> +	shim->rings[shim_ring_id] = ring;
> +
> +	/* Configure ring information control/status words resource. */
> +	ring_info_words_ptr = &ring->resources.info_words;
> +	ring_words_off = shim_ring_id * MLXBF_PKA_RING_WORDS_SPACING;
> +	ring_info_words_ptr->base = ring_words_off + shim->mem_res.eip154_base +
> +				    MLXBF_PKA_RING_WORDS_ADDR;
> +	ring_info_words_ptr->size = MLXBF_PKA_RING_WORDS_SIZE;
> +	ring_info_words_ptr->type = MLXBF_PKA_DEV_RES_TYPE_MEM;
> +	ring_info_words_ptr->status = MLXBF_PKA_DEV_RES_STATUS_UNMAPPED;
> +	ring_info_words_ptr->name = "MLXBF_PKA_RING_INFO";
> +
> +	/* Configure ring counters registers resource. */
> +	ring_counters_ptr = &ring->resources.counters;
> +	ring_cntrs_off = shim_ring_id * MLXBF_PKA_RING_CNTRS_SPACING;
> +	ring_counters_ptr->base = ring_cntrs_off + shim->mem_res.eip154_base +
> +				  MLXBF_PKA_RING_CNTRS_ADDR;
> +	ring_counters_ptr->size = MLXBF_PKA_RING_CNTRS_SIZE;
> +	ring_counters_ptr->type = MLXBF_PKA_DEV_RES_TYPE_REG;
> +	ring_counters_ptr->status = MLXBF_PKA_DEV_RES_STATUS_UNMAPPED;
> +	ring_counters_ptr->name = "MLXBF_PKA_RING_CNTRS";
> +
> +	/* Configure ring window RAM resource. */
> +	window_ram_split = shim->window_ram_split;
> +	if (window_ram_split == MLXBF_PKA_SHIM_WINDOW_RAM_SPLIT_ENABLED) {
> +		ring_mem_off = shim_ring_id * MLXBF_PKA_RING_MEM_1_SPACING;
> +		ring_mem_base = ring_mem_off + shim->mem_res.alt_wndw_ram_0_base;
> +	} else {
> +		ring_mem_off = shim_ring_id * MLXBF_PKA_RING_MEM_0_SPACING;
> +		ring_mem_base = ring_mem_off + shim->mem_res.wndw_ram_base;
> +	}
> +
> +	ring_window_ram_ptr = &ring->resources.window_ram;
> +	ring_window_ram_ptr->base = ring_mem_base;
> +	ring_window_ram_ptr->size = MLXBF_PKA_RING_MEM_SIZE;
> +	ring_window_ram_ptr->type = MLXBF_PKA_DEV_RES_TYPE_MEM;
> +	ring_window_ram_ptr->status = MLXBF_PKA_DEV_RES_STATUS_UNMAPPED;
> +	ring_window_ram_ptr->name = "MLXBF_PKA_RING_WINDOW";
> +
> +	ring->ring_info = devm_kzalloc(dev, sizeof(*ring->ring_info), GFP_KERNEL);
> +	if (!ring->ring_info)
> +		return -ENOMEM;
> +
> +	mutex_init(&ring->mutex);

I don't see my comment being addressed here...

> +	ring->status = MLXBF_PKA_DEV_RING_STATUS_INITIALIZED;
> +
> +	return 0;
> +}
> +
> +/* Release a given Ring. */
> +static int mlxbf_pka_dev_release_ring(struct mlxbf_pka_dev_ring_t *ring)
> +{
> +	struct mlxbf_pka_dev_shim_s *shim;
> +	u32 shim_ring_id;
> +
> +	if (ring->status == MLXBF_PKA_DEV_RING_STATUS_UNDEFINED)
> +		return 0;
> +
> +	if (ring->status == MLXBF_PKA_DEV_RING_STATUS_BUSY) {
> +		pr_err("mlxbf_pka error: PKA ring is busy\n");
> +		return -EBUSY;
> +	}
> +
> +	shim = ring->shim;
> +
> +	if (shim->status == MLXBF_PKA_SHIM_STATUS_RUNNING) {
> +		pr_err("mlxbf_pka error: PKA shim is running\n");

...nor here.

I'll stop here. It's inaccetable to claim you did address all my other 
comments while you clearly haven't. :-(

Please go through all my comments against v1 and act on them. Thanks.

--
 i.

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ