1bb04ffe8SClaudio Carvalho // SPDX-License-Identifier: GPL-2.0
2bb04ffe8SClaudio Carvalho /*
3bb04ffe8SClaudio Carvalho  * Ultravisor high level interfaces
4bb04ffe8SClaudio Carvalho  *
5bb04ffe8SClaudio Carvalho  * Copyright 2019, IBM Corporation.
6bb04ffe8SClaudio Carvalho  *
7bb04ffe8SClaudio Carvalho  */
8bb04ffe8SClaudio Carvalho #include <linux/init.h>
9bb04ffe8SClaudio Carvalho #include <linux/printk.h>
10bb04ffe8SClaudio Carvalho #include <linux/of_fdt.h>
1168e0aa8eSClaudio Carvalho #include <linux/of.h>
12bb04ffe8SClaudio Carvalho 
13bb04ffe8SClaudio Carvalho #include <asm/ultravisor.h>
14bb04ffe8SClaudio Carvalho #include <asm/firmware.h>
1568e0aa8eSClaudio Carvalho #include <asm/machdep.h>
1668e0aa8eSClaudio Carvalho 
1768e0aa8eSClaudio Carvalho #include "powernv.h"
1868e0aa8eSClaudio Carvalho 
1968e0aa8eSClaudio Carvalho static struct kobject *ultravisor_kobj;
20bb04ffe8SClaudio Carvalho 
early_init_dt_scan_ultravisor(unsigned long node,const char * uname,int depth,void * data)21bb04ffe8SClaudio Carvalho int __init early_init_dt_scan_ultravisor(unsigned long node, const char *uname,
22bb04ffe8SClaudio Carvalho 					 int depth, void *data)
23bb04ffe8SClaudio Carvalho {
24bb04ffe8SClaudio Carvalho 	if (!of_flat_dt_is_compatible(node, "ibm,ultravisor"))
25bb04ffe8SClaudio Carvalho 		return 0;
26bb04ffe8SClaudio Carvalho 
27bb04ffe8SClaudio Carvalho 	powerpc_firmware_features |= FW_FEATURE_ULTRAVISOR;
28bb04ffe8SClaudio Carvalho 	pr_debug("Ultravisor detected!\n");
29bb04ffe8SClaudio Carvalho 	return 1;
30bb04ffe8SClaudio Carvalho }
3168e0aa8eSClaudio Carvalho 
3268e0aa8eSClaudio Carvalho static struct memcons *uv_memcons;
3368e0aa8eSClaudio Carvalho 
uv_msglog_read(struct file * file,struct kobject * kobj,struct bin_attribute * bin_attr,char * to,loff_t pos,size_t count)3468e0aa8eSClaudio Carvalho static ssize_t uv_msglog_read(struct file *file, struct kobject *kobj,
3568e0aa8eSClaudio Carvalho 			      struct bin_attribute *bin_attr, char *to,
3668e0aa8eSClaudio Carvalho 			      loff_t pos, size_t count)
3768e0aa8eSClaudio Carvalho {
3868e0aa8eSClaudio Carvalho 	return memcons_copy(uv_memcons, to, pos, count);
3968e0aa8eSClaudio Carvalho }
4068e0aa8eSClaudio Carvalho 
4168e0aa8eSClaudio Carvalho static struct bin_attribute uv_msglog_attr = {
4268e0aa8eSClaudio Carvalho 	.attr = {.name = "msglog", .mode = 0400},
4368e0aa8eSClaudio Carvalho 	.read = uv_msglog_read
4468e0aa8eSClaudio Carvalho };
4568e0aa8eSClaudio Carvalho 
uv_init(void)4668e0aa8eSClaudio Carvalho static int __init uv_init(void)
4768e0aa8eSClaudio Carvalho {
4868e0aa8eSClaudio Carvalho 	struct device_node *node;
4968e0aa8eSClaudio Carvalho 
5068e0aa8eSClaudio Carvalho 	if (!firmware_has_feature(FW_FEATURE_ULTRAVISOR))
5168e0aa8eSClaudio Carvalho 		return 0;
5268e0aa8eSClaudio Carvalho 
5368e0aa8eSClaudio Carvalho 	node = of_find_compatible_node(NULL, NULL, "ibm,uv-firmware");
5468e0aa8eSClaudio Carvalho 	if (!node)
5568e0aa8eSClaudio Carvalho 		return -ENODEV;
5668e0aa8eSClaudio Carvalho 
5768e0aa8eSClaudio Carvalho 	uv_memcons = memcons_init(node, "memcons");
58a4a6a382SLv Ruyi 	of_node_put(node);
5968e0aa8eSClaudio Carvalho 	if (!uv_memcons)
6068e0aa8eSClaudio Carvalho 		return -ENOENT;
6168e0aa8eSClaudio Carvalho 
6268e0aa8eSClaudio Carvalho 	uv_msglog_attr.size = memcons_get_size(uv_memcons);
6368e0aa8eSClaudio Carvalho 
6468e0aa8eSClaudio Carvalho 	ultravisor_kobj = kobject_create_and_add("ultravisor", firmware_kobj);
6568e0aa8eSClaudio Carvalho 	if (!ultravisor_kobj)
6668e0aa8eSClaudio Carvalho 		return -ENOMEM;
6768e0aa8eSClaudio Carvalho 
6868e0aa8eSClaudio Carvalho 	return sysfs_create_bin_file(ultravisor_kobj, &uv_msglog_attr);
6968e0aa8eSClaudio Carvalho }
7068e0aa8eSClaudio Carvalho machine_subsys_initcall(powernv, uv_init);
71