diff mbox series

[v2,6/8] crypto: ccp - Add vdata for platform device

Message ID 20230213092429.1167812-7-jpiotrowski@linux.microsoft.com
State Superseded
Headers show
Series Support ACPI PSP on Hyper-V | expand

Commit Message

Jeremi Piotrowski Feb. 13, 2023, 9:24 a.m. UTC
When matching the "psp" platform_device, the register offsets are
determined at runtime from the ASP ACPI table. The structure containing
the offset is passed through the platform data field provided before
registering the platform device.

To support this scenario, dynamically allocate vdata structs and fill
those in with offsets provided by the platform. Due to the fields of the
structs being const, it was necessary to use temporary structs and
memcpy, as any assignment of the whole struct fails with an 'read-only
location' compiler error.

Signed-off-by: Jeremi Piotrowski <jpiotrowski@linux.microsoft.com>
---
 drivers/crypto/ccp/sp-platform.c | 57 ++++++++++++++++++++++++++++++++
 1 file changed, 57 insertions(+)
diff mbox series

Patch

diff --git a/drivers/crypto/ccp/sp-platform.c b/drivers/crypto/ccp/sp-platform.c
index 5dcc834deb72..2e57ec15046b 100644
--- a/drivers/crypto/ccp/sp-platform.c
+++ b/drivers/crypto/ccp/sp-platform.c
@@ -22,6 +22,7 @@ 
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/acpi.h>
+#include <linux/platform_data/psp.h>
 
 #include "ccp-dev.h"
 
@@ -86,6 +87,60 @@  static struct sp_dev_vdata *sp_get_acpi_version(struct platform_device *pdev)
 	return NULL;
 }
 
+static void sp_platform_fill_vdata(struct sp_dev_vdata *vdata, struct psp_vdata *psp,
+				   struct sev_vdata *sev, const struct psp_platform_data *pdata)
+{
+	struct sev_vdata sevtmp = {
+		.cmdresp_reg = pdata->sev_cmd_resp_reg,
+		.cmdbuff_addr_lo_reg = pdata->sev_cmd_buf_lo_reg,
+		.cmdbuff_addr_hi_reg = pdata->sev_cmd_buf_hi_reg,
+	};
+	struct psp_vdata psptmp = {
+		.sev = sev,
+		.feature_reg = pdata->feature_reg,
+		.inten_reg = pdata->irq_en_reg,
+		.intsts_reg = pdata->irq_st_reg,
+	};
+
+	memcpy(sev, &sevtmp, sizeof(*sev));
+	memcpy(psp, &psptmp, sizeof(*psp));
+	vdata->psp_vdata = psp;
+}
+
+static struct sp_dev_vdata *sp_get_platform_version(struct sp_device *sp)
+{
+	struct psp_platform_data *pdata;
+	struct device *dev = sp->dev;
+	struct sp_dev_vdata *vdata;
+	struct psp_vdata *psp;
+	struct sev_vdata *sev;
+
+	pdata = dev_get_platdata(dev);
+	if (!pdata) {
+		dev_err(dev, "missing platform data\n");
+		return NULL;
+	}
+
+	vdata = devm_kzalloc(dev, sizeof(*vdata) + sizeof(*psp) + sizeof(*sev), GFP_KERNEL);
+	if (!vdata)
+		return NULL;
+
+	psp = (void *)vdata + sizeof(*vdata);
+	sev = (void *)psp + sizeof(*psp);
+	sp_platform_fill_vdata(vdata, psp, sev, pdata);
+
+	dev_dbg(dev, "PSP feature register:\t%x\n", psp->feature_reg);
+	dev_dbg(dev, "PSP IRQ enable register:\t%x\n", psp->inten_reg);
+	dev_dbg(dev, "PSP IRQ status register:\t%x\n", psp->intsts_reg);
+	dev_dbg(dev, "SEV cmdresp register:\t%x\n", sev->cmdresp_reg);
+	dev_dbg(dev, "SEV cmdbuf lo register:\t%x\n", sev->cmdbuff_addr_lo_reg);
+	dev_dbg(dev, "SEV cmdbuf hi register:\t%x\n", sev->cmdbuff_addr_hi_reg);
+	dev_dbg(dev, "SEV cmdresp IRQ:\t%x\n", pdata->mbox_irq_id);
+	dev_dbg(dev, "ACPI cmdresp register:\t%x\n", pdata->acpi_cmd_resp_reg);
+
+	return vdata;
+}
+
 static int sp_get_irqs(struct sp_device *sp)
 {
 	struct sp_platform *sp_platform = sp->dev_specific;
@@ -137,6 +192,8 @@  static int sp_platform_probe(struct platform_device *pdev)
 	sp->dev_specific = sp_platform;
 	sp->dev_vdata = pdev->dev.of_node ? sp_get_of_version(pdev)
 					 : sp_get_acpi_version(pdev);
+	if (!sp->dev_vdata)
+		sp->dev_vdata = sp_get_platform_version(sp);
 	if (!sp->dev_vdata) {
 		ret = -ENODEV;
 		dev_err(dev, "missing driver data\n");