ANDROID: KVM: arm64: Parse S2MPU MMIO region

Start EL1 portion of the S2MPU driver with an init function which
probes the Device tree for nodes compatible with 'google,s2mpu'.
Parse and check the base, size and power domain ID.

Test: builds, boots
Bug: 190463801
Change-Id: I5f0b32febb4e922fdfdfe10a9a9c823e20b8e26f
Signed-off-by: David Brazdil <dbrazdil@google.com>
(cherry picked from commit 4e91a00153)
Signed-off-by: Mostafa Saleh <smostafa@google.com>
This commit is contained in:
David Brazdil
2021-06-17 14:23:25 +00:00
committed by Mostafa Saleh
parent 0295ee70f1
commit 0762b05d9c
2 changed files with 92 additions and 1 deletions

View File

@@ -0,0 +1,16 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2021 - Google LLC
* Author: David Brazdil <dbrazdil@google.com>
*/
#ifndef __ARM64_KVM_S2MPU_H__
#define __ARM64_KVM_S2MPU_H__
enum s2mpu_power_state {
S2MPU_POWER_ALWAYS_ON,
S2MPU_POWER_ON,
S2MPU_POWER_OFF,
};
#endif /* __ARM64_KVM_S2MPU_H__ */

View File

@@ -5,9 +5,84 @@
*/
#include <linux/kvm_host.h>
#include <linux/of_platform.h>
#include <asm/kvm_mmu.h>
#include <asm/kvm_s2mpu.h>
#define S2MPU_MMIO_SIZE SZ_64K
static int s2mpu_probe(struct platform_device *pdev)
{
struct resource *res;
void __iomem *kaddr;
size_t res_size;
enum s2mpu_power_state power_state = S2MPU_POWER_ALWAYS_ON;
u32 power_domain_id = 0;
int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "failed to parse 'reg'");
return -EINVAL;
}
/* devm_ioremap_resource internally calls devm_request_mem_region. */
kaddr = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(kaddr)) {
dev_err(&pdev->dev, "could not ioremap resource: %ld",
PTR_ERR(kaddr));
return PTR_ERR(kaddr);
}
if (!PAGE_ALIGNED(res->start)) {
dev_err(&pdev->dev, "base address must be page-aligned (0x%llx)",
res->start);
return -EINVAL;
}
res_size = resource_size(res);
if (res_size != S2MPU_MMIO_SIZE) {
dev_err(&pdev->dev,
"unexpected device region size (expected=%u, actual=%lu)",
S2MPU_MMIO_SIZE, res_size);
return -EINVAL;
}
ret = of_property_read_u32(pdev->dev.of_node, "power-domain-id",
&power_domain_id);
if (!ret) {
power_state = S2MPU_POWER_ON;
} else if (ret != -EINVAL) {
dev_err(&pdev->dev, "failed to parse power-domain-id: %d", ret);
return ret;
}
return 0;
}
static const struct of_device_id of_table[] = {
{ .compatible = "google,s2mpu" },
{},
};
static struct platform_driver of_driver = {
.driver = {
.name = "kvm,s2mpu",
.of_match_table = of_table,
},
};
int kvm_s2mpu_init(void)
{
int ret;
ret = platform_driver_probe(&of_driver, s2mpu_probe);
if (ret)
goto out;
kvm_info("S2MPU driver initialized\n");
return 0;
out:
return ret;
}