[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <8abccdcc-ad40-8f08-457b-d5567aee7083@linux.intel.com>
Date: Thu, 6 Nov 2025 16:17:34 +0200 (EET)
From: Ilpo Järvinen <ilpo.jarvinen@...ux.intel.com>
To: Ron Li <xiangrongl@...dia.com>, Herbert Xu <herbert@...dor.apana.org.au>,
"David S. Miller" <davem@...emloft.net>, linux-crypto@...r.kernel.org
cc: 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 v3 1/3] platform/mellanox/mlxbf_pka: Add core BlueField
PKA platform driver
On Fri, 19 Sep 2025, Ron Li wrote:
> Add the initial 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.
Hi,
Before I spend more time on this, I dug up your earlier reply:
https://lore.kernel.org/all/DS7PR12MB57191E5CCC239A43370B8729A999A@DS7PR12MB5719.namprd12.prod.outlook.com/
You stated there:
"This PKA module is a platform-specific implementation that allows user
space drivers to read/write the BlueField PKA hardware registers. It
doesn’t offer any crypto service to the kernel or implement any crypto
API."
Yet, crypto operations ARE provided (to user space), is that correct?
Crypto API also has an user spac interface [1] so to me it looks here
you're trying to build another interface that provides user space crypto
services but is independent of crypto API?
[1] Documentation/crypto/userspace-if.rst
--
i.
> This patch wires up the platform driver and the device/shim layer:
>
> - ACPI matching for BF1/BF2/BF3 (MLNXBF10/20/51)
> - Probe flow to verify boot status, discover EIP154, Window RAM, alt Window RAM,
> and CSR resources
> - Register a PKA "shim" via the device layer, which maps resources and tracks
> per-shim state
> - Provide shim lifecycle helpers (register/unregister)
>
> This driver is placed under drivers/platform/mellanox as it exposes platform
> resources and does not provide in-kernel crypto offload.
>
> Reviewed-by: David Thompson <davthompson@...dia.com>
> Reviewed-by: Khalil Blaiech <kblaiech@...dia.com>
> Signed-off-by: Ron Li <xiangrongl@...dia.com>
> ---
> .../ABI/testing/sysfs-platform-mellanox-pka | 16 +
> MAINTAINERS | 8 +
> drivers/platform/mellanox/Kconfig | 10 +
> drivers/platform/mellanox/Makefile | 1 +
> drivers/platform/mellanox/mlxbf_pka/Makefile | 10 +
> .../mellanox/mlxbf_pka/mlxbf_pka_dev.c | 395 +++++++++++++++++
> .../mellanox/mlxbf_pka/mlxbf_pka_dev.h | 298 +++++++++++++
> .../mellanox/mlxbf_pka/mlxbf_pka_drv.c | 413 ++++++++++++++++++
> 8 files changed, 1151 insertions(+)
> create mode 100644 Documentation/ABI/testing/sysfs-platform-mellanox-pka
> create mode 100644 drivers/platform/mellanox/mlxbf_pka/Makefile
> create mode 100644 drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_dev.c
> create mode 100644 drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_dev.h
> create mode 100644 drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_drv.c
>
> diff --git a/Documentation/ABI/testing/sysfs-platform-mellanox-pka b/Documentation/ABI/testing/sysfs-platform-mellanox-pka
> new file mode 100644
> index 000000000000..cf8dd292c781
> --- /dev/null
> +++ b/Documentation/ABI/testing/sysfs-platform-mellanox-pka
> @@ -0,0 +1,16 @@
> +What: /sys/devices/platform/<pka-device-id>/<pka-ring-device-id>
> +Date: Oct 2025
> +KernelVersion: 6.18
> +Contact: "Ron Li <xiangrongl@...dia.com>"
> +Description:
> + The mlxbf_pka driver to support the BlueField SoC Public Key Acceleration (PKA)
> + hardware. It supports direct access to the public key hardware resources from the
> + user space.
> +
> + There are three PKA device IDs that support different BlueField product:
> +
> + =========== ==============================================
> + BlueField-1 MLNXBF10:xx, where xx ranges from '00' to '03'
> + BlueField-2 MLNXBF20:xx, where xx ranges from '00' to '07'
> + BlueField-3 MLNXBF51:xx, where xx ranges from '00' to '17'
> + =========== ==============================================
> diff --git a/MAINTAINERS b/MAINTAINERS
> index f6206963efbf..64b995b16d1a 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -15755,6 +15755,14 @@ L: linux-i2c@...r.kernel.org
> S: Supported
> F: drivers/i2c/busses/i2c-mlxbf.c
>
> +MELLANOX BLUEFIELD PKA DRIVER
> +M: Ron Li <xiangrongl@...dia.com>
> +M: Khalil Blaiech <kblaiech@...dia.com>
> +L: platform-driver-x86@...r.kernel.org
> +S: Supported
> +F: Documentation/ABI/testing/sysfs-platform-mellanox-pka
> +F: drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_*
> +
> MELLANOX ETHERNET DRIVER (mlx4_en)
> M: Tariq Toukan <tariqt@...dia.com>
> L: netdev@...r.kernel.org
> diff --git a/drivers/platform/mellanox/Kconfig b/drivers/platform/mellanox/Kconfig
> index e3afbe62c7f6..b09681c137e6 100644
> --- a/drivers/platform/mellanox/Kconfig
> +++ b/drivers/platform/mellanox/Kconfig
> @@ -121,4 +121,14 @@ config NVSW_SN2201
> C3338R which is one of the Denverton product families.
> System equipped with Nvidia®Spectrum-1 32x100GbE Ethernet switch.
>
> +config MLXBF_PKA
> + tristate "Mellanox BlueField Public Key Accelerator driver"
> + depends on ARM64 && ACPI
> + help
> + If you say yes to this option, support will be included for the
> + Public Key Accelerator device on Mellanox BlueField SoCs.
> +
> + This driver can also be built as a module. If so, the module will
> + be called pka-mlxbf.
> +
> endif # MELLANOX_PLATFORM
> diff --git a/drivers/platform/mellanox/Makefile b/drivers/platform/mellanox/Makefile
> index e86723b44c2e..a6535959cde4 100644
> --- a/drivers/platform/mellanox/Makefile
> +++ b/drivers/platform/mellanox/Makefile
> @@ -5,6 +5,7 @@
> #
> obj-$(CONFIG_MLX_PLATFORM) += mlx-platform.o
> obj-$(CONFIG_MLXBF_BOOTCTL) += mlxbf-bootctl.o
> +obj-$(CONFIG_MLXBF_PKA) += mlxbf_pka/
> obj-$(CONFIG_MLXBF_PMC) += mlxbf-pmc.o
> obj-$(CONFIG_MLXBF_TMFIFO) += mlxbf-tmfifo.o
> obj-$(CONFIG_MLXREG_DPU) += mlxreg-dpu.o
> diff --git a/drivers/platform/mellanox/mlxbf_pka/Makefile b/drivers/platform/mellanox/mlxbf_pka/Makefile
> new file mode 100644
> index 000000000000..67465a63edb8
> --- /dev/null
> +++ b/drivers/platform/mellanox/mlxbf_pka/Makefile
> @@ -0,0 +1,10 @@
> +# SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause
> +# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION. All rights reserved.
> +#
> +# Mellanox BlueField PKA Driver
> +#
> +
> +obj-$(CONFIG_MLXBF_PKA) += mlxbf-pka.o
> +
> +mlxbf-pka-objs := mlxbf_pka_drv.o
> +mlxbf-pka-objs += mlxbf_pka_dev.o
> 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..0a5db1be6eaa
> --- /dev/null
> +++ b/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_dev.c
> @@ -0,0 +1,395 @@
> +// 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"
> +
> +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];
> +
> +/* 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))
> + continue;
> +
> + 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. */
> +void mlxbf_pka_dev_unset_resource_config(struct device *dev,
> + 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;
> +
> + dev_dbg(dev, "PKA device resource released\n");
> + res_ptr->status = MLXBF_PKA_DEV_RES_STATUS_UNMAPPED;
> +}
> +
> +/*
> + * mlxbf_pka_dev_create_shim - Create shim.
> + *
> + * Set shim parameters and configure shim resources.
> + *
> + * Return: 0 on success, a negative error code on failure.
> + */
> +static int mlxbf_pka_dev_create_shim(struct device *dev,
> + struct mlxbf_pka_dev_shim_s *shim,
> + u32 shim_id,
> + u8 split,
> + struct mlxbf_pka_dev_mem_res *mem_res)
> +{
> + u64 reg_base;
> + u64 reg_size;
> + int ret;
> +
> + if (shim->status == MLXBF_PKA_SHIM_STATUS_CREATED)
> + return 0;
> +
> + if (shim->status != MLXBF_PKA_SHIM_STATUS_UNDEFINED) {
> + dev_err(dev, "PKA device must be undefined\n");
> + return -EPERM;
> + }
> +
> + if (shim_id > MLXBF_PKA_MAX_NUM_IO_BLOCKS - 1) {
> + dev_err(dev, "invalid shim identifier\n");
> + return -EINVAL;
> + }
> +
> + shim->shim_id = shim_id;
> + shim->mem_res = *mem_res;
> +
> + if (split)
> + shim->window_ram_split = MLXBF_PKA_SHIM_WINDOW_RAM_SPLIT_ENABLED;
> + else
> + shim->window_ram_split = MLXBF_PKA_SHIM_WINDOW_RAM_SPLIT_DISABLED;
> +
> + /* Set PKA device Buffer RAM config. */
> + ret = mlxbf_pka_dev_set_resource_config(dev,
> + shim,
> + &shim->resources.buffer_ram,
> + MLXBF_PKA_BUFFER_RAM_BASE,
> + MLXBF_PKA_BUFFER_RAM_SIZE,
> + MLXBF_PKA_DEV_RES_TYPE_MEM,
> + "MLXBF_PKA_BUFFER_RAM");
> + if (ret) {
> + dev_err(dev, "unable to set Buffer RAM config\n");
> + return ret;
> + }
> +
> + /* Set PKA device Master Controller register. */
> + reg_size = PAGE_SIZE;
> + reg_base = mlxbf_pka_dev_get_register_base(shim->mem_res.eip154_base,
> + MLXBF_PKA_MASTER_SEQ_CTRL_ADDR);
> + ret = mlxbf_pka_dev_set_resource_config(dev,
> + shim,
> + &shim->resources.master_seq_ctrl,
> + reg_base,
> + reg_size,
> + MLXBF_PKA_DEV_RES_TYPE_REG,
> + "MLXBF_PKA_MASTER_SEQ_CTRL");
> + if (ret) {
> + dev_err(dev, "unable to set Master Controller register config\n");
> + return ret;
> + }
> +
> + /* Set PKA device AIC registers. */
> + reg_size = PAGE_SIZE;
> + reg_base = mlxbf_pka_dev_get_register_base(shim->mem_res.eip154_base,
> + MLXBF_PKA_AIC_POL_CTRL_ADDR);
> + ret = mlxbf_pka_dev_set_resource_config(dev,
> + shim,
> + &shim->resources.aic_csr,
> + reg_base,
> + reg_size,
> + MLXBF_PKA_DEV_RES_TYPE_REG,
> + "MLXBF_PKA_AIC_CSR");
> + if (ret) {
> + dev_err(dev, "unable to set AIC registers config\n");
> + return ret;
> + }
> +
> + shim->status = MLXBF_PKA_SHIM_STATUS_CREATED;
> +
> + return ret;
> +}
> +
> +/* Delete shim and unset shim resources. */
> +static int mlxbf_pka_dev_delete_shim(struct device *dev, struct mlxbf_pka_dev_shim_s *shim)
> +{
> + struct mlxbf_pka_dev_res_t *res_master_seq_ctrl, *res_aic_csr;
> + struct mlxbf_pka_dev_res_t *res_buffer_ram;
> +
> + dev_dbg(dev, "PKA device delete shim\n");
> +
> + if (shim->status == MLXBF_PKA_SHIM_STATUS_UNDEFINED)
> + return 0;
> +
> + if (shim->status != MLXBF_PKA_SHIM_STATUS_FINALIZED &&
> + shim->status != MLXBF_PKA_SHIM_STATUS_CREATED) {
> + dev_err(dev, "PKA device status must be finalized\n");
> + return -EPERM;
> + }
> +
> + res_buffer_ram = &shim->resources.buffer_ram;
> + res_master_seq_ctrl = &shim->resources.master_seq_ctrl;
> + res_aic_csr = &shim->resources.aic_csr;
> +
> + mlxbf_pka_dev_unset_resource_config(dev, shim, res_buffer_ram);
> + mlxbf_pka_dev_unset_resource_config(dev, shim, res_master_seq_ctrl);
> + mlxbf_pka_dev_unset_resource_config(dev, shim, res_aic_csr);
> +
> + shim->status = MLXBF_PKA_SHIM_STATUS_UNDEFINED;
> +
> + return 0;
> +}
> +
> +/*
> + * Initialize PKA IO block referred to as shim. It configures shim's
> + * parameters and prepares resources by mapping corresponding memory. The
> + * function also configures shim registers and loads firmware to shim
> + * internal rams. The struct mlxbf_pka_dev_shim_s passed as input is also
> + * an output. It returns 0 on success, a negative error code on failure.
> + */
> +static int mlxbf_pka_dev_init_shim(struct device *dev, struct mlxbf_pka_dev_shim_s *shim)
> +{
> + int ret;
> +
> + if (shim->status != MLXBF_PKA_SHIM_STATUS_CREATED) {
> + dev_err(dev, "PKA device must be created\n");
> + return -EPERM;
> + }
> +
> + ret = devm_mutex_init(dev, &shim->mutex);
> + if (ret)
> + return ret;
> +
> + shim->status = MLXBF_PKA_SHIM_STATUS_INITIALIZED;
> +
> + return ret;
> +}
> +
> +/* Release a given shim. */
> +static int mlxbf_pka_dev_release_shim(struct device *dev, struct mlxbf_pka_dev_shim_s *shim)
> +{
> + int ret = 0;
> +
> + if (shim->status != MLXBF_PKA_SHIM_STATUS_INITIALIZED &&
> + shim->status != MLXBF_PKA_SHIM_STATUS_STOPPED) {
> + dev_err(dev, "PKA device must be initialized or stopped\n");
> + return -EPERM;
> + }
> +
> + shim->status = MLXBF_PKA_SHIM_STATUS_FINALIZED;
> +
> + return ret;
> +}
> +
> +/* Return the shim associated with the given identifier. */
> +struct mlxbf_pka_dev_shim_s *mlxbf_pka_dev_get_shim(u32 shim_id)
> +{
> + return mlxbf_pka_gbl_config.dev_shims[shim_id];
> +}
> +
> +int mlxbf_pka_dev_register_shim(struct device *dev,
> + u32 shim_id,
> + struct mlxbf_pka_dev_mem_res *mem_res,
> + struct mlxbf_pka_dev_shim_s **shim)
> +{
> + struct mlxbf_pka_dev_shim_s *shim_ptr;
> + u8 split;
> + int ret;
> +
> + if (!shim)
> + return -EINVAL;
> +
> + dev_dbg(dev, "register shim id=%u\n", shim_id);
> +
> + shim_ptr = devm_kzalloc(dev, sizeof(*shim_ptr), GFP_KERNEL);
> + if (!shim_ptr)
> + return -ENOMEM;
> +
> + /*
> + * Shim state MUST be set to undefined before calling
> + * 'mlxbf_pka_dev_create_shim' function.
> + */
> + shim_ptr->status = MLXBF_PKA_SHIM_STATUS_UNDEFINED;
> +
> + /* Set the Window RAM user mode. */
> + split = MLXBF_PKA_SPLIT_WINDOW_RAM_MODE;
> +
> + /* Create PKA shim. */
> + ret = mlxbf_pka_dev_create_shim(dev, shim_ptr, shim_id, split, mem_res);
> + if (ret) {
> + dev_err(dev, "failed to create shim %u\n", shim_id);
> + mlxbf_pka_dev_delete_shim(dev, shim_ptr);
> + goto exit_create_shim;
> + }
> +
> + /* Initialize PKA shim. */
> + ret = mlxbf_pka_dev_init_shim(dev, shim_ptr);
> + if (ret) {
> + dev_err(dev, "failed to init shim %u\n", shim_id);
> + goto exit_init_shim;
> + }
> +
> + mlxbf_pka_gbl_config.dev_shims[shim_ptr->shim_id] = shim_ptr;
> + mlxbf_pka_gbl_config.dev_shims_cnt += 1;
> +
> + *shim = shim_ptr;
> + return 0;
> +
> +exit_init_shim:
> + mlxbf_pka_dev_release_shim(dev, shim_ptr);
> +
> +exit_create_shim:
> + mlxbf_pka_dev_delete_shim(dev, shim_ptr);
> + return ret;
> +}
> +
> +int mlxbf_pka_dev_unregister_shim(struct device *dev, struct mlxbf_pka_dev_shim_s *shim)
> +{
> + int ret;
> +
> + if (!shim)
> + return -EINVAL;
> +
> + mlxbf_pka_gbl_config.dev_shims[shim->shim_id] = NULL;
> + mlxbf_pka_gbl_config.dev_shims_cnt -= 1;
> +
> + /* Release shim. */
> + ret = mlxbf_pka_dev_release_shim(dev, shim);
> + if (ret)
> + return ret;
> +
> + /* Delete shim. */
> + return mlxbf_pka_dev_delete_shim(dev, shim);
> +}
> diff --git a/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_dev.h b/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_dev.h
> new file mode 100644
> index 000000000000..df51202f79bd
> --- /dev/null
> +++ b/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_dev.h
> @@ -0,0 +1,298 @@
> +/* SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause */
> +/* SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION. All rights reserved. */
> +
> +#ifndef __MLXBF_PKA_DEV_H__
> +#define __MLXBF_PKA_DEV_H__
> +
> +/*
> + * @file
> + *
> + * API to handle the PKA EIP-154 I/O block (shim). It provides functions and
> + * data structures to initialize and configure the PKA shim. It's the "southband
> + * interface" for communication with PKA hardware resources.
> + */
> +
> +#include <linux/bitfield.h>
> +#include <linux/bits.h>
> +#include <linux/ioctl.h>
> +#include <linux/mutex.h>
> +#include <linux/sizes.h>
> +#include <linux/types.h>
> +#include <linux/units.h>
> +
> +#define MASTER_CONTROLLER_OUT_OF_RESET 0
> +
> +/* PKA address related definitions. */
> +
> +/*
> + * Global Control Space CSR addresses/offsets. These are accessed from the ARM
> + * as 8 byte reads/writes. However only the bottom 32 bits are implemented.
> + */
> +#define MLXBF_PKA_CLK_FORCE_ADDR 0x11C80
> +
> +/*
> + * Advanced Interrupt Controller CSR addresses/offsets. These are accessed from
> + * the ARM as 8 byte reads/writes. However only the bottom 32 bits are
> + * implemented.
> + */
> +#define MLXBF_PKA_AIC_POL_CTRL_ADDR 0x11E00
> +
> +/*
> + * Control register address/offset. This is accessed from the ARM using 8 byte
> + * reads/writes. However only the bottom 32 bits are implemented.
> + */
> +#define MLXBF_PKA_MASTER_SEQ_CTRL_ADDR 0x27F90
> +
> +/* PKA buffer RAM */
> +#define MLXBF_PKA_BUFFER_RAM_BASE 0x00000
> +#define MLXBF_PKA_BUFFER_RAM_SIZE SZ_16K
> +
> +/*
> + * PKA Buffer RAM offsets. These are NOT real CSR's but instead are specific
> + * offset/addresses within the EIP154 MLXBF_PKA_BUFFER_RAM.
> + */
> +
> +/* Alternate Window RAM size. */
> +#define MLXBF_PKA_WINDOW_RAM_REGION_SIZE SZ_16K
> +
> +/* PKA configuration related definitions. */
> +
> +/* The maximum number of PKA shims referred to as IO blocks. */
> +#define MLXBF_PKA_MAX_NUM_IO_BLOCKS 24
> +
> +/*
> + * PKA Window RAM parameters.
> + * Define whether to split window RAM during PKA device creation phase.
> + */
> +#define MLXBF_PKA_SPLIT_WINDOW_RAM_MODE 0
> +
> +/* Defines for window RAM partition, valid for 16K memory. */
> +#define MLXBF_PKA_WINDOW_RAM_DATA_MEM_SIZE 0x3800 /* 14KB. */
> +
> +/* Window RAM/Alternate window RAM offset mask for BF1 and BF2. */
> +#define MLXBF_PKA_WINDOW_RAM_OFFSET_BF1_BF2_MASK (GENMASK(17, 16) | GENMASK(22, 20))
> +
> +/* Window RAM/Alternate window RAM offset mask for BF3. */
> +#define MLXBF_PKA_WINDOW_RAM_OFFSET_BF3_MASK GENMASK(18, 16)
> +
> +/*
> + * PKA Master Sequencer Control/Status Register.
> + * Writing '1' to bit [31] puts the Master controller Sequencer in a reset
> + * state. Resetting the Sequencer (in order to load other firmware) should
> + * only be done when the EIP-154 is not performing any operations.
> + */
> +#define MLXBF_PKA_MASTER_SEQ_CTRL_RESET BIT(31)
> +/*
> + * Writing '1' to bit [30] will reset all Command and Result counters. This bit
> + * is write-only and self clearing and can only be set if the 'Reset' bit [31]
> + * is '1'.
> + */
> +#define MLXBF_PKA_MASTER_SEQ_CTRL_CLEAR_COUNTERS BIT(30)
> +
> +/**
> + * struct mlxbf_pka_dev_res_t - Device resource structure
> + * @ioaddr: The (iore)mapped version of addr, driver internal use
> + * @base: Base address of the device's resource
> + * @size: Size of IO
> + * @type: Type of resource addr points to
> + * @status: Status of the resource
> + * @name: Name of the resource
> + */
> +struct mlxbf_pka_dev_res_t {
> + void __iomem *ioaddr;
> + u64 base;
> + u64 size;
> + u8 type;
> + s8 status;
> + char *name;
> +};
> +
> +/* Defines for mlxbf_pka_dev_res->type. */
> +#define MLXBF_PKA_DEV_RES_TYPE_MEM 1 /* Resource type is memory. */
> +#define MLXBF_PKA_DEV_RES_TYPE_REG 2 /* Resource type is register. */
> +
> +/* Defines for mlxbf_pka_dev_res->status. */
> +#define MLXBF_PKA_DEV_RES_STATUS_MAPPED 1 /* The resource is (iore)mapped. */
> +#define MLXBF_PKA_DEV_RES_STATUS_UNMAPPED -1 /* The resource is unmapped. */
> +
> +/**
> + * struct mlxbf_pka_dev_shim_res_t - PKA Shim resources structure
> + * @buffer_ram: Buffer RAM
> + * @master_seq_ctrl: Master sequencer controller CSR
> + * @aic_csr: Interrupt controller CSRs
> + */
> +struct mlxbf_pka_dev_shim_res_t {
> + struct mlxbf_pka_dev_res_t buffer_ram;
> + struct mlxbf_pka_dev_res_t master_seq_ctrl;
> + struct mlxbf_pka_dev_res_t aic_csr;
> +};
> +
> +/* Number of PKA device resources. */
> +#define MLXBF_PKA_DEV_SHIM_RES_CNT 6
> +
> +/* Platform global shim resource information. */
> +struct mlxbf_pka_dev_gbl_shim_res_info_t {
> + struct mlxbf_pka_dev_res_t *res_tbl[MLXBF_PKA_DEV_SHIM_RES_CNT];
> + u8 res_cnt;
> +};
> +
> +/**
> + * struct mlxbf_pka_dev_mem_res - PKA device memory resources
> + * @eip154_base: Base address for EIP154 mmio registers
> + * @eip154_size: EIP154 mmio register region size
> + * @wndw_ram_off_mask: Common offset mask for alt window RAM and window RAM
> + * @wndw_ram_base: Base address for window RAM
> + * @wndw_ram_size: Window RAM region size
> + * @alt_wndw_ram_0_base: Base address for alternate window RAM 0
> + * @alt_wndw_ram_1_base: Base address for alternate window RAM 1
> + * @alt_wndw_ram_2_base: Base address for alternate window RAM 2
> + * @alt_wndw_ram_3_base: Base address for alternate window RAM 3
> + * @alt_wndw_ram_size: Alternate window RAM regions size
> + * @csr_base: Base address for CSR registers
> + * @csr_size: CSR area size
> + */
> +struct mlxbf_pka_dev_mem_res {
> + u64 eip154_base;
> + u64 eip154_size;
> +
> + u64 wndw_ram_off_mask;
> + u64 wndw_ram_base;
> + u64 wndw_ram_size;
> +
> + u64 alt_wndw_ram_0_base;
> + u64 alt_wndw_ram_1_base;
> + u64 alt_wndw_ram_2_base;
> + u64 alt_wndw_ram_3_base;
> + u64 alt_wndw_ram_size;
> +
> + u64 csr_base;
> + u64 csr_size;
> +};
> +
> +/**
> + * struct mlxbf_pka_dev_shim_s - PKA Shim structure
> + * @mem_res: Memory resources
> + * @shim_id: Shim identifier
> + * @resources: Shim resources
> + * @window_ram_split: If non-zero, the split window RAM scheme is used
> + * @status: Status of the shim
> + * @mutex: Mutex lock for sharing shim
> + */
> +struct mlxbf_pka_dev_shim_s {
> + struct mlxbf_pka_dev_mem_res mem_res;
> + u32 shim_id;
> + struct mlxbf_pka_dev_shim_res_t resources;
> + u8 window_ram_split;
> + s8 status;
> + struct mutex mutex;
> +};
> +
> +/* Defines for mlxbf_pka_dev_shim->status. */
> +#define MLXBF_PKA_SHIM_STATUS_UNDEFINED -1
> +#define MLXBF_PKA_SHIM_STATUS_CREATED 1
> +#define MLXBF_PKA_SHIM_STATUS_INITIALIZED 2
> +#define MLXBF_PKA_SHIM_STATUS_RUNNING 3
> +#define MLXBF_PKA_SHIM_STATUS_STOPPED 4
> +#define MLXBF_PKA_SHIM_STATUS_FINALIZED 5
> +
> +/* Defines for mlxbf_pka_dev_shim->window_ram_split. */
> +
> +/* Window RAM is split into 4 * 16KB blocks. */
> +#define MLXBF_PKA_SHIM_WINDOW_RAM_SPLIT_ENABLED 1
> +/* Window RAM is not split and occupies 64KB. */
> +#define MLXBF_PKA_SHIM_WINDOW_RAM_SPLIT_DISABLED 2
> +
> +/**
> + * struct mlxbf_pka_dev_gbl_config_t - Platform global configuration structure
> + * @dev_shims_cnt: Number of registered PKA shims
> + * @dev_shims: Table of registered PKA shims
> + */
> +struct mlxbf_pka_dev_gbl_config_t {
> + u32 dev_shims_cnt;
> + struct mlxbf_pka_dev_shim_s *dev_shims[MLXBF_PKA_MAX_NUM_IO_BLOCKS];
> +};
> +
> +extern struct mlxbf_pka_dev_gbl_config_t mlxbf_pka_gbl_config;
> +
> +/*
> + * Processor speed in hertz, used in routines which might be called very early
> + * in boot.
> + */
> +static inline u64 mlxbf_pka_early_cpu_speed(void)
> +{
> + /*
> + * Initial guess at our CPU speed. We set this to be larger than any
> + * possible real speed, so that any calculated delays will be too long,
> + * rather than too short.
> + *
> + * CPU Freq for High/Bin Chip - 1.255GHz.
> + */
> + return 1255 * HZ_PER_MHZ;
> +}
> +
> +/* 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;
> +}
> +
> +/* 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);
> +}
> +
> +/*
> + * Shim getter for mlxbf_pka_dev_gbl_config_t structure which holds all system
> + * global configuration. This configuration is shared and common to kernel
> + * device driver associated with PKA hardware.
> + */
> +struct mlxbf_pka_dev_shim_s *mlxbf_pka_dev_get_shim(u32 shim_id);
> +
> +void mlxbf_pka_dev_unset_resource_config(struct device *dev,
> + struct mlxbf_pka_dev_shim_s *shim,
> + struct mlxbf_pka_dev_res_t *res_ptr);
> +
> +/*
> + * Register PKA IO block. This function initializes a shim and configures its
> + * related resources, and returns the error code.
> + */
> +int mlxbf_pka_dev_register_shim(struct device *dev,
> + u32 shim_id,
> + struct mlxbf_pka_dev_mem_res *mem_res,
> + struct mlxbf_pka_dev_shim_s **shim);
> +
> +/* Unregister PKA IO block. */
> +int mlxbf_pka_dev_unregister_shim(struct device *dev, struct mlxbf_pka_dev_shim_s *shim);
> +
> +#endif /* __MLXBF_PKA_DEV_H__ */
> diff --git a/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_drv.c b/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_drv.c
> new file mode 100644
> index 000000000000..42bfe30fbe49
> --- /dev/null
> +++ b/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_drv.c
> @@ -0,0 +1,413 @@
> +// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause
> +// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION. All rights reserved.
> +
> +#include <linux/acpi.h>
> +#include <linux/bitfield.h>
> +#include <linux/cdev.h>
> +#include <linux/cleanup.h>
> +#include <linux/device.h>
> +#include <linux/idr.h>
> +#include <linux/interrupt.h>
> +#include <linux/iommu.h>
> +#include <linux/ioport.h>
> +#include <linux/kdev_t.h>
> +#include <linux/kernel.h>
> +#include <linux/miscdevice.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <linux/types.h>
> +#include <linux/uaccess.h>
> +
> +#include "mlxbf_pka_dev.h"
> +
> +#define MLXBF_PKA_DRIVER_DESCRIPTION "BlueField PKA driver"
> +
> +#define MLXBF_PKA_DEVICE_ACPIHID_BF1 "MLNXBF10"
> +
> +#define MLXBF_PKA_DEVICE_ACPIHID_BF2 "MLNXBF20"
> +
> +#define MLXBF_PKA_DEVICE_ACPIHID_BF3 "MLNXBF51"
> +
> +#define MLXBF_PKA_DEVICE_ACCESS_MODE 0666
> +#define MLXBF_PKA_DEVICE_RES_CNT 7
> +#define MLXBF_PKA_DEVICE_NAME_MAX 14
> +
> +enum mlxbf_pka_mem_res_idx {
> + MLXBF_PKA_ACPI_EIP154_IDX = 0,
> + MLXBF_PKA_ACPI_WNDW_RAM_IDX,
> + MLXBF_PKA_ACPI_ALT_WNDW_RAM_0_IDX,
> + MLXBF_PKA_ACPI_ALT_WNDW_RAM_1_IDX,
> + MLXBF_PKA_ACPI_ALT_WNDW_RAM_2_IDX,
> + MLXBF_PKA_ACPI_ALT_WNDW_RAM_3_IDX,
> + MLXBF_PKA_ACPI_CSR_IDX
> +};
> +
> +enum mlxbf_pka_plat_type {
> + /* Platform type Bluefield-1. */
> + MLXBF_PKA_PLAT_TYPE_BF1 = 0,
> + /* Platform type Bluefield-2. */
> + MLXBF_PKA_PLAT_TYPE_BF2,
> + /* Platform type Bluefield-3. */
> + MLXBF_PKA_PLAT_TYPE_BF3
> +};
> +
> +struct mlxbf_pka_drv_plat_info {
> + enum mlxbf_pka_plat_type type;
> + u64 wndw_ram_off_mask;
> +};
> +
> +static const struct mlxbf_pka_drv_plat_info mlxbf_pka_bf1_info = {
> + .type = MLXBF_PKA_PLAT_TYPE_BF1,
> + .wndw_ram_off_mask = MLXBF_PKA_WINDOW_RAM_OFFSET_BF1_BF2_MASK,
> +};
> +
> +static const struct mlxbf_pka_drv_plat_info mlxbf_pka_bf2_info = {
> + .type = MLXBF_PKA_PLAT_TYPE_BF2,
> + .wndw_ram_off_mask = MLXBF_PKA_WINDOW_RAM_OFFSET_BF1_BF2_MASK,
> +};
> +
> +static const struct mlxbf_pka_drv_plat_info mlxbf_pka_bf3_info = {
> + .type = MLXBF_PKA_PLAT_TYPE_BF3,
> + .wndw_ram_off_mask = MLXBF_PKA_WINDOW_RAM_OFFSET_BF3_MASK,
> +};
> +
> +static DEFINE_MUTEX(mlxbf_pka_drv_lock);
> +
> +static u32 mlxbf_pka_device_cnt;
> +
> +static const char mlxbf_pka_acpihid_bf1[] = MLXBF_PKA_DEVICE_ACPIHID_BF1;
> +
> +static const char mlxbf_pka_acpihid_bf2[] = MLXBF_PKA_DEVICE_ACPIHID_BF2;
> +
> +static const char mlxbf_pka_acpihid_bf3[] = MLXBF_PKA_DEVICE_ACPIHID_BF3;
> +
> +static const struct acpi_device_id mlxbf_pka_drv_acpi_ids[] = {
> + { MLXBF_PKA_DEVICE_ACPIHID_BF1, (kernel_ulong_t)&mlxbf_pka_bf1_info, 0, 0 },
> + { MLXBF_PKA_DEVICE_ACPIHID_BF2, (kernel_ulong_t)&mlxbf_pka_bf2_info, 0, 0 },
> + { MLXBF_PKA_DEVICE_ACPIHID_BF3, (kernel_ulong_t)&mlxbf_pka_bf3_info, 0, 0 },
> + {},
> +};
> +
> +struct mlxbf_pka_info {
> + /* The device this info struct belongs to. */
> + struct device *dev;
> + /* Device name. */
> + const char *name;
> + /* Device ACPI HID. */
> + const char *acpihid;
> + /* Device flags. */
> + u8 flag;
> + struct module *module;
> + /* Optional private data. */
> + void *priv;
> +};
> +
> +/* Defines for mlxbf_pka_info->flags. */
> +#define MLXBF_PKA_DRIVER_FLAG_DEVICE 2
> +
> +struct mlxbf_pka_platdata {
> + struct platform_device *pdev;
> + struct mlxbf_pka_info *info;
> + /* Generic spinlock. */
> + spinlock_t lock;
> +};
> +
> +#define MLXBF_PKA_DRIVER_DEV_MAX MLXBF_PKA_MAX_NUM_IO_BLOCKS
> +
> +struct mlxbf_pka_device {
> + struct mlxbf_pka_info *info;
> + struct device *device;
> + u32 device_id;
> + struct resource *resource[MLXBF_PKA_DEVICE_RES_CNT];
> + struct mlxbf_pka_dev_shim_s *shim;
> +};
> +
> +static int mlxbf_pka_drv_verify_bootup_status(struct device *dev)
> +{
> + const char *bootup_status;
> + int ret;
> +
> + ret = device_property_read_string(dev, "bootup_done", &bootup_status);
> + if (ret < 0) {
> + dev_err(dev, "failed to read bootup_done property\n");
> + return ret;
> + }
> +
> + if (strcmp(bootup_status, "true")) {
> + dev_err(dev, "device bootup required\n");
> + return -ENODEV;
> + }
> +
> + return 0;
> +}
> +
> +static void mlxbf_pka_drv_get_mem_res(struct mlxbf_pka_device *mlxbf_pka_dev,
> + struct mlxbf_pka_dev_mem_res *mem_res,
> + u64 wndw_ram_off_mask)
> +{
> + enum mlxbf_pka_mem_res_idx acpi_mem_idx;
> +
> + acpi_mem_idx = MLXBF_PKA_ACPI_EIP154_IDX;
> + mem_res->wndw_ram_off_mask = wndw_ram_off_mask;
> +
> + /* PKA EIP154 MMIO base address. */
> + mem_res->eip154_base = mlxbf_pka_dev->resource[acpi_mem_idx]->start;
> + mem_res->eip154_size = resource_size(mlxbf_pka_dev->resource[acpi_mem_idx]);
> + acpi_mem_idx++;
> +
> + /* PKA window RAM base address. */
> + mem_res->wndw_ram_base = mlxbf_pka_dev->resource[acpi_mem_idx]->start;
> + mem_res->wndw_ram_size = resource_size(mlxbf_pka_dev->resource[acpi_mem_idx]);
> + acpi_mem_idx++;
> +
> + /*
> + * PKA alternate window RAM base address.
> + * Note: the size of all the alt window RAM is the same, depicted by
> + * 'alt_wndw_ram_size' variable. All alt window RAM resources are read
> + * here even though not all of them are used currently.
> + */
> + mem_res->alt_wndw_ram_0_base = mlxbf_pka_dev->resource[acpi_mem_idx]->start;
> + mem_res->alt_wndw_ram_size = resource_size(mlxbf_pka_dev->resource[acpi_mem_idx]);
> +
> + if (mem_res->alt_wndw_ram_size != MLXBF_PKA_WINDOW_RAM_REGION_SIZE)
> + dev_warn(mlxbf_pka_dev->device, "alternate Window RAM size from ACPI is wrong.\n");
> +
> + acpi_mem_idx++;
> +
> + mem_res->alt_wndw_ram_1_base = mlxbf_pka_dev->resource[acpi_mem_idx]->start;
> + acpi_mem_idx++;
> +
> + mem_res->alt_wndw_ram_2_base = mlxbf_pka_dev->resource[acpi_mem_idx]->start;
> + acpi_mem_idx++;
> +
> + mem_res->alt_wndw_ram_3_base = mlxbf_pka_dev->resource[acpi_mem_idx]->start;
> + acpi_mem_idx++;
> +
> + /* PKA CSR base address. */
> + mem_res->csr_base = mlxbf_pka_dev->resource[acpi_mem_idx]->start;
> + mem_res->csr_size = resource_size(mlxbf_pka_dev->resource[acpi_mem_idx]);
> +}
> +
> +/*
> + * Note: this function must be serialized because it calls
> + * 'mlxbf_pka_dev_register_shim' which manipulates common counters for the
> + * PKA devices.
> + */
> +static int mlxbf_pka_drv_register_device(struct mlxbf_pka_device *mlxbf_pka_dev,
> + u64 wndw_ram_off_mask)
> +{
> + struct mlxbf_pka_dev_mem_res mem_res;
> + u32 mlxbf_pka_shim_id;
> + int ret;
> +
> + /* Assert that the driver lock is held for serialization */
> + lockdep_assert_held(&mlxbf_pka_drv_lock);
> +
> + mlxbf_pka_shim_id = mlxbf_pka_dev->device_id;
> +
> + mlxbf_pka_drv_get_mem_res(mlxbf_pka_dev, &mem_res, wndw_ram_off_mask);
> +
> + ret = mlxbf_pka_dev_register_shim(mlxbf_pka_dev->device,
> + mlxbf_pka_shim_id,
> + &mem_res,
> + &mlxbf_pka_dev->shim);
> + if (ret) {
> + dev_dbg(mlxbf_pka_dev->device, "failed to register shim\n");
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static int mlxbf_pka_drv_unregister_device(struct mlxbf_pka_device *mlxbf_pka_dev)
> +{
> + if (!mlxbf_pka_dev || !mlxbf_pka_dev->shim)
> + return -EINVAL;
> +
> + dev_dbg(mlxbf_pka_dev->device, "unregister device shim\n");
> + return mlxbf_pka_dev_unregister_shim(mlxbf_pka_dev->device, mlxbf_pka_dev->shim);
> +}
> +
> +static int mlxbf_pka_drv_probe_device(struct mlxbf_pka_info *info)
> +{
> + struct mlxbf_pka_drv_plat_info *plat_info;
> + enum mlxbf_pka_mem_res_idx acpi_mem_idx;
> + struct mlxbf_pka_device *mlxbf_pka_dev;
> + const struct acpi_device_id *aid;
> + struct platform_device *pdev;
> + u64 wndw_ram_off_mask;
> + struct device *dev;
> + int ret;
> +
> + if (!info)
> + return -EINVAL;
> +
> + dev = info->dev;
> + pdev = to_platform_device(dev);
> +
> + mlxbf_pka_dev = devm_kzalloc(dev, sizeof(*mlxbf_pka_dev), GFP_KERNEL);
> + if (!mlxbf_pka_dev)
> + return -ENOMEM;
> +
> + scoped_guard(mutex, &mlxbf_pka_drv_lock) {
> + mlxbf_pka_device_cnt += 1;
> + if (mlxbf_pka_device_cnt > MLXBF_PKA_DRIVER_DEV_MAX) {
> + dev_dbg(dev, "cannot support %u devices\n", mlxbf_pka_device_cnt);
> + return -ENOSPC;
> + }
> + mlxbf_pka_dev->device_id = mlxbf_pka_device_cnt - 1;
> + }
> +
> + mlxbf_pka_dev->info = info;
> + mlxbf_pka_dev->device = dev;
> + info->flag = MLXBF_PKA_DRIVER_FLAG_DEVICE;
> +
> + for (acpi_mem_idx = MLXBF_PKA_ACPI_EIP154_IDX;
> + acpi_mem_idx < MLXBF_PKA_DEVICE_RES_CNT;
> + acpi_mem_idx++) {
> + mlxbf_pka_dev->resource[acpi_mem_idx] = platform_get_resource(pdev,
> + IORESOURCE_MEM,
> + acpi_mem_idx);
> + }
> +
> + /* Verify PKA bootup status. */
> + ret = mlxbf_pka_drv_verify_bootup_status(dev);
> + if (ret)
> + return ret;
> +
> + /* Window RAM offset mask is platform dependent. */
> + aid = acpi_match_device(mlxbf_pka_drv_acpi_ids, dev);
> + if (!aid)
> + return -ENODEV;
> +
> + plat_info = (struct mlxbf_pka_drv_plat_info *)aid->driver_data;
> + if (!plat_info) {
> + dev_err(dev, "missing platform data\n");
> + return -EINVAL;
> + }
> +
> + wndw_ram_off_mask = plat_info->wndw_ram_off_mask;
> +
> + scoped_guard(mutex, &mlxbf_pka_drv_lock) {
> + ret = mlxbf_pka_drv_register_device(mlxbf_pka_dev, wndw_ram_off_mask);
> + if (ret) {
> + dev_dbg(dev, "failed to register shim\n");
> + return ret;
> + }
> + }
> +
> + info->priv = mlxbf_pka_dev;
> +
> + return 0;
> +}
> +
> +static void mlxbf_pka_drv_remove_device(struct platform_device *pdev)
> +{
> + struct mlxbf_pka_platdata *priv = platform_get_drvdata(pdev);
> + struct mlxbf_pka_info *info = priv->info;
> + struct mlxbf_pka_device *mlxbf_pka_dev = (struct mlxbf_pka_device *)info->priv;
> +
> + if (!mlxbf_pka_dev)
> + return;
> +
> + mlxbf_pka_drv_unregister_device(mlxbf_pka_dev);
> +}
> +
> +static int mlxbf_pka_drv_acpi_probe(struct platform_device *pdev, struct mlxbf_pka_info *info)
> +{
> + struct device *dev = &pdev->dev;
> + struct acpi_device *adev;
> + int ret;
> +
> + if (acpi_disabled)
> + return -ENOENT;
> +
> + adev = ACPI_COMPANION(dev);
> + if (!adev) {
> + dev_dbg(dev, "ACPI companion device not found for %s\n", pdev->name);
> + return -ENODEV;
> + }
> +
> + info->acpihid = acpi_device_hid(adev);
> + if (WARN_ON(!info->acpihid))
> + return -EINVAL;
> +
> + if (!strcmp(info->acpihid, mlxbf_pka_acpihid_bf1) ||
> + !strcmp(info->acpihid, mlxbf_pka_acpihid_bf2) ||
> + !strcmp(info->acpihid, mlxbf_pka_acpihid_bf3)) {
> + ret = mlxbf_pka_drv_probe_device(info);
> + if (ret) {
> + dev_dbg(dev, "failed to register device\n");
> + return ret;
> + }
> + dev_info(dev, "device probed\n");
> + }
> +
> + return 0;
> +}
> +
> +static int mlxbf_pka_drv_probe(struct platform_device *pdev)
> +{
> + struct mlxbf_pka_platdata *priv;
> + struct device *dev = &pdev->dev;
> + struct mlxbf_pka_info *info;
> + int ret;
> +
> + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> + if (!priv)
> + return -ENOMEM;
> +
> + spin_lock_init(&priv->lock);
> + priv->pdev = pdev;
> +
> + info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
> + if (!info)
> + return -ENOMEM;
> +
> + info->name = pdev->name;
> + info->module = THIS_MODULE;
> + info->dev = dev;
> + priv->info = info;
> +
> + platform_set_drvdata(pdev, priv);
> +
> + ret = mlxbf_pka_drv_acpi_probe(pdev, info);
> + if (ret) {
> + dev_dbg(dev, "unknown device\n");
> + return ret;
> + }
> +
> + return ret;
> +}
> +
> +static void mlxbf_pka_drv_remove(struct platform_device *pdev)
> +{
> + struct mlxbf_pka_platdata *priv = platform_get_drvdata(pdev);
> + struct mlxbf_pka_info *info = priv->info;
> +
> + if (info->flag == MLXBF_PKA_DRIVER_FLAG_DEVICE) {
> + dev_info(&pdev->dev, "remove PKA device\n");
> + mlxbf_pka_drv_remove_device(pdev);
> + }
> +}
> +
> +MODULE_DEVICE_TABLE(acpi, mlxbf_pka_drv_acpi_ids);
> +
> +static struct platform_driver mlxbf_pka_drv = {
> + .driver = {
> + .name = KBUILD_MODNAME,
> + .acpi_match_table = ACPI_PTR(mlxbf_pka_drv_acpi_ids),
> + },
> + .probe = mlxbf_pka_drv_probe,
> + .remove = mlxbf_pka_drv_remove,
> +};
> +
> +module_platform_driver(mlxbf_pka_drv);
> +MODULE_DESCRIPTION(MLXBF_PKA_DRIVER_DESCRIPTION);
> +MODULE_AUTHOR("Ron Li <xiangrongl@...dia.com>");
> +MODULE_AUTHOR("Khalil Blaiech <kblaiech@...dia.com>");
> +MODULE_AUTHOR("Mahantesh Salimath <mahantesh@...dia.com>");
> +MODULE_AUTHOR("Shih-Yi Chen <shihyic@...dia.com>");
> +MODULE_LICENSE("Dual BSD/GPL");
>
--
i.
Powered by blists - more mailing lists