From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from PH8PR06CU001.outbound.protection.outlook.com (mail-westus3azon11012037.outbound.protection.outlook.com [40.107.209.37]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3B49A2D780A for ; Tue, 7 Jul 2026 09:56:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.209.37 ARC-Seal:i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783418202; cv=fail; b=W63SIlYSjlpKGKOcGt6D4vwrfO5UQEt/8ietYnhNzxC4ir8id9ZkUhLnaARnTl8dhzoteHdBJ0ht/yhdU/g9NuYJPwnW5+uL4hipLpD7uwASe2g/ZdAN8lb+WuGuG7Lxtlf/uYKL2bGfbRqTfAeDeBl/krsCiQLIOxHVJpPo0qk= ARC-Message-Signature:i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783418202; c=relaxed/simple; bh=jHjwCamtncF5ozWw7W9Oyj25lkgvQb9sf4MXCG+SPKs=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Q1J863PKOkPjYoIigaxtE9sE4426N9YhhMnScX/+Ajet2qn4ufHBXlBdgZOJkB7amuCRfysjhRzJY6pY6FAg/bLp9rJUghlUfLJNOFA/E9LYkLZacVNBzb+Tm5pERAUuA5hU872L+yvC9MTqfA2X9pD2mMWkg3OKU3JoYjtRmcE= ARC-Authentication-Results:i=2; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amd.com; spf=fail smtp.mailfrom=amd.com; dkim=pass (1024-bit key) header.d=amd.com header.i=@amd.com header.b=tF+Qpsh3; arc=fail smtp.client-ip=40.107.209.37 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amd.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=amd.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=amd.com header.i=@amd.com header.b="tF+Qpsh3" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=KnIqEaT7X/uuwgAbNAENkf1vZNLgiZeyvu/G8xmrM3AIfutZbdCDqqYWT/4GbP+IuCMhgHl45cY/ljCGV9/fljlb3WoPR8bJ9PhizVp8Gr6Hf0gJ5hodPmuYDt/S8szqTjTwZRCD11CiDCIfejm0c3wXO7VQp68wa0AO7xHuDONfsZHqFbS7zfNUI6ftYAgHpHP07+9011wpRK6bTLkWfoQEHWezf0RdcYUnj9iUGqzDRLq4HvpVLFsT5b0b2xpTHq4WFC5uEATwAcN9vF7CjsiOkPO3XP8n37igEhM5EBVzGnUrnOzcgOTHiUxkb5FcPXq/s71iAhqTmjKnQlKzAA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=eKSTcDgkrkGXeSwC+Fpm00JCCsUvA0udL7xPSkzfHII=; b=GqcY/SsNLsv03jxYYJNWuL7t7DT93fJ/UqrCK1aCSp8Zv/Fn254HzFfua8b5SOlNlx7vmvZ/rl8cJIR153TDiAiR2w8HbIVEA1ve+WlhrF9dXXwjjkwBbQqzxlpwu9I6KA58OWUDGs3fSprZxDahmEajSeI14/izQwT8GjI1SyYAd4dtRNlA5iTPH6rYk6NNbnslYA6rQIhuLYIuN/asvByEsSJKSZJF5WZfE3vZuiMvFQhmOoKmsSKhVFoocClUqLEpD9YVK/hV8f/YZD3wAIfO7TPRV3ak73m1PKCIEMbQaAc762HMtN9Pk/C8TUiekdwW5ms7eYla2VchZDqZCQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 165.204.84.17) smtp.rcpttodomain=arndb.de smtp.mailfrom=amd.com; dmarc=pass (p=quarantine sp=quarantine pct=100) action=none header.from=amd.com; dkim=none (message not signed); arc=none (0) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amd.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=eKSTcDgkrkGXeSwC+Fpm00JCCsUvA0udL7xPSkzfHII=; b=tF+Qpsh3Ph9YyFWb1QuHgD3nhzsqMhjPCqhU7QKviy5/zikG+K8EtSpQFO2PjHAEscDOOS7MDbPT5xwW8hwHX8Kl4E53VxaONN2gxV8xzTwDz2ga8t50hTWcZzzcK7CC6iH/yMwWb1Kp4qUJ4Mt4JSRLLifOxWsEKK5HkHb0MGc= Received: from PH8PR05CA0013.namprd05.prod.outlook.com (2603:10b6:510:2cc::13) by MN0PR12MB6320.namprd12.prod.outlook.com (2603:10b6:208:3d3::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.181.10; Tue, 7 Jul 2026 09:56:31 +0000 Received: from SA2PEPF0000150A.namprd04.prod.outlook.com (2603:10b6:510:2cc:cafe::a3) by PH8PR05CA0013.outlook.office365.com (2603:10b6:510:2cc::13) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.21.202.9 via Frontend Transport; Tue, 7 Jul 2026 09:56:31 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 165.204.84.17) smtp.mailfrom=amd.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=amd.com; Received-SPF: Pass (protection.outlook.com: domain of amd.com designates 165.204.84.17 as permitted sender) receiver=protection.outlook.com; client-ip=165.204.84.17; helo=satlexmb08.amd.com; pr=C Received: from satlexmb08.amd.com (165.204.84.17) by SA2PEPF0000150A.mail.protection.outlook.com (10.167.242.42) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.181.6 via Frontend Transport; Tue, 7 Jul 2026 09:56:31 +0000 Received: from satlexmb07.amd.com (10.181.42.216) by satlexmb08.amd.com (10.181.42.217) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.41; Tue, 7 Jul 2026 04:56:30 -0500 Received: from xhdharshj40.xilinx.com (10.180.168.240) by satlexmb07.amd.com (10.181.42.216) with Microsoft SMTP Server id 15.2.2562.41 via Frontend Transport; Tue, 7 Jul 2026 04:56:28 -0500 From: Harsh Jain To: , , , , , CC: Harsh Jain Subject: [PATCH 2/2] misc: Add Xilinx PUF driver Date: Tue, 7 Jul 2026 15:26:20 +0530 Message-ID: <20260707095620.2795456-3-h.jain@amd.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260707095620.2795456-1-h.jain@amd.com> References: <20260707095620.2795456-1-h.jain@amd.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Content-Type: text/plain X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: SA2PEPF0000150A:EE_|MN0PR12MB6320:EE_ X-MS-Office365-Filtering-Correlation-Id: ae233bc3-493d-4f08-cbab-08dedc0e0568 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|82310400026|1800799024|36860700016|376014|23010399003|11063799006|5023799004|6133799003|56012099006|22082099003|18002099003|3023799007; X-Microsoft-Antispam-Message-Info: N2wviMRykBsrmB+6kvoDRjwXm/ZHf3s0YlJyn8KhkGX5f1bcGW6lkFSvTRu8qKFmjhuG61SqFbe8LKUUSoKv0AL7FZMmMUngO/ntBQLqP+zicLocGTGmxXTiAJhqbVe0RnzGhnfGmSKvTp4xdIZhkDk4ZH5rVTrrVUFwQdMyQorp5QVJ1yGk04zZh/N4SXefqvD8ZZZTmLS8uWYxZRkLFtrpwps4amQxoDEyDqKQTbrDfXANak9u4XHqWEB9XWf3Rj8RHmoEXCQcj4U1aFlohpstJmlFR2B7CUY59Fr/jKydo6czKMInT0Lxr9L+G1eIG0SRrrzUeogPzsNwl+RhE4Sfdbyl7DGYfDeekXeMbCuoe9kknn7sGerobUCQe3ioGRrzJ7vhRsTWR7NpOKJft5BkQZ7ssPPlxNTg+HV+JnMWCT2z2XXqaWzP3E7MNwx0DBOx232r++6AojSm9y1GV+NkuU19tp1+xMtl2Xf9yZNqEw4NtBlkcAKkIgGcbwxr+lf8lwtqqow3cmq2rfYEtogVHtErXtUaIoXhTyZ5kSFf14Bd1Zfbv4qFvEHNft/FkUdzyOCtDgtMUnlUp2b8RWc6dKXKW9MNbfpQsHOLcFbLf4I+njcfLqJUecRDQomc8tu8MVvpAnvmmlBVXA49mxDsfkepuN7C9r4v/xIHaDHbYqeNEJL9e+00kaDqg2qO/30d2sWAnSo1+7vi3Qt3Ew== X-Forefront-Antispam-Report: CIP:165.204.84.17;CTRY:US;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:satlexmb08.amd.com;PTR:InfoDomainNonexistent;CAT:NONE;SFS:(13230040)(82310400026)(1800799024)(36860700016)(376014)(23010399003)(11063799006)(5023799004)(6133799003)(56012099006)(22082099003)(18002099003)(3023799007);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: C/OE0jIcpRfcOgKikhM2G0mY1FtoPb0e95QA1gEZZCu6q8SXQDuPQP/BEqYnVkb0B44dMypS+j55H0LX0oCxdySMcKsgaR3VxYgDQJVLc1hr0u1/JLFC2bV6WRAE1pIYfDmE1dnwHsSZzUgH9yd+w517sPPVHw1uIUbfLcqFjRuYZUQQtI4l8AaHfBWZtkqUWWKcfjPZK5/RATs1Y4BDNRX+UecaIVVDJc9JAumcPXwjBn/s1XIXudCqZ4QWQ5OHOyyQ0j3zR1NIWbEiwygX3jnpIDDk2V+3r1Tc7KmZnTiAt2O6eudLRTJUl1FQoBxtJ+OVLjH1Ibal505wph36/9HgKub9ONKgOvIH5cUNcbnjgTM2+QzfMFk3aH3iPL9rQMv2sz92N8P+dd2eJ/xdd3W+uggREKjjaWJIg2g9FvXjBY6O6640IjpKZjWWOSKU X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 07 Jul 2026 09:56:31.1291 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: ae233bc3-493d-4f08-cbab-08dedc0e0568 X-MS-Exchange-CrossTenant-Id: 3dd8961f-e488-4e60-8e11-a82d994e183d X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=3dd8961f-e488-4e60-8e11-a82d994e183d;Ip=[165.204.84.17];Helo=[satlexmb08.amd.com] X-MS-Exchange-CrossTenant-AuthSource: SA2PEPF0000150A.namprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: MN0PR12MB6320 Versal devices contain a physically unclonable function (PUF) block that derives device-unique secrets from intrinsic silicon characteristics. The PUF generates a Key Encryption Key (KEK) used internally by the AES engine for secure key storage, which is not externally accessible. In addition, the PUF provides a readable device-unique identifier derived from the same entropy source. Add a misc character driver to support PUF registration and regeneration. Registration generates a unique secret and outputs binary helper data that can later be used during regeneration to reproduce the same secrets. The driver also implements PUF_CLEAR_ID and PUF_CLEAR_KEY ioctls to clear the PUF ID and PUF-derived AES key via firmware. They are disabled by default unless puf_clear is set. Signed-off-by: Harsh Jain --- MAINTAINERS | 6 + drivers/misc/Kconfig | 11 + drivers/misc/Makefile | 1 + drivers/misc/xilinx_puf.c | 377 +++++++++++++++++++++++++++++++++ include/uapi/misc/xilinx_puf.h | 82 +++++++ 5 files changed, 477 insertions(+) create mode 100644 drivers/misc/xilinx_puf.c create mode 100644 include/uapi/misc/xilinx_puf.h diff --git a/MAINTAINERS b/MAINTAINERS index 15011f5752a9..a46a34f163b4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -29546,6 +29546,12 @@ L: netdev@vger.kernel.org S: Orphan F: drivers/net/ethernet/xilinx/ll_temac* +XILINX PUF DRIVER +M: Harsh Jain +S: Maintained +F: drivers/misc/xilinx_puf.c +F: include/uapi/misc/xilinx_puf.h + XILINX PWM DRIVER M: Sean Anderson S: Maintained diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 390256ed91f4..98ec00765647 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -490,6 +490,17 @@ config XILINX_SDFEC If unsure, say N. +config XILINX_PUF + tristate "Xilinx PUF driver" + depends on ZYNQMP_FIRMWARE + help + This option enables support for the Xilinx Physically Unclonable Function + (PUF) driver on AMD Versal devices. + It is a configurable driver to generate PUF KEK source either by using + PUF registration or regeneration command. + + If unsure, say N. + config MISC_RTSX tristate default MISC_RTSX_PCI || MISC_RTSX_USB diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index fed47c7672b9..66d1ea5d1f13 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -55,6 +55,7 @@ obj-$(CONFIG_BCM_VK) += bcm-vk/ obj-y += cardreader/ obj-$(CONFIG_PVPANIC) += pvpanic/ obj-$(CONFIG_UACCE) += uacce/ +obj-$(CONFIG_XILINX_PUF) += xilinx_puf.o obj-$(CONFIG_XILINX_SDFEC) += xilinx_sdfec.o obj-$(CONFIG_HISI_HIKEY_USB) += hisi_hikey_usb.o obj-$(CONFIG_NTSYNC) += ntsync.o diff --git a/drivers/misc/xilinx_puf.c b/drivers/misc/xilinx_puf.c new file mode 100644 index 000000000000..ad8ada58b105 --- /dev/null +++ b/drivers/misc/xilinx_puf.c @@ -0,0 +1,377 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for Xilinx PUF device. + * + * Copyright (C) 2022 - 2026, Advanced Micro Devices, Inc. + * + * Description: + * This driver is developed for PUF registration and regeneration support. + */ + +#include +#include +#include +#include +#include +#include + +static bool puf_clear; +module_param(puf_clear, bool, 0600); +MODULE_PARM_DESC(puf_clear, "Flag to enable clearing of PUF ID and key."); + +/** + * struct puf_params - parameters for PUF + * @pufoperation: PUF registration or regeneration operation + * @globalvarfilter: global variation filter + * @readoption: option to read PUF data from efuse cache or ram address + * @reserved: explicit padding to match the Versal PLM PUF parameter layout. + * @shuttervalue: shutter value for PUF registration/regeneration + * @readsyndromeaddr: address to store the syndrome data during registration + * @chashaddr: CHASH address + * @auxaddr: AUX address + * @pufidaddr: PUF ID address + * @writesyndromeaddr: address where syndrome data is present and it is passed to the user + * @trimsyndataaddr: trimmed syndrome data will be stored + */ +struct puf_params { + u8 pufoperation; + u8 globalvarfilter; + u8 readoption; + u8 reserved; + u32 shuttervalue; + u64 readsyndromeaddr; + u64 chashaddr; + u64 auxaddr; + u64 pufidaddr; + u64 writesyndromeaddr; + u64 trimsyndataaddr; +}; + +/** + * struct xpuf_dev - Driver data for PUF + * @dev: pointer to device struct + * @miscdev: misc device handle + */ +struct xpuf_dev { + struct device *dev; + struct miscdevice miscdev; +}; + +static int xlnx_puf_regis(struct xpuf_dev *puf, struct puf_usrparams *pufreq) +{ + struct puf_params *pufin; + struct pufdata *pufdat; + dma_addr_t dma_addr_data; + dma_addr_t dma_addr_in; + u32 buflen; + void *buf; + int ret; + + if (pufreq->pufoperation != PUF_REGIS) + return -EINVAL; + + if (pufreq->readoption != PUF_READ_FROM_RAM && + pufreq->readoption != PUF_READ_FROM_EFUSE_CACHE) + return -EINVAL; + + buflen = sizeof(struct puf_params) + sizeof(struct pufdata); + buf = kzalloc(buflen, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + pufin = buf; + pufin->pufoperation = pufreq->pufoperation; + pufin->globalvarfilter = pufreq->globalvarfilter; + pufin->readoption = pufreq->readoption; + pufin->shuttervalue = pufreq->shuttervalue; + + pufdat = buf + sizeof(struct puf_params); + dma_addr_in = dma_map_single(puf->dev, buf, buflen, DMA_BIDIRECTIONAL); + if (dma_mapping_error(puf->dev, dma_addr_in)) { + ret = -ENOMEM; + goto cleanup; + } + + dma_addr_data = dma_addr_in + sizeof(struct puf_params); + pufin->readsyndromeaddr = (u64)dma_addr_data; + pufin->chashaddr = (u64)(pufin->readsyndromeaddr + sizeof(pufdat->pufhd.syndata)); + pufin->auxaddr = (u64)(pufin->chashaddr + sizeof(pufdat->pufhd.chash)); + pufin->pufidaddr = (u64)(pufin->auxaddr + sizeof(pufdat->pufhd.aux)); + pufin->trimsyndataaddr = (u64)(pufin->pufidaddr + sizeof(pufdat->pufid)); + + dma_sync_single_for_device(puf->dev, dma_addr_in, buflen, DMA_BIDIRECTIONAL); + ret = versal_pm_puf_registration(dma_addr_in); + dma_unmap_single(puf->dev, dma_addr_in, buflen, DMA_BIDIRECTIONAL); + if (ret) + goto cleanup; + + if (copy_to_user(u64_to_user_ptr(pufreq->pufdataaddr), pufdat, sizeof(struct pufdata))) { + ret = -EFAULT; + goto cleanup; + } + +cleanup: + kfree(buf); + + return ret; +} + +static int xlnx_puf_regen_id(struct xpuf_dev *puf, struct puf_usrparams *pufreq) +{ + struct puf_helperdata *pufhd; + struct puf_params *pufin; + dma_addr_t dma_addr_data; + dma_addr_t dma_addr_in; + u32 buflen; + void *buf; + int ret; + + if (pufreq->pufoperation != PUF_REGEN && + pufreq->pufoperation != PUF_REGEN_ID) + return -EINVAL; + + if (pufreq->readoption != PUF_READ_FROM_RAM && + pufreq->readoption != PUF_READ_FROM_EFUSE_CACHE) + return -EINVAL; + + buflen = sizeof(struct puf_params) + sizeof(struct puf_helperdata) + + PUF_ID_LEN_IN_BYTES; + + buf = kzalloc(buflen, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + pufin = buf; + pufin->pufoperation = pufreq->pufoperation; + pufin->globalvarfilter = pufreq->globalvarfilter; + pufin->shuttervalue = pufreq->shuttervalue; + pufin->readoption = pufreq->readoption; + + pufhd = buf + sizeof(struct puf_params); + if (copy_from_user(pufhd, u64_to_user_ptr(pufreq->pufdataaddr), + sizeof(struct puf_helperdata))) { + ret = -EFAULT; + goto cleanup; + } + + dma_addr_in = dma_map_single(puf->dev, buf, buflen, DMA_BIDIRECTIONAL); + if (dma_mapping_error(puf->dev, dma_addr_in)) { + ret = -ENOMEM; + goto cleanup; + } + + dma_addr_data = dma_addr_in + sizeof(struct puf_params); + pufin->writesyndromeaddr = (u64)dma_addr_data; + pufin->chashaddr = (u64)(pufin->writesyndromeaddr + sizeof(pufhd->syndata)); + pufin->auxaddr = (u64)(pufin->chashaddr + sizeof(pufhd->chash)); + pufin->pufidaddr = (u64)(pufin->auxaddr + sizeof(pufhd->aux)); + + dma_sync_single_for_device(puf->dev, dma_addr_in, buflen, DMA_BIDIRECTIONAL); + ret = versal_pm_puf_regeneration(dma_addr_in); + dma_unmap_single(puf->dev, dma_addr_in, buflen, DMA_BIDIRECTIONAL); + if (ret) + goto cleanup; + + if (copy_to_user(u64_to_user_ptr(pufreq->pufidaddr), ((char *)pufhd + + sizeof(struct puf_helperdata)), + PUF_ID_LEN_IN_BYTES)) { + ret = -EFAULT; + goto cleanup; + } + +cleanup: + kfree(buf); + + return ret; +} + +static long xlnx_puf_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct xpuf_dev *puf = file->private_data; + struct puf_usrparams pufreq; + void __user *data = NULL; + int ret; + + if (_IOC_TYPE(cmd) != PUF_IOC_MAGIC) + return -ENOTTY; + + /* check if ioctl argument is present and valid */ + if (_IOC_DIR(cmd) != _IOC_NONE) { + data = (void __user *)arg; + if (!data) + return -EINVAL; + + if (copy_from_user(&pufreq, data, sizeof(struct puf_usrparams))) + return -EFAULT; + } + + switch (cmd) { + case PUF_REGISTRATION: + ret = xlnx_puf_regis(puf, &pufreq); + break; + case PUF_REGENERATION: + case PUF_REGEN_ID_ONLY: + ret = xlnx_puf_regen_id(puf, &pufreq); + break; + case PUF_CLEAR_ID: + if (!puf_clear) { + ret = -EOPNOTSUPP; + break; + } + ret = versal_pm_puf_clear_id(); + break; + case PUF_CLEAR_KEY: + if (!puf_clear) { + ret = -EOPNOTSUPP; + break; + } + ret = versal_pm_aes_init(); + if (!ret) + ret = versal_pm_puf_key_zero(); + break; + default: + return -ENOTTY; + } + + return ret; +} + +/** + * xlnx_puf_open - open puf device + * @inode: inode object + * @file: file object + * + * Return: 0 if successful; otherwise -errno + */ +static int xlnx_puf_open(struct inode *inode, struct file *file) +{ + struct xpuf_dev *xpuf; + + xpuf = container_of(file->private_data, struct xpuf_dev, miscdev); + file->private_data = xpuf; + + dev_dbg(xpuf->dev, "device /dev/xpuf opened\n"); + + return 0; +} + +/** + * xlnx_puf_release - release puf resources + * @inode: inode object + * @file: file object + * + * Return: 0 if successful; otherwise -errno + */ +static int xlnx_puf_release(struct inode *inode, struct file *file) +{ + struct xpuf_dev *xpuf = file->private_data; + + dev_dbg(xpuf->dev, "device /dev/xpuf closed\n"); + + return 0; +} + +static const struct file_operations xlnx_puf_fops = { + .owner = THIS_MODULE, + .open = xlnx_puf_open, + .release = xlnx_puf_release, + .unlocked_ioctl = xlnx_puf_ioctl, + .compat_ioctl = compat_ptr_ioctl, +}; + +/** + * xlnx_puf_probe - probe puf device + * @pdev: Pointer to puf platform device structure + * + * Return: 0 if successful; otherwise -errno + */ +static int xlnx_puf_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct xpuf_dev *xpuf; + int ret; + + xpuf = devm_kzalloc(dev, sizeof(*xpuf), GFP_KERNEL); + if (!xpuf) + return -ENOMEM; + + xpuf->dev = dev; + + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); + if (ret < 0) { + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); + if (ret < 0) { + dev_err(dev, "no usable DMA configuration\n"); + return ret; + } + } + + xpuf->miscdev.minor = MISC_DYNAMIC_MINOR; + xpuf->miscdev.name = "xpuf"; + xpuf->miscdev.fops = &xlnx_puf_fops; + xpuf->miscdev.parent = dev; + + ret = misc_register(&xpuf->miscdev); + if (ret) + return ret; + + platform_set_drvdata(pdev, xpuf); + + dev_dbg(dev, "puf registered as /dev/xpuf successfully\n"); + + return 0; +} + +/** + * xlnx_puf_remove - clean up structures + * @pdev: The structure containing the device's details + */ +static void xlnx_puf_remove(struct platform_device *pdev) +{ + struct xpuf_dev *xpuf = platform_get_drvdata(pdev); + + misc_deregister(&xpuf->miscdev); + + dev_dbg(xpuf->dev, "device /dev/xpuf removed\n"); +} + +static struct platform_driver xlnx_puf_drv = { + .probe = xlnx_puf_probe, + .remove = xlnx_puf_remove, + .driver = { + .name = "xlnx-puf", + }, +}; + +static struct platform_device *xlnx_puf_pdev; + +static int __init xlnx_puf_driver_init(void) +{ + int ret; + + ret = platform_driver_register(&xlnx_puf_drv); + if (ret) + return ret; + + xlnx_puf_pdev = platform_device_register_simple(xlnx_puf_drv.driver.name, + 0, NULL, 0); + if (IS_ERR(xlnx_puf_pdev)) { + ret = PTR_ERR(xlnx_puf_pdev); + platform_driver_unregister(&xlnx_puf_drv); + } + + return ret; +} + +static void __exit xlnx_puf_driver_exit(void) +{ + platform_device_unregister(xlnx_puf_pdev); + platform_driver_unregister(&xlnx_puf_drv); +} + +module_init(xlnx_puf_driver_init); +module_exit(xlnx_puf_driver_exit); + +MODULE_AUTHOR("AMD"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Xilinx Versal PUF driver"); diff --git a/include/uapi/misc/xilinx_puf.h b/include/uapi/misc/xilinx_puf.h new file mode 100644 index 000000000000..32565a748df3 --- /dev/null +++ b/include/uapi/misc/xilinx_puf.h @@ -0,0 +1,82 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Driver for Xilinx PUF device. + * + * Copyright (C) 2022 - 2026, Advanced Micro Devices, Inc. + * + * Description: + * This driver is developed for PUF registration and regeneration support. + */ + +#ifndef _UAPI_MISC_XILINX_PUF_H_ +#define _UAPI_MISC_XILINX_PUF_H_ + +#include +#include + +#define PUF_MAX_SYNDROME_DATA_LEN_IN_WORDS 140 +#define PUF_EFUSE_TRIM_SYN_DATA_IN_WORDS 127 +#define PUF_ID_LEN_IN_WORDS 8 +#define PUF_ID_LEN_IN_BYTES 32 +#define PUF_REGIS 0 +#define PUF_REGEN 1 +#define PUF_REGEN_ID 2 + +/** + * struct puf_usrparams - user parameters for PUF from user space. + * @pufoperation: PUF registration or regeneration operation + * @globalvarfilter: global variation filter + * @readoption: option to read PUF data from efuse cache or ram address + * @reserved: explicit padding to match the Versal PLM PUF parameter layout + * @shuttervalue: shutter value for PUF registration/regeneration + * @pufdataaddr: address to store/get the puf data during registration/regeneration + * @pufidaddr: puf id will be stored either during registration/regeneration + */ +struct puf_usrparams { + __u8 pufoperation; + __u8 globalvarfilter; + __u8 readoption; + __u8 reserved; + __u32 shuttervalue; + __u64 pufdataaddr; + __u64 pufidaddr; +}; + +/** + * struct puf_helperdata - parameters for puf helper data. + * @syndata: PUF syndrome data + * @chash: PUF chash + * @aux: PUF aux + */ +struct puf_helperdata { + __u32 syndata[PUF_MAX_SYNDROME_DATA_LEN_IN_WORDS]; + __u32 chash; + __u32 aux; +}; + +/** + * struct pufdata - parameters for puf data. + * @pufhd: puf helper data of type struct puf_helperdata + * @pufid: PUF id + * @efusesyndata: PUF efuse syndrome data + */ +struct pufdata { + struct puf_helperdata pufhd; + __u32 pufid[PUF_ID_LEN_IN_WORDS]; + __u32 efusesyndata[PUF_EFUSE_TRIM_SYN_DATA_IN_WORDS]; +}; + +enum pufreadoption { + PUF_READ_FROM_RAM = 0, + PUF_READ_FROM_EFUSE_CACHE = 1 +}; + +#define PUF_IOC_MAGIC 'P' + +#define PUF_REGISTRATION _IOWR(PUF_IOC_MAGIC, 1, struct puf_usrparams) +#define PUF_REGENERATION _IOWR(PUF_IOC_MAGIC, 2, struct puf_usrparams) +#define PUF_REGEN_ID_ONLY _IOWR(PUF_IOC_MAGIC, 3, struct puf_usrparams) +#define PUF_CLEAR_ID _IO(PUF_IOC_MAGIC, 4) +#define PUF_CLEAR_KEY _IO(PUF_IOC_MAGIC, 5) + +#endif /* _UAPI_MISC_XILINX_PUF_H_ */ -- 2.34.1