File Index
Files and directories
Sign in
FILE

ufs-rpmb.c

File preview with syntax highlighting.

linux-6.19.14/drivers/ufs/core/ufs-rpmb.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * UFS OP-TEE based RPMB Driver
  4 *
  5 * Copyright (C) 2025 Micron Technology, Inc.
  6 * Copyright (C) 2025 Qualcomm Technologies, Inc.
  7 *
  8 * Authors:
  9 *	Bean Huo <beanhuo@micron.com>
 10 *	Can Guo <can.guo@oss.qualcomm.com>
 11 */
 12
 13#include <linux/module.h>
 14#include <linux/device.h>
 15#include <linux/kernel.h>
 16#include <linux/types.h>
 17#include <linux/rpmb.h>
 18#include <linux/string.h>
 19#include <linux/list.h>
 20#include <ufs/ufshcd.h>
 21#include <linux/unaligned.h>
 22#include "ufshcd-priv.h"
 23
 24#define UFS_RPMB_SEC_PROTOCOL		0xEC	/* JEDEC UFS application */
 25#define UFS_RPMB_SEC_PROTOCOL_ID	0x01	/* JEDEC UFS RPMB protocol ID, CDB byte3 */
 26
 27static const struct bus_type ufs_rpmb_bus_type = {
 28	.name = "ufs_rpmb",
 29};
 30
 31/* UFS RPMB device structure */
 32struct ufs_rpmb_dev {
 33	u8 region_id;
 34	struct device dev;
 35	struct rpmb_dev *rdev;
 36	struct ufs_hba *hba;
 37	struct list_head node;
 38};
 39
 40static int ufs_sec_submit(struct ufs_hba *hba, u16 spsp, void *buffer, size_t len, bool send)
 41{
 42	struct scsi_device *sdev = hba->ufs_rpmb_wlun;
 43	u8 cdb[12] = { };
 44
 45	cdb[0] = send ? SECURITY_PROTOCOL_OUT : SECURITY_PROTOCOL_IN;
 46	cdb[1] = UFS_RPMB_SEC_PROTOCOL;
 47	put_unaligned_be16(spsp, &cdb[2]);
 48	put_unaligned_be32(len, &cdb[6]);
 49
 50	return scsi_execute_cmd(sdev, cdb, send ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN,
 51				buffer, len, /*timeout=*/30 * HZ, 0, NULL);
 52}
 53
 54/* UFS RPMB route frames implementation */
 55static int ufs_rpmb_route_frames(struct device *dev, u8 *req, unsigned int req_len, u8 *resp,
 56					unsigned int resp_len)
 57{
 58	struct ufs_rpmb_dev *ufs_rpmb = dev_get_drvdata(dev);
 59	struct rpmb_frame *frm_out = (struct rpmb_frame *)req;
 60	bool need_result_read = true;
 61	u16 req_type, protocol_id;
 62	struct ufs_hba *hba;
 63	int ret;
 64
 65	if (!ufs_rpmb) {
 66		dev_err(dev, "Missing driver data\n");
 67		return -ENODEV;
 68	}
 69
 70	hba = ufs_rpmb->hba;
 71
 72	req_type = be16_to_cpu(frm_out->req_resp);
 73
 74	switch (req_type) {
 75	case RPMB_PROGRAM_KEY:
 76		if (req_len != sizeof(struct rpmb_frame) || resp_len != sizeof(struct rpmb_frame))
 77			return -EINVAL;
 78		break;
 79	case RPMB_GET_WRITE_COUNTER:
 80		if (req_len != sizeof(struct rpmb_frame) || resp_len != sizeof(struct rpmb_frame))
 81			return -EINVAL;
 82		need_result_read = false;
 83		break;
 84	case RPMB_WRITE_DATA:
 85		if (req_len % sizeof(struct rpmb_frame) || resp_len != sizeof(struct rpmb_frame))
 86			return -EINVAL;
 87		break;
 88	case RPMB_READ_DATA:
 89		if (req_len != sizeof(struct rpmb_frame) || resp_len % sizeof(struct rpmb_frame))
 90			return -EINVAL;
 91		need_result_read = false;
 92		break;
 93	default:
 94		dev_err(dev, "Unknown request type=0x%04x\n", req_type);
 95		return -EINVAL;
 96	}
 97
 98	protocol_id = ufs_rpmb->region_id << 8 | UFS_RPMB_SEC_PROTOCOL_ID;
 99
100	ret = ufs_sec_submit(hba, protocol_id, req, req_len, true);
101	if (ret) {
102		dev_err(dev, "Command failed with ret=%d\n", ret);
103		return ret;
104	}
105
106	if (need_result_read) {
107		struct rpmb_frame *frm_resp = (struct rpmb_frame *)resp;
108
109		memset(frm_resp, 0, sizeof(*frm_resp));
110		frm_resp->req_resp = cpu_to_be16(RPMB_RESULT_READ);
111		ret = ufs_sec_submit(hba, protocol_id, resp, resp_len, true);
112		if (ret) {
113			dev_err(dev, "Result read request failed with ret=%d\n", ret);
114			return ret;
115		}
116	}
117
118	if (!ret) {
119		ret = ufs_sec_submit(hba, protocol_id, resp, resp_len, false);
120		if (ret)
121			dev_err(dev, "Response read failed with ret=%d\n", ret);
122	}
123
124	return ret;
125}
126
127static void ufs_rpmb_device_release(struct device *dev)
128{
129	struct ufs_rpmb_dev *ufs_rpmb = dev_get_drvdata(dev);
130
131	rpmb_dev_unregister(ufs_rpmb->rdev);
132}
133
134/* UFS RPMB device registration */
135int ufs_rpmb_probe(struct ufs_hba *hba)
136{
137	struct ufs_rpmb_dev *ufs_rpmb, *it, *tmp;
138	struct rpmb_dev *rdev;
139	char *cid = NULL;
140	int region;
141	u32 cap;
142	int ret;
143
144	if (!hba->ufs_rpmb_wlun || hba->dev_info.b_advanced_rpmb_en) {
145		dev_info(hba->dev, "Skip OP-TEE RPMB registration\n");
146		return -ENODEV;
147	}
148
149	/* Check if device_id is available */
150	if (!hba->dev_info.device_id) {
151		dev_err(hba->dev, "UFS Device ID not available\n");
152		return -EINVAL;
153	}
154
155	INIT_LIST_HEAD(&hba->rpmbs);
156
157	struct rpmb_descr descr = {
158		.type = RPMB_TYPE_UFS,
159		.route_frames = ufs_rpmb_route_frames,
160		.reliable_wr_count = hba->dev_info.rpmb_io_size,
161	};
162
163	for (region = 0; region < ARRAY_SIZE(hba->dev_info.rpmb_region_size); region++) {
164		cap = hba->dev_info.rpmb_region_size[region];
165		if (!cap)
166			continue;
167
168		ufs_rpmb = devm_kzalloc(hba->dev, sizeof(*ufs_rpmb), GFP_KERNEL);
169		if (!ufs_rpmb) {
170			ret = -ENOMEM;
171			goto err_out;
172		}
173
174		ufs_rpmb->hba = hba;
175		ufs_rpmb->dev.parent = &hba->ufs_rpmb_wlun->sdev_gendev;
176		ufs_rpmb->dev.bus = &ufs_rpmb_bus_type;
177		ufs_rpmb->dev.release = ufs_rpmb_device_release;
178		dev_set_name(&ufs_rpmb->dev, "ufs_rpmb%d", region);
179
180		/* Set driver data BEFORE device_register */
181		dev_set_drvdata(&ufs_rpmb->dev, ufs_rpmb);
182
183		ret = device_register(&ufs_rpmb->dev);
184		if (ret) {
185			dev_err(hba->dev, "Failed to register UFS RPMB device %d\n", region);
186			put_device(&ufs_rpmb->dev);
187			goto err_out;
188		}
189
190		/* Create unique ID by appending region number to device_id */
191		cid = kasprintf(GFP_KERNEL, "%s-R%d", hba->dev_info.device_id, region);
192		if (!cid) {
193			device_unregister(&ufs_rpmb->dev);
194			ret = -ENOMEM;
195			goto err_out;
196		}
197
198		descr.dev_id = cid;
199		descr.dev_id_len = strlen(cid);
200		descr.capacity = cap;
201
202		/* Register RPMB device */
203		rdev = rpmb_dev_register(&ufs_rpmb->dev, &descr);
204		if (IS_ERR(rdev)) {
205			dev_err(hba->dev, "Failed to register UFS RPMB device.\n");
206			device_unregister(&ufs_rpmb->dev);
207			ret = PTR_ERR(rdev);
208			goto err_out;
209		}
210
211		kfree(cid);
212		cid = NULL;
213
214		ufs_rpmb->rdev = rdev;
215		ufs_rpmb->region_id = region;
216
217		list_add_tail(&ufs_rpmb->node, &hba->rpmbs);
218
219		dev_info(hba->dev, "UFS RPMB region %d registered (capacity=%u)\n", region, cap);
220	}
221
222	return 0;
223err_out:
224	kfree(cid);
225	list_for_each_entry_safe(it, tmp, &hba->rpmbs, node) {
226		list_del(&it->node);
227		device_unregister(&it->dev);
228	}
229
230	return ret;
231}
232
233/* UFS RPMB remove handler */
234void ufs_rpmb_remove(struct ufs_hba *hba)
235{
236	struct ufs_rpmb_dev *ufs_rpmb, *tmp;
237
238	if (list_empty(&hba->rpmbs))
239		return;
240
241	/* Remove all registered RPMB devices */
242	list_for_each_entry_safe(ufs_rpmb, tmp, &hba->rpmbs, node) {
243		dev_info(hba->dev, "Removing UFS RPMB region %d\n", ufs_rpmb->region_id);
244		/* Remove from list first */
245		list_del(&ufs_rpmb->node);
246		/* Unregister device */
247		device_unregister(&ufs_rpmb->dev);
248	}
249
250	dev_info(hba->dev, "All UFS RPMB devices unregistered\n");
251}
252
253MODULE_LICENSE("GPL v2");
254MODULE_DESCRIPTION("OP-TEE UFS RPMB driver");
~/ Read-only file preview.