brintos

brintos / linux-shallow public Read only

0
0
Text · 5.5 KiB · 1b8ed33 Raw
228 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * AMD Platform Security Processor (PSP) Platform Access interface4 *5 * Copyright (C) 2023 Advanced Micro Devices, Inc.6 *7 * Author: Mario Limonciello <mario.limonciello@amd.com>8 *9 * Some of this code is adapted from drivers/i2c/busses/i2c-designware-amdpsp.c10 * developed by Jan Dabros <jsd@semihalf.com> and Copyright (C) 2022 Google Inc.11 *12 */13 14#include <linux/bitfield.h>15#include <linux/errno.h>16#include <linux/iopoll.h>17#include <linux/mutex.h>18 19#include "platform-access.h"20 21#define PSP_CMD_TIMEOUT_US	(500 * USEC_PER_MSEC)22#define DOORBELL_CMDRESP_STS	GENMASK(7, 0)23 24/* Recovery field should be equal 0 to start sending commands */25static int check_recovery(u32 __iomem *cmd)26{27	return FIELD_GET(PSP_CMDRESP_RECOVERY, ioread32(cmd));28}29 30static int wait_cmd(u32 __iomem *cmd)31{32	u32 tmp, expected;33 34	/* Expect mbox_cmd to be cleared and ready bit to be set by PSP */35	expected = FIELD_PREP(PSP_CMDRESP_RESP, 1);36 37	/*38	 * Check for readiness of PSP mailbox in a tight loop in order to39	 * process further as soon as command was consumed.40	 */41	return readl_poll_timeout(cmd, tmp, (tmp & expected), 0,42				  PSP_CMD_TIMEOUT_US);43}44 45int psp_check_platform_access_status(void)46{47	struct psp_device *psp = psp_get_master_device();48 49	if (!psp || !psp->platform_access_data)50		return -ENODEV;51 52	return 0;53}54EXPORT_SYMBOL(psp_check_platform_access_status);55 56int psp_send_platform_access_msg(enum psp_platform_access_msg msg,57				 struct psp_request *req)58{59	struct psp_device *psp = psp_get_master_device();60	u32 __iomem *cmd, *lo, *hi;61	struct psp_platform_access_device *pa_dev;62	phys_addr_t req_addr;63	u32 cmd_reg;64	int ret;65 66	if (!psp || !psp->platform_access_data)67		return -ENODEV;68 69	pa_dev = psp->platform_access_data;70 71	if (!pa_dev->vdata->cmdresp_reg || !pa_dev->vdata->cmdbuff_addr_lo_reg ||72	    !pa_dev->vdata->cmdbuff_addr_hi_reg)73		return -ENODEV;74 75	cmd = psp->io_regs + pa_dev->vdata->cmdresp_reg;76	lo = psp->io_regs + pa_dev->vdata->cmdbuff_addr_lo_reg;77	hi = psp->io_regs + pa_dev->vdata->cmdbuff_addr_hi_reg;78 79	mutex_lock(&pa_dev->mailbox_mutex);80 81	if (check_recovery(cmd)) {82		dev_dbg(psp->dev, "platform mailbox is in recovery\n");83		ret = -EBUSY;84		goto unlock;85	}86 87	if (wait_cmd(cmd)) {88		dev_dbg(psp->dev, "platform mailbox is not done processing command\n");89		ret = -EBUSY;90		goto unlock;91	}92 93	/*94	 * Fill mailbox with address of command-response buffer, which will be95	 * used for sending i2c requests as well as reading status returned by96	 * PSP. Use physical address of buffer, since PSP will map this region.97	 */98	req_addr = __psp_pa(req);99	iowrite32(lower_32_bits(req_addr), lo);100	iowrite32(upper_32_bits(req_addr), hi);101 102	print_hex_dump_debug("->psp ", DUMP_PREFIX_OFFSET, 16, 2, req,103			     req->header.payload_size, false);104 105	/* Write command register to trigger processing */106	cmd_reg = FIELD_PREP(PSP_CMDRESP_CMD, msg);107	iowrite32(cmd_reg, cmd);108 109	if (wait_cmd(cmd)) {110		ret = -ETIMEDOUT;111		goto unlock;112	}113 114	/* Ensure it was triggered by this driver */115	if (ioread32(lo) != lower_32_bits(req_addr) ||116	    ioread32(hi) != upper_32_bits(req_addr)) {117		ret = -EBUSY;118		goto unlock;119	}120 121	/*122	 * Read status from PSP. If status is non-zero, it indicates an error123	 * occurred during "processing" of the command.124	 * If status is zero, it indicates the command was "processed"125	 * successfully, but the result of the command is in the payload.126	 * Return both cases to the caller as -EIO to investigate.127	 */128	cmd_reg = ioread32(cmd);129	if (FIELD_GET(PSP_CMDRESP_STS, cmd_reg))130		req->header.status = FIELD_GET(PSP_CMDRESP_STS, cmd_reg);131	if (req->header.status) {132		ret = -EIO;133		goto unlock;134	}135 136	print_hex_dump_debug("<-psp ", DUMP_PREFIX_OFFSET, 16, 2, req,137			     req->header.payload_size, false);138 139	ret = 0;140 141unlock:142	mutex_unlock(&pa_dev->mailbox_mutex);143 144	return ret;145}146EXPORT_SYMBOL_GPL(psp_send_platform_access_msg);147 148int psp_ring_platform_doorbell(int msg, u32 *result)149{150	struct psp_device *psp = psp_get_master_device();151	struct psp_platform_access_device *pa_dev;152	u32 __iomem *button, *cmd;153	int ret, val;154 155	if (!psp || !psp->platform_access_data)156		return -ENODEV;157 158	pa_dev = psp->platform_access_data;159	button = psp->io_regs + pa_dev->vdata->doorbell_button_reg;160	cmd = psp->io_regs + pa_dev->vdata->doorbell_cmd_reg;161 162	mutex_lock(&pa_dev->doorbell_mutex);163 164	if (wait_cmd(cmd)) {165		dev_err(psp->dev, "doorbell command not done processing\n");166		ret = -EBUSY;167		goto unlock;168	}169 170	iowrite32(FIELD_PREP(DOORBELL_CMDRESP_STS, msg), cmd);171	iowrite32(PSP_DRBL_RING, button);172 173	if (wait_cmd(cmd)) {174		ret = -ETIMEDOUT;175		goto unlock;176	}177 178	val = FIELD_GET(DOORBELL_CMDRESP_STS, ioread32(cmd));179	if (val) {180		if (result)181			*result = val;182		ret = -EIO;183		goto unlock;184	}185 186	ret = 0;187unlock:188	mutex_unlock(&pa_dev->doorbell_mutex);189 190	return ret;191}192EXPORT_SYMBOL_GPL(psp_ring_platform_doorbell);193 194void platform_access_dev_destroy(struct psp_device *psp)195{196	struct psp_platform_access_device *pa_dev = psp->platform_access_data;197 198	if (!pa_dev)199		return;200 201	mutex_destroy(&pa_dev->mailbox_mutex);202	mutex_destroy(&pa_dev->doorbell_mutex);203	psp->platform_access_data = NULL;204}205 206int platform_access_dev_init(struct psp_device *psp)207{208	struct device *dev = psp->dev;209	struct psp_platform_access_device *pa_dev;210 211	pa_dev = devm_kzalloc(dev, sizeof(*pa_dev), GFP_KERNEL);212	if (!pa_dev)213		return -ENOMEM;214 215	psp->platform_access_data = pa_dev;216	pa_dev->psp = psp;217	pa_dev->dev = dev;218 219	pa_dev->vdata = (struct platform_access_vdata *)psp->vdata->platform_access;220 221	mutex_init(&pa_dev->mailbox_mutex);222	mutex_init(&pa_dev->doorbell_mutex);223 224	dev_dbg(dev, "platform access enabled\n");225 226	return 0;227}228