All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC v2 0/8] Introduce SCI-mediator feature
@ 2022-02-08 18:00 Oleksii Moisieiev
  2022-02-08 18:00 ` [RFC v2 1/8] xen/hypfs: support fo nested dynamic hypfs nodes Oleksii Moisieiev
                   ` (7 more replies)
  0 siblings, 8 replies; 45+ messages in thread
From: Oleksii Moisieiev @ 2022-02-08 18:00 UTC (permalink / raw)
  To: xen-devel
  Cc: Oleksii Moisieiev, Juergen Gross, Wei Liu, Stefano Stabellini,
	Julien Grall, Volodymyr Babchuk, Bertrand Marquis, Andrew Cooper,
	George Dunlap, Jan Beulich, Nick Rosbrook, Anthony PERARD,
	Paul Durrant

Introducing the feature, called SCI mediator.
It's purpose is to redirect SCMI requests from the domains to firmware
(SCP, ATF etc), which controls the power/clock/resets etc.
The idea is to make SCP firmware (or similar, such as AT-F) responsible for
control power/clock/resets and provide SCMI interface so controls can be shared
between the Domains.
Originally, we've met a problem, that the devices, shared between different
Domains, can't have an access to HW registers to work with clocks/resets/power
etc. You have to pass cpg to the Domain, so the devices can access HW directly.
The solution for this is to move HW controls over power/clock/resets to
SCP firmware and use Linux-kernel SCMI drivers to pass requests to SCP.
Xen is responsible for permissions setting, so Domain can access only to
power/clock/resets which are related to this Domain. Also XEN is the mediator
which redirects SCMI requests, adding agentID so firmware should know the
sender.
SMC is currently used as transport, but this should be configurable.

Here is the high level design:

ARM_SCI (System Control Interface) feature can be enabled in xen_config:
> CONFIG_ARM_SCI=y
Mediator can be configured:
> CONFIG_SCMI_SMC=y

Currently, only SCMI_SMC mediator is implemented, which using shared memory
region to communicate with firmware and SMC as transport.

Xen scmi should be configured in the device-tree.
Format is the following:
	cpu_scp_shm: scp-shmem@0x53FF0000 {
		compatible = "arm,scmi-shmem";
		reg = <0x0 0x53FF0000 0x0 0x1000>;
	};

	firmware {
		scmi {
			compatible = "arm,scmi-smc";
			arm,smc-id = <0x82000002>;
			shmem = <&cpu_scp_shm>;
			#address-cells = <1>;
			#size-cells = <0>;

			scmi_power: protocol@11 {
				reg = <0x11>;
				#power-domain-cells = <1>;
			};

			scmi_clock: protocol@14 {
				reg = <0x14>;
				#clock-cells = <1>;
			};

			scmi_reset: protocol@16 {
				reg = <0x16>;
				#reset-cells = <1>;
			};
		};
	};

Where:
&cpu_scp_shm is the shared memory for scmi buffers;
0x53FF0000, size 0x1000 is the platform specific free address, which provide
space for the communication.
&scmi node, which should be copied to Dom0 device-tree.

Device configured to use scmi: 
&avb {
	scmi_devid = <0>;
	clocks = <&scmi_clock 0>;
	power-domains = <&scmi_power 0>;
	resets = <&scmi_reset 0>;
};

Where:
scmi_devid - id from the firmware, which is assigned for AVB.

During initialization, XEN scans probes the first SCI-mediator driver which has
matching node in the device-tree. If no device-tree was provided, then the
first registered mediator driver should be probed.

DomX should be configured:
Device-tree should include the same nodes, described above.
&cpu_scp_shm should be altered during domain creation. Xen allocates free page
from the memory region, provided in &cpu_scp_shm in XEN device-tree, so each
domain should have unique page. Nodes &cpu_scp_shm and /firmware/scmi should be
copied from partial device-tree to domain device-tree, so kernel can initialize
scmi driver.

SCI mediator can be enabled in dom.cfg the following way:
>arm_sci = "scmi_smc"

which sets scmi_smc to be used for the domain.
--
Changes since v1:

- renamed sci to arm_sci
- updated golang bindings
- reused XEN_DOMCTL_assign_device logic to add arm_sci devices instead of
adding new hypercall
- minor style changes
- fixed arm32 compilation issues
- use ioremap_cache instead of vmap to map shared memory for SCMI
- introduced memcpy_fromio and memcpy_toio fucntions instead of memcpy, moved
from Linux kernel source code
- use DOMID_XEN for HYP_CHANNEL in channel_list
- export host device-tree to hypfs so toolstack can access host device-tree nodes
- create arm,scmi-shmem node from scratch for the domain device-tree
- create arm,scmi_smc from scratch if it wasn't provided in partial device-tree
- removed xc_domain_add_sci_device function 
- do not use linux,scmi_mem to describe scmi shared memory
- define static address for the SCMI page in the domU
- introduced config parameter force_assign_without_iommu = 1 to domain config
- require force_assign_without_iommu parameter to assign non-DMA masters
present in dtdev
- unmap memory after sending discover agent on SCMI init stage
--
Oleksii Moisieiev (8):
  xen/hypfs: support fo nested dynamic hypfs nodes
  libs: libxenhypfs - handle blob properties
  xen/arm: Export host device-tree to hypfs
  xen/arm: add generic SCI mediator framework
  xen/arm: introduce SCMI-SMC mediator driver
  tools/arm: Introduce force_assign_without_iommu option to xl.cfg
  tools/arm: add "arm_sci" option to xl.cfg
  xen/arm: add SCI mediator support for DomUs

 MAINTAINERS                           |   6 +
 docs/man/xl.cfg.5.pod.in              |  29 +
 tools/golang/xenlight/helpers.gen.go  |   7 +
 tools/golang/xenlight/types.gen.go    |   8 +
 tools/include/libxl.h                 |   5 +
 tools/include/xenctrl.h               |   3 +
 tools/libs/hypfs/core.c               |   2 -
 tools/libs/light/libxl_arm.c          | 217 +++++-
 tools/libs/light/libxl_create.c       |  44 +-
 tools/libs/light/libxl_internal.h     |   3 +
 tools/libs/light/libxl_types.idl      |   7 +
 tools/xl/xl_parse.c                   |  12 +
 xen/arch/arm/Kconfig                  |  19 +
 xen/arch/arm/Makefile                 |   2 +
 xen/arch/arm/domain.c                 |  22 +
 xen/arch/arm/domain_build.c           |  11 +
 xen/arch/arm/domctl.c                 |   7 +
 xen/arch/arm/host_dtb_export.c        | 307 +++++++++
 xen/arch/arm/sci/Kconfig              |  10 +
 xen/arch/arm/sci/Makefile             |   2 +
 xen/arch/arm/sci/sci.c                | 152 ++++
 xen/arch/arm/sci/scmi_smc.c           | 959 ++++++++++++++++++++++++++
 xen/arch/arm/setup.c                  |   1 +
 xen/arch/arm/vsmc.c                   |   5 +-
 xen/arch/arm/xen.lds.S                |   7 +
 xen/common/domain.c                   |   2 +-
 xen/common/hypfs.c                    |  83 ++-
 xen/drivers/passthrough/device_tree.c |  19 +-
 xen/drivers/passthrough/iommu.c       |   5 +-
 xen/include/asm-arm/domain.h          |   4 +
 xen/include/asm-arm/sci/sci.h         | 162 +++++
 xen/include/public/arch-arm.h         |  15 +
 xen/include/public/device_tree_defs.h |   1 +
 xen/include/public/domctl.h           |   5 +-
 xen/include/xen/hypfs.h               |  14 +-
 xen/include/xen/iommu.h               |   3 +
 36 files changed, 2122 insertions(+), 38 deletions(-)
 create mode 100644 xen/arch/arm/host_dtb_export.c
 create mode 100644 xen/arch/arm/sci/Kconfig
 create mode 100644 xen/arch/arm/sci/Makefile
 create mode 100644 xen/arch/arm/sci/sci.c
 create mode 100644 xen/arch/arm/sci/scmi_smc.c
 create mode 100644 xen/include/asm-arm/sci/sci.h

-- 
2.27.0


^ permalink raw reply	[flat|nested] 45+ messages in thread

* [RFC v2 1/8] xen/hypfs: support fo nested dynamic hypfs nodes
  2022-02-08 18:00 [RFC v2 0/8] Introduce SCI-mediator feature Oleksii Moisieiev
@ 2022-02-08 18:00 ` Oleksii Moisieiev
  2022-02-10  7:34   ` Juergen Gross
  2022-02-08 18:00 ` [RFC v2 2/8] libs: libxenhypfs - handle blob properties Oleksii Moisieiev
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 45+ messages in thread
From: Oleksii Moisieiev @ 2022-02-08 18:00 UTC (permalink / raw)
  To: xen-devel; +Cc: Oleksii Moisieiev, Juergen Gross

Add new api:
- hypfs_read_dyndir_entry
- hypfs_gen_dyndir_entry
which are the extension of the dynamic hypfs nodes support, presented in
0b3b53be8cf226d947a79c2535a9efbb2dd7bc38.
This allows nested dynamic nodes to be added. Also input parameter is
hypfs_entry, so properties can also be generated dynamically.

Generating mixed list of dirs and properties is also supported.
Same as to the dynamic hypfs nodes, this is anchored in percpu pointer,
which can be retriewed on any level of the dynamic entries.
This handle should be allocated on enter() callback and released on
exit() callback. When using nested dynamic dirs and properties handle
should be allocated on the first enter() call and released on the last
exit() call.

Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@epam.com>
---
 xen/common/hypfs.c      | 83 +++++++++++++++++++++++++++++++++--------
 xen/include/xen/hypfs.h | 14 ++++++-
 2 files changed, 79 insertions(+), 18 deletions(-)

diff --git a/xen/common/hypfs.c b/xen/common/hypfs.c
index e71f7df479..6901f5e311 100644
--- a/xen/common/hypfs.c
+++ b/xen/common/hypfs.c
@@ -367,28 +367,27 @@ unsigned int hypfs_getsize(const struct hypfs_entry *entry)
 
 /*
  * Fill the direntry for a dynamically generated entry. Especially the
- * generated name needs to be kept in sync with hypfs_gen_dyndir_id_entry().
+ * generated name needs to be kept in sync with hypfs_gen_dyndir_entry().
  */
-int hypfs_read_dyndir_id_entry(const struct hypfs_entry_dir *template,
-                               unsigned int id, bool is_last,
+int hypfs_read_dyndir_entry(const struct hypfs_entry *template,
+                               const char *name, unsigned int namelen,
+                               bool is_last,
                                XEN_GUEST_HANDLE_PARAM(void) *uaddr)
 {
     struct xen_hypfs_dirlistentry direntry;
-    char name[HYPFS_DYNDIR_ID_NAMELEN];
-    unsigned int e_namelen, e_len;
+    unsigned int e_len;
 
-    e_namelen = snprintf(name, sizeof(name), template->e.name, id);
-    e_len = DIRENTRY_SIZE(e_namelen);
+    e_len = DIRENTRY_SIZE(namelen);
     direntry.e.pad = 0;
-    direntry.e.type = template->e.type;
-    direntry.e.encoding = template->e.encoding;
-    direntry.e.content_len = template->e.funcs->getsize(&template->e);
-    direntry.e.max_write_len = template->e.max_size;
+    direntry.e.type = template->type;
+    direntry.e.encoding = template->encoding;
+    direntry.e.content_len = template->funcs->getsize(template);
+    direntry.e.max_write_len = template->max_size;
     direntry.off_next = is_last ? 0 : e_len;
     if ( copy_to_guest(*uaddr, &direntry, 1) )
         return -EFAULT;
     if ( copy_to_guest_offset(*uaddr, DIRENTRY_NAME_OFF, name,
-                              e_namelen + 1) )
+                              namelen + 1) )
         return -EFAULT;
 
     guest_handle_add_offset(*uaddr, e_len);
@@ -396,6 +395,22 @@ int hypfs_read_dyndir_id_entry(const struct hypfs_entry_dir *template,
     return 0;
 }
 
+/*
+ * Fill the direntry for a dynamically generated entry. Especially the
+ * generated name needs to be kept in sync with hypfs_gen_dyndir_id_entry().
+ */
+int hypfs_read_dyndir_id_entry(const struct hypfs_entry_dir *template,
+                               unsigned int id, bool is_last,
+                               XEN_GUEST_HANDLE_PARAM(void) *uaddr)
+{
+    char name[HYPFS_DYNDIR_ID_NAMELEN];
+    unsigned int e_namelen;
+
+    e_namelen = snprintf(name, sizeof(name), template->e.name, id);
+    return hypfs_read_dyndir_entry(&template->e, name, e_namelen, is_last, uaddr);
+}
+
+
 static const struct hypfs_entry *hypfs_dyndir_enter(
     const struct hypfs_entry *entry)
 {
@@ -404,7 +419,7 @@ static const struct hypfs_entry *hypfs_dyndir_enter(
     data = hypfs_get_dyndata();
 
     /* Use template with original enter function. */
-    return data->template->e.funcs->enter(&data->template->e);
+    return data->template->funcs->enter(data->template);
 }
 
 static struct hypfs_entry *hypfs_dyndir_findentry(
@@ -415,7 +430,7 @@ static struct hypfs_entry *hypfs_dyndir_findentry(
     data = hypfs_get_dyndata();
 
     /* Use template with original findentry function. */
-    return data->template->e.funcs->findentry(data->template, name, name_len);
+    return data->template->funcs->findentry(&data->dir, name, name_len);
 }
 
 static int hypfs_read_dyndir(const struct hypfs_entry *entry,
@@ -426,7 +441,36 @@ static int hypfs_read_dyndir(const struct hypfs_entry *entry,
     data = hypfs_get_dyndata();
 
     /* Use template with original read function. */
-    return data->template->e.funcs->read(&data->template->e, uaddr);
+    return data->template->funcs->read(data->template, uaddr);
+}
+
+/*
+ * Fill dyndata with a dynamically generated entry based on a template
+ * and a name.
+ * Needs to be kept in sync with hypfs_read_dyndir_entry() regarding the
+ * name generated.
+ */
+struct hypfs_entry *hypfs_gen_dyndir_entry(
+    const struct hypfs_entry *template, const char *name,
+    void *data)
+{
+    struct hypfs_dyndir_id *dyndata;
+
+    dyndata = hypfs_get_dyndata();
+
+    dyndata->template = template;
+    dyndata->data = data;
+    memcpy(dyndata->name, name, strlen(name));
+    dyndata->dir.e = *template;
+    dyndata->dir.e.name = dyndata->name;
+
+    dyndata->dir.e.funcs = &dyndata->funcs;
+    dyndata->funcs = *template->funcs;
+    dyndata->funcs.enter = hypfs_dyndir_enter;
+    dyndata->funcs.findentry = hypfs_dyndir_findentry;
+    dyndata->funcs.read = hypfs_read_dyndir;
+
+    return &dyndata->dir.e;
 }
 
 /*
@@ -442,12 +486,13 @@ struct hypfs_entry *hypfs_gen_dyndir_id_entry(
 
     dyndata = hypfs_get_dyndata();
 
-    dyndata->template = template;
+    dyndata->template = &template->e;
     dyndata->id = id;
     dyndata->data = data;
     snprintf(dyndata->name, sizeof(dyndata->name), template->e.name, id);
     dyndata->dir = *template;
     dyndata->dir.e.name = dyndata->name;
+
     dyndata->dir.e.funcs = &dyndata->funcs;
     dyndata->funcs = *template->e.funcs;
     dyndata->funcs.enter = hypfs_dyndir_enter;
@@ -457,6 +502,12 @@ struct hypfs_entry *hypfs_gen_dyndir_id_entry(
     return &dyndata->dir.e;
 }
 
+unsigned int hypfs_dyndir_entry_size(const struct hypfs_entry *template,
+                                    const char *name)
+{
+    return DIRENTRY_SIZE(strlen(name));
+}
+
 unsigned int hypfs_dynid_entry_size(const struct hypfs_entry *template,
                                     unsigned int id)
 {
diff --git a/xen/include/xen/hypfs.h b/xen/include/xen/hypfs.h
index e9d4c2555b..5d2728b963 100644
--- a/xen/include/xen/hypfs.h
+++ b/xen/include/xen/hypfs.h
@@ -79,8 +79,8 @@ struct hypfs_entry_dir {
 struct hypfs_dyndir_id {
     struct hypfs_entry_dir dir;             /* Modified copy of template. */
     struct hypfs_funcs funcs;               /* Dynamic functions. */
-    const struct hypfs_entry_dir *template; /* Template used. */
-#define HYPFS_DYNDIR_ID_NAMELEN 12
+    const struct hypfs_entry *template; /* Template used. */
+#define HYPFS_DYNDIR_ID_NAMELEN 32
     char name[HYPFS_DYNDIR_ID_NAMELEN];     /* Name of hypfs entry. */
 
     unsigned int id;                        /* Numerical id. */
@@ -197,13 +197,23 @@ void *hypfs_alloc_dyndata(unsigned long size);
 #define hypfs_alloc_dyndata(type) ((type *)hypfs_alloc_dyndata(sizeof(type)))
 void *hypfs_get_dyndata(void);
 void hypfs_free_dyndata(void);
+int hypfs_read_dyndir_entry(const struct hypfs_entry *template,
+                               const char *name, unsigned int namelen,
+                               bool is_last,
+                               XEN_GUEST_HANDLE_PARAM(void) *uaddr);
 int hypfs_read_dyndir_id_entry(const struct hypfs_entry_dir *template,
                                unsigned int id, bool is_last,
                                XEN_GUEST_HANDLE_PARAM(void) *uaddr);
+struct hypfs_entry *hypfs_gen_dyndir_entry(
+    const struct hypfs_entry *template, const char *name,
+    void *data);
 struct hypfs_entry *hypfs_gen_dyndir_id_entry(
     const struct hypfs_entry_dir *template, unsigned int id, void *data);
 unsigned int hypfs_dynid_entry_size(const struct hypfs_entry *template,
                                     unsigned int id);
+unsigned int hypfs_dyndir_entry_size(const struct hypfs_entry *template,
+                                    const char *name);
+
 #endif
 
 #endif /* __XEN_HYPFS_H__ */
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [RFC v2 2/8] libs: libxenhypfs - handle blob properties
  2022-02-08 18:00 [RFC v2 0/8] Introduce SCI-mediator feature Oleksii Moisieiev
  2022-02-08 18:00 ` [RFC v2 1/8] xen/hypfs: support fo nested dynamic hypfs nodes Oleksii Moisieiev
@ 2022-02-08 18:00 ` Oleksii Moisieiev
  2022-02-09 13:47   ` Oleksandr Andrushchenko
  2022-02-09 14:04   ` Juergen Gross
  2022-02-08 18:00 ` [RFC v2 3/8] xen/arm: Export host device-tree to hypfs Oleksii Moisieiev
                   ` (5 subsequent siblings)
  7 siblings, 2 replies; 45+ messages in thread
From: Oleksii Moisieiev @ 2022-02-08 18:00 UTC (permalink / raw)
  To: xen-devel; +Cc: Oleksii Moisieiev, Juergen Gross, Wei Liu

libxenhypfs will return blob properties as is. This output can be used
to retrieve information from the hypfs. Caller is responsible for
parsing property value.

Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@epam.com>
---
 tools/libs/hypfs/core.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/tools/libs/hypfs/core.c b/tools/libs/hypfs/core.c
index 52b30db8d7..d09bba7d8c 100644
--- a/tools/libs/hypfs/core.c
+++ b/tools/libs/hypfs/core.c
@@ -307,8 +307,6 @@ char *xenhypfs_read(xenhypfs_handle *fshdl, const char *path)
         errno = EISDIR;
         break;
     case xenhypfs_type_blob:
-        errno = EDOM;
-        break;
     case xenhypfs_type_string:
         ret_buf = buf;
         buf = NULL;
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [RFC v2 3/8] xen/arm: Export host device-tree to hypfs
  2022-02-08 18:00 [RFC v2 0/8] Introduce SCI-mediator feature Oleksii Moisieiev
  2022-02-08 18:00 ` [RFC v2 1/8] xen/hypfs: support fo nested dynamic hypfs nodes Oleksii Moisieiev
  2022-02-08 18:00 ` [RFC v2 2/8] libs: libxenhypfs - handle blob properties Oleksii Moisieiev
@ 2022-02-08 18:00 ` Oleksii Moisieiev
  2022-02-08 18:26   ` Julien Grall
  2022-02-08 18:00 ` [RFC v2 4/8] xen/arm: add generic SCI mediator framework Oleksii Moisieiev
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 45+ messages in thread
From: Oleksii Moisieiev @ 2022-02-08 18:00 UTC (permalink / raw)
  To: xen-devel
  Cc: Oleksii Moisieiev, Stefano Stabellini, Julien Grall,
	Volodymyr Babchuk, Bertrand Marquis

If enabled, host device-tree will be exported to hypfs and can be
accessed through /devicetree path.
Exported device-tree has the same format, as the device-tree
exported to the sysfs by the Linux kernel.
This is useful when XEN toolstack needs an access to the host device-tree.

Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@epam.com>
---
 xen/arch/arm/Kconfig           |   8 +
 xen/arch/arm/Makefile          |   1 +
 xen/arch/arm/host_dtb_export.c | 307 +++++++++++++++++++++++++++++++++
 3 files changed, 316 insertions(+)
 create mode 100644 xen/arch/arm/host_dtb_export.c

diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig
index ecfa6822e4..895016b21e 100644
--- a/xen/arch/arm/Kconfig
+++ b/xen/arch/arm/Kconfig
@@ -33,6 +33,14 @@ config ACPI
 	  Advanced Configuration and Power Interface (ACPI) support for Xen is
 	  an alternative to device tree on ARM64.
 
+config HOST_DTB_EXPORT
+	bool "Export host device tree to hypfs if enabled"
+	depends on ARM && HYPFS && !ACPI
+	---help---
+
+	  Export host device-tree to hypfs so toolstack can have an access for the
+	  host device tree from Dom0. If you unsure say N.
+
 config GICV3
 	bool "GICv3 driver"
 	depends on ARM_64 && !NEW_VGIC
diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index 07f634508e..0a41f68f8c 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -8,6 +8,7 @@ obj-y += platforms/
 endif
 obj-$(CONFIG_TEE) += tee/
 obj-$(CONFIG_HAS_VPCI) += vpci.o
+obj-$(CONFIG_HOST_DTB_EXPORT) += host_dtb_export.o
 
 obj-$(CONFIG_HAS_ALTERNATIVE) += alternative.o
 obj-y += bootfdt.init.o
diff --git a/xen/arch/arm/host_dtb_export.c b/xen/arch/arm/host_dtb_export.c
new file mode 100644
index 0000000000..794395683c
--- /dev/null
+++ b/xen/arch/arm/host_dtb_export.c
@@ -0,0 +1,307 @@
+/*
+ * xen/arch/arm/host_dtb_export.c
+ *
+ * Export host device-tree to the hypfs so toolstack can access
+ * host device-tree from Dom0
+ *
+ * Oleksii Moisieiev <oleksii_moisieiev@epam.com>
+ * Copyright (C) 2021, EPAM Systems.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <xen/device_tree.h>
+#include <xen/err.h>
+#include <xen/guest_access.h>
+#include <xen/hypfs.h>
+#include <xen/init.h>
+
+#define HOST_DT_DIR "devicetree"
+
+static int host_dt_dir_read(const struct hypfs_entry *entry,
+                            XEN_GUEST_HANDLE_PARAM(void) uaddr);
+static unsigned int host_dt_dir_getsize(const struct hypfs_entry *entry);
+
+static const struct hypfs_entry *host_dt_dir_enter(
+    const struct hypfs_entry *entry);
+static void host_dt_dir_exit(const struct hypfs_entry *entry);
+
+static struct hypfs_entry *host_dt_dir_findentry(
+    const struct hypfs_entry_dir *dir, const char *name, unsigned int name_len);
+
+static const struct hypfs_funcs host_dt_dir_funcs = {
+    .enter = host_dt_dir_enter,
+    .exit = host_dt_dir_exit,
+    .read = host_dt_dir_read,
+    .write = hypfs_write_deny,
+    .getsize = host_dt_dir_getsize,
+    .findentry = host_dt_dir_findentry,
+};
+
+static int host_dt_prop_read(const struct hypfs_entry *entry,
+                    XEN_GUEST_HANDLE_PARAM(void) uaddr);
+
+static unsigned int host_dt_prop_getsize(const struct hypfs_entry *entry);
+
+const struct hypfs_funcs host_dt_prop_ro_funcs = {
+    .enter = host_dt_dir_enter,
+    .exit = host_dt_dir_exit,
+    .read = host_dt_prop_read,
+    .write = hypfs_write_deny,
+    .getsize = host_dt_prop_getsize,
+    .findentry = hypfs_leaf_findentry,
+};
+
+static HYPFS_DIR_INIT_FUNC(dt_dir, "node_template", &host_dt_dir_funcs);
+
+#define HYPFS_PROPERTY_MAX_SIZE 256
+static HYPFS_VARSIZE_INIT(dt_prop, XEN_HYPFS_TYPE_BLOB, "prop_template",
+                            HYPFS_PROPERTY_MAX_SIZE, &host_dt_prop_ro_funcs);
+
+static const char *get_name_from_path(const char *path)
+{
+    const char *name = strrchr(path, '/');
+    if ( !name )
+        name = path;
+    else
+    {
+        name++;
+        if ( !*name )
+            name--;
+    }
+
+    return name;
+}
+
+static char *get_root_from_path(const char *path, char *name)
+{
+    const char *nm = strchr(path, '/');
+    if ( !nm )
+        nm = path + strlen(path);
+    else
+    {
+        if ( !*nm )
+            nm--;
+    }
+
+    return memcpy(name, path, nm - path);
+}
+
+static int host_dt_dir_read(const struct hypfs_entry *entry,
+                            XEN_GUEST_HANDLE_PARAM(void) uaddr)
+{
+    int ret = 0;
+    struct dt_device_node *node;
+    struct dt_device_node *child;
+    const struct dt_property *prop;
+    struct hypfs_dyndir_id *data;
+
+    data = hypfs_get_dyndata();
+    if ( !data )
+        return -EINVAL;
+
+    node = data->data;
+    if ( !node )
+        return -EINVAL;
+
+    dt_for_each_property_node( node, prop )
+    {
+        ret = hypfs_read_dyndir_entry(&dt_prop.e, prop->name,
+                                      strlen(prop->name),
+                                      !prop->next && !node->child,
+                                      &uaddr);
+
+        if ( ret )
+            break;
+    }
+
+    for ( child = node->child; child != NULL; child = child->sibling )
+    {
+        const char *parsed_name = get_name_from_path(child->full_name);
+        data->data = child;
+
+        ret = hypfs_read_dyndir_entry(&dt_dir.e, parsed_name,
+                                         strlen(parsed_name),
+                                         child->sibling == NULL,
+                                         &uaddr);
+
+        if ( ret )
+            break;
+    }
+
+    return ret;
+}
+
+static unsigned int host_dt_dir_getsize(const struct hypfs_entry *entry)
+{
+    struct dt_device_node *node;
+    struct dt_device_node *child;
+    struct hypfs_dyndir_id *data;
+    const struct dt_property *prop;
+    unsigned int size = 0;
+
+    data = hypfs_get_dyndata();
+    if ( !data )
+        return -EINVAL;
+
+    node = data->data;
+    if ( !node )
+        return -EINVAL;
+
+    dt_for_each_property_node( node, prop )
+    {
+        size += hypfs_dyndir_entry_size(entry, prop->name);
+    }
+
+    for ( child = node->child; child != NULL; child = child->sibling )
+    {
+        const char *parsed_name = get_name_from_path(child->full_name);
+        size += hypfs_dyndir_entry_size(entry, parsed_name);
+    }
+
+    return size;
+}
+
+static DEFINE_PER_CPU(bool, data_alloc);
+
+static inline bool data_is_alloc(void)
+{
+    unsigned int cpu = smp_processor_id();
+    return per_cpu(data_alloc, cpu);
+}
+
+static inline void set_data_alloc(void)
+{
+    unsigned int cpu = smp_processor_id();
+    ASSERT(!per_cpu(data_alloc, cpu));
+
+    this_cpu(data_alloc) = true;
+}
+
+static inline void unset_data_alloc(void)
+{
+    this_cpu(data_alloc) = false;
+}
+
+static const struct hypfs_entry *host_dt_dir_enter(
+    const struct hypfs_entry *entry)
+{
+    struct hypfs_dyndir_id *data;
+
+    if ( !data_is_alloc() )
+    {
+        data = hypfs_alloc_dyndata(struct hypfs_dyndir_id);
+        if ( !data )
+            return ERR_PTR(-ENOMEM);
+
+        set_data_alloc();
+    }
+
+    if ( strcmp(entry->name, HOST_DT_DIR) == 0 )
+    {
+        data = hypfs_get_dyndata();
+        data->data = dt_host;
+    }
+
+    return entry;
+}
+
+static void host_dt_dir_exit(const struct hypfs_entry *entry)
+{
+    if ( !data_is_alloc() )
+        return;
+
+    hypfs_free_dyndata();
+    unset_data_alloc();
+}
+
+static struct hypfs_entry *host_dt_dir_findentry(
+    const struct hypfs_entry_dir *dir, const char *name, unsigned int name_len)
+{
+    struct dt_device_node *node;
+    char root_name[HYPFS_DYNDIR_ID_NAMELEN];
+    struct dt_device_node *child;
+    struct hypfs_dyndir_id *data;
+    struct dt_property *prop;
+
+    data = hypfs_get_dyndata();
+    if ( !data )
+        return ERR_PTR(-EINVAL);
+
+    node = data->data;
+    if ( !node )
+        return ERR_PTR(-EINVAL);
+
+    memset(root_name, 0, sizeof(root_name));
+    get_root_from_path(name, root_name);
+
+    for ( child = node->child; child != NULL; child = child->sibling )
+    {
+        if ( strcmp(get_name_from_path(child->full_name), root_name) == 0 )
+            return hypfs_gen_dyndir_entry(&dt_dir.e,
+                                  get_name_from_path(child->full_name), child);
+    }
+
+    dt_for_each_property_node( node, prop )
+    {
+
+        if ( dt_property_name_is_equal(prop, root_name) )
+            return hypfs_gen_dyndir_entry(&dt_prop.e, prop->name, prop);
+    }
+
+    return ERR_PTR(-ENOENT);
+};
+
+static int host_dt_prop_read(const struct hypfs_entry *entry,
+                    XEN_GUEST_HANDLE_PARAM(void) uaddr)
+{
+    const struct dt_property *prop;
+    struct hypfs_dyndir_id *data;
+
+    data = hypfs_get_dyndata();
+    if ( !data )
+        return -EINVAL;
+
+    prop = data->data;
+    if ( !prop )
+        return -EINVAL;
+
+    return copy_to_guest(uaddr, prop->value, prop->length) ?  -EFAULT : 0;
+}
+
+static unsigned int host_dt_prop_getsize(const struct hypfs_entry *entry)
+{
+    const struct hypfs_dyndir_id *data;
+    const struct dt_property *prop;
+
+    data = hypfs_get_dyndata();
+    if ( !data )
+        return -EINVAL;
+
+    prop = data->data;
+    if ( !prop )
+        return -EINVAL;
+
+    return prop->length;
+}
+
+static HYPFS_DIR_INIT_FUNC(host_dt_dir, HOST_DT_DIR, &host_dt_dir_funcs);
+
+static int __init host_dtb_export_init(void)
+{
+    ASSERT(dt_host && (dt_host->sibling == NULL));
+    unset_data_alloc();
+
+    hypfs_add_dir(&hypfs_root, &host_dt_dir, true);
+    hypfs_add_dyndir(&hypfs_root, &dt_dir);
+    return 0;
+}
+__initcall(host_dtb_export_init);
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [RFC v2 4/8] xen/arm: add generic SCI mediator framework
  2022-02-08 18:00 [RFC v2 0/8] Introduce SCI-mediator feature Oleksii Moisieiev
                   ` (2 preceding siblings ...)
  2022-02-08 18:00 ` [RFC v2 3/8] xen/arm: Export host device-tree to hypfs Oleksii Moisieiev
@ 2022-02-08 18:00 ` Oleksii Moisieiev
  2022-02-08 18:00 ` [RFC v2 5/8] xen/arm: introduce SCMI-SMC mediator driver Oleksii Moisieiev
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 45+ messages in thread
From: Oleksii Moisieiev @ 2022-02-08 18:00 UTC (permalink / raw)
  To: xen-devel
  Cc: Oleksii Moisieiev, Andrew Cooper, George Dunlap, Jan Beulich,
	Julien Grall, Stefano Stabellini, Wei Liu, Volodymyr Babchuk,
	Bertrand Marquis

This patch adds the basic framework for SCI mediator.
SCI is System Control Interface, which is designed to redirect
requests from the Domains to Firmware. This will allow the devices,
passed-through to the different Domains, to access to the System Controls
(such as clocks/resets etc) by sending requests to the firmware.
Xen mediates requests between the Domains and the Firmware, also it is
responsible for permission handling during Domain crateion.

SCI mediator register itself with REGISTER_SCI_MEDIATOR() macro.

At run-time, during initialization, framework calls probe for the first
matching device in the device-tree. When no device-tree is present - the
first registered mediator should be probed.

Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@epam.com>
---
 MAINTAINERS                   |   6 ++
 xen/arch/arm/Kconfig          |   9 ++
 xen/arch/arm/Makefile         |   1 +
 xen/arch/arm/domain.c         |  22 +++++
 xen/arch/arm/domain_build.c   |  11 +++
 xen/arch/arm/sci/Makefile     |   2 +
 xen/arch/arm/sci/sci.c        | 152 +++++++++++++++++++++++++++++++
 xen/arch/arm/setup.c          |   1 +
 xen/arch/arm/vsmc.c           |   5 +-
 xen/arch/arm/xen.lds.S        |   7 ++
 xen/include/asm-arm/domain.h  |   4 +
 xen/include/asm-arm/sci/sci.h | 162 ++++++++++++++++++++++++++++++++++
 xen/include/public/arch-arm.h |  15 ++++
 13 files changed, 396 insertions(+), 1 deletion(-)
 create mode 100644 xen/arch/arm/sci/Makefile
 create mode 100644 xen/arch/arm/sci/sci.c
 create mode 100644 xen/include/asm-arm/sci/sci.h

diff --git a/MAINTAINERS b/MAINTAINERS
index e43dc0edce..5f96ea35ba 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -512,6 +512,12 @@ S:	Supported
 F:	xen/arch/arm/tee/
 F:	xen/include/asm-arm/tee
 
+SCI MEDIATORS
+M:	Oleksii Moisieiev <oleksii_moisieiev@epam.com>
+S:	Supported
+F:	xen/arch/arm/sci
+F:	xen/include/asm-arm/sci
+
 TOOLSTACK
 M:	Wei Liu <wl@xen.org>
 S:	Supported
diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig
index 895016b21e..ab07833582 100644
--- a/xen/arch/arm/Kconfig
+++ b/xen/arch/arm/Kconfig
@@ -114,6 +114,15 @@ config TEE
 
 source "arch/arm/tee/Kconfig"
 
+config ARM_SCI
+	bool "Enable ARM_SCI mediators support"
+	depends on ARM
+	default n
+	help
+	  This option enables generic ARM_SCI (System Control Interface) mediators
+	  support. It allows guests to control system resourcess via one of
+	  ARM_SCI mediators implemented in XEN.
+
 endmenu
 
 menu "ARM errata workaround via the alternative framework"
diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index 0a41f68f8c..f071d912aa 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -8,6 +8,7 @@ obj-y += platforms/
 endif
 obj-$(CONFIG_TEE) += tee/
 obj-$(CONFIG_HAS_VPCI) += vpci.o
+obj-$(CONFIG_ARM_SCI) += sci/
 obj-$(CONFIG_HOST_DTB_EXPORT) += host_dtb_export.o
 
 obj-$(CONFIG_HAS_ALTERNATIVE) += alternative.o
diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index 96e1b23550..607ea8c3a8 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -34,6 +34,7 @@
 #include <asm/platform.h>
 #include <asm/procinfo.h>
 #include <asm/regs.h>
+#include <asm/sci/sci.h>
 #include <asm/tee/tee.h>
 #include <asm/vfp.h>
 #include <asm/vgic.h>
@@ -688,6 +689,13 @@ int arch_sanitise_domain_config(struct xen_domctl_createdomain *config)
         return -EINVAL;
     }
 
+    if ( config->arch.arm_sci_type != XEN_DOMCTL_CONFIG_ARM_SCI_NONE &&
+         config->arch.arm_sci_type != sci_get_type() )
+    {
+        dprintk(XENLOG_INFO, "Unsupported ARM_SCI type\n");
+        return -EINVAL;
+    }
+
     return 0;
 }
 
@@ -764,6 +772,13 @@ int arch_domain_create(struct domain *d,
         /* At this stage vgic_reserve_virq should never fail */
         if ( !vgic_reserve_virq(d, GUEST_EVTCHN_PPI) )
             BUG();
+
+        if ( config->arch.arm_sci_type != XEN_DOMCTL_CONFIG_ARM_SCI_NONE )
+        {
+            if ( (rc = sci_domain_init(d, config->arch.arm_sci_type,
+                                       &config->arch)) != 0)
+                goto fail;
+        }
     }
 
     /*
@@ -796,6 +811,7 @@ void arch_domain_destroy(struct domain *d)
     domain_vgic_free(d);
     domain_vuart_free(d);
     free_xenheap_page(d->shared_info);
+    sci_domain_destroy(d);
 #ifdef CONFIG_ACPI
     free_xenheap_pages(d->arch.efi_acpi_table,
                        get_order_from_bytes(d->arch.efi_acpi_len));
@@ -996,6 +1012,7 @@ enum {
     PROG_xen,
     PROG_page,
     PROG_mapping,
+    PROG_sci,
     PROG_done,
 };
 
@@ -1056,6 +1073,11 @@ int domain_relinquish_resources(struct domain *d)
         if ( ret )
             return ret;
 
+    PROGRESS(sci):
+        ret = sci_relinquish_resources(d);
+        if ( ret )
+            return ret;
+
     PROGRESS(done):
         break;
 
diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index d02bacbcd1..05afd3e8e7 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -22,6 +22,7 @@
 #include <asm/kernel.h>
 #include <asm/setup.h>
 #include <asm/tee/tee.h>
+#include <asm/sci/sci.h>
 #include <asm/platform.h>
 #include <asm/psci.h>
 #include <asm/setup.h>
@@ -1894,6 +1895,10 @@ static int __init handle_device(struct domain *d, struct dt_device_node *dev,
                 return res;
             }
         }
+
+        res = sci_add_dt_device(d, dev);
+        if ( res < 0 )
+            return res;
     }
 
     res = handle_device_interrupts(d, dev, need_mapping);
@@ -3075,6 +3080,10 @@ static int __init construct_dom0(struct domain *d)
     if ( rc < 0 )
         return rc;
 
+    rc = sci_domain_init(d, sci_get_type(), NULL);
+    if ( rc < 0 )
+        return rc;
+
     if ( acpi_disabled )
         rc = prepare_dtb_hwdom(d, &kinfo);
     else
@@ -3109,6 +3118,8 @@ void __init create_dom0(void)
     dom0_cfg.arch.tee_type = tee_get_type();
     dom0_cfg.max_vcpus = dom0_max_vcpus();
 
+    dom0_cfg.arch.arm_sci_type = sci_get_type();
+
     if ( iommu_enabled )
         dom0_cfg.flags |= XEN_DOMCTL_CDF_iommu;
 
diff --git a/xen/arch/arm/sci/Makefile b/xen/arch/arm/sci/Makefile
new file mode 100644
index 0000000000..67f2611872
--- /dev/null
+++ b/xen/arch/arm/sci/Makefile
@@ -0,0 +1,2 @@
+obj-y += sci.o
+obj-$(CONFIG_SCMI_SMC) += scmi_smc.o
diff --git a/xen/arch/arm/sci/sci.c b/xen/arch/arm/sci/sci.c
new file mode 100644
index 0000000000..05c948a071
--- /dev/null
+++ b/xen/arch/arm/sci/sci.c
@@ -0,0 +1,152 @@
+/*
+ * xen/arch/arm/sci/sci.c
+ *
+ * Generic part of SCI mediator driver
+ *
+ * Oleksii Moisieiev <oleksii_moisieiev@epam.com>
+ * Copyright (C) 2021, EPAM Systems.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <xen/acpi.h>
+#include <xen/errno.h>
+#include <xen/init.h>
+#include <xen/sched.h>
+#include <xen/types.h>
+
+#include <asm/sci/sci.h>
+
+extern const struct sci_mediator_desc _sscimediator[], _escimediator[];
+static const struct sci_mediator_desc __read_mostly *cur_mediator;
+
+bool sci_handle_call(struct domain *d, void *args)
+{
+    if ( unlikely(!cur_mediator) )
+        return false;
+
+    return cur_mediator->ops->handle_call(d, args);
+}
+
+int sci_domain_init(struct domain *d, uint16_t sci_type,
+                    struct xen_arch_domainconfig *config)
+{
+    if ( sci_type == XEN_DOMCTL_CONFIG_ARM_SCI_NONE )
+        return 0;
+
+    if ( !cur_mediator )
+        return -ENODEV;
+
+    if ( cur_mediator->sci_type != sci_type )
+        return -EINVAL;
+
+    return cur_mediator->ops->domain_init(d, config);
+}
+
+void sci_domain_destroy(struct domain *d)
+{
+    if ( !cur_mediator )
+        return;
+
+    cur_mediator->ops->domain_destroy(d);
+}
+
+int sci_relinquish_resources(struct domain *d)
+{
+    if ( !cur_mediator )
+        return 0;
+
+    return cur_mediator->ops->relinquish_resources(d);
+}
+
+
+int sci_add_dt_device(struct domain *d, struct dt_device_node *dev)
+{
+    if ( !cur_mediator )
+        return 0;
+
+    return cur_mediator->ops->add_dt_device(d, dev);
+}
+
+uint16_t sci_get_type(void)
+{
+    if ( !cur_mediator )
+        return XEN_DOMCTL_CONFIG_ARM_SCI_NONE;
+
+    return cur_mediator->sci_type;
+}
+
+int sci_do_domctl(
+    struct xen_domctl *domctl, struct domain *d,
+    XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl)
+{
+    int rc = -EINVAL;
+    struct dt_device_node *dev;
+
+    switch ( domctl->cmd )
+    {
+    case XEN_DOMCTL_assign_device:
+        if ( domctl->u.assign_device.dev != XEN_DOMCTL_DEV_DT )
+            break;
+
+        rc = dt_find_node_by_gpath(domctl->u.assign_device.u.dt.path,
+                               domctl->u.assign_device.u.dt.size,
+                               &dev);
+        if ( rc )
+            return rc;
+
+        rc = sci_add_dt_device(d, dev);
+
+        break;
+    default:
+        rc = -ENOSYS;
+        break;
+    }
+
+    return rc;
+}
+
+static int __init sci_init(void)
+{
+    const struct sci_mediator_desc *desc;
+    struct dt_device_node *dt = NULL;
+
+
+    for ( desc = _sscimediator; desc != _escimediator; desc++ )
+    {
+        if ( acpi_disabled )
+        {
+            dt = dt_find_matching_node(dt_host, desc->dt_match);
+            if ( !dt )
+                continue;
+        }
+
+        if ( desc->ops->probe(dt) )
+        {
+            printk(XENLOG_INFO "Using SCI mediator for %s\n", desc->name);
+            cur_mediator = desc;
+            return 0;
+        }
+    }
+
+    return 0;
+}
+
+__initcall(sci_init);
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c
index d5d0792ed4..201de01411 100644
--- a/xen/arch/arm/setup.c
+++ b/xen/arch/arm/setup.c
@@ -50,6 +50,7 @@
 #include <asm/cpufeature.h>
 #include <asm/platform.h>
 #include <asm/procinfo.h>
+#include <asm/sci/sci.h>
 #include <asm/setup.h>
 #include <xsm/xsm.h>
 #include <asm/acpi.h>
diff --git a/xen/arch/arm/vsmc.c b/xen/arch/arm/vsmc.c
index a36db15fff..c68482fbd8 100644
--- a/xen/arch/arm/vsmc.c
+++ b/xen/arch/arm/vsmc.c
@@ -22,6 +22,7 @@
 #include <asm/cpufeature.h>
 #include <asm/monitor.h>
 #include <asm/regs.h>
+#include <asm/sci/sci.h>
 #include <asm/smccc.h>
 #include <asm/tee/tee.h>
 #include <asm/traps.h>
@@ -275,7 +276,9 @@ static bool vsmccc_handle_call(struct cpu_user_regs *regs)
             handled = handle_sssc(regs);
             break;
         case ARM_SMCCC_OWNER_SIP:
-            handled = platform_smc(regs);
+            handled = sci_handle_call(current->domain, regs);
+            if ( !handled )
+                handled = platform_smc(regs);
             break;
         case ARM_SMCCC_OWNER_TRUSTED_APP ... ARM_SMCCC_OWNER_TRUSTED_APP_END:
         case ARM_SMCCC_OWNER_TRUSTED_OS ... ARM_SMCCC_OWNER_TRUSTED_OS_END:
diff --git a/xen/arch/arm/xen.lds.S b/xen/arch/arm/xen.lds.S
index 08016948ab..3683f4821f 100644
--- a/xen/arch/arm/xen.lds.S
+++ b/xen/arch/arm/xen.lds.S
@@ -142,6 +142,13 @@ SECTIONS
       _eteemediator = .;
   } :text
 
+  . = ALIGN(8);
+  .scimediator.info : {
+      _sscimediator = .;
+      *(.scimediator.info)
+      _escimediator = .;
+  } :text
+
   . = ALIGN(PAGE_SIZE);             /* Init code and data */
   __init_begin = .;
   .init.text : {
diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index 9b3647587a..11c8db8db1 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -89,6 +89,10 @@ struct arch_domain
 #ifdef CONFIG_TEE
     void *tee;
 #endif
+
+#ifdef CONFIG_ARM_SCI
+    void *sci;
+#endif
 }  __cacheline_aligned;
 
 struct arch_vcpu
diff --git a/xen/include/asm-arm/sci/sci.h b/xen/include/asm-arm/sci/sci.h
new file mode 100644
index 0000000000..075e11bc16
--- /dev/null
+++ b/xen/include/asm-arm/sci/sci.h
@@ -0,0 +1,162 @@
+/*
+ * xen/include/asm-arm/sci/sci.h
+ *
+ * Generic part of the SCI (System Control Interface) subsystem.
+ *
+ * Oleksii Moisieiev <oleksii_moisieiev@epam.com>
+ * Copyright (C) 2021, EPAM Systems.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ASM_ARM_SCI_H
+#define __ASM_ARM_SCI_H
+
+#include <xen/lib.h>
+#include <xen/types.h>
+#include <xen/device_tree.h>
+#include <public/domctl.h>
+
+#ifdef CONFIG_ARM_SCI
+
+struct sci_mediator_ops {
+
+    /*
+     * Probe for SCI. Should return true if SCI found and
+     * mediator is initialized.
+     */
+    bool (*probe)(struct dt_device_node *scmi_node);
+
+    /*
+     * Called during domain construction if toolstack requests to enable
+     * SCI support so mediator can inform SCP-firmware about new
+     * guest and create own structures for the new domain.
+     */
+    int (*domain_init)(struct domain *d, struct xen_arch_domainconfig *config);
+
+    /*
+     * Called during domain destruction, releases all resources, that
+     * were allocated by the mediator.
+     */
+    void (*domain_destroy)(struct domain *d);
+
+    /*
+     * Called during parsing partial device-sci for the domain.
+     * Passing device_node so mediator could process the device and
+     * mark the device as related to the domain if needed.
+     */
+    int (*add_dt_device)(struct domain *d, struct dt_device_node *dev);
+
+    /*
+     * Called during domain destruction to relinquish resources used
+     * by mediator itself. This function can return -ERESTART to indicate
+     * that it does not finished work and should be called again.
+     */
+    int (*relinquish_resources)(struct domain *d);
+
+    /* Handle call for current domain */
+    bool (*handle_call)(struct domain *d, void *regs);
+};
+
+struct sci_mediator_desc {
+    /* Printable name of the SCI. */
+    const char *name;
+
+    /* Mediator callbacks as described above. */
+    const struct sci_mediator_ops *ops;
+
+    /*
+     * ID of SCI. Corresponds to xen_arch_domainconfig.sci_type.
+     * Should be one of XEN_DOMCTL_CONFIG_ARM_SCI_xxx
+     */
+    uint16_t sci_type;
+
+    /* Match structure to init mediator */
+    const struct dt_device_match *dt_match;
+
+};
+
+int sci_domain_init(struct domain *d, uint16_t sci_type,
+                    struct xen_arch_domainconfig *config);
+void sci_domain_destroy(struct domain *d);
+int sci_add_dt_device(struct domain *d, struct dt_device_node *dev);
+int sci_relinquish_resources(struct domain *d);
+bool sci_handle_call(struct domain *d, void *args);
+uint16_t sci_get_type(void);
+int sci_do_domctl(
+    struct xen_domctl *domctl, struct domain *d,
+    XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl);
+
+#define REGISTER_SCI_MEDIATOR(_name, _namestr, _type, _match, _ops) \
+static const struct sci_mediator_desc __sci_desc_##_name __used     \
+__section(".scimediator.info") = {                                  \
+    .name = _namestr,                                               \
+    .ops = _ops,                                                    \
+    .sci_type = _type,                                              \
+    .dt_match = _match                                              \
+}
+
+#else
+
+static inline int sci_domain_init(struct domain *d, uint16_t sci_type,
+                    struct xen_arch_domainconfig *config)
+{
+    if ( likely(sci_type == XEN_DOMCTL_CONFIG_ARM_SCI_NONE) )
+        return 0;
+
+    return -ENODEV;
+}
+
+static inline void sci_domain_destroy(struct domain *d)
+{
+}
+
+static inline int sci_add_dt_device(struct domain *d,
+                                    struct dt_device_node *dev)
+{
+    return 0;
+}
+
+static inline int sci_relinquish_resources(struct domain *d)
+{
+    return 0;
+}
+
+static inline bool sci_handle_call(struct domain *d, void *args)
+{
+    return false;
+}
+
+static inline uint16_t sci_get_type(void)
+{
+    return XEN_DOMCTL_CONFIG_ARM_SCI_NONE;
+}
+
+static inline int sci_do_domctl(
+    struct xen_domctl *domctl, struct domain *d,
+    XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl)
+{
+    return -ENOSYS;
+}
+
+
+#endif  /* CONFIG_ARM_SCI */
+
+#endif /* __ASM_ARM_SCI_H */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/include/public/arch-arm.h b/xen/include/public/arch-arm.h
index 94b31511dd..a6131ab1fd 100644
--- a/xen/include/public/arch-arm.h
+++ b/xen/include/public/arch-arm.h
@@ -314,12 +314,17 @@ DEFINE_XEN_GUEST_HANDLE(vcpu_guest_context_t);
 #define XEN_DOMCTL_CONFIG_TEE_NONE      0
 #define XEN_DOMCTL_CONFIG_TEE_OPTEE     1
 
+#define XEN_DOMCTL_CONFIG_ARM_SCI_NONE      0
+#define XEN_DOMCTL_CONFIG_ARM_SCI_SCMI_SMC  1
+
 struct xen_arch_domainconfig {
     /* IN/OUT */
     uint8_t gic_version;
     /* IN */
     uint16_t tee_type;
     /* IN */
+    uint16_t arm_sci_type;
+    /* IN */
     uint32_t nr_spis;
     /*
      * OUT
@@ -335,6 +340,12 @@ struct xen_arch_domainconfig {
      *
      */
     uint32_t clock_frequency;
+
+    /* Sets shared address to sw domains.
+     * This information is needed to set correct channel in Domain partial
+     * device-tree
+     */
+    uint64_t arm_sci_agent_paddr;
 };
 #endif /* __XEN__ || __XEN_TOOLS__ */
 
@@ -429,6 +440,10 @@ typedef uint64_t xen_callback_t;
 #define GUEST_ACPI_BASE xen_mk_ullong(0x20000000)
 #define GUEST_ACPI_SIZE xen_mk_ullong(0x02000000)
 
+/* SCMI shared memory address */
+#define GUEST_SCI_SHMEM_BASE   xen_mk_ullong(0x05ff0000)
+#define GUEST_SCI_SHMEM_SIZE   xen_mk_ullong(0x01000)
+
 /* PL011 mappings */
 #define GUEST_PL011_BASE    xen_mk_ullong(0x22000000)
 #define GUEST_PL011_SIZE    xen_mk_ullong(0x00001000)
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [RFC v2 5/8] xen/arm: introduce SCMI-SMC mediator driver
  2022-02-08 18:00 [RFC v2 0/8] Introduce SCI-mediator feature Oleksii Moisieiev
                   ` (3 preceding siblings ...)
  2022-02-08 18:00 ` [RFC v2 4/8] xen/arm: add generic SCI mediator framework Oleksii Moisieiev
@ 2022-02-08 18:00 ` Oleksii Moisieiev
  2022-02-09 15:02   ` Oleksandr Andrushchenko
  2022-02-11  8:46   ` Bertrand Marquis
  2022-02-08 18:00 ` [RFC v2 6/8] tools/arm: Introduce force_assign_without_iommu option to xl.cfg Oleksii Moisieiev
                   ` (2 subsequent siblings)
  7 siblings, 2 replies; 45+ messages in thread
From: Oleksii Moisieiev @ 2022-02-08 18:00 UTC (permalink / raw)
  To: xen-devel
  Cc: Oleksii Moisieiev, Stefano Stabellini, Julien Grall,
	Volodymyr Babchuk, Bertrand Marquis

This is the implementation of SCI interface, called SCMI-SMC driver,
which works as the mediator between XEN Domains and Firmware (SCP, ATF etc).
This allows devices from the Domains to work with clocks, resets and
power-domains without access to CPG.

Originally, cpg should be passed to the domain so it can work with
power-domains/clocks/resets etc. Considering that cpg can't be split between
the Domains, we get the limitation that the devices, which are using
power-domains/clocks/resets etc, couldn't be split between the domains.
The solution is to move the power-domain/clock/resets etc to the
Firmware (such as SCP firmware or ATF) and provide interface for the
Domains. XEN should have an entity, caled SCI-Mediator, which is
responsible for messages redirection between Domains and Firmware and
for permission handling.

The following features are implemented:
- request SCMI channels from ATF and pass channels to Domains;
- set device permissions for Domains based on the Domain partial
device-tree. Devices with permissions are able to work with clocks,
resets and power-domains via SCMI;
- redirect scmi messages from Domains to ATF.

Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@epam.com>
---
 xen/arch/arm/Kconfig        |   2 +
 xen/arch/arm/sci/Kconfig    |  10 +
 xen/arch/arm/sci/scmi_smc.c | 959 ++++++++++++++++++++++++++++++++++++
 3 files changed, 971 insertions(+)
 create mode 100644 xen/arch/arm/sci/Kconfig
 create mode 100644 xen/arch/arm/sci/scmi_smc.c

diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig
index ab07833582..3b0dfc57b6 100644
--- a/xen/arch/arm/Kconfig
+++ b/xen/arch/arm/Kconfig
@@ -123,6 +123,8 @@ config ARM_SCI
 	  support. It allows guests to control system resourcess via one of
 	  ARM_SCI mediators implemented in XEN.
 
+	source "arch/arm/sci/Kconfig"
+
 endmenu
 
 menu "ARM errata workaround via the alternative framework"
diff --git a/xen/arch/arm/sci/Kconfig b/xen/arch/arm/sci/Kconfig
new file mode 100644
index 0000000000..10b634d2ed
--- /dev/null
+++ b/xen/arch/arm/sci/Kconfig
@@ -0,0 +1,10 @@
+config SCMI_SMC
+	bool "Enable SCMI-SMC mediator driver"
+	default n
+	depends on ARM_SCI && HOST_DTB_EXPORT
+	---help---
+
+	Enables mediator in XEN to pass SCMI requests from Domains to ATF.
+	This feature allows drivers from Domains to work with System
+	Controllers (such as power,resets,clock etc.). SCP is used as transport
+	for communication.
diff --git a/xen/arch/arm/sci/scmi_smc.c b/xen/arch/arm/sci/scmi_smc.c
new file mode 100644
index 0000000000..103529dfab
--- /dev/null
+++ b/xen/arch/arm/sci/scmi_smc.c
@@ -0,0 +1,959 @@
+/*
+ * xen/arch/arm/sci/scmi_smc.c
+ *
+ * SCMI mediator driver, using SCP as transport.
+ *
+ * Oleksii Moisieiev <oleksii_moisieiev@epam.com>
+ * Copyright (C) 2021, EPAM Systems.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <asm/sci/sci.h>
+#include <asm/smccc.h>
+#include <asm/io.h>
+#include <xen/bitops.h>
+#include <xen/config.h>
+#include <xen/sched.h>
+#include <xen/device_tree.h>
+#include <xen/iocap.h>
+#include <xen/init.h>
+#include <xen/err.h>
+#include <xen/lib.h>
+#include <xen/list.h>
+#include <xen/mm.h>
+#include <xen/string.h>
+#include <xen/time.h>
+#include <xen/vmap.h>
+
+#define SCMI_BASE_PROTOCOL                  0x10
+#define SCMI_BASE_PROTOCOL_ATTIBUTES        0x1
+#define SCMI_BASE_SET_DEVICE_PERMISSIONS    0x9
+#define SCMI_BASE_RESET_AGENT_CONFIGURATION 0xB
+#define SCMI_BASE_DISCOVER_AGENT            0x7
+
+/* SCMI return codes. See section 4.1.4 of SCMI spec (DEN0056C) */
+#define SCMI_SUCCESS              0
+#define SCMI_NOT_SUPPORTED      (-1)
+#define SCMI_INVALID_PARAMETERS (-2)
+#define SCMI_DENIED             (-3)
+#define SCMI_NOT_FOUND          (-4)
+#define SCMI_OUT_OF_RANGE       (-5)
+#define SCMI_BUSY               (-6)
+#define SCMI_COMMS_ERROR        (-7)
+#define SCMI_GENERIC_ERROR      (-8)
+#define SCMI_HARDWARE_ERROR     (-9)
+#define SCMI_PROTOCOL_ERROR     (-10)
+
+#define DT_MATCH_SCMI_SMC DT_MATCH_COMPATIBLE("arm,scmi-smc")
+
+#define SCMI_SMC_ID                        "arm,smc-id"
+#define SCMI_SHARED_MEMORY                 "arm,scmi-shmem"
+#define SCMI_SHMEM                         "shmem"
+#define SCMI_SHMEM_MAPPED_SIZE             PAGE_SIZE
+
+#define HYP_CHANNEL                          0x0
+
+#define HDR_ID                             GENMASK(7,0)
+#define HDR_TYPE                           GENMASK(9, 8)
+#define HDR_PROTO                          GENMASK(17, 10)
+
+/* SCMI protocol, refer to section 4.2.2.2 (DEN0056C) */
+#define MSG_N_AGENTS_MASK                  GENMASK(15, 8)
+
+#define FIELD_GET(_mask, _reg)\
+    ((typeof(_mask))(((_reg) & (_mask)) >> (ffs64(_mask) - 1)))
+#define FIELD_PREP(_mask, _val)\
+    (((typeof(_mask))(_val) << (ffs64(_mask) - 1)) & (_mask))
+
+typedef struct scmi_msg_header {
+    uint8_t id;
+    uint8_t type;
+    uint8_t protocol;
+} scmi_msg_header_t;
+
+#define SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE   BIT(0, UL)
+#define SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR  BIT(1, UL)
+
+#define SCMI_ALLOW_ACCESS                   BIT(0, UL)
+
+struct scmi_shared_mem {
+    uint32_t reserved;
+    uint32_t channel_status;
+    uint32_t reserved1[2];
+    uint32_t flags;
+    uint32_t length;
+    uint32_t msg_header;
+    uint8_t msg_payload[];
+};
+
+struct dt_channel_addr {
+    u64 addr;
+    u64 size;
+    struct list_head list;
+};
+
+struct scmi_channel {
+    int chan_id;
+    int agent_id;
+    uint32_t func_id;
+    domid_t domain_id;
+    uint64_t paddr;
+    uint64_t len;
+    struct scmi_shared_mem *shmem;
+    spinlock_t lock;
+    struct list_head list;
+};
+
+struct scmi_data {
+    struct list_head channel_list;
+    spinlock_t channel_list_lock;
+    bool initialized;
+};
+
+static struct scmi_data scmi_data;
+
+
+/*
+ * pack_scmi_header() - packs and returns 32-bit header
+ *
+ * @hdr: pointer to header containing all the information on message id,
+ *    protocol id and type id.
+ *
+ * Return: 32-bit packed message header to be sent to the platform.
+ */
+static inline uint32_t pack_scmi_header(scmi_msg_header_t *hdr)
+{
+    return FIELD_PREP(HDR_ID, hdr->id) |
+        FIELD_PREP(HDR_TYPE, hdr->type) |
+        FIELD_PREP(HDR_PROTO, hdr->protocol);
+}
+
+/*
+ * unpack_scmi_header() - unpacks and records message and protocol id
+ *
+ * @msg_hdr: 32-bit packed message header sent from the platform
+ * @hdr: pointer to header to fetch message and protocol id.
+ */
+static inline void unpack_scmi_header(uint32_t msg_hdr, scmi_msg_header_t *hdr)
+{
+    hdr->id = FIELD_GET(HDR_ID, msg_hdr);
+    hdr->type = FIELD_GET(HDR_TYPE, msg_hdr);
+    hdr->protocol = FIELD_GET(HDR_PROTO, msg_hdr);
+}
+
+static inline int channel_is_free(struct scmi_channel *chan_info)
+{
+    return ( chan_info->shmem->channel_status
+            & SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE ) ? 0 : -EBUSY;
+}
+
+/*
+ * Copy data from IO memory space to "real" memory space.
+ */
+void __memcpy_fromio(void *to, const volatile void __iomem *from, size_t count)
+{
+    while (count && !IS_ALIGNED((unsigned long)from, 4)) {
+        *(u8 *)to = __raw_readb(from);
+        from++;
+        to++;
+        count--;
+    }
+
+    while (count >= 4) {
+        *(u32 *)to = __raw_readl(from);
+        from += 4;
+        to += 4;
+        count -= 4;
+    }
+
+    while (count) {
+        *(u8 *)to = __raw_readb(from);
+        from++;
+        to++;
+        count--;
+    }
+}
+
+/*
+ * Copy data from "real" memory space to IO memory space.
+ */
+void __memcpy_toio(volatile void __iomem *to, const void *from, size_t count)
+{
+    while (count && !IS_ALIGNED((unsigned long)to, 4)) {
+        __raw_writeb(*(u8 *)from, to);
+        from++;
+        to++;
+        count--;
+    }
+
+    while (count >= 4) {
+        __raw_writel(*(u32 *)from, to);
+        from += 4;
+        to += 4;
+        count -= 4;
+    }
+
+    while (count) {
+        __raw_writeb(*(u8 *)from, to);
+        from++;
+        to++;
+        count--;
+    }
+}
+
+static int send_smc_message(struct scmi_channel *chan_info,
+                            scmi_msg_header_t *hdr, void *data, int len)
+{
+    struct arm_smccc_res resp;
+    int ret;
+
+    if ( (len + sizeof(chan_info->shmem->msg_header)) >
+                         SCMI_SHMEM_MAPPED_SIZE )
+    {
+        printk(XENLOG_ERR
+               "scmi: Wrong size of smc message. Data is invalid\n");
+        return -EINVAL;
+    }
+
+    printk(XENLOG_DEBUG "scmi: status =%d len=%d\n",
+           chan_info->shmem->channel_status, len);
+    printk(XENLOG_DEBUG "scmi: header id = %d type = %d, proto = %d\n",
+           hdr->id, hdr->type, hdr->protocol);
+
+    ret = channel_is_free(chan_info);
+    if ( IS_ERR_VALUE(ret) )
+        return ret;
+
+    chan_info->shmem->channel_status = 0x0;
+    /* Writing 0x0 right now, but SCMI_SHMEM_FLAG_INTR_ENABLED can be set */
+    chan_info->shmem->flags = 0x0;
+    chan_info->shmem->length = sizeof(chan_info->shmem->msg_header) + len;
+    chan_info->shmem->msg_header = pack_scmi_header(hdr);
+
+    printk(XENLOG_DEBUG "scmi: Writing to shmem address %p\n",
+           chan_info->shmem);
+    if ( len > 0 && data )
+        __memcpy_toio((void *)(chan_info->shmem->msg_payload), data, len);
+
+    arm_smccc_smc(chan_info->func_id, 0, 0, 0, 0, 0, 0, chan_info->chan_id,
+                  &resp);
+
+    printk(XENLOG_DEBUG "scmi: scmccc_smc response %d\n", (int)(resp.a0));
+
+    if ( resp.a0 )
+        return -EOPNOTSUPP;
+
+    return 0;
+}
+
+static int check_scmi_status(int scmi_status)
+{
+    if ( scmi_status == SCMI_SUCCESS )
+        return 0;
+
+    printk(XENLOG_DEBUG "scmi: Error received: %d\n", scmi_status);
+
+    switch ( scmi_status )
+    {
+    case SCMI_NOT_SUPPORTED:
+        return -EOPNOTSUPP;
+    case SCMI_INVALID_PARAMETERS:
+        return -EINVAL;
+    case SCMI_DENIED:
+        return -EACCES;
+    case SCMI_NOT_FOUND:
+        return -ENOENT;
+    case SCMI_OUT_OF_RANGE:
+        return -ERANGE;
+    case SCMI_BUSY:
+        return -EBUSY;
+    case SCMI_COMMS_ERROR:
+        return -ENOTCONN;
+    case SCMI_GENERIC_ERROR:
+        return -EIO;
+    case SCMI_HARDWARE_ERROR:
+        return -ENXIO;
+    case SCMI_PROTOCOL_ERROR:
+        return -EBADMSG;
+    default:
+        return -EINVAL;
+    }
+}
+
+static int get_smc_response(struct scmi_channel *chan_info,
+                            scmi_msg_header_t *hdr, void *data, int len)
+{
+    int recv_len;
+    int ret;
+
+    printk(XENLOG_DEBUG "scmi: get smc responce msgid %d\n", hdr->id);
+
+    if ( len >= SCMI_SHMEM_MAPPED_SIZE - sizeof(chan_info->shmem) )
+    {
+        printk(XENLOG_ERR
+               "scmi: Wrong size of input smc message. Data may be invalid\n");
+        return -EINVAL;
+    }
+
+    ret = channel_is_free(chan_info);
+    if ( IS_ERR_VALUE(ret) )
+        return ret;
+
+    recv_len = chan_info->shmem->length - sizeof(chan_info->shmem->msg_header);
+
+    if ( recv_len < 0 )
+    {
+        printk(XENLOG_ERR
+               "scmi: Wrong size of smc message. Data may be invalid\n");
+        return -EINVAL;
+    }
+
+    if ( recv_len > len )
+    {
+        printk(XENLOG_ERR
+               "scmi: Not enough buffer for message %d, expecting %d\n",
+               recv_len, len);
+        return -EINVAL;
+    }
+
+    unpack_scmi_header(chan_info->shmem->msg_header, hdr);
+
+    if ( recv_len > 0 )
+    {
+        __memcpy_fromio(data, chan_info->shmem->msg_payload, recv_len);
+    }
+
+    return 0;
+}
+
+static int do_smc_xfer(struct scmi_channel *channel, scmi_msg_header_t *hdr, void *tx_data, int tx_size,
+                       void *rx_data, int rx_size)
+{
+    int ret = 0;
+
+    ASSERT( channel && channel->shmem);
+
+    if ( !hdr )
+        return -EINVAL;
+
+    spin_lock(&channel->lock);
+
+    ret = send_smc_message(channel, hdr, tx_data, tx_size);
+    if ( ret )
+        goto clean;
+
+    ret = get_smc_response(channel, hdr, rx_data, rx_size);
+clean:
+    spin_unlock(&channel->lock);
+
+    return ret;
+}
+
+static struct scmi_channel *get_channel_by_id(uint8_t chan_id)
+{
+    struct scmi_channel *curr;
+    bool found = false;
+
+    spin_lock(&scmi_data.channel_list_lock);
+    list_for_each_entry(curr, &scmi_data.channel_list, list)
+    {
+        if ( curr->chan_id == chan_id )
+        {
+            found = true;
+            break;
+        }
+    }
+
+    spin_unlock(&scmi_data.channel_list_lock);
+    if ( found )
+        return curr;
+
+    return NULL;
+}
+
+static struct scmi_channel *aquire_scmi_channel(domid_t domain_id)
+{
+    struct scmi_channel *curr;
+    bool found = false;
+
+    ASSERT(domain_id != DOMID_INVALID && domain_id >= 0);
+
+    spin_lock(&scmi_data.channel_list_lock);
+    list_for_each_entry(curr, &scmi_data.channel_list, list)
+    {
+        if ( curr->domain_id == DOMID_INVALID )
+        {
+            curr->domain_id = domain_id;
+            found = true;
+            break;
+        }
+    }
+
+    spin_unlock(&scmi_data.channel_list_lock);
+    if ( found )
+        return curr;
+
+    return NULL;
+}
+
+static void relinquish_scmi_channel(struct scmi_channel *channel)
+{
+    ASSERT(channel != NULL);
+
+    spin_lock(&scmi_data.channel_list_lock);
+    channel->domain_id = DOMID_INVALID;
+    spin_unlock(&scmi_data.channel_list_lock);
+}
+
+static int map_channel_memory(struct scmi_channel *channel)
+{
+    ASSERT( channel && channel->paddr );
+    channel->shmem = ioremap_cache(channel->paddr, SCMI_SHMEM_MAPPED_SIZE);
+    if ( !channel->shmem )
+        return -ENOMEM;
+
+    channel->shmem->channel_status = SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE;
+    printk(XENLOG_DEBUG "scmi: Got shmem after vmap %p\n", channel->shmem);
+    return 0;
+}
+
+static void unmap_channel_memory(struct scmi_channel *channel)
+{
+    ASSERT( channel && channel->shmem );
+    iounmap(channel->shmem);
+    channel->shmem = NULL;
+}
+
+static struct scmi_channel *smc_create_channel(uint8_t chan_id,
+                                               uint32_t func_id, uint64_t addr)
+{
+    struct scmi_channel *channel;
+
+    channel = get_channel_by_id(chan_id);
+    if ( channel )
+        return ERR_PTR(EEXIST);
+
+    channel = xmalloc(struct scmi_channel);
+    if ( !channel )
+        return ERR_PTR(ENOMEM);
+
+    channel->chan_id = chan_id;
+    channel->func_id = func_id;
+    channel->domain_id = DOMID_INVALID;
+    channel->shmem = NULL;
+    channel->paddr = addr;
+    spin_lock_init(&channel->lock);
+    spin_lock(&scmi_data.channel_list_lock);
+    list_add(&channel->list, &scmi_data.channel_list);
+    spin_unlock(&scmi_data.channel_list_lock);
+    return channel;
+}
+
+static int mem_permit_access(struct domain *d, uint64_t addr, uint64_t len)
+{
+    return iomem_permit_access(d, paddr_to_pfn(addr),
+                paddr_to_pfn(PAGE_ALIGN(addr + len -1)));
+}
+
+static int mem_deny_access(struct domain *d, uint64_t addr,
+                                     uint64_t len)
+{
+    return iomem_deny_access(d, paddr_to_pfn(addr),
+                paddr_to_pfn(PAGE_ALIGN(addr + len -1)));
+}
+
+static int dt_update_domain_range(uint64_t addr, uint64_t size)
+{
+    struct dt_device_node *shmem_node;
+    __be32 *hw_reg;
+    const struct dt_property *pp;
+    uint32_t len;
+
+    shmem_node = dt_find_compatible_node(NULL, NULL, SCMI_SHARED_MEMORY);
+    if ( !shmem_node )
+    {
+        printk(XENLOG_ERR "scmi: Unable to find %s node in DT\n", SCMI_SHMEM);
+        return -EINVAL;
+    }
+
+    pp = dt_find_property(shmem_node, "reg", &len);
+    if ( !pp )
+    {
+        printk(XENLOG_ERR "scmi: Unable to find regs entry in shmem node\n");
+        return -ENOENT;
+    }
+
+    hw_reg = pp->value;
+    dt_set_range(&hw_reg, shmem_node, addr, size);
+
+    return 0;
+}
+
+static void free_channel_list(void)
+{
+    struct scmi_channel *curr, *_curr;
+
+    spin_lock(&scmi_data.channel_list_lock);
+    list_for_each_entry_safe (curr, _curr, &scmi_data.channel_list, list)
+    {
+        list_del(&curr->list);
+        xfree(curr);
+    }
+
+    spin_unlock(&scmi_data.channel_list_lock);
+}
+
+static struct dt_device_node *get_dt_node_from_property(
+                struct dt_device_node *node, const char * p_name)
+{
+    const __be32 *prop;
+
+    ASSERT( node );
+
+    prop = dt_get_property(node, p_name, NULL);
+    if ( !prop )
+        return ERR_PTR(-EINVAL);
+
+    return dt_find_node_by_phandle(be32_to_cpup(prop));
+}
+
+static int get_shmem_regions(struct list_head *head, u64 hyp_addr)
+{
+    struct dt_device_node *node;
+    int ret;
+    struct dt_channel_addr *lchan;
+    u64 laddr, lsize;
+
+    node = dt_find_compatible_node(NULL, NULL, SCMI_SHARED_MEMORY);
+    if ( !node )
+        return -ENOENT;
+
+    while ( node )
+    {
+        ret = dt_device_get_address(node, 0, &laddr, &lsize);
+        if ( ret )
+            return ret;
+
+        if ( laddr != hyp_addr )
+        {
+            lchan = xmalloc(struct dt_channel_addr);
+            if ( !lchan )
+                return -ENOMEM;
+            lchan->addr = laddr;
+            lchan->size = lsize;
+
+            list_add_tail(&lchan->list, head);
+        }
+
+        node = dt_find_compatible_node(node, NULL, SCMI_SHARED_MEMORY);
+    }
+
+    return 0;
+}
+
+static int read_hyp_channel_addr(struct dt_device_node *scmi_node,
+                                 u64 *addr, u64 *size)
+{
+    struct dt_device_node *shmem_node;
+    shmem_node = get_dt_node_from_property(scmi_node, "shmem");
+    if ( IS_ERR_OR_NULL(shmem_node) )
+    {
+        printk(XENLOG_ERR
+               "scmi: Device tree error, can't parse reserved memory %ld\n",
+               PTR_ERR(shmem_node));
+        return PTR_ERR(shmem_node);
+    }
+
+    return dt_device_get_address(shmem_node, 0, addr, size);
+}
+
+static void free_shmem_regions(struct list_head *addr_list)
+{
+    struct dt_channel_addr *curr, *_curr;
+
+    list_for_each_entry_safe (curr, _curr, addr_list, list)
+    {
+        list_del(&curr->list);
+        xfree(curr);
+    }
+}
+
+static __init bool scmi_probe(struct dt_device_node *scmi_node)
+{
+    u64 addr, size;
+    int ret, i;
+    struct scmi_channel *channel, *agent_channel;
+    int n_agents;
+    scmi_msg_header_t hdr;
+    struct rx_t {
+        int32_t status;
+        uint32_t attributes;
+    } rx;
+    struct dt_channel_addr *entry;
+    struct list_head addr_list;
+
+    uint32_t func_id;
+
+    ASSERT(scmi_node != NULL);
+
+    INIT_LIST_HEAD(&scmi_data.channel_list);
+    spin_lock_init(&scmi_data.channel_list_lock);
+
+    if ( !dt_property_read_u32(scmi_node, SCMI_SMC_ID, &func_id) )
+    {
+        printk(XENLOG_ERR "scmi: Unable to read smc-id from DT\n");
+        return false;
+    }
+
+    ret = read_hyp_channel_addr(scmi_node, &addr, &size);
+    if ( IS_ERR_VALUE(ret) )
+        return false;
+
+    if ( !IS_ALIGNED(size, SCMI_SHMEM_MAPPED_SIZE) )
+    {
+        printk(XENLOG_ERR "scmi: Reserved memory is not aligned\n");
+        return false;
+    }
+
+    INIT_LIST_HEAD(&addr_list);
+
+    ret = get_shmem_regions(&addr_list, addr);
+    if ( IS_ERR_VALUE(ret) )
+        goto out;
+
+    channel = smc_create_channel(HYP_CHANNEL, func_id, addr);
+    if ( IS_ERR(channel) )
+        goto out;
+
+    ret = map_channel_memory(channel);
+    if ( ret )
+        goto out;
+
+    spin_lock(&scmi_data.channel_list_lock);
+    channel->domain_id = DOMID_XEN;
+    spin_unlock(&scmi_data.channel_list_lock);
+
+    hdr.id = SCMI_BASE_PROTOCOL_ATTIBUTES;
+    hdr.type = 0;
+    hdr.protocol = SCMI_BASE_PROTOCOL;
+
+    ret = do_smc_xfer(channel, &hdr, NULL, 0, &rx, sizeof(rx));
+    if ( ret )
+        goto error;
+
+    ret = check_scmi_status(rx.status);
+    if ( ret )
+        goto error;
+
+    n_agents = FIELD_GET(MSG_N_AGENTS_MASK, rx.attributes);
+    printk(XENLOG_DEBUG "scmi: Got agent count %d\n", n_agents);
+
+    i = 1;
+    list_for_each_entry(entry, &addr_list, list)
+    {
+        uint32_t tx_agent_id = 0xFFFFFFFF;
+        struct {
+            int32_t status;
+            uint32_t agent_id;
+            char name[16];
+        } da_rx;
+
+        agent_channel = smc_create_channel(i, func_id,
+                                           entry->addr);
+        if ( IS_ERR(agent_channel) )
+        {
+            ret = PTR_ERR(agent_channel);
+            goto error;
+        }
+
+        ret = map_channel_memory(agent_channel);
+        if ( ret )
+            goto error;
+
+        hdr.id = SCMI_BASE_DISCOVER_AGENT;
+        hdr.type = 0;
+        hdr.protocol = SCMI_BASE_PROTOCOL;
+
+        ret = do_smc_xfer(agent_channel, &hdr, &tx_agent_id,
+                          sizeof(tx_agent_id), &da_rx, sizeof(da_rx));
+        if ( ret )
+        {
+            unmap_channel_memory(agent_channel);
+            goto error;
+        }
+
+        unmap_channel_memory(agent_channel);
+
+        ret = check_scmi_status(da_rx.status);
+        if ( ret )
+            goto error;
+
+        printk(XENLOG_DEBUG "scmi: status=0x%x id=0x%x name=%s\n",
+                da_rx.status, da_rx.agent_id, da_rx.name);
+
+        agent_channel->agent_id = da_rx.agent_id;
+
+        if ( i == n_agents )
+            break;
+
+        i++;
+    }
+
+    scmi_data.initialized = true;
+    goto out;
+
+error:
+    unmap_channel_memory(channel);
+    free_channel_list();
+out:
+    free_shmem_regions(&addr_list);
+    return ret == 0;
+}
+
+static int scmi_domain_init(struct domain *d,
+                           struct xen_arch_domainconfig *config)
+{
+    struct scmi_channel *channel;
+    int ret;
+
+    if ( !scmi_data.initialized )
+        return 0;
+
+    printk(XENLOG_INFO "scmi: domain_id = %d\n", d->domain_id);
+
+    channel = aquire_scmi_channel(d->domain_id);
+    if ( IS_ERR_OR_NULL(channel) )
+        return -ENOENT;
+
+#ifdef CONFIG_ARM_32
+    printk(XENLOG_INFO
+           "scmi: Aquire SCMI channel id = 0x%x , domain_id = %d paddr = 0x%llx\n",
+           channel->chan_id, channel->domain_id, channel->paddr);
+#else
+    printk(XENLOG_INFO
+           "scmi: Aquire SCMI channel id = 0x%x , domain_id = %d paddr = 0x%lx\n",
+           channel->chan_id, channel->domain_id, channel->paddr);
+#endif
+
+    if ( is_hardware_domain(d) )
+    {
+        ret = mem_permit_access(d, channel->paddr, PAGE_SIZE);
+        if ( IS_ERR_VALUE(ret) )
+            goto error;
+
+        ret = dt_update_domain_range(channel->paddr, PAGE_SIZE);
+        if ( IS_ERR_VALUE(ret) )
+        {
+            int rc = mem_deny_access(d, channel->paddr, PAGE_SIZE);
+            if ( rc )
+                printk(XENLOG_ERR "Unable to mem_deny_access\n");
+
+            goto error;
+        }
+    }
+
+    d->arch.sci = channel;
+    if ( config )
+        config->arm_sci_agent_paddr = channel->paddr;
+
+    return 0;
+error:
+    relinquish_scmi_channel(channel);
+
+    return ret;
+}
+
+static int scmi_add_device_by_devid(struct domain *d, uint32_t scmi_devid)
+{
+    struct scmi_channel *channel, *agent_channel;
+    scmi_msg_header_t hdr;
+    struct scmi_perms_tx {
+        uint32_t agent_id;
+        uint32_t device_id;
+        uint32_t flags;
+    } tx;
+    struct rx_t {
+        int32_t status;
+        uint32_t attributes;
+    } rx;
+    int ret;
+
+    if ( !scmi_data.initialized )
+        return 0;
+
+    printk(XENLOG_DEBUG "scmi: scmi_devid = %d\n", scmi_devid);
+
+    agent_channel = d->arch.sci;
+    if ( IS_ERR_OR_NULL(agent_channel) )
+        return PTR_ERR(agent_channel);
+
+    channel = get_channel_by_id(HYP_CHANNEL);
+    if ( IS_ERR_OR_NULL(channel) )
+        return PTR_ERR(channel);
+
+    hdr.id = SCMI_BASE_SET_DEVICE_PERMISSIONS;
+    hdr.type = 0;
+    hdr.protocol = SCMI_BASE_PROTOCOL;
+
+    tx.agent_id = agent_channel->agent_id;
+    tx.device_id = scmi_devid;
+    tx.flags = SCMI_ALLOW_ACCESS;
+
+    ret = do_smc_xfer(channel, &hdr, &tx, sizeof(tx), &rx, sizeof(&rx));
+    if ( IS_ERR_VALUE(ret) )
+        return ret;
+
+    ret = check_scmi_status(rx.status);
+    if ( IS_ERR_VALUE(ret) )
+        return ret;
+
+    return 0;
+}
+
+static int scmi_add_dt_device(struct domain *d, struct dt_device_node *dev)
+{
+    uint32_t scmi_devid;
+
+    if ( (!scmi_data.initialized) || (!d->arch.sci) )
+        return 0;
+
+    if ( !dt_property_read_u32(dev, "scmi_devid", &scmi_devid) )
+        return 0;
+
+    printk(XENLOG_INFO "scmi: dt_node = %s\n", dt_node_full_name(dev));
+
+    return scmi_add_device_by_devid(d, scmi_devid);
+}
+
+static int scmi_relinquish_resources(struct domain *d)
+{
+    int ret;
+    struct scmi_channel *channel, *agent_channel;
+    scmi_msg_header_t hdr;
+    struct reset_agent_tx {
+        uint32_t agent_id;
+        uint32_t flags;
+    } tx;
+    uint32_t rx;
+
+    if ( !d->arch.sci )
+        return 0;
+
+    agent_channel = d->arch.sci;
+
+    spin_lock(&agent_channel->lock);
+    tx.agent_id = agent_channel->agent_id;
+    spin_unlock(&agent_channel->lock);
+
+    channel = get_channel_by_id(HYP_CHANNEL);
+    if ( !channel )
+    {
+        printk(XENLOG_ERR
+               "scmi: Unable to get Hypervisor scmi channel for domain %d\n",
+               d->domain_id);
+        return -EINVAL;
+    }
+
+    hdr.id = SCMI_BASE_RESET_AGENT_CONFIGURATION;
+    hdr.type = 0;
+    hdr.protocol = SCMI_BASE_PROTOCOL;
+
+    tx.flags = 0;
+
+    ret = do_smc_xfer(channel, &hdr, &tx, sizeof(tx), &rx, sizeof(rx));
+    if ( ret )
+        return ret;
+
+    ret = check_scmi_status(rx);
+
+    return ret;
+}
+
+static void scmi_domain_destroy(struct domain *d)
+{
+    struct scmi_channel *channel;
+
+    if ( !d->arch.sci )
+        return;
+
+    channel = d->arch.sci;
+    spin_lock(&channel->lock);
+
+    relinquish_scmi_channel(channel);
+    printk(XENLOG_DEBUG "scmi: Free domain %d\n", d->domain_id);
+
+    d->arch.sci = NULL;
+
+    mem_deny_access(d, channel->paddr, PAGE_SIZE);
+    spin_unlock(&channel->lock);
+}
+
+static bool scmi_handle_call(struct domain *d, void *args)
+{
+    bool res = false;
+    struct scmi_channel *agent_channel;
+    struct arm_smccc_res resp;
+    struct cpu_user_regs *regs = args;
+
+    if ( !d->arch.sci )
+        return false;
+
+    agent_channel = d->arch.sci;
+    spin_lock(&agent_channel->lock);
+
+    if ( agent_channel->func_id != regs->r0 )
+    {
+        res = false;
+        goto unlock;
+    }
+
+    arm_smccc_smc(agent_channel->func_id, 0, 0, 0, 0, 0, 0,
+                  agent_channel->chan_id, &resp);
+
+    set_user_reg(regs, 0, resp.a0);
+    set_user_reg(regs, 1, resp.a1);
+    set_user_reg(regs, 2, resp.a2);
+    set_user_reg(regs, 3, resp.a3);
+    res = true;
+unlock:
+    spin_unlock(&agent_channel->lock);
+
+    return res;
+}
+
+static const struct dt_device_match scmi_smc_match[] __initconst =
+{
+    DT_MATCH_SCMI_SMC,
+    { /* sentinel */ },
+};
+
+static const struct sci_mediator_ops scmi_ops =
+{
+    .probe = scmi_probe,
+    .domain_init = scmi_domain_init,
+    .domain_destroy = scmi_domain_destroy,
+    .add_dt_device = scmi_add_dt_device,
+    .relinquish_resources = scmi_relinquish_resources,
+    .handle_call = scmi_handle_call,
+};
+
+REGISTER_SCI_MEDIATOR(scmi_smc, "SCMI-SMC", XEN_DOMCTL_CONFIG_ARM_SCI_SCMI_SMC,
+                      scmi_smc_match, &scmi_ops);
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [RFC v2 6/8] tools/arm: Introduce force_assign_without_iommu option to xl.cfg
  2022-02-08 18:00 [RFC v2 0/8] Introduce SCI-mediator feature Oleksii Moisieiev
                   ` (4 preceding siblings ...)
  2022-02-08 18:00 ` [RFC v2 5/8] xen/arm: introduce SCMI-SMC mediator driver Oleksii Moisieiev
@ 2022-02-08 18:00 ` Oleksii Moisieiev
  2022-02-17 14:52   ` Anthony PERARD
                     ` (2 more replies)
  2022-02-08 18:00 ` [RFC v2 7/8] tools/arm: add "arm_sci" " Oleksii Moisieiev
  2022-02-08 18:00 ` [RFC v2 8/8] xen/arm: add SCI mediator support for DomUs Oleksii Moisieiev
  7 siblings, 3 replies; 45+ messages in thread
From: Oleksii Moisieiev @ 2022-02-08 18:00 UTC (permalink / raw)
  To: xen-devel
  Cc: Oleksii Moisieiev, Wei Liu, Andrew Cooper, George Dunlap,
	Jan Beulich, Julien Grall, Stefano Stabellini, Nick Rosbrook,
	Anthony PERARD, Juergen Gross, Paul Durrant

If set, Xen is allowed to assign the devices even if they are not under
IOMMU.
Can be confugired from dom.cfg in the following format:
force_assign_without_iommu = 1

This parameter has the same purpose as xen,force-assign-without-iommu
property in dom0less archtecture.

Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@epam.com>
---
 docs/man/xl.cfg.5.pod.in              |  9 +++++++++
 tools/golang/xenlight/helpers.gen.go  |  5 +++++
 tools/golang/xenlight/types.gen.go    |  1 +
 tools/libs/light/libxl_arm.c          |  3 +++
 tools/libs/light/libxl_types.idl      |  1 +
 tools/xl/xl_parse.c                   |  3 +++
 xen/common/domain.c                   |  2 +-
 xen/drivers/passthrough/device_tree.c | 19 +++++++++++++++++--
 xen/drivers/passthrough/iommu.c       |  5 ++++-
 xen/include/public/domctl.h           |  5 ++++-
 xen/include/xen/iommu.h               |  3 +++
 11 files changed, 51 insertions(+), 5 deletions(-)

diff --git a/docs/man/xl.cfg.5.pod.in b/docs/man/xl.cfg.5.pod.in
index b98d161398..ddf82cb3bc 100644
--- a/docs/man/xl.cfg.5.pod.in
+++ b/docs/man/xl.cfg.5.pod.in
@@ -1614,6 +1614,15 @@ This feature is a B<technology preview>.
 
 =back
 
+=over 4
+
+=item B<force_assign_without_iommu=BOOLEAN>
+
+If set, Xen allows to assign a devices even if it is not behind an IOMMU.
+This renders your platform *unsafe* if the device is DMA-capable.
+
+=back
+
 =back
 
 =head2 Paravirtualised (PV) Guest Specific Options
diff --git a/tools/golang/xenlight/helpers.gen.go b/tools/golang/xenlight/helpers.gen.go
index b746ff1081..664933bbb8 100644
--- a/tools/golang/xenlight/helpers.gen.go
+++ b/tools/golang/xenlight/helpers.gen.go
@@ -1091,6 +1091,11 @@ if err := x.DmRestrict.fromC(&xc.dm_restrict);err != nil {
 return fmt.Errorf("converting field DmRestrict: %v", err)
 }
 x.Tee = TeeType(xc.tee)
+
+if err := x.ForceAssignWithoutIommu.fromC(&xc.force_assign_without_iommu);err != nil {
+return fmt.Errorf("converting field ForceAssignWithoutIommu: %v", err)
+}
+
 x.Type = DomainType(xc._type)
 switch x.Type{
 case DomainTypeHvm:
diff --git a/tools/golang/xenlight/types.gen.go b/tools/golang/xenlight/types.gen.go
index b1e84d5258..2f7a088c3b 100644
--- a/tools/golang/xenlight/types.gen.go
+++ b/tools/golang/xenlight/types.gen.go
@@ -512,6 +512,7 @@ NestedHvm Defbool
 Apic Defbool
 DmRestrict Defbool
 Tee TeeType
+ForceAssignWithoutIommu Defbool
 Type DomainType
 TypeUnion DomainBuildInfoTypeUnion
 ArchArm struct {
diff --git a/tools/libs/light/libxl_arm.c b/tools/libs/light/libxl_arm.c
index eef1de0939..c5090e2b32 100644
--- a/tools/libs/light/libxl_arm.c
+++ b/tools/libs/light/libxl_arm.c
@@ -101,6 +101,9 @@ int libxl__arch_domain_prepare_config(libxl__gc *gc,
         return ERROR_FAIL;
     }
 
+    if (libxl_defbool_val(d_config->b_info.force_assign_without_iommu))
+        config->iommu_opts |= XEN_DOMCTL_IOMMU_force_iommu;
+
     return 0;
 }
 
diff --git a/tools/libs/light/libxl_types.idl b/tools/libs/light/libxl_types.idl
index 2a42da2f7d..1080966c33 100644
--- a/tools/libs/light/libxl_types.idl
+++ b/tools/libs/light/libxl_types.idl
@@ -564,6 +564,7 @@ libxl_domain_build_info = Struct("domain_build_info",[
     ("apic",             libxl_defbool),
     ("dm_restrict",      libxl_defbool),
     ("tee",              libxl_tee_type),
+    ("force_assign_without_iommu", libxl_defbool),
     ("u", KeyedUnion(None, libxl_domain_type, "type",
                 [("hvm", Struct(None, [("firmware",         string),
                                        ("bios",             libxl_bios_type),
diff --git a/tools/xl/xl_parse.c b/tools/xl/xl_parse.c
index 117fcdcb2b..67fa96d949 100644
--- a/tools/xl/xl_parse.c
+++ b/tools/xl/xl_parse.c
@@ -2747,6 +2747,9 @@ skip_usbdev:
         }
     }
 
+    xlu_cfg_get_defbool(config, "force_assign_without_iommu",
+                        &b_info->force_assign_without_iommu, 0);
+
     parse_vkb_list(config, d_config);
 
     xlu_cfg_get_defbool(config, "xend_suspend_evtchn_compat",
diff --git a/xen/common/domain.c b/xen/common/domain.c
index 093bb4403f..f1f19bf711 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -512,7 +512,7 @@ static int sanitise_domain_config(struct xen_domctl_createdomain *config)
 
     if ( iommu )
     {
-        if ( config->iommu_opts & ~XEN_DOMCTL_IOMMU_no_sharept )
+        if ( config->iommu_opts >> XEN_DOMCTL_IOMMU_MAX )
         {
             dprintk(XENLOG_INFO, "Unknown IOMMU options %#x\n",
                     config->iommu_opts);
diff --git a/xen/drivers/passthrough/device_tree.c b/xen/drivers/passthrough/device_tree.c
index 98f2aa0dad..103608dec1 100644
--- a/xen/drivers/passthrough/device_tree.c
+++ b/xen/drivers/passthrough/device_tree.c
@@ -198,6 +198,7 @@ int iommu_do_dt_domctl(struct xen_domctl *domctl, struct domain *d,
 {
     int ret;
     struct dt_device_node *dev;
+    struct domain_iommu *hd = dom_iommu(d);
 
     switch ( domctl->cmd )
     {
@@ -238,6 +239,16 @@ int iommu_do_dt_domctl(struct xen_domctl *domctl, struct domain *d,
             return -EINVAL;
 
         ret = iommu_add_dt_device(dev);
+
+        /*
+         * iommu_add_dt_device returns 1 if iommu is disabled or device don't
+         * have iommus property
+         */
+        if ( (ret == 1) && (hd->force_assign_iommu) ) {
+            ret = -ENOSYS;
+            break;
+        }
+
         if ( ret < 0 )
         {
             printk(XENLOG_G_ERR "Failed to add %s to the IOMMU\n",
@@ -275,10 +286,14 @@ int iommu_do_dt_domctl(struct xen_domctl *domctl, struct domain *d,
 
         ret = iommu_deassign_dt_device(d, dev);
 
-        if ( ret )
-            printk(XENLOG_G_ERR "XEN_DOMCTL_assign_dt_device: assign \"%s\""
+        if ( ret ) {
+            if ( hd->force_assign_iommu )
+                ret = -ENOSYS;
+            else
+                printk(XENLOG_G_ERR "XEN_DOMCTL_assign_dt_device: assign \"%s\""
                    " to dom%u failed (%d)\n",
                    dt_node_full_name(dev), d->domain_id, ret);
+        }
         break;
 
     default:
diff --git a/xen/drivers/passthrough/iommu.c b/xen/drivers/passthrough/iommu.c
index 6334370109..216a9058c0 100644
--- a/xen/drivers/passthrough/iommu.c
+++ b/xen/drivers/passthrough/iommu.c
@@ -193,6 +193,8 @@ int iommu_domain_init(struct domain *d, unsigned int opts)
     hd->node = NUMA_NO_NODE;
 #endif
 
+    hd->force_assign_iommu = opts & XEN_DOMCTL_IOMMU_force_iommu;
+
     ret = arch_iommu_domain_init(d);
     if ( ret )
         return ret;
@@ -534,6 +536,7 @@ int iommu_do_domctl(
 {
     int ret = -ENODEV;
 
+
     if ( !is_iommu_enabled(d) )
         return -EOPNOTSUPP;
 
@@ -542,7 +545,7 @@ int iommu_do_domctl(
 #endif
 
 #ifdef CONFIG_HAS_DEVICE_TREE
-    if ( ret == -ENODEV )
+    if ( ret == -ENOSYS )
         ret = iommu_do_dt_domctl(domctl, d, u_domctl);
 #endif
 
diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
index b85e6170b0..bf5f8c5b6b 100644
--- a/xen/include/public/domctl.h
+++ b/xen/include/public/domctl.h
@@ -81,8 +81,11 @@ struct xen_domctl_createdomain {
 #define _XEN_DOMCTL_IOMMU_no_sharept  0
 #define XEN_DOMCTL_IOMMU_no_sharept   (1U << _XEN_DOMCTL_IOMMU_no_sharept)
 
+#define _XEN_DOMCTL_IOMMU_force_iommu 1
+#define XEN_DOMCTL_IOMMU_force_iommu  (1U << _XEN_DOMCTL_IOMMU_force_iommu)
+
 /* Max XEN_DOMCTL_IOMMU_* constant.  Used for ABI checking. */
-#define XEN_DOMCTL_IOMMU_MAX XEN_DOMCTL_IOMMU_no_sharept
+#define XEN_DOMCTL_IOMMU_MAX XEN_DOMCTL_IOMMU_force_iommu
 
     uint32_t iommu_opts;
 
diff --git a/xen/include/xen/iommu.h b/xen/include/xen/iommu.h
index 6b2cdffa4a..a9cf2334af 100644
--- a/xen/include/xen/iommu.h
+++ b/xen/include/xen/iommu.h
@@ -330,6 +330,9 @@ struct domain_iommu {
      * necessarily imply this is true.
      */
     bool need_sync;
+
+    /* Do not return error if the device without iommu is assigned */
+    bool force_assign_iommu;
 };
 
 #define dom_iommu(d)              (&(d)->iommu)
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [RFC v2 7/8] tools/arm: add "arm_sci" option to xl.cfg
  2022-02-08 18:00 [RFC v2 0/8] Introduce SCI-mediator feature Oleksii Moisieiev
                   ` (5 preceding siblings ...)
  2022-02-08 18:00 ` [RFC v2 6/8] tools/arm: Introduce force_assign_without_iommu option to xl.cfg Oleksii Moisieiev
@ 2022-02-08 18:00 ` Oleksii Moisieiev
  2022-02-08 18:00 ` [RFC v2 8/8] xen/arm: add SCI mediator support for DomUs Oleksii Moisieiev
  7 siblings, 0 replies; 45+ messages in thread
From: Oleksii Moisieiev @ 2022-02-08 18:00 UTC (permalink / raw)
  To: xen-devel
  Cc: Oleksii Moisieiev, Wei Liu, George Dunlap, Nick Rosbrook,
	Anthony PERARD, Juergen Gross

This enumeration sets SCI type for the domain. Currently there is
two possible options: either 'none' or 'scmi_smc'.

'none' is the default value and it disables SCI support at all.

'scmi_smc' enables access to the Firmware from the domains using SCMI
protocol and SMC as transport.

Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@epam.com>
---
 docs/man/xl.cfg.5.pod.in             | 20 ++++++++++++++++++++
 tools/golang/xenlight/helpers.gen.go |  2 ++
 tools/golang/xenlight/types.gen.go   |  7 +++++++
 tools/include/libxl.h                |  5 +++++
 tools/libs/light/libxl_types.idl     |  6 ++++++
 tools/xl/xl_parse.c                  |  9 +++++++++
 6 files changed, 49 insertions(+)

diff --git a/docs/man/xl.cfg.5.pod.in b/docs/man/xl.cfg.5.pod.in
index ddf82cb3bc..f960e367c4 100644
--- a/docs/man/xl.cfg.5.pod.in
+++ b/docs/man/xl.cfg.5.pod.in
@@ -1614,8 +1614,28 @@ This feature is a B<technology preview>.
 
 =back
 
+=item B<arm_sci="STRING">
+
+B<Arm only> Set ARM_SCI type for the guest. ARM_SCI is System Control Protocol
+allows domain to manage various functions that are provided by HW platform.
+
 =over 4
 
+=item B<none>
+
+Don't allow guest to use ARM_SCI if present on the platform. This is the
+default value.
+
+=item B<scmi_smc>
+
+Enables SCMI_SMC support for the guest. SCMI is System Control Management
+Inferface - allows domain to manage various functions that are provided by HW
+platform, such as clocks, resets and power-domains. Xen will mediate access to
+clocks, power-domains and resets between Domains and ATF. Disabled by default.
+SCP is used as transport.
+
+=back
+
 =item B<force_assign_without_iommu=BOOLEAN>
 
 If set, Xen allows to assign a devices even if it is not behind an IOMMU.
diff --git a/tools/golang/xenlight/helpers.gen.go b/tools/golang/xenlight/helpers.gen.go
index 664933bbb8..6cf7725735 100644
--- a/tools/golang/xenlight/helpers.gen.go
+++ b/tools/golang/xenlight/helpers.gen.go
@@ -1091,6 +1091,7 @@ if err := x.DmRestrict.fromC(&xc.dm_restrict);err != nil {
 return fmt.Errorf("converting field DmRestrict: %v", err)
 }
 x.Tee = TeeType(xc.tee)
+x.ArmSci = ArmSciType(xc.arm_sci)
 
 if err := x.ForceAssignWithoutIommu.fromC(&xc.force_assign_without_iommu);err != nil {
 return fmt.Errorf("converting field ForceAssignWithoutIommu: %v", err)
@@ -1439,6 +1440,7 @@ if err := x.DmRestrict.toC(&xc.dm_restrict); err != nil {
 return fmt.Errorf("converting field DmRestrict: %v", err)
 }
 xc.tee = C.libxl_tee_type(x.Tee)
+xc.arm_sci = C.libxl_arm_sci_type(x.ArmSci)
 xc._type = C.libxl_domain_type(x.Type)
 switch x.Type{
 case DomainTypeHvm:
diff --git a/tools/golang/xenlight/types.gen.go b/tools/golang/xenlight/types.gen.go
index 2f7a088c3b..3b5c959215 100644
--- a/tools/golang/xenlight/types.gen.go
+++ b/tools/golang/xenlight/types.gen.go
@@ -443,6 +443,12 @@ TeeTypeNone TeeType = 0
 TeeTypeOptee TeeType = 1
 )
 
+type ArmSciType int
+const(
+ArmSciTypeNone ArmSciType = 0
+ArmSciTypeScmi ArmSciType = 1
+)
+
 type RdmReserve struct {
 Strategy RdmReserveStrategy
 Policy RdmReservePolicy
@@ -512,6 +518,7 @@ NestedHvm Defbool
 Apic Defbool
 DmRestrict Defbool
 Tee TeeType
+ArmSci ArmSciType
 ForceAssignWithoutIommu Defbool
 Type DomainType
 TypeUnion DomainBuildInfoTypeUnion
diff --git a/tools/include/libxl.h b/tools/include/libxl.h
index 2bbbd21f0b..30e5aee119 100644
--- a/tools/include/libxl.h
+++ b/tools/include/libxl.h
@@ -278,6 +278,11 @@
  */
 #define LIBXL_HAVE_BUILDINFO_ARCH_ARM_TEE 1
 
+/*
+ * libxl_domain_build_info has the arch_arm.sci field.
+ */
+#define LIBXL_HAVE_BUILDINFO_ARCH_ARM_SCI 1
+
 /*
  * LIBXL_HAVE_SOFT_RESET indicates that libxl supports performing
  * 'soft reset' for domains and there is 'soft_reset' shutdown reason
diff --git a/tools/libs/light/libxl_types.idl b/tools/libs/light/libxl_types.idl
index 1080966c33..1878c115c3 100644
--- a/tools/libs/light/libxl_types.idl
+++ b/tools/libs/light/libxl_types.idl
@@ -480,6 +480,11 @@ libxl_tee_type = Enumeration("tee_type", [
     (1, "optee")
     ], init_val = "LIBXL_TEE_TYPE_NONE")
 
+libxl_arm_sci_type = Enumeration("arm_sci_type", [
+    (0, "none"),
+    (1, "scmi_smc")
+    ], init_val = "LIBXL_ARM_SCI_TYPE_NONE")
+
 libxl_rdm_reserve = Struct("rdm_reserve", [
     ("strategy",    libxl_rdm_reserve_strategy),
     ("policy",      libxl_rdm_reserve_policy),
@@ -564,6 +569,7 @@ libxl_domain_build_info = Struct("domain_build_info",[
     ("apic",             libxl_defbool),
     ("dm_restrict",      libxl_defbool),
     ("tee",              libxl_tee_type),
+    ("arm_sci",          libxl_arm_sci_type),
     ("force_assign_without_iommu", libxl_defbool),
     ("u", KeyedUnion(None, libxl_domain_type, "type",
                 [("hvm", Struct(None, [("firmware",         string),
diff --git a/tools/xl/xl_parse.c b/tools/xl/xl_parse.c
index 67fa96d949..d53c9b1271 100644
--- a/tools/xl/xl_parse.c
+++ b/tools/xl/xl_parse.c
@@ -2747,6 +2747,15 @@ skip_usbdev:
         }
     }
 
+    if (!xlu_cfg_get_string (config, "arm_sci", &buf, 1)) {
+        e = libxl_arm_sci_type_from_string(buf, &b_info->arm_sci);
+        if (e) {
+            fprintf(stderr,
+                    "Unknown arm_sci \"%s\" specified\n", buf);
+            exit(-ERROR_FAIL);
+        }
+    }
+
     xlu_cfg_get_defbool(config, "force_assign_without_iommu",
                         &b_info->force_assign_without_iommu, 0);
 
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [RFC v2 8/8] xen/arm: add SCI mediator support for DomUs
  2022-02-08 18:00 [RFC v2 0/8] Introduce SCI-mediator feature Oleksii Moisieiev
                   ` (6 preceding siblings ...)
  2022-02-08 18:00 ` [RFC v2 7/8] tools/arm: add "arm_sci" " Oleksii Moisieiev
@ 2022-02-08 18:00 ` Oleksii Moisieiev
  7 siblings, 0 replies; 45+ messages in thread
From: Oleksii Moisieiev @ 2022-02-08 18:00 UTC (permalink / raw)
  To: xen-devel
  Cc: Oleksii Moisieiev, Wei Liu, Juergen Gross, Andrew Cooper,
	George Dunlap, Jan Beulich, Julien Grall, Stefano Stabellini,
	Anthony PERARD, Volodymyr Babchuk, Bertrand Marquis

Integration of the SCMI mediator with xen libs:
- add hypercalls to aquire SCI channel and set device permissions
for DomUs;
- add SCMI_SMC nodes to DomUs device-tree based on partial device-tree;
- SCI requests redirection from DomUs to Firmware.

Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@epam.com>
---
 tools/include/xenctrl.h               |   3 +
 tools/libs/light/libxl_arm.c          | 214 ++++++++++++++++++++++++--
 tools/libs/light/libxl_create.c       |  44 +++++-
 tools/libs/light/libxl_internal.h     |   3 +
 xen/arch/arm/domctl.c                 |   7 +
 xen/include/public/device_tree_defs.h |   1 +
 6 files changed, 260 insertions(+), 12 deletions(-)

diff --git a/tools/include/xenctrl.h b/tools/include/xenctrl.h
index 07b96e6671..cdd14f465f 100644
--- a/tools/include/xenctrl.h
+++ b/tools/include/xenctrl.h
@@ -1238,6 +1238,9 @@ int xc_domain_getvnuma(xc_interface *xch,
 int xc_domain_soft_reset(xc_interface *xch,
                          uint32_t domid);
 
+int xc_domain_add_sci_device(xc_interface *xch,
+                              uint32_t domid, char *path);
+
 #if defined(__i386__) || defined(__x86_64__)
 /*
  * PC BIOS standard E820 types and structure.
diff --git a/tools/libs/light/libxl_arm.c b/tools/libs/light/libxl_arm.c
index c5090e2b32..106ff33c84 100644
--- a/tools/libs/light/libxl_arm.c
+++ b/tools/libs/light/libxl_arm.c
@@ -7,6 +7,12 @@
 #include <libfdt.h>
 #include <assert.h>
 #include <xen/device_tree_defs.h>
+#include <xenhypfs.h>
+
+#define SCMI_NODE_PATH         "/firmware/scmi"
+#define SCMI_NODE_COMPATIBLE   "arm,scmi-smc"
+#define SCMI_SHMEM_COMPATIBLE  "arm,scmi-shmem"
+#define HYPFS_DEVICETREE_PATH  "/devicetree"
 
 static const char *gicv_to_string(libxl_gic_version gic_version)
 {
@@ -101,6 +107,19 @@ int libxl__arch_domain_prepare_config(libxl__gc *gc,
         return ERROR_FAIL;
     }
 
+    switch (d_config->b_info.arm_sci) {
+    case LIBXL_ARM_SCI_TYPE_NONE:
+        config->arch.arm_sci_type = XEN_DOMCTL_CONFIG_ARM_SCI_NONE;
+        break;
+    case LIBXL_ARM_SCI_TYPE_SCMI_SMC:
+        config->arch.arm_sci_type = XEN_DOMCTL_CONFIG_ARM_SCI_SCMI_SMC;
+        break;
+    default:
+        LOG(ERROR, "Unknown ARM_SCI type %d",
+            d_config->b_info.arm_sci);
+        return ERROR_FAIL;
+    }
+
     if (libxl_defbool_val(d_config->b_info.force_assign_without_iommu))
         config->iommu_opts |= XEN_DOMCTL_IOMMU_force_iommu;
 
@@ -125,6 +144,7 @@ int libxl__arch_domain_save_config(libxl__gc *gc,
     }
 
     state->clock_frequency = config->arch.clock_frequency;
+    state->arm_sci_agent_paddr = config->arch.arm_sci_agent_paddr;
 
     return 0;
 }
@@ -505,9 +525,6 @@ static int make_optee_node(libxl__gc *gc, void *fdt)
     int res;
     LOG(DEBUG, "Creating OP-TEE node in dtb");
 
-    res = fdt_begin_node(fdt, "firmware");
-    if (res) return res;
-
     res = fdt_begin_node(fdt, "optee");
     if (res) return res;
 
@@ -520,9 +537,6 @@ static int make_optee_node(libxl__gc *gc, void *fdt)
     res = fdt_end_node(fdt);
     if (res) return res;
 
-    res = fdt_end_node(fdt);
-    if (res) return res;
-
     return 0;
 }
 
@@ -905,10 +919,9 @@ static int copy_node(libxl__gc *gc, void *fdt, void *pfdt,
     return 0;
 }
 
-static int copy_node_by_path(libxl__gc *gc, const char *path,
-                             void *fdt, void *pfdt)
+static int get_path_nodeoff(const char *path, void *pfdt)
 {
-    int nodeoff, r;
+    int nodeoff;
     const char *name = strrchr(path, '/');
 
     if (!name)
@@ -928,12 +941,189 @@ static int copy_node_by_path(libxl__gc *gc, const char *path,
     if (strcmp(fdt_get_name(pfdt, nodeoff, NULL), name))
         return -FDT_ERR_NOTFOUND;
 
+    return nodeoff;
+}
+
+static int copy_node_by_path(libxl__gc *gc, const char *path,
+                             void *fdt, void *pfdt)
+{
+    int nodeoff, r;
+
+    nodeoff = get_path_nodeoff(path, pfdt);
+    if (nodeoff < 0)
+        return nodeoff;
+
     r = copy_node(gc, fdt, pfdt, nodeoff, 0);
     if (r) return r;
 
     return 0;
 }
 
+static int make_scmi_shmem_node(libxl__gc *gc, void *fdt, void *pfdt)
+{
+    int res;
+    char buf[64];
+
+#ifdef CONFIG_ARM_32
+    snprintf(buf, sizeof(buf), "scp-shmem@%lx",
+             GUEST_SCI_SHMEM_BASE);
+#else
+    snprintf(buf, sizeof(buf), "scp-shmem@%llx",
+             GUEST_SCI_SHMEM_BASE);
+#endif
+
+    res = fdt_begin_node(fdt, buf);
+    if (res) return res;
+
+    res = fdt_property_compat(gc, fdt, 1, SCMI_SHMEM_COMPATIBLE);
+    if (res) return res;
+
+    res = fdt_property_regs(gc, fdt, GUEST_ROOT_ADDRESS_CELLS,
+                    GUEST_ROOT_SIZE_CELLS, 1,
+                    GUEST_SCI_SHMEM_BASE, GUEST_SCI_SHMEM_SIZE);
+    if (res) return res;
+
+    res = fdt_property_cell(fdt, "phandle", GUEST_PHANDLE_SCMI);
+    if (res) return res;
+
+    res = fdt_end_node(fdt);
+    if (res) return res;
+
+    return 0;
+}
+
+static int create_hypfs_property(struct xenhypfs_handle *hdl, void *fdt,
+                                 char *path, char *name)
+{
+    char *p, *result;
+    int ret = 0;
+    struct xenhypfs_dirent *ent;
+
+    if (strcmp(name, "shmem") == 0)
+        return fdt_property_cell(fdt, name, GUEST_PHANDLE_SCMI);
+
+    ret = asprintf(&p, "%s%s", HYPFS_DEVICETREE_PATH, path);
+    result = xenhypfs_read_raw(hdl, p, &ent);
+    free(p);
+    if (!result)
+        return -EINVAL;
+
+    ret = fdt_property(fdt, name, result, ent->size);
+    free(result);
+    free(ent);
+
+    return ret;
+}
+static int create_hypfs_subnode(struct xenhypfs_handle *hdl, void *fdt,
+                                const char *path, const char *name)
+{
+    struct xenhypfs_dirent *ent;
+    unsigned int n, i;
+    char *p, *p_sub;
+    int res = 0;
+
+    res = asprintf(&p, "%s%s", HYPFS_DEVICETREE_PATH, path);
+    if (res < 0)
+        return -ENOMEM;
+
+    ent = xenhypfs_readdir(hdl, p, &n);
+    free(p);
+    if (!ent)
+        return -EINVAL;
+
+    res = fdt_begin_node(fdt, name);
+    if (res) return res;
+
+    for (i = 0; i < n; i++) {
+        res = asprintf(&p_sub,"%s/%s", path, ent[i].name);
+        if (res < 0)
+            break;
+
+        if (ent[i].type == xenhypfs_type_dir)
+             res = create_hypfs_subnode(hdl, fdt, p_sub, ent[i].name);
+        else
+             res = create_hypfs_property(hdl, fdt, p_sub, ent[i].name);
+
+        free(p_sub);
+        if (res)
+            break;
+    }
+
+    res = fdt_end_node(fdt);
+    free(ent);
+    return res;
+}
+
+static int create_scmi_from_hypfs(void *fdt, const char *path)
+{
+    struct xenhypfs_handle *hdl;
+    int res;
+    hdl = xenhypfs_open(NULL, 0);
+    if (!hdl)
+        return -EINVAL;
+
+    res = create_hypfs_subnode(hdl, fdt, path, "scmi");
+    xenhypfs_close(hdl);
+
+    return res;
+}
+
+static int set_shmem_phandle(void *fdt, const char *scmi_node_copmat)
+{
+    uint32_t val;
+    int nodeoff = fdt_node_offset_by_compatible(fdt, 0, scmi_node_copmat);
+    if (nodeoff < 0)
+        return -EINVAL;
+
+    val = cpu_to_fdt32(GUEST_PHANDLE_SCMI);
+    return fdt_setprop_inplace(fdt, nodeoff, "shmem", &val, sizeof(val));
+}
+
+static int make_scmi_node(libxl__gc *gc, void *fdt, void *pfdt)
+{
+    int res = 0;
+    int nodeoff =
+        fdt_node_offset_by_compatible(pfdt, 0, SCMI_NODE_COMPATIBLE);
+    if (nodeoff > 0) {
+        res = copy_node(gc, fdt, pfdt, nodeoff, 0);
+        if (res) return res;
+
+        res = set_shmem_phandle(fdt, SCMI_NODE_COMPATIBLE);
+        if (res) return res;
+    }
+    else
+        res = create_scmi_from_hypfs(fdt, SCMI_NODE_PATH);
+
+    return res;
+}
+
+static int make_firmware_node(libxl__gc *gc, void *fdt, void *pfdt, int tee,
+                              int sci)
+{
+    int res;
+
+    if ((tee == LIBXL_TEE_TYPE_NONE) && (sci == LIBXL_ARM_SCI_TYPE_NONE))
+        return 0;
+
+    res = fdt_begin_node(fdt, "firmware");
+    if (res) return res;
+
+    if (tee == LIBXL_TEE_TYPE_OPTEE) {
+       res = make_optee_node(gc, fdt);
+       if (res) return res;
+    }
+
+    if (sci == LIBXL_ARM_SCI_TYPE_SCMI_SMC) {
+        res = make_scmi_node(gc, fdt, pfdt);
+        if (res) return res;
+    }
+
+    res = fdt_end_node(fdt);
+    if (res) return res;
+
+    return 0;
+}
+
 /*
  * The partial device tree is not copied entirely. Only the relevant bits are
  * copied to the guest device tree:
@@ -1091,8 +1281,10 @@ next_resize:
         if (info->arch_arm.vuart == LIBXL_VUART_TYPE_SBSA_UART)
             FDT( make_vpl011_uart_node(gc, fdt, ainfo, dom) );
 
-        if (info->tee == LIBXL_TEE_TYPE_OPTEE)
-            FDT( make_optee_node(gc, fdt) );
+        if (info->arm_sci == LIBXL_ARM_SCI_TYPE_SCMI_SMC)
+            FDT( make_scmi_shmem_node(gc, fdt, pfdt) );
+
+        FDT( make_firmware_node(gc, fdt, pfdt, info->tee, info->arm_sci) );
 
         if (d_config->num_pcidevs)
             FDT( make_vpci_node(gc, fdt, ainfo, dom) );
diff --git a/tools/libs/light/libxl_create.c b/tools/libs/light/libxl_create.c
index dcd09d32ba..f1f1e66275 100644
--- a/tools/libs/light/libxl_create.c
+++ b/tools/libs/light/libxl_create.c
@@ -596,6 +596,38 @@ out:
     return ret;
 }
 
+static int map_sci_page(libxl__gc *gc, uint32_t domid, uint64_t paddr,
+                         uint64_t guest_addr)
+{
+    int ret;
+    uint64_t _paddr_pfn = paddr >> XC_PAGE_SHIFT;
+    uint64_t _guest_pfn = guest_addr >> XC_PAGE_SHIFT;
+
+    assert(paddr && guest_addr);
+    LOG(DEBUG, "iomem %"PRIx64, _paddr_pfn);
+
+    ret = xc_domain_iomem_permission(CTX->xch, domid, _paddr_pfn, 1, 1);
+    if (ret < 0) {
+        LOG(ERROR,
+              "failed give domain access to iomem page %"PRIx64,
+             _paddr_pfn);
+        return ret;
+    }
+
+    ret = xc_domain_memory_mapping(CTX->xch, domid,
+                                   _guest_pfn, _paddr_pfn,
+                                   1, 1);
+    if (ret < 0) {
+        LOG(ERROR,
+              "failed to map to domain iomem page %"PRIx64
+              " to guest address %"PRIx64,
+              _paddr_pfn, _guest_pfn);
+        return ret;
+    }
+
+    return 0;
+}
+
 int libxl__domain_make(libxl__gc *gc, libxl_domain_config *d_config,
                        libxl__domain_build_state *state,
                        uint32_t *domid, bool soft_reset)
@@ -762,6 +794,16 @@ int libxl__domain_make(libxl__gc *gc, libxl_domain_config *d_config,
         goto out;
     }
 
+    if (d_config->b_info.arm_sci == LIBXL_ARM_SCI_TYPE_SCMI_SMC) {
+        ret = map_sci_page(gc, *domid, state->arm_sci_agent_paddr,
+                            GUEST_SCI_SHMEM_BASE);
+        if (ret < 0) {
+            LOGED(ERROR, *domid, "map scmi fail");
+            rc = ERROR_FAIL;
+            goto out;
+        }
+    }
+
     dom_path = libxl__xs_get_dompath(gc, *domid);
     if (!dom_path) {
         rc = ERROR_FAIL;
@@ -1825,7 +1867,7 @@ static void libxl__add_dtdevs(libxl__egc *egc, libxl__ao *ao, uint32_t domid,
         LOGD(DEBUG, domid, "Assign device \"%s\" to domain", dtdev->path);
         rc = xc_assign_dt_device(CTX->xch, domid, dtdev->path);
         if (rc < 0) {
-            LOGD(ERROR, domid, "xc_assign_dtdevice failed: %d", rc);
+            LOGD(ERROR, domid, "xc_assign_dt_device failed: %d", rc);
             goto out;
         }
     }
diff --git a/tools/libs/light/libxl_internal.h b/tools/libs/light/libxl_internal.h
index 0b4671318c..79f38b60d4 100644
--- a/tools/libs/light/libxl_internal.h
+++ b/tools/libs/light/libxl_internal.h
@@ -1407,6 +1407,9 @@ typedef struct {
     /* Whether this domain is being migrated/restored, or booting fresh.  Only
      * applicable to the primary domain, not support domains (e.g. stub QEMU). */
     bool restore;
+
+    /* arm_sci channel paddr to be set to device-tree node */
+    uint64_t arm_sci_agent_paddr;
 } libxl__domain_build_state;
 
 _hidden void libxl__domain_build_state_init(libxl__domain_build_state *s);
diff --git a/xen/arch/arm/domctl.c b/xen/arch/arm/domctl.c
index 6245af6d0b..23c44f3a13 100644
--- a/xen/arch/arm/domctl.c
+++ b/xen/arch/arm/domctl.c
@@ -4,6 +4,7 @@
  * Copyright (c) 2012, Citrix Systems
  */
 
+#include <asm/sci/sci.h>
 #include <xen/errno.h>
 #include <xen/guest_access.h>
 #include <xen/hypercall.h>
@@ -182,7 +183,13 @@ long arch_do_domctl(struct xen_domctl *domctl, struct domain *d,
         rc = subarch_do_domctl(domctl, d, u_domctl);
 
         if ( rc == -ENOSYS )
+        {
             rc = iommu_do_domctl(domctl, d, u_domctl);
+            if ( (rc) && (rc != -ENOSYS) )
+                return rc;
+
+            rc = sci_do_domctl(domctl, d, u_domctl);
+        }
 
         return rc;
     }
diff --git a/xen/include/public/device_tree_defs.h b/xen/include/public/device_tree_defs.h
index 209d43de3f..f57684547b 100644
--- a/xen/include/public/device_tree_defs.h
+++ b/xen/include/public/device_tree_defs.h
@@ -7,6 +7,7 @@
  * onwards. Reserve a high value for the GIC phandle.
  */
 #define GUEST_PHANDLE_GIC (65000)
+#define GUEST_PHANDLE_SCMI (67000)
 
 #define GUEST_ROOT_ADDRESS_CELLS 2
 #define GUEST_ROOT_SIZE_CELLS 2
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* Re: [RFC v2 3/8] xen/arm: Export host device-tree to hypfs
  2022-02-08 18:00 ` [RFC v2 3/8] xen/arm: Export host device-tree to hypfs Oleksii Moisieiev
@ 2022-02-08 18:26   ` Julien Grall
  2022-02-09 10:20     ` Oleksii Moisieiev
  2022-02-09 14:03     ` Juergen Gross
  0 siblings, 2 replies; 45+ messages in thread
From: Julien Grall @ 2022-02-08 18:26 UTC (permalink / raw)
  To: Oleksii Moisieiev, xen-devel
  Cc: Stefano Stabellini, Volodymyr Babchuk, Bertrand Marquis, Juergen Gross

Hi Oleksii,

On 08/02/2022 18:00, Oleksii Moisieiev wrote:
> If enabled, host device-tree will be exported to hypfs and can be
> accessed through /devicetree path.
> Exported device-tree has the same format, as the device-tree
> exported to the sysfs by the Linux kernel.
> This is useful when XEN toolstack needs an access to the host device-tree.
> 
> Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@epam.com>
> ---
>   xen/arch/arm/Kconfig           |   8 +
>   xen/arch/arm/Makefile          |   1 +
>   xen/arch/arm/host_dtb_export.c | 307 +++++++++++++++++++++++++++++++++

There is nothing specific in this file. So can this be moved in common/?

>   3 files changed, 316 insertions(+)
>   create mode 100644 xen/arch/arm/host_dtb_export.c
> 
> diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig
> index ecfa6822e4..895016b21e 100644
> --- a/xen/arch/arm/Kconfig
> +++ b/xen/arch/arm/Kconfig
> @@ -33,6 +33,14 @@ config ACPI
>   	  Advanced Configuration and Power Interface (ACPI) support for Xen is
>   	  an alternative to device tree on ARM64.
>   
> +config HOST_DTB_EXPORT
> +	bool "Export host device tree to hypfs if enabled"
> +	depends on ARM && HYPFS && !ACPI

A Xen built with ACPI enabled will still be able to boot on a host using 
Device-Tree. So I don't think should depend on ACPI.

Also, I think this should depend on HAS_DEVICE_TREE rather than ARM.

> +	---help---
> +
> +	  Export host device-tree to hypfs so toolstack can have an access for the
> +	  host device tree from Dom0. If you unsure say N.
> +
>   config GICV3
>   	bool "GICv3 driver"
>   	depends on ARM_64 && !NEW_VGIC
> diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
> index 07f634508e..0a41f68f8c 100644
> --- a/xen/arch/arm/Makefile
> +++ b/xen/arch/arm/Makefile
> @@ -8,6 +8,7 @@ obj-y += platforms/
>   endif
>   obj-$(CONFIG_TEE) += tee/
>   obj-$(CONFIG_HAS_VPCI) += vpci.o
> +obj-$(CONFIG_HOST_DTB_EXPORT) += host_dtb_export.o
>   
>   obj-$(CONFIG_HAS_ALTERNATIVE) += alternative.o
>   obj-y += bootfdt.init.o
> diff --git a/xen/arch/arm/host_dtb_export.c b/xen/arch/arm/host_dtb_export.c
> new file mode 100644
> index 0000000000..794395683c
> --- /dev/null
> +++ b/xen/arch/arm/host_dtb_export.c

This is mostly hypfs related. So CCing Juergen for his input on the code.

> @@ -0,0 +1,307 @@
> +/*
> + * xen/arch/arm/host_dtb_export.c
> + *
> + * Export host device-tree to the hypfs so toolstack can access
> + * host device-tree from Dom0
> + *
> + * Oleksii Moisieiev <oleksii_moisieiev@epam.com>
> + * Copyright (C) 2021, EPAM Systems.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <xen/device_tree.h>
> +#include <xen/err.h>
> +#include <xen/guest_access.h>
> +#include <xen/hypfs.h>
> +#include <xen/init.h>
> +
> +#define HOST_DT_DIR "devicetree"
> +
> +static int host_dt_dir_read(const struct hypfs_entry *entry,
> +                            XEN_GUEST_HANDLE_PARAM(void) uaddr);
> +static unsigned int host_dt_dir_getsize(const struct hypfs_entry *entry);
> +
> +static const struct hypfs_entry *host_dt_dir_enter(
> +    const struct hypfs_entry *entry);
> +static void host_dt_dir_exit(const struct hypfs_entry *entry);
> +
> +static struct hypfs_entry *host_dt_dir_findentry(
> +    const struct hypfs_entry_dir *dir, const char *name, unsigned int name_len);

This is new code. So can you please make sure to avoid forward 
declaration by re-ordering the code.


[...]

> +static char *get_root_from_path(const char *path, char *name)
> +{
> +    const char *nm = strchr(path, '/');
> +    if ( !nm )
> +        nm = path + strlen(path);
> +    else
> +    {
> +        if ( !*nm )
> +            nm--;
> +    }
> +
> +    return memcpy(name, path, nm - path);

What does guaranteee that name will be big enough for the new value?

> +}
> +
> +static int host_dt_dir_read(const struct hypfs_entry *entry,
> +                            XEN_GUEST_HANDLE_PARAM(void) uaddr)
> +{
> +    int ret = 0;
> +    struct dt_device_node *node;
> +    struct dt_device_node *child;

The hypfs should not modify the device-tree. So can this be const?

> +    const struct dt_property *prop;
> +    struct hypfs_dyndir_id *data;
> +
> +    data = hypfs_get_dyndata();
> +    if ( !data )
> +        return -EINVAL;

[...]

> +static struct hypfs_entry *host_dt_dir_findentry(
> +    const struct hypfs_entry_dir *dir, const char *name, unsigned int name_len)
> +{
> +    struct dt_device_node *node;
> +    char root_name[HYPFS_DYNDIR_ID_NAMELEN];
> +    struct dt_device_node *child;
> +    struct hypfs_dyndir_id *data;
> +    struct dt_property *prop;
> +
> +    data = hypfs_get_dyndata();
> +    if ( !data )
> +        return ERR_PTR(-EINVAL);
> +
> +    node = data->data;
> +    if ( !node )
> +        return ERR_PTR(-EINVAL);
> +
> +    memset(root_name, 0, sizeof(root_name));
> +    get_root_from_path(name, root_name);
> +
> +    for ( child = node->child; child != NULL; child = child->sibling )
> +    {
> +        if ( strcmp(get_name_from_path(child->full_name), root_name) == 0 )
> +            return hypfs_gen_dyndir_entry(&dt_dir.e,
> +                                  get_name_from_path(child->full_name), child);
> +    }
> +
> +    dt_for_each_property_node( node, prop )
> +    {
> +
> +        if ( dt_property_name_is_equal(prop, root_name) )
> +            return hypfs_gen_dyndir_entry(&dt_prop.e, prop->name, prop);
> +    }
> +
> +    return ERR_PTR(-ENOENT);

[...]

> +static HYPFS_DIR_INIT_FUNC(host_dt_dir, HOST_DT_DIR, &host_dt_dir_funcs);
> +
> +static int __init host_dtb_export_init(void)
> +{
> +    ASSERT(dt_host && (dt_host->sibling == NULL));

dt_host can be NULL when booting on ACPI platform. So I think this wants 
to be turned to a normal check and return directly.

Also could you explain why you need to check dt_host->sibling?

Cheers,

-- 
Julien Grall


^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [RFC v2 3/8] xen/arm: Export host device-tree to hypfs
  2022-02-08 18:26   ` Julien Grall
@ 2022-02-09 10:20     ` Oleksii Moisieiev
  2022-02-09 12:17       ` Julien Grall
  2022-02-09 14:03     ` Juergen Gross
  1 sibling, 1 reply; 45+ messages in thread
From: Oleksii Moisieiev @ 2022-02-09 10:20 UTC (permalink / raw)
  To: Julien Grall
  Cc: xen-devel, Stefano Stabellini, Volodymyr Babchuk,
	Bertrand Marquis, Juergen Gross

Hi Julien,

On Tue, Feb 08, 2022 at 06:26:54PM +0000, Julien Grall wrote:
> Hi Oleksii,
> 
> On 08/02/2022 18:00, Oleksii Moisieiev wrote:
> > If enabled, host device-tree will be exported to hypfs and can be
> > accessed through /devicetree path.
> > Exported device-tree has the same format, as the device-tree
> > exported to the sysfs by the Linux kernel.
> > This is useful when XEN toolstack needs an access to the host device-tree.
> > 
> > Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@epam.com>
> > ---
> >   xen/arch/arm/Kconfig           |   8 +
> >   xen/arch/arm/Makefile          |   1 +
> >   xen/arch/arm/host_dtb_export.c | 307 +++++++++++++++++++++++++++++++++
> 
> There is nothing specific in this file. So can this be moved in common/?

You're right. I will move it to common.

> 
> >   3 files changed, 316 insertions(+)
> >   create mode 100644 xen/arch/arm/host_dtb_export.c
> > 
> > diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig
> > index ecfa6822e4..895016b21e 100644
> > --- a/xen/arch/arm/Kconfig
> > +++ b/xen/arch/arm/Kconfig
> > @@ -33,6 +33,14 @@ config ACPI
> >   	  Advanced Configuration and Power Interface (ACPI) support for Xen is
> >   	  an alternative to device tree on ARM64.
> > +config HOST_DTB_EXPORT
> > +	bool "Export host device tree to hypfs if enabled"
> > +	depends on ARM && HYPFS && !ACPI
> 
> A Xen built with ACPI enabled will still be able to boot on a host using
> Device-Tree. So I don't think should depend on ACPI.
> 
> Also, I think this should depend on HAS_DEVICE_TREE rather than ARM.

I agree. Thank you.

> 
> > +	---help---
> > +
> > +	  Export host device-tree to hypfs so toolstack can have an access for the
> > +	  host device tree from Dom0. If you unsure say N.
> > +
> >   config GICV3
> >   	bool "GICv3 driver"
> >   	depends on ARM_64 && !NEW_VGIC
> > diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
> > index 07f634508e..0a41f68f8c 100644
> > --- a/xen/arch/arm/Makefile
> > +++ b/xen/arch/arm/Makefile
> > @@ -8,6 +8,7 @@ obj-y += platforms/
> >   endif
> >   obj-$(CONFIG_TEE) += tee/
> >   obj-$(CONFIG_HAS_VPCI) += vpci.o
> > +obj-$(CONFIG_HOST_DTB_EXPORT) += host_dtb_export.o
> >   obj-$(CONFIG_HAS_ALTERNATIVE) += alternative.o
> >   obj-y += bootfdt.init.o
> > diff --git a/xen/arch/arm/host_dtb_export.c b/xen/arch/arm/host_dtb_export.c
> > new file mode 100644
> > index 0000000000..794395683c
> > --- /dev/null
> > +++ b/xen/arch/arm/host_dtb_export.c
> 
> This is mostly hypfs related. So CCing Juergen for his input on the code.

Thank you.

> 
> > @@ -0,0 +1,307 @@
> > +/*
> > + * xen/arch/arm/host_dtb_export.c
> > + *
> > + * Export host device-tree to the hypfs so toolstack can access
> > + * host device-tree from Dom0
> > + *
> > + * Oleksii Moisieiev <oleksii_moisieiev@epam.com>
> > + * Copyright (C) 2021, EPAM Systems.
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License as published by
> > + * the Free Software Foundation; either version 2 of the License, or
> > + * (at your option) any later version.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > + * GNU General Public License for more details.
> > + */
> > +
> > +#include <xen/device_tree.h>
> > +#include <xen/err.h>
> > +#include <xen/guest_access.h>
> > +#include <xen/hypfs.h>
> > +#include <xen/init.h>
> > +
> > +#define HOST_DT_DIR "devicetree"
> > +
> > +static int host_dt_dir_read(const struct hypfs_entry *entry,
> > +                            XEN_GUEST_HANDLE_PARAM(void) uaddr);
> > +static unsigned int host_dt_dir_getsize(const struct hypfs_entry *entry);
> > +
> > +static const struct hypfs_entry *host_dt_dir_enter(
> > +    const struct hypfs_entry *entry);
> > +static void host_dt_dir_exit(const struct hypfs_entry *entry);
> > +
> > +static struct hypfs_entry *host_dt_dir_findentry(
> > +    const struct hypfs_entry_dir *dir, const char *name, unsigned int name_len);
> 
> This is new code. So can you please make sure to avoid forward declaration
> by re-ordering the code.
> 

I can't avoid forward declaration here because all those functions
should be passed as callbacks for node template dt_dir. And dt_dir is
used in read and findentry functions.

> 
> [...]
> 
> > +static char *get_root_from_path(const char *path, char *name)
> > +{
> > +    const char *nm = strchr(path, '/');
> > +    if ( !nm )
> > +        nm = path + strlen(path);
> > +    else
> > +    {
> > +        if ( !*nm )
> > +            nm--;
> > +    }
> > +
> > +    return memcpy(name, path, nm - path);
> 
> What does guaranteee that name will be big enough for the new value?

I will refactor that.

> 
> > +}
> > +
> > +static int host_dt_dir_read(const struct hypfs_entry *entry,
> > +                            XEN_GUEST_HANDLE_PARAM(void) uaddr)
> > +{
> > +    int ret = 0;
> > +    struct dt_device_node *node;
> > +    struct dt_device_node *child;
> 
> The hypfs should not modify the device-tree. So can this be const?

That's a good point.
Unfortunatelly child can't be const because it is going to be passed to
data->data pointer, but node can be const I think. In any case I will go
through the file and see where const for the device_node can be set.

> 
> > +    const struct dt_property *prop;
> > +    struct hypfs_dyndir_id *data;
> > +
> > +    data = hypfs_get_dyndata();
> > +    if ( !data )
> > +        return -EINVAL;
> 
> [...]
> 
> > +static struct hypfs_entry *host_dt_dir_findentry(
> > +    const struct hypfs_entry_dir *dir, const char *name, unsigned int name_len)
> > +{
> > +    struct dt_device_node *node;
> > +    char root_name[HYPFS_DYNDIR_ID_NAMELEN];
> > +    struct dt_device_node *child;
> > +    struct hypfs_dyndir_id *data;
> > +    struct dt_property *prop;
> > +
> > +    data = hypfs_get_dyndata();
> > +    if ( !data )
> > +        return ERR_PTR(-EINVAL);
> > +
> > +    node = data->data;
> > +    if ( !node )
> > +        return ERR_PTR(-EINVAL);
> > +
> > +    memset(root_name, 0, sizeof(root_name));
> > +    get_root_from_path(name, root_name);
> > +
> > +    for ( child = node->child; child != NULL; child = child->sibling )
> > +    {
> > +        if ( strcmp(get_name_from_path(child->full_name), root_name) == 0 )
> > +            return hypfs_gen_dyndir_entry(&dt_dir.e,
> > +                                  get_name_from_path(child->full_name), child);
> > +    }
> > +
> > +    dt_for_each_property_node( node, prop )
> > +    {
> > +
> > +        if ( dt_property_name_is_equal(prop, root_name) )
> > +            return hypfs_gen_dyndir_entry(&dt_prop.e, prop->name, prop);
> > +    }
> > +
> > +    return ERR_PTR(-ENOENT);
> 
> [...]
> 
> > +static HYPFS_DIR_INIT_FUNC(host_dt_dir, HOST_DT_DIR, &host_dt_dir_funcs);
> > +
> > +static int __init host_dtb_export_init(void)
> > +{
> > +    ASSERT(dt_host && (dt_host->sibling == NULL));
> 
> dt_host can be NULL when booting on ACPI platform. So I think this wants to
> be turned to a normal check and return directly.
> 

I will replace if with
if ( !acpi_disabled )
    return -ENODEV;

> Also could you explain why you need to check dt_host->sibling?
> 

This is my way to check if dt_host points to the top of the device-tree.
In any case I will replace it with !acpi_disabled as I mentioned
earlier.

Best regards,
Oleksii

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [RFC v2 3/8] xen/arm: Export host device-tree to hypfs
  2022-02-09 10:20     ` Oleksii Moisieiev
@ 2022-02-09 12:17       ` Julien Grall
  2022-02-09 14:17         ` Oleksii Moisieiev
  2022-02-09 18:51         ` Oleksii Moisieiev
  0 siblings, 2 replies; 45+ messages in thread
From: Julien Grall @ 2022-02-09 12:17 UTC (permalink / raw)
  To: Oleksii Moisieiev
  Cc: xen-devel, Stefano Stabellini, Volodymyr Babchuk,
	Bertrand Marquis, Juergen Gross



On 09/02/2022 10:20, Oleksii Moisieiev wrote:
> Hi Julien,

Hi,

> 
> On Tue, Feb 08, 2022 at 06:26:54PM +0000, Julien Grall wrote:
>> Hi Oleksii,
>>
>> On 08/02/2022 18:00, Oleksii Moisieiev wrote:
>>> If enabled, host device-tree will be exported to hypfs and can be
>>> accessed through /devicetree path.
>>> Exported device-tree has the same format, as the device-tree
>>> exported to the sysfs by the Linux kernel.
>>> This is useful when XEN toolstack needs an access to the host device-tree.
>>>
>>> Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@epam.com>
>>> ---
>>>    xen/arch/arm/Kconfig           |   8 +
>>>    xen/arch/arm/Makefile          |   1 +
>>>    xen/arch/arm/host_dtb_export.c | 307 +++++++++++++++++++++++++++++++++
>>
>> There is nothing specific in this file. So can this be moved in common/?
> 
> You're right. I will move it to common.
> 
>>
>>>    3 files changed, 316 insertions(+)
>>>    create mode 100644 xen/arch/arm/host_dtb_export.c
>>>
>>> diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig
>>> index ecfa6822e4..895016b21e 100644
>>> --- a/xen/arch/arm/Kconfig
>>> +++ b/xen/arch/arm/Kconfig
>>> @@ -33,6 +33,14 @@ config ACPI
>>>    	  Advanced Configuration and Power Interface (ACPI) support for Xen is
>>>    	  an alternative to device tree on ARM64.
>>> +config HOST_DTB_EXPORT
>>> +	bool "Export host device tree to hypfs if enabled"
>>> +	depends on ARM && HYPFS && !ACPI
>>
>> A Xen built with ACPI enabled will still be able to boot on a host using
>> Device-Tree. So I don't think should depend on ACPI.
>>
>> Also, I think this should depend on HAS_DEVICE_TREE rather than ARM.
> 
> I agree. Thank you.
> 
>>
>>> +	---help---
>>> +
>>> +	  Export host device-tree to hypfs so toolstack can have an access for the
>>> +	  host device tree from Dom0. If you unsure say N.
>>> +
>>>    config GICV3
>>>    	bool "GICv3 driver"
>>>    	depends on ARM_64 && !NEW_VGIC
>>> diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
>>> index 07f634508e..0a41f68f8c 100644
>>> --- a/xen/arch/arm/Makefile
>>> +++ b/xen/arch/arm/Makefile
>>> @@ -8,6 +8,7 @@ obj-y += platforms/
>>>    endif
>>>    obj-$(CONFIG_TEE) += tee/
>>>    obj-$(CONFIG_HAS_VPCI) += vpci.o
>>> +obj-$(CONFIG_HOST_DTB_EXPORT) += host_dtb_export.o
>>>    obj-$(CONFIG_HAS_ALTERNATIVE) += alternative.o
>>>    obj-y += bootfdt.init.o
>>> diff --git a/xen/arch/arm/host_dtb_export.c b/xen/arch/arm/host_dtb_export.c
>>> new file mode 100644
>>> index 0000000000..794395683c
>>> --- /dev/null
>>> +++ b/xen/arch/arm/host_dtb_export.c
>>
>> This is mostly hypfs related. So CCing Juergen for his input on the code.
> 
> Thank you.
> 
>>
>>> @@ -0,0 +1,307 @@
>>> +/*
>>> + * xen/arch/arm/host_dtb_export.c
>>> + *
>>> + * Export host device-tree to the hypfs so toolstack can access
>>> + * host device-tree from Dom0
>>> + *
>>> + * Oleksii Moisieiev <oleksii_moisieiev@epam.com>
>>> + * Copyright (C) 2021, EPAM Systems.
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify
>>> + * it under the terms of the GNU General Public License as published by
>>> + * the Free Software Foundation; either version 2 of the License, or
>>> + * (at your option) any later version.
>>> + *
>>> + * This program is distributed in the hope that it will be useful,
>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>> + * GNU General Public License for more details.
>>> + */
>>> +
>>> +#include <xen/device_tree.h>
>>> +#include <xen/err.h>
>>> +#include <xen/guest_access.h>
>>> +#include <xen/hypfs.h>
>>> +#include <xen/init.h>
>>> +
>>> +#define HOST_DT_DIR "devicetree"
>>> +
>>> +static int host_dt_dir_read(const struct hypfs_entry *entry,
>>> +                            XEN_GUEST_HANDLE_PARAM(void) uaddr);
>>> +static unsigned int host_dt_dir_getsize(const struct hypfs_entry *entry);
>>> +
>>> +static const struct hypfs_entry *host_dt_dir_enter(
>>> +    const struct hypfs_entry *entry);
>>> +static void host_dt_dir_exit(const struct hypfs_entry *entry);
>>> +
>>> +static struct hypfs_entry *host_dt_dir_findentry(
>>> +    const struct hypfs_entry_dir *dir, const char *name, unsigned int name_len);
>>
>> This is new code. So can you please make sure to avoid forward declaration
>> by re-ordering the code.
>>
> 
> I can't avoid forward declaration here because all those functions
> should be passed as callbacks for node template dt_dir. And dt_dir is
> used in read and findentry functions.

You can avoid most of those forward declarations if you define the 
static variable now but fill them up after (see [1]). I don't think we 
can avoid the static variable forward declaration without reworking the API.

BTW, I could not fully apply the series on the staging tree:

Applying: xen/hypfs: support fo nested dynamic hypfs nodes
Applying: libs: libxenhypfs - handle blob properties
Applying: xen/arm: Export host device-tree to hypfs
Applying: xen/arm: add generic SCI mediator framework
error: patch failed: MAINTAINERS:512
error: MAINTAINERS: patch does not apply
error: patch failed: xen/arch/arm/domain_build.c:1894
error: xen/arch/arm/domain_build.c: patch does not apply
error: xen/include/asm-arm/domain.h: does not exist in index
Patch failed at 0004 xen/arm: add generic SCI mediator framework
hint: Use 'git am --show-current-patch=diff' to see the failed patch
When you have resolved this problem, run "git am --continue".
If you prefer to skip this patch, run "git am --skip" instead.
To restore the original branch and stop patching, run "git am --abort".

 From the errors, it sounds like your baseline is from a couple of 
months ago. Please make sure to send your series based on the latest 
staging (at the time you send it).

>>> +static int host_dt_dir_read(const struct hypfs_entry *entry,
>>> +                            XEN_GUEST_HANDLE_PARAM(void) uaddr)
>>> +{
>>> +    int ret = 0;
>>> +    struct dt_device_node *node;
>>> +    struct dt_device_node *child;
>>
>> The hypfs should not modify the device-tree. So can this be const?
> 
> That's a good point.
> Unfortunatelly child can't be const because it is going to be passed to
> data->data pointer, but node can be const I think. In any case I will go
> through the file and see where const for the device_node can be set.

Can you explain why that data->data is not const?
>>> +static HYPFS_DIR_INIT_FUNC(host_dt_dir, HOST_DT_DIR, &host_dt_dir_funcs);
>>> +
>>> +static int __init host_dtb_export_init(void)
>>> +{
>>> +    ASSERT(dt_host && (dt_host->sibling == NULL));
>>
>> dt_host can be NULL when booting on ACPI platform. So I think this wants to
>> be turned to a normal check and return directly.
>>
> 
> I will replace if with
> if ( !acpi_disabled )
>      return -ENODEV;
> 
>> Also could you explain why you need to check dt_host->sibling?
>>
> 
> This is my way to check if dt_host points to the top of the device-tree.
> In any case I will replace it with !acpi_disabled as I mentioned
> earlier.

dt_host will always points to the root of the host device-tree. I don't 
think it is the job of hypfs to enforce it unless you expect the code to 
be buggy if this happens. But then I would argue the code should be 
hardened.

Cheers,

[1]

diff --git a/xen/arch/arm/host_dtb_export.c b/xen/arch/arm/host_dtb_export.c
index 794395683cd1..5f242b2cb683 100644
--- a/xen/arch/arm/host_dtb_export.c
+++ b/xen/arch/arm/host_dtb_export.c
@@ -26,39 +26,9 @@

  #define HOST_DT_DIR "devicetree"

-static int host_dt_dir_read(const struct hypfs_entry *entry,
-                            XEN_GUEST_HANDLE_PARAM(void) uaddr);
-static unsigned int host_dt_dir_getsize(const struct hypfs_entry *entry);
-
-static const struct hypfs_entry *host_dt_dir_enter(
-    const struct hypfs_entry *entry);
-static void host_dt_dir_exit(const struct hypfs_entry *entry);
-
-static struct hypfs_entry *host_dt_dir_findentry(
-    const struct hypfs_entry_dir *dir, const char *name, unsigned int 
name_len);
-
-static const struct hypfs_funcs host_dt_dir_funcs = {
-    .enter = host_dt_dir_enter,
-    .exit = host_dt_dir_exit,
-    .read = host_dt_dir_read,
-    .write = hypfs_write_deny,
-    .getsize = host_dt_dir_getsize,
-    .findentry = host_dt_dir_findentry,
-};
-
-static int host_dt_prop_read(const struct hypfs_entry *entry,
-                    XEN_GUEST_HANDLE_PARAM(void) uaddr);
-
-static unsigned int host_dt_prop_getsize(const struct hypfs_entry *entry);
-
-const struct hypfs_funcs host_dt_prop_ro_funcs = {
-    .enter = host_dt_dir_enter,
-    .exit = host_dt_dir_exit,
-    .read = host_dt_prop_read,
-    .write = hypfs_write_deny,
-    .getsize = host_dt_prop_getsize,
-    .findentry = hypfs_leaf_findentry,
-};
+/* Forward declare it */
+static const struct hypfs_funcs host_dt_dir_funcs;
+static const struct hypfs_funcs host_dt_prop_ro_funcs;

  static HYPFS_DIR_INIT_FUNC(dt_dir, "node_template", &host_dt_dir_funcs);

@@ -260,6 +230,15 @@ static struct hypfs_entry *host_dt_dir_findentry(
      return ERR_PTR(-ENOENT);
  };

+static const struct hypfs_funcs host_dt_dir_funcs = {
+    .enter = host_dt_dir_enter,
+    .exit = host_dt_dir_exit,
+    .read = host_dt_dir_read,
+    .write = hypfs_write_deny,
+    .getsize = host_dt_dir_getsize,
+    .findentry = host_dt_dir_findentry,
+};
+
  static int host_dt_prop_read(const struct hypfs_entry *entry,
                      XEN_GUEST_HANDLE_PARAM(void) uaddr)
  {
@@ -293,6 +272,15 @@ static unsigned int host_dt_prop_getsize(const 
struct hypfs_entry *entry)
      return prop->length;
  }

+static const struct hypfs_funcs host_dt_prop_ro_funcs = {
+    .enter = host_dt_dir_enter,
+    .exit = host_dt_dir_exit,
+    .read = host_dt_prop_read,
+    .write = hypfs_write_deny,
+    .getsize = host_dt_prop_getsize,
+    .findentry = hypfs_leaf_findentry,
+};
+
  static HYPFS_DIR_INIT_FUNC(host_dt_dir, HOST_DT_DIR, &host_dt_dir_funcs);

  static int __init host_dtb_export_init(void)

-- 
Julien Grall


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* Re: [RFC v2 2/8] libs: libxenhypfs - handle blob properties
  2022-02-08 18:00 ` [RFC v2 2/8] libs: libxenhypfs - handle blob properties Oleksii Moisieiev
@ 2022-02-09 13:47   ` Oleksandr Andrushchenko
  2022-02-09 14:01     ` Jan Beulich
  2022-02-09 14:04   ` Juergen Gross
  1 sibling, 1 reply; 45+ messages in thread
From: Oleksandr Andrushchenko @ 2022-02-09 13:47 UTC (permalink / raw)
  To: Oleksii Moisieiev, xen-devel; +Cc: Juergen Gross, Wei Liu

Hi, Oleksii!

On 08.02.22 20:00, Oleksii Moisieiev wrote:
> libxenhypfs will return blob properties as is. This output can be used
> to retrieve information from the hypfs. Caller is responsible for
> parsing property value.
>
> Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@epam.com>
> ---
>   tools/libs/hypfs/core.c | 2 --
>   1 file changed, 2 deletions(-)
>
> diff --git a/tools/libs/hypfs/core.c b/tools/libs/hypfs/core.c
> index 52b30db8d7..d09bba7d8c 100644
> --- a/tools/libs/hypfs/core.c
> +++ b/tools/libs/hypfs/core.c
> @@ -307,8 +307,6 @@ char *xenhypfs_read(xenhypfs_handle *fshdl, const char *path)
>           errno = EISDIR;
>           break;
>       case xenhypfs_type_blob:
> -        errno = EDOM;
> -        break;
This will need a /* fallthrough */ I guess
>       case xenhypfs_type_string:
>           ret_buf = buf;
>           buf = NULL;
Thank you,
Oleksandr

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [RFC v2 2/8] libs: libxenhypfs - handle blob properties
  2022-02-09 13:47   ` Oleksandr Andrushchenko
@ 2022-02-09 14:01     ` Jan Beulich
  2022-02-09 14:04       ` Oleksandr Andrushchenko
  0 siblings, 1 reply; 45+ messages in thread
From: Jan Beulich @ 2022-02-09 14:01 UTC (permalink / raw)
  To: Oleksandr Andrushchenko
  Cc: Juergen Gross, Wei Liu, Oleksii Moisieiev, xen-devel

On 09.02.2022 14:47, Oleksandr Andrushchenko wrote:
> Hi, Oleksii!
> 
> On 08.02.22 20:00, Oleksii Moisieiev wrote:
>> libxenhypfs will return blob properties as is. This output can be used
>> to retrieve information from the hypfs. Caller is responsible for
>> parsing property value.
>>
>> Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@epam.com>
>> ---
>>   tools/libs/hypfs/core.c | 2 --
>>   1 file changed, 2 deletions(-)
>>
>> diff --git a/tools/libs/hypfs/core.c b/tools/libs/hypfs/core.c
>> index 52b30db8d7..d09bba7d8c 100644
>> --- a/tools/libs/hypfs/core.c
>> +++ b/tools/libs/hypfs/core.c
>> @@ -307,8 +307,6 @@ char *xenhypfs_read(xenhypfs_handle *fshdl, const char *path)
>>           errno = EISDIR;
>>           break;
>>       case xenhypfs_type_blob:
>> -        errno = EDOM;
>> -        break;
> This will need a /* fallthrough */ I guess

Why? There's no statement left before the next case label.

Jan

>>       case xenhypfs_type_string:
>>           ret_buf = buf;
>>           buf = NULL;



^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [RFC v2 3/8] xen/arm: Export host device-tree to hypfs
  2022-02-08 18:26   ` Julien Grall
  2022-02-09 10:20     ` Oleksii Moisieiev
@ 2022-02-09 14:03     ` Juergen Gross
  1 sibling, 0 replies; 45+ messages in thread
From: Juergen Gross @ 2022-02-09 14:03 UTC (permalink / raw)
  To: Julien Grall, Oleksii Moisieiev, xen-devel
  Cc: Stefano Stabellini, Volodymyr Babchuk, Bertrand Marquis


[-- Attachment #1.1.1: Type: text/plain, Size: 833 bytes --]

On 08.02.22 19:26, Julien Grall wrote:
> Hi Oleksii,
> 
> On 08/02/2022 18:00, Oleksii Moisieiev wrote:
>> If enabled, host device-tree will be exported to hypfs and can be
>> accessed through /devicetree path.
>> Exported device-tree has the same format, as the device-tree
>> exported to the sysfs by the Linux kernel.
>> This is useful when XEN toolstack needs an access to the host 
>> device-tree.
>>
>> Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@epam.com>
>> ---
>>   xen/arch/arm/Kconfig           |   8 +
>>   xen/arch/arm/Makefile          |   1 +
>>   xen/arch/arm/host_dtb_export.c | 307 +++++++++++++++++++++++++++++++++

The related doc changes in docs/misc/hypfs-paths.pandoc are missing.

Without those its rather hard to verify the code is correct.


Juergen

[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 3149 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 495 bytes --]

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [RFC v2 2/8] libs: libxenhypfs - handle blob properties
  2022-02-08 18:00 ` [RFC v2 2/8] libs: libxenhypfs - handle blob properties Oleksii Moisieiev
  2022-02-09 13:47   ` Oleksandr Andrushchenko
@ 2022-02-09 14:04   ` Juergen Gross
  1 sibling, 0 replies; 45+ messages in thread
From: Juergen Gross @ 2022-02-09 14:04 UTC (permalink / raw)
  To: Oleksii Moisieiev, xen-devel; +Cc: Wei Liu


[-- Attachment #1.1.1: Type: text/plain, Size: 345 bytes --]

On 08.02.22 19:00, Oleksii Moisieiev wrote:
> libxenhypfs will return blob properties as is. This output can be used
> to retrieve information from the hypfs. Caller is responsible for
> parsing property value.
> 
> Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@epam.com>

Reviewed-by: Juergen Gross <jgross@suse.com>


Juergen

[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 3149 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 495 bytes --]

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [RFC v2 2/8] libs: libxenhypfs - handle blob properties
  2022-02-09 14:01     ` Jan Beulich
@ 2022-02-09 14:04       ` Oleksandr Andrushchenko
  0 siblings, 0 replies; 45+ messages in thread
From: Oleksandr Andrushchenko @ 2022-02-09 14:04 UTC (permalink / raw)
  To: Jan Beulich; +Cc: Juergen Gross, Wei Liu, Oleksii Moisieiev, xen-devel



On 09.02.22 16:01, Jan Beulich wrote:
> On 09.02.2022 14:47, Oleksandr Andrushchenko wrote:
>> Hi, Oleksii!
>>
>> On 08.02.22 20:00, Oleksii Moisieiev wrote:
>>> libxenhypfs will return blob properties as is. This output can be used
>>> to retrieve information from the hypfs. Caller is responsible for
>>> parsing property value.
>>>
>>> Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@epam.com>
>>> ---
>>>    tools/libs/hypfs/core.c | 2 --
>>>    1 file changed, 2 deletions(-)
>>>
>>> diff --git a/tools/libs/hypfs/core.c b/tools/libs/hypfs/core.c
>>> index 52b30db8d7..d09bba7d8c 100644
>>> --- a/tools/libs/hypfs/core.c
>>> +++ b/tools/libs/hypfs/core.c
>>> @@ -307,8 +307,6 @@ char *xenhypfs_read(xenhypfs_handle *fshdl, const char *path)
>>>            errno = EISDIR;
>>>            break;
>>>        case xenhypfs_type_blob:
>>> -        errno = EDOM;
>>> -        break;
>> This will need a /* fallthrough */ I guess
> Why? There's no statement left before the next case label.
You are right, no need
Sorry
>
> Jan
>
>>>        case xenhypfs_type_string:
>>>            ret_buf = buf;
>>>            buf = NULL;
>

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [RFC v2 3/8] xen/arm: Export host device-tree to hypfs
  2022-02-09 12:17       ` Julien Grall
@ 2022-02-09 14:17         ` Oleksii Moisieiev
  2022-02-09 18:51         ` Oleksii Moisieiev
  1 sibling, 0 replies; 45+ messages in thread
From: Oleksii Moisieiev @ 2022-02-09 14:17 UTC (permalink / raw)
  To: Julien Grall
  Cc: xen-devel, Stefano Stabellini, Volodymyr Babchuk,
	Bertrand Marquis, Juergen Gross

Hi Julien,

On Wed, Feb 09, 2022 at 12:17:17PM +0000, Julien Grall wrote:
> 
> 
> On 09/02/2022 10:20, Oleksii Moisieiev wrote:
> > Hi Julien,
> 
> Hi,
> 
> > 
> > On Tue, Feb 08, 2022 at 06:26:54PM +0000, Julien Grall wrote:
> > > Hi Oleksii,
> > > 
> > > On 08/02/2022 18:00, Oleksii Moisieiev wrote:
> > > > If enabled, host device-tree will be exported to hypfs and can be
> > > > accessed through /devicetree path.
> > > > Exported device-tree has the same format, as the device-tree
> > > > exported to the sysfs by the Linux kernel.
> > > > This is useful when XEN toolstack needs an access to the host device-tree.
> > > > 
> > > > Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@epam.com>
> > > > ---
> > > >    xen/arch/arm/Kconfig           |   8 +
> > > >    xen/arch/arm/Makefile          |   1 +
> > > >    xen/arch/arm/host_dtb_export.c | 307 +++++++++++++++++++++++++++++++++
> > > 
> > > There is nothing specific in this file. So can this be moved in common/?
> > 
> > You're right. I will move it to common.
> > 
> > > 
> > > >    3 files changed, 316 insertions(+)
> > > >    create mode 100644 xen/arch/arm/host_dtb_export.c
> > > > 
> > > > diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig
> > > > index ecfa6822e4..895016b21e 100644
> > > > --- a/xen/arch/arm/Kconfig
> > > > +++ b/xen/arch/arm/Kconfig
> > > > @@ -33,6 +33,14 @@ config ACPI
> > > >    	  Advanced Configuration and Power Interface (ACPI) support for Xen is
> > > >    	  an alternative to device tree on ARM64.
> > > > +config HOST_DTB_EXPORT
> > > > +	bool "Export host device tree to hypfs if enabled"
> > > > +	depends on ARM && HYPFS && !ACPI
> > > 
> > > A Xen built with ACPI enabled will still be able to boot on a host using
> > > Device-Tree. So I don't think should depend on ACPI.
> > > 
> > > Also, I think this should depend on HAS_DEVICE_TREE rather than ARM.
> > 
> > I agree. Thank you.
> > 
> > > 
> > > > +	---help---
> > > > +
> > > > +	  Export host device-tree to hypfs so toolstack can have an access for the
> > > > +	  host device tree from Dom0. If you unsure say N.
> > > > +
> > > >    config GICV3
> > > >    	bool "GICv3 driver"
> > > >    	depends on ARM_64 && !NEW_VGIC
> > > > diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
> > > > index 07f634508e..0a41f68f8c 100644
> > > > --- a/xen/arch/arm/Makefile
> > > > +++ b/xen/arch/arm/Makefile
> > > > @@ -8,6 +8,7 @@ obj-y += platforms/
> > > >    endif
> > > >    obj-$(CONFIG_TEE) += tee/
> > > >    obj-$(CONFIG_HAS_VPCI) += vpci.o
> > > > +obj-$(CONFIG_HOST_DTB_EXPORT) += host_dtb_export.o
> > > >    obj-$(CONFIG_HAS_ALTERNATIVE) += alternative.o
> > > >    obj-y += bootfdt.init.o
> > > > diff --git a/xen/arch/arm/host_dtb_export.c b/xen/arch/arm/host_dtb_export.c
> > > > new file mode 100644
> > > > index 0000000000..794395683c
> > > > --- /dev/null
> > > > +++ b/xen/arch/arm/host_dtb_export.c
> > > 
> > > This is mostly hypfs related. So CCing Juergen for his input on the code.
> > 
> > Thank you.
> > 
> > > 
> > > > @@ -0,0 +1,307 @@
> > > > +/*
> > > > + * xen/arch/arm/host_dtb_export.c
> > > > + *
> > > > + * Export host device-tree to the hypfs so toolstack can access
> > > > + * host device-tree from Dom0
> > > > + *
> > > > + * Oleksii Moisieiev <oleksii_moisieiev@epam.com>
> > > > + * Copyright (C) 2021, EPAM Systems.
> > > > + *
> > > > + * This program is free software; you can redistribute it and/or modify
> > > > + * it under the terms of the GNU General Public License as published by
> > > > + * the Free Software Foundation; either version 2 of the License, or
> > > > + * (at your option) any later version.
> > > > + *
> > > > + * This program is distributed in the hope that it will be useful,
> > > > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > > > + * GNU General Public License for more details.
> > > > + */
> > > > +
> > > > +#include <xen/device_tree.h>
> > > > +#include <xen/err.h>
> > > > +#include <xen/guest_access.h>
> > > > +#include <xen/hypfs.h>
> > > > +#include <xen/init.h>
> > > > +
> > > > +#define HOST_DT_DIR "devicetree"
> > > > +
> > > > +static int host_dt_dir_read(const struct hypfs_entry *entry,
> > > > +                            XEN_GUEST_HANDLE_PARAM(void) uaddr);
> > > > +static unsigned int host_dt_dir_getsize(const struct hypfs_entry *entry);
> > > > +
> > > > +static const struct hypfs_entry *host_dt_dir_enter(
> > > > +    const struct hypfs_entry *entry);
> > > > +static void host_dt_dir_exit(const struct hypfs_entry *entry);
> > > > +
> > > > +static struct hypfs_entry *host_dt_dir_findentry(
> > > > +    const struct hypfs_entry_dir *dir, const char *name, unsigned int name_len);
> > > 
> > > This is new code. So can you please make sure to avoid forward declaration
> > > by re-ordering the code.
> > > 
> > 
> > I can't avoid forward declaration here because all those functions
> > should be passed as callbacks for node template dt_dir. And dt_dir is
> > used in read and findentry functions.
> 
> You can avoid most of those forward declarations if you define the static
> variable now but fill them up after (see [1]). I don't think we can avoid
> the static variable forward declaration without reworking the API.
> 
> BTW, I could not fully apply the series on the staging tree:
> 
> Applying: xen/hypfs: support fo nested dynamic hypfs nodes
> Applying: libs: libxenhypfs - handle blob properties
> Applying: xen/arm: Export host device-tree to hypfs
> Applying: xen/arm: add generic SCI mediator framework
> error: patch failed: MAINTAINERS:512
> error: MAINTAINERS: patch does not apply
> error: patch failed: xen/arch/arm/domain_build.c:1894
> error: xen/arch/arm/domain_build.c: patch does not apply
> error: xen/include/asm-arm/domain.h: does not exist in index
> Patch failed at 0004 xen/arm: add generic SCI mediator framework
> hint: Use 'git am --show-current-patch=diff' to see the failed patch
> When you have resolved this problem, run "git am --continue".
> If you prefer to skip this patch, run "git am --skip" instead.
> To restore the original branch and stop patching, run "git am --abort".
> 
> From the errors, it sounds like your baseline is from a couple of months
> ago. Please make sure to send your series based on the latest staging (at
> the time you send it).
> 

I'm sorry for that. I will fix all comments, mentioned above, make a
rebase and post v3 shortly.

> > > > +static int host_dt_dir_read(const struct hypfs_entry *entry,
> > > > +                            XEN_GUEST_HANDLE_PARAM(void) uaddr)
> > > > +{
> > > > +    int ret = 0;
> > > > +    struct dt_device_node *node;
> > > > +    struct dt_device_node *child;
> > > 
> > > The hypfs should not modify the device-tree. So can this be const?
> > 
> > That's a good point.
> > Unfortunatelly child can't be const because it is going to be passed to
> > data->data pointer, but node can be const I think. In any case I will go
> > through the file and see where const for the device_node can be set.
> 
> Can you explain why that data->data is not const?

I reused struct hypfs_dyndir_id, added by @Juergen Gross in
4f1e5ed49c2292d3dd18160b7e728b1aa9453206 hope he will help to answer
this question.

> > > > +static HYPFS_DIR_INIT_FUNC(host_dt_dir, HOST_DT_DIR, &host_dt_dir_funcs);
> > > > +
> > > > +static int __init host_dtb_export_init(void)
> > > > +{
> > > > +    ASSERT(dt_host && (dt_host->sibling == NULL));
> > > 
> > > dt_host can be NULL when booting on ACPI platform. So I think this wants to
> > > be turned to a normal check and return directly.
> > > 
> > 
> > I will replace if with
> > if ( !acpi_disabled )
> >      return -ENODEV;
> > 
> > > Also could you explain why you need to check dt_host->sibling?
> > > 
> > 
> > This is my way to check if dt_host points to the top of the device-tree.
> > In any case I will replace it with !acpi_disabled as I mentioned
> > earlier.
> 
> dt_host will always points to the root of the host device-tree. I don't
> think it is the job of hypfs to enforce it unless you expect the code to be
> buggy if this happens. But then I would argue the code should be hardened.
> 

I will refactor this check.

Best regards,
Oleksii.

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [RFC v2 5/8] xen/arm: introduce SCMI-SMC mediator driver
  2022-02-08 18:00 ` [RFC v2 5/8] xen/arm: introduce SCMI-SMC mediator driver Oleksii Moisieiev
@ 2022-02-09 15:02   ` Oleksandr Andrushchenko
  2022-02-09 15:23     ` Julien Grall
  2022-02-11  8:46   ` Bertrand Marquis
  1 sibling, 1 reply; 45+ messages in thread
From: Oleksandr Andrushchenko @ 2022-02-09 15:02 UTC (permalink / raw)
  To: Oleksii Moisieiev, xen-devel
  Cc: Stefano Stabellini, Julien Grall, Volodymyr Babchuk, Bertrand Marquis

Hi, Oleksii!

On 08.02.22 20:00, Oleksii Moisieiev wrote:
> This is the implementation of SCI interface, called SCMI-SMC driver,
> which works as the mediator between XEN Domains and Firmware (SCP, ATF etc).
> This allows devices from the Domains to work with clocks, resets and
> power-domains without access to CPG.
>
> Originally, cpg should be passed to the domain so it can work with
> power-domains/clocks/resets etc. Considering that cpg can't be split between
> the Domains, we get the limitation that the devices, which are using
> power-domains/clocks/resets etc, couldn't be split between the domains.
> The solution is to move the power-domain/clock/resets etc to the
> Firmware (such as SCP firmware or ATF) and provide interface for the
> Domains. XEN should have an entity, caled SCI-Mediator, which is
> responsible for messages redirection between Domains and Firmware and
> for permission handling.
>
> The following features are implemented:
> - request SCMI channels from ATF and pass channels to Domains;
> - set device permissions for Domains based on the Domain partial
> device-tree. Devices with permissions are able to work with clocks,
> resets and power-domains via SCMI;
> - redirect scmi messages from Domains to ATF.
>
> Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@epam.com>
> ---
>   xen/arch/arm/Kconfig        |   2 +
>   xen/arch/arm/sci/Kconfig    |  10 +
>   xen/arch/arm/sci/scmi_smc.c | 959 ++++++++++++++++++++++++++++++++++++
>   3 files changed, 971 insertions(+)
>   create mode 100644 xen/arch/arm/sci/Kconfig
>   create mode 100644 xen/arch/arm/sci/scmi_smc.c
>
> diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig
> index ab07833582..3b0dfc57b6 100644
> --- a/xen/arch/arm/Kconfig
> +++ b/xen/arch/arm/Kconfig
> @@ -123,6 +123,8 @@ config ARM_SCI
>   	  support. It allows guests to control system resourcess via one of
>   	  ARM_SCI mediators implemented in XEN.
>   
> +	source "arch/arm/sci/Kconfig"
> +
>   endmenu
>   
>   menu "ARM errata workaround via the alternative framework"
> diff --git a/xen/arch/arm/sci/Kconfig b/xen/arch/arm/sci/Kconfig
> new file mode 100644
> index 0000000000..10b634d2ed
> --- /dev/null
> +++ b/xen/arch/arm/sci/Kconfig
> @@ -0,0 +1,10 @@
> +config SCMI_SMC
> +	bool "Enable SCMI-SMC mediator driver"
> +	default n
> +	depends on ARM_SCI && HOST_DTB_EXPORT
> +	---help---
> +
> +	Enables mediator in XEN to pass SCMI requests from Domains to ATF.
> +	This feature allows drivers from Domains to work with System
> +	Controllers (such as power,resets,clock etc.). SCP is used as transport
> +	for communication.
> diff --git a/xen/arch/arm/sci/scmi_smc.c b/xen/arch/arm/sci/scmi_smc.c
> new file mode 100644
> index 0000000000..103529dfab
> --- /dev/null
> +++ b/xen/arch/arm/sci/scmi_smc.c
> @@ -0,0 +1,959 @@
> +/*
> + * xen/arch/arm/sci/scmi_smc.c
> + *
> + * SCMI mediator driver, using SCP as transport.
> + *
> + * Oleksii Moisieiev <oleksii_moisieiev@epam.com>
> + * Copyright (C) 2021, EPAM Systems.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <asm/sci/sci.h>
> +#include <asm/smccc.h>
> +#include <asm/io.h>
> +#include <xen/bitops.h>
> +#include <xen/config.h>
> +#include <xen/sched.h>
> +#include <xen/device_tree.h>
> +#include <xen/iocap.h>
> +#include <xen/init.h>
> +#include <xen/err.h>
> +#include <xen/lib.h>
> +#include <xen/list.h>
> +#include <xen/mm.h>
> +#include <xen/string.h>
> +#include <xen/time.h>
> +#include <xen/vmap.h>
> +
> +#define SCMI_BASE_PROTOCOL                  0x10
> +#define SCMI_BASE_PROTOCOL_ATTIBUTES        0x1
> +#define SCMI_BASE_SET_DEVICE_PERMISSIONS    0x9
> +#define SCMI_BASE_RESET_AGENT_CONFIGURATION 0xB
> +#define SCMI_BASE_DISCOVER_AGENT            0x7
Can the above be sorted?
> +
> +/* SCMI return codes. See section 4.1.4 of SCMI spec (DEN0056C) */
> +#define SCMI_SUCCESS              0
> +#define SCMI_NOT_SUPPORTED      (-1)
> +#define SCMI_INVALID_PARAMETERS (-2)
> +#define SCMI_DENIED             (-3)
> +#define SCMI_NOT_FOUND          (-4)
> +#define SCMI_OUT_OF_RANGE       (-5)
> +#define SCMI_BUSY               (-6)
> +#define SCMI_COMMS_ERROR        (-7)
> +#define SCMI_GENERIC_ERROR      (-8)
> +#define SCMI_HARDWARE_ERROR     (-9)
> +#define SCMI_PROTOCOL_ERROR     (-10)
> +
> +#define DT_MATCH_SCMI_SMC DT_MATCH_COMPATIBLE("arm,scmi-smc")
> +
> +#define SCMI_SMC_ID                        "arm,smc-id"
> +#define SCMI_SHARED_MEMORY                 "arm,scmi-shmem"
> +#define SCMI_SHMEM                         "shmem"
> +#define SCMI_SHMEM_MAPPED_SIZE             PAGE_SIZE
> +
> +#define HYP_CHANNEL                          0x0
Alignment
> +
> +#define HDR_ID                             GENMASK(7,0)
> +#define HDR_TYPE                           GENMASK(9, 8)
> +#define HDR_PROTO                          GENMASK(17, 10)
> +
> +/* SCMI protocol, refer to section 4.2.2.2 (DEN0056C) */
> +#define MSG_N_AGENTS_MASK                  GENMASK(15, 8)
> +
> +#define FIELD_GET(_mask, _reg)\
> +    ((typeof(_mask))(((_reg) & (_mask)) >> (ffs64(_mask) - 1)))
> +#define FIELD_PREP(_mask, _val)\
> +    (((typeof(_mask))(_val) << (ffs64(_mask) - 1)) & (_mask))
> +
> +typedef struct scmi_msg_header {
> +    uint8_t id;
> +    uint8_t type;
> +    uint8_t protocol;
> +} scmi_msg_header_t;
> +
> +#define SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE   BIT(0, UL)
> +#define SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR  BIT(1, UL)
> +
> +#define SCMI_ALLOW_ACCESS                   BIT(0, UL)
> +
> +struct scmi_shared_mem {
> +    uint32_t reserved;
> +    uint32_t channel_status;
> +    uint32_t reserved1[2];
> +    uint32_t flags;
> +    uint32_t length;
> +    uint32_t msg_header;
> +    uint8_t msg_payload[];
> +};
> +
> +struct dt_channel_addr {
> +    u64 addr;
> +    u64 size;
Here and elsewhere: do not use uXX in new code
and use uintXX_t instead
> +    struct list_head list;
> +};
> +
> +struct scmi_channel {
> +    int chan_id;
> +    int agent_id;
Can these be unsigned int?
Below in get_channel_by_id you have it as uint8_t chan_id...
> +    uint32_t func_id;
> +    domid_t domain_id;
> +    uint64_t paddr;
> +    uint64_t len;
> +    struct scmi_shared_mem *shmem;
> +    spinlock_t lock;
> +    struct list_head list;
> +};
> +
> +struct scmi_data {
> +    struct list_head channel_list;
> +    spinlock_t channel_list_lock;
> +    bool initialized;
> +};
> +
> +static struct scmi_data scmi_data;
> +
> +
> +/*
> + * pack_scmi_header() - packs and returns 32-bit header
> + *
> + * @hdr: pointer to header containing all the information on message id,
> + *    protocol id and type id.
> + *
> + * Return: 32-bit packed message header to be sent to the platform.
> + */
> +static inline uint32_t pack_scmi_header(scmi_msg_header_t *hdr)
Use of inline is doubtful, please see [1]
> +{
> +    return FIELD_PREP(HDR_ID, hdr->id) |
> +        FIELD_PREP(HDR_TYPE, hdr->type) |
> +        FIELD_PREP(HDR_PROTO, hdr->protocol);
> +}
> +
> +/*
> + * unpack_scmi_header() - unpacks and records message and protocol id
> + *
> + * @msg_hdr: 32-bit packed message header sent from the platform
> + * @hdr: pointer to header to fetch message and protocol id.
> + */
> +static inline void unpack_scmi_header(uint32_t msg_hdr, scmi_msg_header_t *hdr)
> +{
> +    hdr->id = FIELD_GET(HDR_ID, msg_hdr);
> +    hdr->type = FIELD_GET(HDR_TYPE, msg_hdr);
> +    hdr->protocol = FIELD_GET(HDR_PROTO, msg_hdr);
> +}
> +
> +static inline int channel_is_free(struct scmi_channel *chan_info)
> +{
> +    return ( chan_info->shmem->channel_status
> +            & SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE ) ? 0 : -EBUSY;
> +}
> +
> +/*
> + * Copy data from IO memory space to "real" memory space.
> + */
> +void __memcpy_fromio(void *to, const volatile void __iomem *from, size_t count)
This seems to be a copy of [2].
We should think about moving this into a dedicated file like in Linux,
preserving the authorship+
> +{
> +    while (count && !IS_ALIGNED((unsigned long)from, 4)) {
> +        *(u8 *)to = __raw_readb(from);
> +        from++;
> +        to++;
> +        count--;
> +    }
> +
> +    while (count >= 4) {
> +        *(u32 *)to = __raw_readl(from);
> +        from += 4;
> +        to += 4;
> +        count -= 4;
> +    }
> +
> +    while (count) {
> +        *(u8 *)to = __raw_readb(from);
> +        from++;
> +        to++;
> +        count--;
> +    }
> +}
> +
> +/*
> + * Copy data from "real" memory space to IO memory space.
> + */
> +void __memcpy_toio(volatile void __iomem *to, const void *from, size_t count)
> +{
> +    while (count && !IS_ALIGNED((unsigned long)to, 4)) {
> +        __raw_writeb(*(u8 *)from, to);
> +        from++;
> +        to++;
> +        count--;
> +    }
> +
> +    while (count >= 4) {
> +        __raw_writel(*(u32 *)from, to);
> +        from += 4;
> +        to += 4;
> +        count -= 4;
> +    }
> +
> +    while (count) {
> +        __raw_writeb(*(u8 *)from, to);
> +        from++;
> +        to++;
> +        count--;
> +    }
> +}
> +
> +static int send_smc_message(struct scmi_channel *chan_info,
> +                            scmi_msg_header_t *hdr, void *data, int len)
> +{
> +    struct arm_smccc_res resp;
> +    int ret;
> +
> +    if ( (len + sizeof(chan_info->shmem->msg_header)) >
> +                         SCMI_SHMEM_MAPPED_SIZE )
> +    {
> +        printk(XENLOG_ERR
> +               "scmi: Wrong size of smc message. Data is invalid\n");
> +        return -EINVAL;
> +    }
> +
> +    printk(XENLOG_DEBUG "scmi: status =%d len=%d\n",
> +           chan_info->shmem->channel_status, len);
> +    printk(XENLOG_DEBUG "scmi: header id = %d type = %d, proto = %d\n",
> +           hdr->id, hdr->type, hdr->protocol);
> +
> +    ret = channel_is_free(chan_info);
> +    if ( IS_ERR_VALUE(ret) )
> +        return ret;
> +
> +    chan_info->shmem->channel_status = 0x0;
Could it be just 0?
> +    /* Writing 0x0 right now, but SCMI_SHMEM_FLAG_INTR_ENABLED can be set */
> +    chan_info->shmem->flags = 0x0;
> +    chan_info->shmem->length = sizeof(chan_info->shmem->msg_header) + len;
> +    chan_info->shmem->msg_header = pack_scmi_header(hdr);
> +
> +    printk(XENLOG_DEBUG "scmi: Writing to shmem address %p\n",
> +           chan_info->shmem);
> +    if ( len > 0 && data )
Here and elsewhere: please consider using parentheses
> +        __memcpy_toio((void *)(chan_info->shmem->msg_payload), data, len);
> +
> +    arm_smccc_smc(chan_info->func_id, 0, 0, 0, 0, 0, 0, chan_info->chan_id,
> +                  &resp);
> +
> +    printk(XENLOG_DEBUG "scmi: scmccc_smc response %d\n", (int)(resp.a0));
> +
> +    if ( resp.a0 )
> +        return -EOPNOTSUPP;
> +
> +    return 0;
> +}
> +
> +static int check_scmi_status(int scmi_status)
> +{
> +    if ( scmi_status == SCMI_SUCCESS )
> +        return 0;
> +
> +    printk(XENLOG_DEBUG "scmi: Error received: %d\n", scmi_status);
> +
> +    switch ( scmi_status )
> +    {
> +    case SCMI_NOT_SUPPORTED:
> +        return -EOPNOTSUPP;
> +    case SCMI_INVALID_PARAMETERS:
> +        return -EINVAL;
> +    case SCMI_DENIED:
> +        return -EACCES;
> +    case SCMI_NOT_FOUND:
> +        return -ENOENT;
> +    case SCMI_OUT_OF_RANGE:
> +        return -ERANGE;
> +    case SCMI_BUSY:
> +        return -EBUSY;
> +    case SCMI_COMMS_ERROR:
> +        return -ENOTCONN;
> +    case SCMI_GENERIC_ERROR:
> +        return -EIO;
> +    case SCMI_HARDWARE_ERROR:
> +        return -ENXIO;
> +    case SCMI_PROTOCOL_ERROR:
> +        return -EBADMSG;
> +    default:
> +        return -EINVAL;
> +    }
> +}
> +
> +static int get_smc_response(struct scmi_channel *chan_info,
> +                            scmi_msg_header_t *hdr, void *data, int len)
> +{
> +    int recv_len;
> +    int ret;
> +
> +    printk(XENLOG_DEBUG "scmi: get smc responce msgid %d\n", hdr->id);
> +
> +    if ( len >= SCMI_SHMEM_MAPPED_SIZE - sizeof(chan_info->shmem) )
Parentheses, as mentioned above, may improve code readability
> +    {
> +        printk(XENLOG_ERR
> +               "scmi: Wrong size of input smc message. Data may be invalid\n");
> +        return -EINVAL;
> +    }
> +
> +    ret = channel_is_free(chan_info);
> +    if ( IS_ERR_VALUE(ret) )
> +        return ret;
> +
> +    recv_len = chan_info->shmem->length - sizeof(chan_info->shmem->msg_header);
> +
> +    if ( recv_len < 0 )
> +    {
> +        printk(XENLOG_ERR
> +               "scmi: Wrong size of smc message. Data may be invalid\n");
> +        return -EINVAL;
> +    }
> +
> +    if ( recv_len > len )
> +    {
> +        printk(XENLOG_ERR
> +               "scmi: Not enough buffer for message %d, expecting %d\n",
> +               recv_len, len);
> +        return -EINVAL;
> +    }
> +
> +    unpack_scmi_header(chan_info->shmem->msg_header, hdr);
> +
> +    if ( recv_len > 0 )
> +    {
> +        __memcpy_fromio(data, chan_info->shmem->msg_payload, recv_len);
> +    }
No need for parentheses for a single statement
> +
> +    return 0;
> +}
> +
> +static int do_smc_xfer(struct scmi_channel *channel, scmi_msg_header_t *hdr, void *tx_data, int tx_size,
> +                       void *rx_data, int rx_size)
> +{
> +    int ret = 0;
> +
> +    ASSERT( channel && channel->shmem);
> +
> +    if ( !hdr )
> +        return -EINVAL;
> +
> +    spin_lock(&channel->lock);
> +
> +    ret = send_smc_message(channel, hdr, tx_data, tx_size);
> +    if ( ret )
> +        goto clean;
> +
> +    ret = get_smc_response(channel, hdr, rx_data, rx_size);
Blank line
> +clean:
> +    spin_unlock(&channel->lock);
> +
> +    return ret;
> +}
> +
> +static struct scmi_channel *get_channel_by_id(uint8_t chan_id)
> +{
> +    struct scmi_channel *curr;
> +    bool found = false;
> +
> +    spin_lock(&scmi_data.channel_list_lock);
> +    list_for_each_entry(curr, &scmi_data.channel_list, list)
> +    {
> +        if ( curr->chan_id == chan_id )
> +        {
> +            found = true;
> +            break;
> +        }
> +    }
> +
Extra line and in the code below
> +    spin_unlock(&scmi_data.channel_list_lock);
> +    if ( found )
> +        return curr;
> +
> +    return NULL;
> +}
> +
> +static struct scmi_channel *aquire_scmi_channel(domid_t domain_id)
> +{
> +    struct scmi_channel *curr;
> +    bool found = false;
> +
> +    ASSERT(domain_id != DOMID_INVALID && domain_id >= 0);
> +
> +    spin_lock(&scmi_data.channel_list_lock);
> +    list_for_each_entry(curr, &scmi_data.channel_list, list)
> +    {
> +        if ( curr->domain_id == DOMID_INVALID )
> +        {
> +            curr->domain_id = domain_id;
> +            found = true;
> +            break;
> +        }
> +    }
> +
> +    spin_unlock(&scmi_data.channel_list_lock);
> +    if ( found )
> +        return curr;
> +
> +    return NULL;
> +}
> +
> +static void relinquish_scmi_channel(struct scmi_channel *channel)
> +{
> +    ASSERT(channel != NULL);
> +
> +    spin_lock(&scmi_data.channel_list_lock);
> +    channel->domain_id = DOMID_INVALID;
> +    spin_unlock(&scmi_data.channel_list_lock);
> +}
> +
> +static int map_channel_memory(struct scmi_channel *channel)
> +{
> +    ASSERT( channel && channel->paddr );
> +    channel->shmem = ioremap_cache(channel->paddr, SCMI_SHMEM_MAPPED_SIZE);
> +    if ( !channel->shmem )
> +        return -ENOMEM;
> +
> +    channel->shmem->channel_status = SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE;
> +    printk(XENLOG_DEBUG "scmi: Got shmem after vmap %p\n", channel->shmem);
> +    return 0;
> +}
> +
> +static void unmap_channel_memory(struct scmi_channel *channel)
> +{
> +    ASSERT( channel && channel->shmem );
> +    iounmap(channel->shmem);
> +    channel->shmem = NULL;
> +}
> +
> +static struct scmi_channel *smc_create_channel(uint8_t chan_id,
> +                                               uint32_t func_id, uint64_t addr)
> +{
> +    struct scmi_channel *channel;
> +
> +    channel = get_channel_by_id(chan_id);
> +    if ( channel )
> +        return ERR_PTR(EEXIST);
> +
> +    channel = xmalloc(struct scmi_channel);
> +    if ( !channel )
> +        return ERR_PTR(ENOMEM);
> +
> +    channel->chan_id = chan_id;
> +    channel->func_id = func_id;
> +    channel->domain_id = DOMID_INVALID;
> +    channel->shmem = NULL;
> +    channel->paddr = addr;
> +    spin_lock_init(&channel->lock);
> +    spin_lock(&scmi_data.channel_list_lock);
> +    list_add(&channel->list, &scmi_data.channel_list);
> +    spin_unlock(&scmi_data.channel_list_lock);
> +    return channel;
> +}
> +
> +static int mem_permit_access(struct domain *d, uint64_t addr, uint64_t len)
> +{
> +    return iomem_permit_access(d, paddr_to_pfn(addr),
> +                paddr_to_pfn(PAGE_ALIGN(addr + len -1)));
> +}
> +
> +static int mem_deny_access(struct domain *d, uint64_t addr,
> +                                     uint64_t len)
> +{
> +    return iomem_deny_access(d, paddr_to_pfn(addr),
> +                paddr_to_pfn(PAGE_ALIGN(addr + len -1)));
> +}
> +
> +static int dt_update_domain_range(uint64_t addr, uint64_t size)
> +{
> +    struct dt_device_node *shmem_node;
> +    __be32 *hw_reg;
> +    const struct dt_property *pp;
> +    uint32_t len;
> +
> +    shmem_node = dt_find_compatible_node(NULL, NULL, SCMI_SHARED_MEMORY);
> +    if ( !shmem_node )
> +    {
> +        printk(XENLOG_ERR "scmi: Unable to find %s node in DT\n", SCMI_SHMEM);
> +        return -EINVAL;
> +    }
> +
> +    pp = dt_find_property(shmem_node, "reg", &len);
> +    if ( !pp )
> +    {
> +        printk(XENLOG_ERR "scmi: Unable to find regs entry in shmem node\n");
> +        return -ENOENT;
> +    }
> +
> +    hw_reg = pp->value;
> +    dt_set_range(&hw_reg, shmem_node, addr, size);
> +
> +    return 0;
> +}
> +
> +static void free_channel_list(void)
> +{
> +    struct scmi_channel *curr, *_curr;
> +
> +    spin_lock(&scmi_data.channel_list_lock);
> +    list_for_each_entry_safe (curr, _curr, &scmi_data.channel_list, list)
> +    {
> +        list_del(&curr->list);
> +        xfree(curr);
> +    }
> +
This looks like a pattern you use with a blank line after list_for_each
> +    spin_unlock(&scmi_data.channel_list_lock);
> +}
> +
> +static struct dt_device_node *get_dt_node_from_property(
> +                struct dt_device_node *node, const char * p_name)
> +{
> +    const __be32 *prop;
> +
> +    ASSERT( node );
> +
> +    prop = dt_get_property(node, p_name, NULL);
> +    if ( !prop )
> +        return ERR_PTR(-EINVAL);
> +
> +    return dt_find_node_by_phandle(be32_to_cpup(prop));
> +}
> +
> +static int get_shmem_regions(struct list_head *head, u64 hyp_addr)
> +{
> +    struct dt_device_node *node;
> +    int ret;
> +    struct dt_channel_addr *lchan;
> +    u64 laddr, lsize;
> +
> +    node = dt_find_compatible_node(NULL, NULL, SCMI_SHARED_MEMORY);
> +    if ( !node )
> +        return -ENOENT;
> +
> +    while ( node )
> +    {
> +        ret = dt_device_get_address(node, 0, &laddr, &lsize);
> +        if ( ret )
> +            return ret;
> +
> +        if ( laddr != hyp_addr )
> +        {
> +            lchan = xmalloc(struct dt_channel_addr);
> +            if ( !lchan )
> +                return -ENOMEM;
> +            lchan->addr = laddr;
> +            lchan->size = lsize;
> +
> +            list_add_tail(&lchan->list, head);
> +        }
> +
> +        node = dt_find_compatible_node(node, NULL, SCMI_SHARED_MEMORY);
> +    }
> +
> +    return 0;
> +}
> +
> +static int read_hyp_channel_addr(struct dt_device_node *scmi_node,
> +                                 u64 *addr, u64 *size)
> +{
> +    struct dt_device_node *shmem_node;
> +    shmem_node = get_dt_node_from_property(scmi_node, "shmem");
> +    if ( IS_ERR_OR_NULL(shmem_node) )
> +    {
> +        printk(XENLOG_ERR
> +               "scmi: Device tree error, can't parse reserved memory %ld\n",
> +               PTR_ERR(shmem_node));
> +        return PTR_ERR(shmem_node);
> +    }
> +
> +    return dt_device_get_address(shmem_node, 0, addr, size);
> +}
> +
> +static void free_shmem_regions(struct list_head *addr_list)
> +{
> +    struct dt_channel_addr *curr, *_curr;
> +
> +    list_for_each_entry_safe (curr, _curr, addr_list, list)
> +    {
> +        list_del(&curr->list);
> +        xfree(curr);
> +    }
> +}
> +
> +static __init bool scmi_probe(struct dt_device_node *scmi_node)
> +{
> +    u64 addr, size;
> +    int ret, i;
> +    struct scmi_channel *channel, *agent_channel;
> +    int n_agents;
> +    scmi_msg_header_t hdr;
> +    struct rx_t {
> +        int32_t status;
> +        uint32_t attributes;
> +    } rx;
> +    struct dt_channel_addr *entry;
> +    struct list_head addr_list;
> +
> +    uint32_t func_id;
> +
> +    ASSERT(scmi_node != NULL);
> +
> +    INIT_LIST_HEAD(&scmi_data.channel_list);
> +    spin_lock_init(&scmi_data.channel_list_lock);
> +
> +    if ( !dt_property_read_u32(scmi_node, SCMI_SMC_ID, &func_id) )
> +    {
> +        printk(XENLOG_ERR "scmi: Unable to read smc-id from DT\n");
> +        return false;
> +    }
> +
> +    ret = read_hyp_channel_addr(scmi_node, &addr, &size);
> +    if ( IS_ERR_VALUE(ret) )
> +        return false;
> +
> +    if ( !IS_ALIGNED(size, SCMI_SHMEM_MAPPED_SIZE) )
> +    {
> +        printk(XENLOG_ERR "scmi: Reserved memory is not aligned\n");
> +        return false;
> +    }
> +
> +    INIT_LIST_HEAD(&addr_list);
> +
> +    ret = get_shmem_regions(&addr_list, addr);
> +    if ( IS_ERR_VALUE(ret) )
> +        goto out;
> +
> +    channel = smc_create_channel(HYP_CHANNEL, func_id, addr);
> +    if ( IS_ERR(channel) )
> +        goto out;
> +
> +    ret = map_channel_memory(channel);
> +    if ( ret )
> +        goto out;
> +
> +    spin_lock(&scmi_data.channel_list_lock);
> +    channel->domain_id = DOMID_XEN;
> +    spin_unlock(&scmi_data.channel_list_lock);
> +
> +    hdr.id = SCMI_BASE_PROTOCOL_ATTIBUTES;
> +    hdr.type = 0;
> +    hdr.protocol = SCMI_BASE_PROTOCOL;
> +
> +    ret = do_smc_xfer(channel, &hdr, NULL, 0, &rx, sizeof(rx));
> +    if ( ret )
> +        goto error;
> +
> +    ret = check_scmi_status(rx.status);
> +    if ( ret )
You should consider either using IS_ERR_VALUE in everywhere or
don't use it at all
> +        goto error;
> +
> +    n_agents = FIELD_GET(MSG_N_AGENTS_MASK, rx.attributes);
> +    printk(XENLOG_DEBUG "scmi: Got agent count %d\n", n_agents);
> +
> +    i = 1;
> +    list_for_each_entry(entry, &addr_list, list)
> +    {
> +        uint32_t tx_agent_id = 0xFFFFFFFF;
> +        struct {
> +            int32_t status;
> +            uint32_t agent_id;
> +            char name[16];
> +        } da_rx;
> +
> +        agent_channel = smc_create_channel(i, func_id,
> +                                           entry->addr);
This should fit in a single line
> +        if ( IS_ERR(agent_channel) )
> +        {
> +            ret = PTR_ERR(agent_channel);
> +            goto error;
> +        }
> +
> +        ret = map_channel_memory(agent_channel);
> +        if ( ret )
> +            goto error;
> +
> +        hdr.id = SCMI_BASE_DISCOVER_AGENT;
> +        hdr.type = 0;
> +        hdr.protocol = SCMI_BASE_PROTOCOL;
> +
> +        ret = do_smc_xfer(agent_channel, &hdr, &tx_agent_id,
> +                          sizeof(tx_agent_id), &da_rx, sizeof(da_rx));
> +        if ( ret )
> +        {
> +            unmap_channel_memory(agent_channel);
> +            goto error;
> +        }
> +
> +        unmap_channel_memory(agent_channel);
This could be moved before checking ret value
> +
> +        ret = check_scmi_status(da_rx.status);
> +        if ( ret )
> +            goto error;
> +
> +        printk(XENLOG_DEBUG "scmi: status=0x%x id=0x%x name=%s\n",
> +                da_rx.status, da_rx.agent_id, da_rx.name);
> +
> +        agent_channel->agent_id = da_rx.agent_id;
> +
> +        if ( i == n_agents )
> +            break;
> +
> +        i++;
> +    }
> +
> +    scmi_data.initialized = true;
> +    goto out;
> +
> +error:
This label sounds strange while returning without error,
could it be like "unmap_channel" or something?
> +    unmap_channel_memory(channel);
> +    free_channel_list();
> +out:
> +    free_shmem_regions(&addr_list);
> +    return ret == 0;
> +}
> +
> +static int scmi_domain_init(struct domain *d,
> +                           struct xen_arch_domainconfig *config)
> +{
> +    struct scmi_channel *channel;
> +    int ret;
> +
> +    if ( !scmi_data.initialized )
> +        return 0;
> +
> +    printk(XENLOG_INFO "scmi: domain_id = %d\n", d->domain_id);
> +
> +    channel = aquire_scmi_channel(d->domain_id);
> +    if ( IS_ERR_OR_NULL(channel) )
> +        return -ENOENT;
> +
> +#ifdef CONFIG_ARM_32
> +    printk(XENLOG_INFO
> +           "scmi: Aquire SCMI channel id = 0x%x , domain_id = %d paddr = 0x%llx\n",
> +           channel->chan_id, channel->domain_id, channel->paddr);
> +#else
> +    printk(XENLOG_INFO
> +           "scmi: Aquire SCMI channel id = 0x%x , domain_id = %d paddr = 0x%lx\n",
> +           channel->chan_id, channel->domain_id, channel->paddr);
> +#endif
> +
> +    if ( is_hardware_domain(d) )
> +    {
> +        ret = mem_permit_access(d, channel->paddr, PAGE_SIZE);
You already have SCMI_SHMEM_MAPPED_SIZE
We should also assert if SCMI_SHMEM_MAPPED_SIZE !- PAGE_SIZE
I guess as currently all the code is built with this assumption
> +        if ( IS_ERR_VALUE(ret) )
> +            goto error;
> +
> +        ret = dt_update_domain_range(channel->paddr, PAGE_SIZE);
> +        if ( IS_ERR_VALUE(ret) )
> +        {
> +            int rc = mem_deny_access(d, channel->paddr, PAGE_SIZE);
> +            if ( rc )
> +                printk(XENLOG_ERR "Unable to mem_deny_access\n");
> +
> +            goto error;
> +        }
> +    }
> +
> +    d->arch.sci = channel;
> +    if ( config )
> +        config->arm_sci_agent_paddr = channel->paddr;
> +
> +    return 0;
Blank line
> +error:
> +    relinquish_scmi_channel(channel);
> +
> +    return ret;
> +}
> +
> +static int scmi_add_device_by_devid(struct domain *d, uint32_t scmi_devid)
> +{
> +    struct scmi_channel *channel, *agent_channel;
> +    scmi_msg_header_t hdr;
> +    struct scmi_perms_tx {
> +        uint32_t agent_id;
> +        uint32_t device_id;
> +        uint32_t flags;
> +    } tx;
> +    struct rx_t {
> +        int32_t status;
> +        uint32_t attributes;
> +    } rx;
> +    int ret;
> +
> +    if ( !scmi_data.initialized )
> +        return 0;
> +
> +    printk(XENLOG_DEBUG "scmi: scmi_devid = %d\n", scmi_devid);
> +
> +    agent_channel = d->arch.sci;
> +    if ( IS_ERR_OR_NULL(agent_channel) )
> +        return PTR_ERR(agent_channel);
> +
> +    channel = get_channel_by_id(HYP_CHANNEL);
> +    if ( IS_ERR_OR_NULL(channel) )
> +        return PTR_ERR(channel);
> +
> +    hdr.id = SCMI_BASE_SET_DEVICE_PERMISSIONS;
> +    hdr.type = 0;
> +    hdr.protocol = SCMI_BASE_PROTOCOL;
> +
> +    tx.agent_id = agent_channel->agent_id;
> +    tx.device_id = scmi_devid;
> +    tx.flags = SCMI_ALLOW_ACCESS;
> +
> +    ret = do_smc_xfer(channel, &hdr, &tx, sizeof(tx), &rx, sizeof(&rx));
> +    if ( IS_ERR_VALUE(ret) )
> +        return ret;
> +
> +    ret = check_scmi_status(rx.status);
> +    if ( IS_ERR_VALUE(ret) )
> +        return ret;
> +
> +    return 0;
> +}
> +
> +static int scmi_add_dt_device(struct domain *d, struct dt_device_node *dev)
> +{
> +    uint32_t scmi_devid;
> +
> +    if ( (!scmi_data.initialized) || (!d->arch.sci) )
> +        return 0;
> +
> +    if ( !dt_property_read_u32(dev, "scmi_devid", &scmi_devid) )
> +        return 0;
> +
> +    printk(XENLOG_INFO "scmi: dt_node = %s\n", dt_node_full_name(dev));
This could be DEBUG print
> +
> +    return scmi_add_device_by_devid(d, scmi_devid);
> +}
> +
> +static int scmi_relinquish_resources(struct domain *d)
> +{
> +    int ret;
> +    struct scmi_channel *channel, *agent_channel;
> +    scmi_msg_header_t hdr;
> +    struct reset_agent_tx {
> +        uint32_t agent_id;
> +        uint32_t flags;
> +    } tx;
> +    uint32_t rx;
> +
> +    if ( !d->arch.sci )
> +        return 0;
> +
> +    agent_channel = d->arch.sci;
> +
> +    spin_lock(&agent_channel->lock);
> +    tx.agent_id = agent_channel->agent_id;
> +    spin_unlock(&agent_channel->lock);
> +
> +    channel = get_channel_by_id(HYP_CHANNEL);
> +    if ( !channel )
> +    {
> +        printk(XENLOG_ERR
> +               "scmi: Unable to get Hypervisor scmi channel for domain %d\n",
> +               d->domain_id);
> +        return -EINVAL;
> +    }
> +
> +    hdr.id = SCMI_BASE_RESET_AGENT_CONFIGURATION;
> +    hdr.type = 0;
> +    hdr.protocol = SCMI_BASE_PROTOCOL;
> +
> +    tx.flags = 0;
> +
> +    ret = do_smc_xfer(channel, &hdr, &tx, sizeof(tx), &rx, sizeof(rx));
> +    if ( ret )
> +        return ret;
> +
> +    ret = check_scmi_status(rx);
> +
> +    return ret;
> +}
> +
> +static void scmi_domain_destroy(struct domain *d)
> +{
> +    struct scmi_channel *channel;
> +
> +    if ( !d->arch.sci )
> +        return;
> +
> +    channel = d->arch.sci;
> +    spin_lock(&channel->lock);
> +
> +    relinquish_scmi_channel(channel);
> +    printk(XENLOG_DEBUG "scmi: Free domain %d\n", d->domain_id);
> +
> +    d->arch.sci = NULL;
> +
> +    mem_deny_access(d, channel->paddr, PAGE_SIZE);
> +    spin_unlock(&channel->lock);
> +}
> +
> +static bool scmi_handle_call(struct domain *d, void *args)
> +{
> +    bool res = false;
> +    struct scmi_channel *agent_channel;
> +    struct arm_smccc_res resp;
> +    struct cpu_user_regs *regs = args;
> +
> +    if ( !d->arch.sci )
> +        return false;
> +
> +    agent_channel = d->arch.sci;
> +    spin_lock(&agent_channel->lock);
> +
> +    if ( agent_channel->func_id != regs->r0 )
> +    {
> +        res = false;
> +        goto unlock;
> +    }
> +
> +    arm_smccc_smc(agent_channel->func_id, 0, 0, 0, 0, 0, 0,
> +                  agent_channel->chan_id, &resp);
> +
> +    set_user_reg(regs, 0, resp.a0);
> +    set_user_reg(regs, 1, resp.a1);
> +    set_user_reg(regs, 2, resp.a2);
> +    set_user_reg(regs, 3, resp.a3);
> +    res = true;
> +unlock:
> +    spin_unlock(&agent_channel->lock);
> +
> +    return res;
> +}
> +
> +static const struct dt_device_match scmi_smc_match[] __initconst =
> +{
> +    DT_MATCH_SCMI_SMC,
> +    { /* sentinel */ },
> +};
> +
> +static const struct sci_mediator_ops scmi_ops =
> +{
> +    .probe = scmi_probe,
> +    .domain_init = scmi_domain_init,
> +    .domain_destroy = scmi_domain_destroy,
> +    .add_dt_device = scmi_add_dt_device,
> +    .relinquish_resources = scmi_relinquish_resources,
> +    .handle_call = scmi_handle_call,
> +};
> +
> +REGISTER_SCI_MEDIATOR(scmi_smc, "SCMI-SMC", XEN_DOMCTL_CONFIG_ARM_SCI_SCMI_SMC,
> +                      scmi_smc_match, &scmi_ops);
> +
> +/*
> + * Local variables:
> + * mode: C
> + * c-file-style: "BSD"
> + * c-basic-offset: 4
> + * indent-tabs-mode: nil
> + * End:
> + */

[1] https://www.kernel.org/doc/local/inline.html
[2] https://elixir.bootlin.com/linux/v5.17-rc3/source/arch/arm64/kernel/io.c

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [RFC v2 5/8] xen/arm: introduce SCMI-SMC mediator driver
  2022-02-09 15:02   ` Oleksandr Andrushchenko
@ 2022-02-09 15:23     ` Julien Grall
  0 siblings, 0 replies; 45+ messages in thread
From: Julien Grall @ 2022-02-09 15:23 UTC (permalink / raw)
  To: Oleksandr Andrushchenko, Oleksii Moisieiev, xen-devel
  Cc: Stefano Stabellini, Volodymyr Babchuk, Bertrand Marquis



On 09/02/2022 15:02, Oleksandr Andrushchenko wrote:
>> +{
>> +    return FIELD_PREP(HDR_ID, hdr->id) |
>> +        FIELD_PREP(HDR_TYPE, hdr->type) |
>> +        FIELD_PREP(HDR_PROTO, hdr->protocol);
>> +}
>> +
>> +/*
>> + * unpack_scmi_header() - unpacks and records message and protocol id
>> + *
>> + * @msg_hdr: 32-bit packed message header sent from the platform
>> + * @hdr: pointer to header to fetch message and protocol id.
>> + */
>> +static inline void unpack_scmi_header(uint32_t msg_hdr, scmi_msg_header_t *hdr)
>> +{
>> +    hdr->id = FIELD_GET(HDR_ID, msg_hdr);
>> +    hdr->type = FIELD_GET(HDR_TYPE, msg_hdr);
>> +    hdr->protocol = FIELD_GET(HDR_PROTO, msg_hdr);
>> +}
>> +
>> +static inline int channel_is_free(struct scmi_channel *chan_info)
>> +{
>> +    return ( chan_info->shmem->channel_status
>> +            & SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE ) ? 0 : -EBUSY;
>> +}
>> +
>> +/*
>> + * Copy data from IO memory space to "real" memory space.
>> + */
>> +void __memcpy_fromio(void *to, const volatile void __iomem *from, size_t count)
> This seems to be a copy of [2].
> We should think about moving this into a dedicated file like in Linux,
> preserving the authorship+

+1. Also this should be in a separate patch.

Cheers,

-- 
Julien Grall


^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [RFC v2 3/8] xen/arm: Export host device-tree to hypfs
  2022-02-09 12:17       ` Julien Grall
  2022-02-09 14:17         ` Oleksii Moisieiev
@ 2022-02-09 18:51         ` Oleksii Moisieiev
  2022-02-09 19:34           ` Julien Grall
  1 sibling, 1 reply; 45+ messages in thread
From: Oleksii Moisieiev @ 2022-02-09 18:51 UTC (permalink / raw)
  To: Julien Grall
  Cc: xen-devel, Stefano Stabellini, Volodymyr Babchuk,
	Bertrand Marquis, Juergen Gross

On Wed, Feb 09, 2022 at 12:17:17PM +0000, Julien Grall wrote:
> > > > +static HYPFS_DIR_INIT_FUNC(host_dt_dir, HOST_DT_DIR, &host_dt_dir_funcs);
> > > > +
> > > > +static int __init host_dtb_export_init(void)
> > > > +{
> > > > +    ASSERT(dt_host && (dt_host->sibling == NULL));
> > > 
> > > dt_host can be NULL when booting on ACPI platform. So I think this wants to
> > > be turned to a normal check and return directly.
> > > 
> > 
> > I will replace if with
> > if ( !acpi_disabled )
> >      return -ENODEV;
> > 
> > > Also could you explain why you need to check dt_host->sibling?
> > > 
> > 
> > This is my way to check if dt_host points to the top of the device-tree.
> > In any case I will replace it with !acpi_disabled as I mentioned
> > earlier.
> 
> dt_host will always points to the root of the host device-tree. I don't
> think it is the job of hypfs to enforce it unless you expect the code to be
> buggy if this happens. But then I would argue the code should be hardened.
> 

Hi Julien,

Unfortunatelly I can't use acpi_disabled in host_dtb_export_init because
I've already moved host_dtb_export.c to the common folder.

As for the host->sibling - I took the whole assert:
ASSERT(dt_host && (dt_host->sibling == NULL));
from the prepare_dtb_hwdom function. And this assertion was added by the
commit b8f1c5e7039efbe1103ed3fe4caedf8c34affe13 authored by you.

What do you think if I omit dt_host->sibling check and make it:

if ( !dt_host )
    return -ENODEV;

Best regards,
Olkesii.

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [RFC v2 3/8] xen/arm: Export host device-tree to hypfs
  2022-02-09 18:51         ` Oleksii Moisieiev
@ 2022-02-09 19:34           ` Julien Grall
  2022-02-10  9:38             ` Oleksii Moisieiev
  0 siblings, 1 reply; 45+ messages in thread
From: Julien Grall @ 2022-02-09 19:34 UTC (permalink / raw)
  To: Oleksii Moisieiev
  Cc: xen-devel, Stefano Stabellini, Volodymyr Babchuk,
	Bertrand Marquis, Juergen Gross

Hi,

On 09/02/2022 18:51, Oleksii Moisieiev wrote:
> On Wed, Feb 09, 2022 at 12:17:17PM +0000, Julien Grall wrote:
>>>>> +static HYPFS_DIR_INIT_FUNC(host_dt_dir, HOST_DT_DIR, &host_dt_dir_funcs);
>>>>> +
>>>>> +static int __init host_dtb_export_init(void)
>>>>> +{
>>>>> +    ASSERT(dt_host && (dt_host->sibling == NULL));
>>>>
>>>> dt_host can be NULL when booting on ACPI platform. So I think this wants to
>>>> be turned to a normal check and return directly.
>>>>
>>>
>>> I will replace if with
>>> if ( !acpi_disabled )
>>>       return -ENODEV;
>>>
>>>> Also could you explain why you need to check dt_host->sibling?
>>>>
>>>
>>> This is my way to check if dt_host points to the top of the device-tree.
>>> In any case I will replace it with !acpi_disabled as I mentioned
>>> earlier.
>>
>> dt_host will always points to the root of the host device-tree. I don't
>> think it is the job of hypfs to enforce it unless you expect the code to be
>> buggy if this happens. But then I would argue the code should be hardened.
>>
> 
> Hi Julien,
> 
> Unfortunatelly I can't use acpi_disabled in host_dtb_export_init because
> I've already moved host_dtb_export.c to the common folder.

I am sorry, but I don't understand why moving the code to common code 
prevents you to use !acpi_disabled. Can you clarify?

> 
> As for the host->sibling - I took the whole assert:
> ASSERT(dt_host && (dt_host->sibling == NULL));
> from the prepare_dtb_hwdom function. And this assertion was added by the
> commit b8f1c5e7039efbe1103ed3fe4caedf8c34affe13 authored by you.

I am not sure what's your point... Yes I wrote the same ASSERT() 9 years 
time. But people view evolves over the time.

There are some code I wished I had written differently (How about you? 
;)). However, I don't have the time to rewrite everything I ever wrote. 
That said, I can at least make sure they are not spread.

> 
> What do you think if I omit dt_host->sibling check and make it:
> 
> if ( !dt_host )
>      return -ENODEV;

We used to set dt_host even when booting with ACPI but that shouldn't be 
the case anymore. So I think this check should be fine.

Cheers,

-- 
Julien Grall


^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [RFC v2 1/8] xen/hypfs: support fo nested dynamic hypfs nodes
  2022-02-08 18:00 ` [RFC v2 1/8] xen/hypfs: support fo nested dynamic hypfs nodes Oleksii Moisieiev
@ 2022-02-10  7:34   ` Juergen Gross
  2022-02-11  8:16     ` Oleksii Moisieiev
  0 siblings, 1 reply; 45+ messages in thread
From: Juergen Gross @ 2022-02-10  7:34 UTC (permalink / raw)
  To: Oleksii Moisieiev, xen-devel


[-- Attachment #1.1.1: Type: text/plain, Size: 10309 bytes --]

On 08.02.22 19:00, Oleksii Moisieiev wrote:

Nit: in the patch title s/fo/for/

> Add new api:
> - hypfs_read_dyndir_entry
> - hypfs_gen_dyndir_entry
> which are the extension of the dynamic hypfs nodes support, presented in
> 0b3b53be8cf226d947a79c2535a9efbb2dd7bc38.
> This allows nested dynamic nodes to be added. Also input parameter is
> hypfs_entry, so properties can also be generated dynamically.
> 
> Generating mixed list of dirs and properties is also supported.
> Same as to the dynamic hypfs nodes, this is anchored in percpu pointer,
> which can be retriewed on any level of the dynamic entries.
> This handle should be allocated on enter() callback and released on
> exit() callback. When using nested dynamic dirs and properties handle
> should be allocated on the first enter() call and released on the last
> exit() call.
> 
> Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@epam.com>
> ---
>   xen/common/hypfs.c      | 83 +++++++++++++++++++++++++++++++++--------
>   xen/include/xen/hypfs.h | 14 ++++++-
>   2 files changed, 79 insertions(+), 18 deletions(-)
> 
> diff --git a/xen/common/hypfs.c b/xen/common/hypfs.c
> index e71f7df479..6901f5e311 100644
> --- a/xen/common/hypfs.c
> +++ b/xen/common/hypfs.c
> @@ -367,28 +367,27 @@ unsigned int hypfs_getsize(const struct hypfs_entry *entry)
>   
>   /*
>    * Fill the direntry for a dynamically generated entry. Especially the
> - * generated name needs to be kept in sync with hypfs_gen_dyndir_id_entry().
> + * generated name needs to be kept in sync with hypfs_gen_dyndir_entry().
>    */
> -int hypfs_read_dyndir_id_entry(const struct hypfs_entry_dir *template,
> -                               unsigned int id, bool is_last,
> +int hypfs_read_dyndir_entry(const struct hypfs_entry *template,
> +                               const char *name, unsigned int namelen,
> +                               bool is_last,
>                                  XEN_GUEST_HANDLE_PARAM(void) *uaddr)

Please fix the indentation of the parameters.

>   {
>       struct xen_hypfs_dirlistentry direntry;
> -    char name[HYPFS_DYNDIR_ID_NAMELEN];
> -    unsigned int e_namelen, e_len;
> +    unsigned int e_len;
>   
> -    e_namelen = snprintf(name, sizeof(name), template->e.name, id);
> -    e_len = DIRENTRY_SIZE(e_namelen);
> +    e_len = DIRENTRY_SIZE(namelen);
>       direntry.e.pad = 0;
> -    direntry.e.type = template->e.type;
> -    direntry.e.encoding = template->e.encoding;
> -    direntry.e.content_len = template->e.funcs->getsize(&template->e);
> -    direntry.e.max_write_len = template->e.max_size;
> +    direntry.e.type = template->type;
> +    direntry.e.encoding = template->encoding;
> +    direntry.e.content_len = template->funcs->getsize(template);
> +    direntry.e.max_write_len = template->max_size;
>       direntry.off_next = is_last ? 0 : e_len;
>       if ( copy_to_guest(*uaddr, &direntry, 1) )
>           return -EFAULT;
>       if ( copy_to_guest_offset(*uaddr, DIRENTRY_NAME_OFF, name,
> -                              e_namelen + 1) )
> +                              namelen + 1) )
>           return -EFAULT;
>   
>       guest_handle_add_offset(*uaddr, e_len);
> @@ -396,6 +395,22 @@ int hypfs_read_dyndir_id_entry(const struct hypfs_entry_dir *template,
>       return 0;
>   }
>   
> +/*
> + * Fill the direntry for a dynamically generated entry. Especially the
> + * generated name needs to be kept in sync with hypfs_gen_dyndir_id_entry().
> + */
> +int hypfs_read_dyndir_id_entry(const struct hypfs_entry_dir *template,
> +                               unsigned int id, bool is_last,
> +                               XEN_GUEST_HANDLE_PARAM(void) *uaddr)
> +{
> +    char name[HYPFS_DYNDIR_ID_NAMELEN];
> +    unsigned int e_namelen;
> +
> +    e_namelen = snprintf(name, sizeof(name), template->e.name, id);
> +    return hypfs_read_dyndir_entry(&template->e, name, e_namelen, is_last, uaddr);
> +}
> +
> +
>   static const struct hypfs_entry *hypfs_dyndir_enter(
>       const struct hypfs_entry *entry)
>   {
> @@ -404,7 +419,7 @@ static const struct hypfs_entry *hypfs_dyndir_enter(
>       data = hypfs_get_dyndata();
>   
>       /* Use template with original enter function. */
> -    return data->template->e.funcs->enter(&data->template->e);
> +    return data->template->funcs->enter(data->template);
>   }
>   
>   static struct hypfs_entry *hypfs_dyndir_findentry(
> @@ -415,7 +430,7 @@ static struct hypfs_entry *hypfs_dyndir_findentry(
>       data = hypfs_get_dyndata();
>   
>       /* Use template with original findentry function. */
> -    return data->template->e.funcs->findentry(data->template, name, name_len);
> +    return data->template->funcs->findentry(&data->dir, name, name_len);
>   }
>   
>   static int hypfs_read_dyndir(const struct hypfs_entry *entry,
> @@ -426,7 +441,36 @@ static int hypfs_read_dyndir(const struct hypfs_entry *entry,
>       data = hypfs_get_dyndata();
>   
>       /* Use template with original read function. */
> -    return data->template->e.funcs->read(&data->template->e, uaddr);
> +    return data->template->funcs->read(data->template, uaddr);
> +}
> +
> +/*
> + * Fill dyndata with a dynamically generated entry based on a template
> + * and a name.
> + * Needs to be kept in sync with hypfs_read_dyndir_entry() regarding the
> + * name generated.
> + */
> +struct hypfs_entry *hypfs_gen_dyndir_entry(
> +    const struct hypfs_entry *template, const char *name,
> +    void *data)
> +{
> +    struct hypfs_dyndir_id *dyndata;
> +
> +    dyndata = hypfs_get_dyndata();
> +
> +    dyndata->template = template;
> +    dyndata->data = data;
> +    memcpy(dyndata->name, name, strlen(name));
> +    dyndata->dir.e = *template;
> +    dyndata->dir.e.name = dyndata->name;
> +
> +    dyndata->dir.e.funcs = &dyndata->funcs;
> +    dyndata->funcs = *template->funcs;
> +    dyndata->funcs.enter = hypfs_dyndir_enter;
> +    dyndata->funcs.findentry = hypfs_dyndir_findentry;
> +    dyndata->funcs.read = hypfs_read_dyndir;
> +
> +    return &dyndata->dir.e;
>   }
>   
>   /*
> @@ -442,12 +486,13 @@ struct hypfs_entry *hypfs_gen_dyndir_id_entry(
>   
>       dyndata = hypfs_get_dyndata();
>   
> -    dyndata->template = template;
> +    dyndata->template = &template->e;
>       dyndata->id = id;
>       dyndata->data = data;
>       snprintf(dyndata->name, sizeof(dyndata->name), template->e.name, id);
>       dyndata->dir = *template;
>       dyndata->dir.e.name = dyndata->name;
> +

Unrelated change?

>       dyndata->dir.e.funcs = &dyndata->funcs;
>       dyndata->funcs = *template->e.funcs;
>       dyndata->funcs.enter = hypfs_dyndir_enter;
> @@ -457,6 +502,12 @@ struct hypfs_entry *hypfs_gen_dyndir_id_entry(
>       return &dyndata->dir.e;
>   }
>   
> +unsigned int hypfs_dyndir_entry_size(const struct hypfs_entry *template,
> +                                    const char *name)

Please fix indentation.

> +{
> +    return DIRENTRY_SIZE(strlen(name));
> +}
> +
>   unsigned int hypfs_dynid_entry_size(const struct hypfs_entry *template,
>                                       unsigned int id)
>   {
> diff --git a/xen/include/xen/hypfs.h b/xen/include/xen/hypfs.h
> index e9d4c2555b..5d2728b963 100644
> --- a/xen/include/xen/hypfs.h
> +++ b/xen/include/xen/hypfs.h
> @@ -79,8 +79,8 @@ struct hypfs_entry_dir {
>   struct hypfs_dyndir_id {

Please rename to struct hypfs_dyndir.

>       struct hypfs_entry_dir dir;             /* Modified copy of template. */
>       struct hypfs_funcs funcs;               /* Dynamic functions. */
> -    const struct hypfs_entry_dir *template; /* Template used. */
> -#define HYPFS_DYNDIR_ID_NAMELEN 12
> +    const struct hypfs_entry *template; /* Template used. */
> +#define HYPFS_DYNDIR_ID_NAMELEN 32
>       char name[HYPFS_DYNDIR_ID_NAMELEN];     /* Name of hypfs entry. */
>   
>       unsigned int id;                        /* Numerical id. */

What about the following change instead:

-    const struct hypfs_entry_dir *template; /* Template used. */
-#define HYPFS_DYNDIR_ID_NAMELEN 12
-    char name[HYPFS_DYNDIR_ID_NAMELEN];     /* Name of hypfs entry. */
-
-    unsigned int id;                        /* Numerical id. */
-    void *data;                             /* Data associated with id. */
+    const struct hypfs_entry *template;  /* Template used. */
+    union {
+#define HYPFS_DYNDIR_NAMELEN    32
+        char name[HYPFS_DYNDIR_NAMELEN]; /* Name of hypfs entry. */
+        struct {
+#define HYPFS_DYNDIR_ID_NAMELEN 12
+            char name[HYPFS_DYNDIR_ID_NAMELEN]; /* Name of id entry. */
+            unsigned int id;                    /* Numerical id. */
+        } id;
+    };
+    void *data;                          /* Data associated with entry. */

> @@ -197,13 +197,23 @@ void *hypfs_alloc_dyndata(unsigned long size);
>   #define hypfs_alloc_dyndata(type) ((type *)hypfs_alloc_dyndata(sizeof(type)))
>   void *hypfs_get_dyndata(void);
>   void hypfs_free_dyndata(void);
> +int hypfs_read_dyndir_entry(const struct hypfs_entry *template,
> +                               const char *name, unsigned int namelen,
> +                               bool is_last,
> +                               XEN_GUEST_HANDLE_PARAM(void) *uaddr);

Again: indentation.

>   int hypfs_read_dyndir_id_entry(const struct hypfs_entry_dir *template,
>                                  unsigned int id, bool is_last,
>                                  XEN_GUEST_HANDLE_PARAM(void) *uaddr);
> +struct hypfs_entry *hypfs_gen_dyndir_entry(
> +    const struct hypfs_entry *template, const char *name,
> +    void *data);
>   struct hypfs_entry *hypfs_gen_dyndir_id_entry(
>       const struct hypfs_entry_dir *template, unsigned int id, void *data);
>   unsigned int hypfs_dynid_entry_size(const struct hypfs_entry *template,
>                                       unsigned int id);
> +unsigned int hypfs_dyndir_entry_size(const struct hypfs_entry *template,
> +                                    const char *name);

Indentation.

> +
>   #endif
>   
>   #endif /* __XEN_HYPFS_H__ */


Juergen

[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 3149 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 495 bytes --]

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [RFC v2 3/8] xen/arm: Export host device-tree to hypfs
  2022-02-09 19:34           ` Julien Grall
@ 2022-02-10  9:38             ` Oleksii Moisieiev
  0 siblings, 0 replies; 45+ messages in thread
From: Oleksii Moisieiev @ 2022-02-10  9:38 UTC (permalink / raw)
  To: Julien Grall
  Cc: xen-devel, Stefano Stabellini, Volodymyr Babchuk,
	Bertrand Marquis, Juergen Gross

On Wed, Feb 09, 2022 at 07:34:57PM +0000, Julien Grall wrote:
> Hi,
> 
> On 09/02/2022 18:51, Oleksii Moisieiev wrote:
> > On Wed, Feb 09, 2022 at 12:17:17PM +0000, Julien Grall wrote:
> > > > > > +static HYPFS_DIR_INIT_FUNC(host_dt_dir, HOST_DT_DIR, &host_dt_dir_funcs);
> > > > > > +
> > > > > > +static int __init host_dtb_export_init(void)
> > > > > > +{
> > > > > > +    ASSERT(dt_host && (dt_host->sibling == NULL));
> > > > > 
> > > > > dt_host can be NULL when booting on ACPI platform. So I think this wants to
> > > > > be turned to a normal check and return directly.
> > > > > 
> > > > 
> > > > I will replace if with
> > > > if ( !acpi_disabled )
> > > >       return -ENODEV;
> > > > 
> > > > > Also could you explain why you need to check dt_host->sibling?
> > > > > 
> > > > 
> > > > This is my way to check if dt_host points to the top of the device-tree.
> > > > In any case I will replace it with !acpi_disabled as I mentioned
> > > > earlier.
> > > 
> > > dt_host will always points to the root of the host device-tree. I don't
> > > think it is the job of hypfs to enforce it unless you expect the code to be
> > > buggy if this happens. But then I would argue the code should be hardened.
> > > 
> > 
> > Hi Julien,
> > 
> > Unfortunatelly I can't use acpi_disabled in host_dtb_export_init because
> > I've already moved host_dtb_export.c to the common folder.
> 
> I am sorry, but I don't understand why moving the code to common code
> prevents you to use !acpi_disabled. Can you clarify?
> 
Sorry, my bad. I thought that acpi_disabled is defined only for arm. Now
I've rechecked and see I was wrong.

> > 
> > As for the host->sibling - I took the whole assert:
> > ASSERT(dt_host && (dt_host->sibling == NULL));
> > from the prepare_dtb_hwdom function. And this assertion was added by the
> > commit b8f1c5e7039efbe1103ed3fe4caedf8c34affe13 authored by you.
> 
> I am not sure what's your point... Yes I wrote the same ASSERT() 9 years
> time. But people view evolves over the time.
> 
> There are some code I wished I had written differently (How about you? ;)).
> However, I don't have the time to rewrite everything I ever wrote. That
> said, I can at least make sure they are not spread.
> 

I'm sorry, I didn't mean to be rude. I've just tried to tell where I
took this assertion from.

> > 
> > What do you think if I omit dt_host->sibling check and make it:
> > 
> > if ( !dt_host )
> >      return -ENODEV;
> 
> We used to set dt_host even when booting with ACPI but that shouldn't be the
> case anymore. So I think this check should be fine.
> 

Ok, thank you. I'll do the change.

Best regards,
Oleksii.

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [RFC v2 1/8] xen/hypfs: support fo nested dynamic hypfs nodes
  2022-02-10  7:34   ` Juergen Gross
@ 2022-02-11  8:16     ` Oleksii Moisieiev
  2022-02-11 13:28       ` Juergen Gross
  0 siblings, 1 reply; 45+ messages in thread
From: Oleksii Moisieiev @ 2022-02-11  8:16 UTC (permalink / raw)
  To: Juergen Gross; +Cc: xen-devel

Hi Juergen,

On Thu, Feb 10, 2022 at 08:34:08AM +0100, Juergen Gross wrote:
> On 08.02.22 19:00, Oleksii Moisieiev wrote:
> 

> > Add new api:
> > - hypfs_read_dyndir_entry
> > - hypfs_gen_dyndir_entry
> > which are the extension of the dynamic hypfs nodes support, presented in
> > 0b3b53be8cf226d947a79c2535a9efbb2dd7bc38.
> > This allows nested dynamic nodes to be added. Also input parameter is
> > hypfs_entry, so properties can also be generated dynamically.
> > 
> > Generating mixed list of dirs and properties is also supported.
> > Same as to the dynamic hypfs nodes, this is anchored in percpu pointer,
> > which can be retriewed on any level of the dynamic entries.
> > This handle should be allocated on enter() callback and released on
> > exit() callback. When using nested dynamic dirs and properties handle
> > should be allocated on the first enter() call and released on the last
> > exit() call.
> > 
> > Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@epam.com>
> > ---
> >   xen/common/hypfs.c      | 83 +++++++++++++++++++++++++++++++++--------
> >   xen/include/xen/hypfs.h | 14 ++++++-
> >   2 files changed, 79 insertions(+), 18 deletions(-)
> > 
> > diff --git a/xen/common/hypfs.c b/xen/common/hypfs.c
> > index e71f7df479..6901f5e311 100644
> > --- a/xen/common/hypfs.c
> > +++ b/xen/common/hypfs.c
> > @@ -367,28 +367,27 @@ unsigned int hypfs_getsize(const struct hypfs_entry *entry)
> >   /*
> >    * Fill the direntry for a dynamically generated entry. Especially the
> > - * generated name needs to be kept in sync with hypfs_gen_dyndir_id_entry().
> > + * generated name needs to be kept in sync with hypfs_gen_dyndir_entry().
> >    */
> > -int hypfs_read_dyndir_id_entry(const struct hypfs_entry_dir *template,
> > -                               unsigned int id, bool is_last,
> > +int hypfs_read_dyndir_entry(const struct hypfs_entry *template,
> > +                               const char *name, unsigned int namelen,
> > +                               bool is_last,
> >                                  XEN_GUEST_HANDLE_PARAM(void) *uaddr)
> 
> Please fix the indentation of the parameters.
> 
> >   {
> >       struct xen_hypfs_dirlistentry direntry;
> > -    char name[HYPFS_DYNDIR_ID_NAMELEN];
> > -    unsigned int e_namelen, e_len;
> > +    unsigned int e_len;
> > -    e_namelen = snprintf(name, sizeof(name), template->e.name, id);
> > -    e_len = DIRENTRY_SIZE(e_namelen);
> > +    e_len = DIRENTRY_SIZE(namelen);
> >       direntry.e.pad = 0;
> > -    direntry.e.type = template->e.type;
> > -    direntry.e.encoding = template->e.encoding;
> > -    direntry.e.content_len = template->e.funcs->getsize(&template->e);
> > -    direntry.e.max_write_len = template->e.max_size;
> > +    direntry.e.type = template->type;
> > +    direntry.e.encoding = template->encoding;
> > +    direntry.e.content_len = template->funcs->getsize(template);
> > +    direntry.e.max_write_len = template->max_size;
> >       direntry.off_next = is_last ? 0 : e_len;
> >       if ( copy_to_guest(*uaddr, &direntry, 1) )
> >           return -EFAULT;
> >       if ( copy_to_guest_offset(*uaddr, DIRENTRY_NAME_OFF, name,
> > -                              e_namelen + 1) )
> > +                              namelen + 1) )
> >           return -EFAULT;
> >       guest_handle_add_offset(*uaddr, e_len);
> > @@ -396,6 +395,22 @@ int hypfs_read_dyndir_id_entry(const struct hypfs_entry_dir *template,
> >       return 0;
> >   }
> > +/*
> > + * Fill the direntry for a dynamically generated entry. Especially the
> > + * generated name needs to be kept in sync with hypfs_gen_dyndir_id_entry().
> > + */
> > +int hypfs_read_dyndir_id_entry(const struct hypfs_entry_dir *template,
> > +                               unsigned int id, bool is_last,
> > +                               XEN_GUEST_HANDLE_PARAM(void) *uaddr)
> > +{
> > +    char name[HYPFS_DYNDIR_ID_NAMELEN];
> > +    unsigned int e_namelen;
> > +
> > +    e_namelen = snprintf(name, sizeof(name), template->e.name, id);
> > +    return hypfs_read_dyndir_entry(&template->e, name, e_namelen, is_last, uaddr);
> > +}
> > +
> > +
> >   static const struct hypfs_entry *hypfs_dyndir_enter(
> >       const struct hypfs_entry *entry)
> >   {
> > @@ -404,7 +419,7 @@ static const struct hypfs_entry *hypfs_dyndir_enter(
> >       data = hypfs_get_dyndata();
> >       /* Use template with original enter function. */
> > -    return data->template->e.funcs->enter(&data->template->e);
> > +    return data->template->funcs->enter(data->template);
> >   }
> >   static struct hypfs_entry *hypfs_dyndir_findentry(
> > @@ -415,7 +430,7 @@ static struct hypfs_entry *hypfs_dyndir_findentry(
> >       data = hypfs_get_dyndata();
> >       /* Use template with original findentry function. */
> > -    return data->template->e.funcs->findentry(data->template, name, name_len);
> > +    return data->template->funcs->findentry(&data->dir, name, name_len);
> >   }
> >   static int hypfs_read_dyndir(const struct hypfs_entry *entry,
> > @@ -426,7 +441,36 @@ static int hypfs_read_dyndir(const struct hypfs_entry *entry,
> >       data = hypfs_get_dyndata();
> >       /* Use template with original read function. */
> > -    return data->template->e.funcs->read(&data->template->e, uaddr);
> > +    return data->template->funcs->read(data->template, uaddr);
> > +}
> > +
> > +/*
> > + * Fill dyndata with a dynamically generated entry based on a template
> > + * and a name.
> > + * Needs to be kept in sync with hypfs_read_dyndir_entry() regarding the
> > + * name generated.
> > + */
> > +struct hypfs_entry *hypfs_gen_dyndir_entry(
> > +    const struct hypfs_entry *template, const char *name,
> > +    void *data)
> > +{
> > +    struct hypfs_dyndir_id *dyndata;
> > +
> > +    dyndata = hypfs_get_dyndata();
> > +
> > +    dyndata->template = template;
> > +    dyndata->data = data;
> > +    memcpy(dyndata->name, name, strlen(name));
> > +    dyndata->dir.e = *template;
> > +    dyndata->dir.e.name = dyndata->name;
> > +
> > +    dyndata->dir.e.funcs = &dyndata->funcs;
> > +    dyndata->funcs = *template->funcs;
> > +    dyndata->funcs.enter = hypfs_dyndir_enter;
> > +    dyndata->funcs.findentry = hypfs_dyndir_findentry;
> > +    dyndata->funcs.read = hypfs_read_dyndir;
> > +
> > +    return &dyndata->dir.e;
> >   }
> >   /*
> > @@ -442,12 +486,13 @@ struct hypfs_entry *hypfs_gen_dyndir_id_entry(
> >       dyndata = hypfs_get_dyndata();
> > -    dyndata->template = template;
> > +    dyndata->template = &template->e;
> >       dyndata->id = id;
> >       dyndata->data = data;
> >       snprintf(dyndata->name, sizeof(dyndata->name), template->e.name, id);
> >       dyndata->dir = *template;
> >       dyndata->dir.e.name = dyndata->name;
> > +
> 
> Unrelated change?
> 
> >       dyndata->dir.e.funcs = &dyndata->funcs;
> >       dyndata->funcs = *template->e.funcs;
> >       dyndata->funcs.enter = hypfs_dyndir_enter;
> > @@ -457,6 +502,12 @@ struct hypfs_entry *hypfs_gen_dyndir_id_entry(
> >       return &dyndata->dir.e;
> >   }
> > +unsigned int hypfs_dyndir_entry_size(const struct hypfs_entry *template,
> > +                                    const char *name)
> 
> Please fix indentation.
> 
> > +{
> > +    return DIRENTRY_SIZE(strlen(name));
> > +}
> > +
> >   unsigned int hypfs_dynid_entry_size(const struct hypfs_entry *template,
> >                                       unsigned int id)
> >   {
> > diff --git a/xen/include/xen/hypfs.h b/xen/include/xen/hypfs.h
> > index e9d4c2555b..5d2728b963 100644
> > --- a/xen/include/xen/hypfs.h
> > +++ b/xen/include/xen/hypfs.h
> > @@ -79,8 +79,8 @@ struct hypfs_entry_dir {
> >   struct hypfs_dyndir_id {
> 
> Please rename to struct hypfs_dyndir.

Ok, thanks.

> 
> >       struct hypfs_entry_dir dir;             /* Modified copy of template. */
> >       struct hypfs_funcs funcs;               /* Dynamic functions. */
> > -    const struct hypfs_entry_dir *template; /* Template used. */
> > -#define HYPFS_DYNDIR_ID_NAMELEN 12
> > +    const struct hypfs_entry *template; /* Template used. */
> > +#define HYPFS_DYNDIR_ID_NAMELEN 32
> >       char name[HYPFS_DYNDIR_ID_NAMELEN];     /* Name of hypfs entry. */
> >       unsigned int id;                        /* Numerical id. */
> 
> What about the following change instead:
> 
> -    const struct hypfs_entry_dir *template; /* Template used. */
> -#define HYPFS_DYNDIR_ID_NAMELEN 12
> -    char name[HYPFS_DYNDIR_ID_NAMELEN];     /* Name of hypfs entry. */
> -
> -    unsigned int id;                        /* Numerical id. */
> -    void *data;                             /* Data associated with id. */
> +    const struct hypfs_entry *template;  /* Template used. */
> +    union {
> +#define HYPFS_DYNDIR_NAMELEN    32
> +        char name[HYPFS_DYNDIR_NAMELEN]; /* Name of hypfs entry. */
> +        struct {
> +#define HYPFS_DYNDIR_ID_NAMELEN 12
> +            char name[HYPFS_DYNDIR_ID_NAMELEN]; /* Name of id entry. */
> +            unsigned int id;                    /* Numerical id. */
> +        } id;
> +    };
> +    void*data;                          /* Data associated with entry. */
> 

I'm not sure I see the benefit from this union. The only one I see is
that struct hypds_dyndir will be smaller by sizeof(unsigned int).
Could you explain please?

Also what do you think about the following change:
-    char name[HYPFS_DYNDIR_ID_NAMELEN];     /* Name of hypfs entry. */
-
-    unsigned int id;                        /* Numerical id. */
-    void *data;                             /* Data associated with id. */
+    char name[HYPFS_DYNDIR_ID_NAMELEN];     /* Name of hypfs entry. */
+
+    unsigned int id;                        /* Numerical id. */
+    union {
+       const void *content;
+       void *data;                             /* Data associated with id. */
+    }
This change is similar to the hypfs_entry_leaf. In this case we can
store const pointer for read-only entries and use data when write access
is needed?

PS: I will address all your comments in v3.

Best regards,
Oleksii.

> > @@ -197,13 +197,23 @@ void *hypfs_alloc_dyndata(unsigned long size);
> >   #define hypfs_alloc_dyndata(type) ((type *)hypfs_alloc_dyndata(sizeof(type)))
> >   void *hypfs_get_dyndata(void);
> >   void hypfs_free_dyndata(void);
> > +int hypfs_read_dyndir_entry(const struct hypfs_entry *template,
> > +                               const char *name, unsigned int namelen,
> > +                               bool is_last,
> > +                               XEN_GUEST_HANDLE_PARAM(void) *uaddr);
> 
> Again: indentation.
> 
> >   int hypfs_read_dyndir_id_entry(const struct hypfs_entry_dir *template,
> >                                  unsigned int id, bool is_last,
> >                                  XEN_GUEST_HANDLE_PARAM(void) *uaddr);
> > +struct hypfs_entry *hypfs_gen_dyndir_entry(
> > +    const struct hypfs_entry *template, const char *name,
> > +    void *data);
> >   struct hypfs_entry *hypfs_gen_dyndir_id_entry(
> >       const struct hypfs_entry_dir *template, unsigned int id, void *data);
> >   unsigned int hypfs_dynid_entry_size(const struct hypfs_entry *template,
> >                                       unsigned int id);
> > +unsigned int hypfs_dyndir_entry_size(const struct hypfs_entry *template,
> > +                                    const char *name);
> 
> Indentation.
> 
> > +
> >   #endif
> >   #endif /* __XEN_HYPFS_H__ */
> 
> 
> Juergen






^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [RFC v2 5/8] xen/arm: introduce SCMI-SMC mediator driver
  2022-02-08 18:00 ` [RFC v2 5/8] xen/arm: introduce SCMI-SMC mediator driver Oleksii Moisieiev
  2022-02-09 15:02   ` Oleksandr Andrushchenko
@ 2022-02-11  8:46   ` Bertrand Marquis
  2022-02-11 10:44     ` Oleksii Moisieiev
  1 sibling, 1 reply; 45+ messages in thread
From: Bertrand Marquis @ 2022-02-11  8:46 UTC (permalink / raw)
  To: Oleksii Moisieiev
  Cc: xen-devel, Stefano Stabellini, Julien Grall, Volodymyr Babchuk

Hi Oleksii,


> On 8 Feb 2022, at 18:00, Oleksii Moisieiev <Oleksii_Moisieiev@epam.com> wrote:
> 
> This is the implementation of SCI interface, called SCMI-SMC driver,
> which works as the mediator between XEN Domains and Firmware (SCP, ATF etc).
> This allows devices from the Domains to work with clocks, resets and
> power-domains without access to CPG.
> 
> Originally, cpg should be passed to the domain so it can work with
> power-domains/clocks/resets etc. Considering that cpg can't be split between
> the Domains, we get the limitation that the devices, which are using
> power-domains/clocks/resets etc, couldn't be split between the domains.
> The solution is to move the power-domain/clock/resets etc to the
> Firmware (such as SCP firmware or ATF) and provide interface for the
> Domains. XEN should have an entity, caled SCI-Mediator, which is
> responsible for messages redirection between Domains and Firmware and
> for permission handling.
> 
> The following features are implemented:
> - request SCMI channels from ATF and pass channels to Domains;
> - set device permissions for Domains based on the Domain partial
> device-tree. Devices with permissions are able to work with clocks,
> resets and power-domains via SCMI;
> - redirect scmi messages from Domains to ATF.

Before going more deeply in the code I would like to discuss the general
design here and ask some questions to prevent to rework the code before
we all agree that this is the right solution and that we want this in Xen.

First I want to point out that clock/reset/power virtualization is a problem
on most applications using device pass-through and I am very glad that
someone is looking into it.
Also SCMI is the current standard existing for this so relying on it is a very
good idea.

Latest version SCMI standard (DEN0056D v3.1) is defining some means
to use SCMI on a virtualised system. In chapter 4.2.1, the standard
recommends to set permissions per agent in the hypervisor so that a VM
could later use the discovery protocol to detect the resources and use them.
Using this kind of scenario the mediator in Xen would just configure the
Permissions in the SCMI and would then rely on it to limit what is possible
by who just by just assigning a channel to a VM.

In your current design (please correct me if I am wrong) you seem to fully
rely on Xen and the FDT for discovery and permission.
Wouldn’t it be a better idea to use the protocol fully ?
Could we get rid of some of the FDT dependencies by using the discovery
system of SCMI ?
How is Linux doing this currently ? Is it relying on device tree to discover
 the SCMI resources ?

Also I understand that you rely on some entries to be declared in the device
tree and also some support to be implemented in ATF or SCP. I checked in
The boards I have access to and the device trees but none of this seem to
be supported there. Could you tell which board/configuration/ATF you are
using so that the implementation could be tested/validated ?


Regards
Bertrand


> 
> Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@epam.com>
> ---
> xen/arch/arm/Kconfig        |   2 +
> xen/arch/arm/sci/Kconfig    |  10 +
> xen/arch/arm/sci/scmi_smc.c | 959 ++++++++++++++++++++++++++++++++++++
> 3 files changed, 971 insertions(+)
> create mode 100644 xen/arch/arm/sci/Kconfig
> create mode 100644 xen/arch/arm/sci/scmi_smc.c
> 
> diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig
> index ab07833582..3b0dfc57b6 100644
> --- a/xen/arch/arm/Kconfig
> +++ b/xen/arch/arm/Kconfig
> @@ -123,6 +123,8 @@ config ARM_SCI
> 	  support. It allows guests to control system resourcess via one of
> 	  ARM_SCI mediators implemented in XEN.
> 
> +	source "arch/arm/sci/Kconfig"
> +
> endmenu
> 
> menu "ARM errata workaround via the alternative framework"
> diff --git a/xen/arch/arm/sci/Kconfig b/xen/arch/arm/sci/Kconfig
> new file mode 100644
> index 0000000000..10b634d2ed
> --- /dev/null
> +++ b/xen/arch/arm/sci/Kconfig
> @@ -0,0 +1,10 @@
> +config SCMI_SMC
> +	bool "Enable SCMI-SMC mediator driver"
> +	default n
> +	depends on ARM_SCI && HOST_DTB_EXPORT
> +	---help---
> +
> +	Enables mediator in XEN to pass SCMI requests from Domains to ATF.
> +	This feature allows drivers from Domains to work with System
> +	Controllers (such as power,resets,clock etc.). SCP is used as transport
> +	for communication.
> diff --git a/xen/arch/arm/sci/scmi_smc.c b/xen/arch/arm/sci/scmi_smc.c
> new file mode 100644
> index 0000000000..103529dfab
> --- /dev/null
> +++ b/xen/arch/arm/sci/scmi_smc.c
> @@ -0,0 +1,959 @@
> +/*
> + * xen/arch/arm/sci/scmi_smc.c
> + *
> + * SCMI mediator driver, using SCP as transport.
> + *
> + * Oleksii Moisieiev <oleksii_moisieiev@epam.com>
> + * Copyright (C) 2021, EPAM Systems.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <asm/sci/sci.h>
> +#include <asm/smccc.h>
> +#include <asm/io.h>
> +#include <xen/bitops.h>
> +#include <xen/config.h>
> +#include <xen/sched.h>
> +#include <xen/device_tree.h>
> +#include <xen/iocap.h>
> +#include <xen/init.h>
> +#include <xen/err.h>
> +#include <xen/lib.h>
> +#include <xen/list.h>
> +#include <xen/mm.h>
> +#include <xen/string.h>
> +#include <xen/time.h>
> +#include <xen/vmap.h>
> +
> +#define SCMI_BASE_PROTOCOL                  0x10
> +#define SCMI_BASE_PROTOCOL_ATTIBUTES        0x1
> +#define SCMI_BASE_SET_DEVICE_PERMISSIONS    0x9
> +#define SCMI_BASE_RESET_AGENT_CONFIGURATION 0xB
> +#define SCMI_BASE_DISCOVER_AGENT            0x7
> +
> +/* SCMI return codes. See section 4.1.4 of SCMI spec (DEN0056C) */
> +#define SCMI_SUCCESS              0
> +#define SCMI_NOT_SUPPORTED      (-1)
> +#define SCMI_INVALID_PARAMETERS (-2)
> +#define SCMI_DENIED             (-3)
> +#define SCMI_NOT_FOUND          (-4)
> +#define SCMI_OUT_OF_RANGE       (-5)
> +#define SCMI_BUSY               (-6)
> +#define SCMI_COMMS_ERROR        (-7)
> +#define SCMI_GENERIC_ERROR      (-8)
> +#define SCMI_HARDWARE_ERROR     (-9)
> +#define SCMI_PROTOCOL_ERROR     (-10)
> +
> +#define DT_MATCH_SCMI_SMC DT_MATCH_COMPATIBLE("arm,scmi-smc")
> +
> +#define SCMI_SMC_ID                        "arm,smc-id"
> +#define SCMI_SHARED_MEMORY                 "arm,scmi-shmem"
> +#define SCMI_SHMEM                         "shmem"
> +#define SCMI_SHMEM_MAPPED_SIZE             PAGE_SIZE
> +
> +#define HYP_CHANNEL                          0x0
> +
> +#define HDR_ID                             GENMASK(7,0)
> +#define HDR_TYPE                           GENMASK(9, 8)
> +#define HDR_PROTO                          GENMASK(17, 10)
> +
> +/* SCMI protocol, refer to section 4.2.2.2 (DEN0056C) */
> +#define MSG_N_AGENTS_MASK                  GENMASK(15, 8)
> +
> +#define FIELD_GET(_mask, _reg)\
> +    ((typeof(_mask))(((_reg) & (_mask)) >> (ffs64(_mask) - 1)))
> +#define FIELD_PREP(_mask, _val)\
> +    (((typeof(_mask))(_val) << (ffs64(_mask) - 1)) & (_mask))
> +
> +typedef struct scmi_msg_header {
> +    uint8_t id;
> +    uint8_t type;
> +    uint8_t protocol;
> +} scmi_msg_header_t;
> +
> +#define SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE   BIT(0, UL)
> +#define SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR  BIT(1, UL)
> +
> +#define SCMI_ALLOW_ACCESS                   BIT(0, UL)
> +
> +struct scmi_shared_mem {
> +    uint32_t reserved;
> +    uint32_t channel_status;
> +    uint32_t reserved1[2];
> +    uint32_t flags;
> +    uint32_t length;
> +    uint32_t msg_header;
> +    uint8_t msg_payload[];
> +};
> +
> +struct dt_channel_addr {
> +    u64 addr;
> +    u64 size;
> +    struct list_head list;
> +};
> +
> +struct scmi_channel {
> +    int chan_id;
> +    int agent_id;
> +    uint32_t func_id;
> +    domid_t domain_id;
> +    uint64_t paddr;
> +    uint64_t len;
> +    struct scmi_shared_mem *shmem;
> +    spinlock_t lock;
> +    struct list_head list;
> +};
> +
> +struct scmi_data {
> +    struct list_head channel_list;
> +    spinlock_t channel_list_lock;
> +    bool initialized;
> +};
> +
> +static struct scmi_data scmi_data;
> +
> +
> +/*
> + * pack_scmi_header() - packs and returns 32-bit header
> + *
> + * @hdr: pointer to header containing all the information on message id,
> + *    protocol id and type id.
> + *
> + * Return: 32-bit packed message header to be sent to the platform.
> + */
> +static inline uint32_t pack_scmi_header(scmi_msg_header_t *hdr)
> +{
> +    return FIELD_PREP(HDR_ID, hdr->id) |
> +        FIELD_PREP(HDR_TYPE, hdr->type) |
> +        FIELD_PREP(HDR_PROTO, hdr->protocol);
> +}
> +
> +/*
> + * unpack_scmi_header() - unpacks and records message and protocol id
> + *
> + * @msg_hdr: 32-bit packed message header sent from the platform
> + * @hdr: pointer to header to fetch message and protocol id.
> + */
> +static inline void unpack_scmi_header(uint32_t msg_hdr, scmi_msg_header_t *hdr)
> +{
> +    hdr->id = FIELD_GET(HDR_ID, msg_hdr);
> +    hdr->type = FIELD_GET(HDR_TYPE, msg_hdr);
> +    hdr->protocol = FIELD_GET(HDR_PROTO, msg_hdr);
> +}
> +
> +static inline int channel_is_free(struct scmi_channel *chan_info)
> +{
> +    return ( chan_info->shmem->channel_status
> +            & SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE ) ? 0 : -EBUSY;
> +}
> +
> +/*
> + * Copy data from IO memory space to "real" memory space.
> + */
> +void __memcpy_fromio(void *to, const volatile void __iomem *from, size_t count)
> +{
> +    while (count && !IS_ALIGNED((unsigned long)from, 4)) {
> +        *(u8 *)to = __raw_readb(from);
> +        from++;
> +        to++;
> +        count--;
> +    }
> +
> +    while (count >= 4) {
> +        *(u32 *)to = __raw_readl(from);
> +        from += 4;
> +        to += 4;
> +        count -= 4;
> +    }
> +
> +    while (count) {
> +        *(u8 *)to = __raw_readb(from);
> +        from++;
> +        to++;
> +        count--;
> +    }
> +}
> +
> +/*
> + * Copy data from "real" memory space to IO memory space.
> + */
> +void __memcpy_toio(volatile void __iomem *to, const void *from, size_t count)
> +{
> +    while (count && !IS_ALIGNED((unsigned long)to, 4)) {
> +        __raw_writeb(*(u8 *)from, to);
> +        from++;
> +        to++;
> +        count--;
> +    }
> +
> +    while (count >= 4) {
> +        __raw_writel(*(u32 *)from, to);
> +        from += 4;
> +        to += 4;
> +        count -= 4;
> +    }
> +
> +    while (count) {
> +        __raw_writeb(*(u8 *)from, to);
> +        from++;
> +        to++;
> +        count--;
> +    }
> +}
> +
> +static int send_smc_message(struct scmi_channel *chan_info,
> +                            scmi_msg_header_t *hdr, void *data, int len)
> +{
> +    struct arm_smccc_res resp;
> +    int ret;
> +
> +    if ( (len + sizeof(chan_info->shmem->msg_header)) >
> +                         SCMI_SHMEM_MAPPED_SIZE )
> +    {
> +        printk(XENLOG_ERR
> +               "scmi: Wrong size of smc message. Data is invalid\n");
> +        return -EINVAL;
> +    }
> +
> +    printk(XENLOG_DEBUG "scmi: status =%d len=%d\n",
> +           chan_info->shmem->channel_status, len);
> +    printk(XENLOG_DEBUG "scmi: header id = %d type = %d, proto = %d\n",
> +           hdr->id, hdr->type, hdr->protocol);
> +
> +    ret = channel_is_free(chan_info);
> +    if ( IS_ERR_VALUE(ret) )
> +        return ret;
> +
> +    chan_info->shmem->channel_status = 0x0;
> +    /* Writing 0x0 right now, but SCMI_SHMEM_FLAG_INTR_ENABLED can be set */
> +    chan_info->shmem->flags = 0x0;
> +    chan_info->shmem->length = sizeof(chan_info->shmem->msg_header) + len;
> +    chan_info->shmem->msg_header = pack_scmi_header(hdr);
> +
> +    printk(XENLOG_DEBUG "scmi: Writing to shmem address %p\n",
> +           chan_info->shmem);
> +    if ( len > 0 && data )
> +        __memcpy_toio((void *)(chan_info->shmem->msg_payload), data, len);
> +
> +    arm_smccc_smc(chan_info->func_id, 0, 0, 0, 0, 0, 0, chan_info->chan_id,
> +                  &resp);
> +
> +    printk(XENLOG_DEBUG "scmi: scmccc_smc response %d\n", (int)(resp.a0));
> +
> +    if ( resp.a0 )
> +        return -EOPNOTSUPP;
> +
> +    return 0;
> +}
> +
> +static int check_scmi_status(int scmi_status)
> +{
> +    if ( scmi_status == SCMI_SUCCESS )
> +        return 0;
> +
> +    printk(XENLOG_DEBUG "scmi: Error received: %d\n", scmi_status);
> +
> +    switch ( scmi_status )
> +    {
> +    case SCMI_NOT_SUPPORTED:
> +        return -EOPNOTSUPP;
> +    case SCMI_INVALID_PARAMETERS:
> +        return -EINVAL;
> +    case SCMI_DENIED:
> +        return -EACCES;
> +    case SCMI_NOT_FOUND:
> +        return -ENOENT;
> +    case SCMI_OUT_OF_RANGE:
> +        return -ERANGE;
> +    case SCMI_BUSY:
> +        return -EBUSY;
> +    case SCMI_COMMS_ERROR:
> +        return -ENOTCONN;
> +    case SCMI_GENERIC_ERROR:
> +        return -EIO;
> +    case SCMI_HARDWARE_ERROR:
> +        return -ENXIO;
> +    case SCMI_PROTOCOL_ERROR:
> +        return -EBADMSG;
> +    default:
> +        return -EINVAL;
> +    }
> +}
> +
> +static int get_smc_response(struct scmi_channel *chan_info,
> +                            scmi_msg_header_t *hdr, void *data, int len)
> +{
> +    int recv_len;
> +    int ret;
> +
> +    printk(XENLOG_DEBUG "scmi: get smc responce msgid %d\n", hdr->id);
> +
> +    if ( len >= SCMI_SHMEM_MAPPED_SIZE - sizeof(chan_info->shmem) )
> +    {
> +        printk(XENLOG_ERR
> +               "scmi: Wrong size of input smc message. Data may be invalid\n");
> +        return -EINVAL;
> +    }
> +
> +    ret = channel_is_free(chan_info);
> +    if ( IS_ERR_VALUE(ret) )
> +        return ret;
> +
> +    recv_len = chan_info->shmem->length - sizeof(chan_info->shmem->msg_header);
> +
> +    if ( recv_len < 0 )
> +    {
> +        printk(XENLOG_ERR
> +               "scmi: Wrong size of smc message. Data may be invalid\n");
> +        return -EINVAL;
> +    }
> +
> +    if ( recv_len > len )
> +    {
> +        printk(XENLOG_ERR
> +               "scmi: Not enough buffer for message %d, expecting %d\n",
> +               recv_len, len);
> +        return -EINVAL;
> +    }
> +
> +    unpack_scmi_header(chan_info->shmem->msg_header, hdr);
> +
> +    if ( recv_len > 0 )
> +    {
> +        __memcpy_fromio(data, chan_info->shmem->msg_payload, recv_len);
> +    }
> +
> +    return 0;
> +}
> +
> +static int do_smc_xfer(struct scmi_channel *channel, scmi_msg_header_t *hdr, void *tx_data, int tx_size,
> +                       void *rx_data, int rx_size)
> +{
> +    int ret = 0;
> +
> +    ASSERT( channel && channel->shmem);
> +
> +    if ( !hdr )
> +        return -EINVAL;
> +
> +    spin_lock(&channel->lock);
> +
> +    ret = send_smc_message(channel, hdr, tx_data, tx_size);
> +    if ( ret )
> +        goto clean;
> +
> +    ret = get_smc_response(channel, hdr, rx_data, rx_size);
> +clean:
> +    spin_unlock(&channel->lock);
> +
> +    return ret;
> +}
> +
> +static struct scmi_channel *get_channel_by_id(uint8_t chan_id)
> +{
> +    struct scmi_channel *curr;
> +    bool found = false;
> +
> +    spin_lock(&scmi_data.channel_list_lock);
> +    list_for_each_entry(curr, &scmi_data.channel_list, list)
> +    {
> +        if ( curr->chan_id == chan_id )
> +        {
> +            found = true;
> +            break;
> +        }
> +    }
> +
> +    spin_unlock(&scmi_data.channel_list_lock);
> +    if ( found )
> +        return curr;
> +
> +    return NULL;
> +}
> +
> +static struct scmi_channel *aquire_scmi_channel(domid_t domain_id)
> +{
> +    struct scmi_channel *curr;
> +    bool found = false;
> +
> +    ASSERT(domain_id != DOMID_INVALID && domain_id >= 0);
> +
> +    spin_lock(&scmi_data.channel_list_lock);
> +    list_for_each_entry(curr, &scmi_data.channel_list, list)
> +    {
> +        if ( curr->domain_id == DOMID_INVALID )
> +        {
> +            curr->domain_id = domain_id;
> +            found = true;
> +            break;
> +        }
> +    }
> +
> +    spin_unlock(&scmi_data.channel_list_lock);
> +    if ( found )
> +        return curr;
> +
> +    return NULL;
> +}
> +
> +static void relinquish_scmi_channel(struct scmi_channel *channel)
> +{
> +    ASSERT(channel != NULL);
> +
> +    spin_lock(&scmi_data.channel_list_lock);
> +    channel->domain_id = DOMID_INVALID;
> +    spin_unlock(&scmi_data.channel_list_lock);
> +}
> +
> +static int map_channel_memory(struct scmi_channel *channel)
> +{
> +    ASSERT( channel && channel->paddr );
> +    channel->shmem = ioremap_cache(channel->paddr, SCMI_SHMEM_MAPPED_SIZE);
> +    if ( !channel->shmem )
> +        return -ENOMEM;
> +
> +    channel->shmem->channel_status = SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE;
> +    printk(XENLOG_DEBUG "scmi: Got shmem after vmap %p\n", channel->shmem);
> +    return 0;
> +}
> +
> +static void unmap_channel_memory(struct scmi_channel *channel)
> +{
> +    ASSERT( channel && channel->shmem );
> +    iounmap(channel->shmem);
> +    channel->shmem = NULL;
> +}
> +
> +static struct scmi_channel *smc_create_channel(uint8_t chan_id,
> +                                               uint32_t func_id, uint64_t addr)
> +{
> +    struct scmi_channel *channel;
> +
> +    channel = get_channel_by_id(chan_id);
> +    if ( channel )
> +        return ERR_PTR(EEXIST);
> +
> +    channel = xmalloc(struct scmi_channel);
> +    if ( !channel )
> +        return ERR_PTR(ENOMEM);
> +
> +    channel->chan_id = chan_id;
> +    channel->func_id = func_id;
> +    channel->domain_id = DOMID_INVALID;
> +    channel->shmem = NULL;
> +    channel->paddr = addr;
> +    spin_lock_init(&channel->lock);
> +    spin_lock(&scmi_data.channel_list_lock);
> +    list_add(&channel->list, &scmi_data.channel_list);
> +    spin_unlock(&scmi_data.channel_list_lock);
> +    return channel;
> +}
> +
> +static int mem_permit_access(struct domain *d, uint64_t addr, uint64_t len)
> +{
> +    return iomem_permit_access(d, paddr_to_pfn(addr),
> +                paddr_to_pfn(PAGE_ALIGN(addr + len -1)));
> +}
> +
> +static int mem_deny_access(struct domain *d, uint64_t addr,
> +                                     uint64_t len)
> +{
> +    return iomem_deny_access(d, paddr_to_pfn(addr),
> +                paddr_to_pfn(PAGE_ALIGN(addr + len -1)));
> +}
> +
> +static int dt_update_domain_range(uint64_t addr, uint64_t size)
> +{
> +    struct dt_device_node *shmem_node;
> +    __be32 *hw_reg;
> +    const struct dt_property *pp;
> +    uint32_t len;
> +
> +    shmem_node = dt_find_compatible_node(NULL, NULL, SCMI_SHARED_MEMORY);
> +    if ( !shmem_node )
> +    {
> +        printk(XENLOG_ERR "scmi: Unable to find %s node in DT\n", SCMI_SHMEM);
> +        return -EINVAL;
> +    }
> +
> +    pp = dt_find_property(shmem_node, "reg", &len);
> +    if ( !pp )
> +    {
> +        printk(XENLOG_ERR "scmi: Unable to find regs entry in shmem node\n");
> +        return -ENOENT;
> +    }
> +
> +    hw_reg = pp->value;
> +    dt_set_range(&hw_reg, shmem_node, addr, size);
> +
> +    return 0;
> +}
> +
> +static void free_channel_list(void)
> +{
> +    struct scmi_channel *curr, *_curr;
> +
> +    spin_lock(&scmi_data.channel_list_lock);
> +    list_for_each_entry_safe (curr, _curr, &scmi_data.channel_list, list)
> +    {
> +        list_del(&curr->list);
> +        xfree(curr);
> +    }
> +
> +    spin_unlock(&scmi_data.channel_list_lock);
> +}
> +
> +static struct dt_device_node *get_dt_node_from_property(
> +                struct dt_device_node *node, const char * p_name)
> +{
> +    const __be32 *prop;
> +
> +    ASSERT( node );
> +
> +    prop = dt_get_property(node, p_name, NULL);
> +    if ( !prop )
> +        return ERR_PTR(-EINVAL);
> +
> +    return dt_find_node_by_phandle(be32_to_cpup(prop));
> +}
> +
> +static int get_shmem_regions(struct list_head *head, u64 hyp_addr)
> +{
> +    struct dt_device_node *node;
> +    int ret;
> +    struct dt_channel_addr *lchan;
> +    u64 laddr, lsize;
> +
> +    node = dt_find_compatible_node(NULL, NULL, SCMI_SHARED_MEMORY);
> +    if ( !node )
> +        return -ENOENT;
> +
> +    while ( node )
> +    {
> +        ret = dt_device_get_address(node, 0, &laddr, &lsize);
> +        if ( ret )
> +            return ret;
> +
> +        if ( laddr != hyp_addr )
> +        {
> +            lchan = xmalloc(struct dt_channel_addr);
> +            if ( !lchan )
> +                return -ENOMEM;
> +            lchan->addr = laddr;
> +            lchan->size = lsize;
> +
> +            list_add_tail(&lchan->list, head);
> +        }
> +
> +        node = dt_find_compatible_node(node, NULL, SCMI_SHARED_MEMORY);
> +    }
> +
> +    return 0;
> +}
> +
> +static int read_hyp_channel_addr(struct dt_device_node *scmi_node,
> +                                 u64 *addr, u64 *size)
> +{
> +    struct dt_device_node *shmem_node;
> +    shmem_node = get_dt_node_from_property(scmi_node, "shmem");
> +    if ( IS_ERR_OR_NULL(shmem_node) )
> +    {
> +        printk(XENLOG_ERR
> +               "scmi: Device tree error, can't parse reserved memory %ld\n",
> +               PTR_ERR(shmem_node));
> +        return PTR_ERR(shmem_node);
> +    }
> +
> +    return dt_device_get_address(shmem_node, 0, addr, size);
> +}
> +
> +static void free_shmem_regions(struct list_head *addr_list)
> +{
> +    struct dt_channel_addr *curr, *_curr;
> +
> +    list_for_each_entry_safe (curr, _curr, addr_list, list)
> +    {
> +        list_del(&curr->list);
> +        xfree(curr);
> +    }
> +}
> +
> +static __init bool scmi_probe(struct dt_device_node *scmi_node)
> +{
> +    u64 addr, size;
> +    int ret, i;
> +    struct scmi_channel *channel, *agent_channel;
> +    int n_agents;
> +    scmi_msg_header_t hdr;
> +    struct rx_t {
> +        int32_t status;
> +        uint32_t attributes;
> +    } rx;
> +    struct dt_channel_addr *entry;
> +    struct list_head addr_list;
> +
> +    uint32_t func_id;
> +
> +    ASSERT(scmi_node != NULL);
> +
> +    INIT_LIST_HEAD(&scmi_data.channel_list);
> +    spin_lock_init(&scmi_data.channel_list_lock);
> +
> +    if ( !dt_property_read_u32(scmi_node, SCMI_SMC_ID, &func_id) )
> +    {
> +        printk(XENLOG_ERR "scmi: Unable to read smc-id from DT\n");
> +        return false;
> +    }
> +
> +    ret = read_hyp_channel_addr(scmi_node, &addr, &size);
> +    if ( IS_ERR_VALUE(ret) )
> +        return false;
> +
> +    if ( !IS_ALIGNED(size, SCMI_SHMEM_MAPPED_SIZE) )
> +    {
> +        printk(XENLOG_ERR "scmi: Reserved memory is not aligned\n");
> +        return false;
> +    }
> +
> +    INIT_LIST_HEAD(&addr_list);
> +
> +    ret = get_shmem_regions(&addr_list, addr);
> +    if ( IS_ERR_VALUE(ret) )
> +        goto out;
> +
> +    channel = smc_create_channel(HYP_CHANNEL, func_id, addr);
> +    if ( IS_ERR(channel) )
> +        goto out;
> +
> +    ret = map_channel_memory(channel);
> +    if ( ret )
> +        goto out;
> +
> +    spin_lock(&scmi_data.channel_list_lock);
> +    channel->domain_id = DOMID_XEN;
> +    spin_unlock(&scmi_data.channel_list_lock);
> +
> +    hdr.id = SCMI_BASE_PROTOCOL_ATTIBUTES;
> +    hdr.type = 0;
> +    hdr.protocol = SCMI_BASE_PROTOCOL;
> +
> +    ret = do_smc_xfer(channel, &hdr, NULL, 0, &rx, sizeof(rx));
> +    if ( ret )
> +        goto error;
> +
> +    ret = check_scmi_status(rx.status);
> +    if ( ret )
> +        goto error;
> +
> +    n_agents = FIELD_GET(MSG_N_AGENTS_MASK, rx.attributes);
> +    printk(XENLOG_DEBUG "scmi: Got agent count %d\n", n_agents);
> +
> +    i = 1;
> +    list_for_each_entry(entry, &addr_list, list)
> +    {
> +        uint32_t tx_agent_id = 0xFFFFFFFF;
> +        struct {
> +            int32_t status;
> +            uint32_t agent_id;
> +            char name[16];
> +        } da_rx;
> +
> +        agent_channel = smc_create_channel(i, func_id,
> +                                           entry->addr);
> +        if ( IS_ERR(agent_channel) )
> +        {
> +            ret = PTR_ERR(agent_channel);
> +            goto error;
> +        }
> +
> +        ret = map_channel_memory(agent_channel);
> +        if ( ret )
> +            goto error;
> +
> +        hdr.id = SCMI_BASE_DISCOVER_AGENT;
> +        hdr.type = 0;
> +        hdr.protocol = SCMI_BASE_PROTOCOL;
> +
> +        ret = do_smc_xfer(agent_channel, &hdr, &tx_agent_id,
> +                          sizeof(tx_agent_id), &da_rx, sizeof(da_rx));
> +        if ( ret )
> +        {
> +            unmap_channel_memory(agent_channel);
> +            goto error;
> +        }
> +
> +        unmap_channel_memory(agent_channel);
> +
> +        ret = check_scmi_status(da_rx.status);
> +        if ( ret )
> +            goto error;
> +
> +        printk(XENLOG_DEBUG "scmi: status=0x%x id=0x%x name=%s\n",
> +                da_rx.status, da_rx.agent_id, da_rx.name);
> +
> +        agent_channel->agent_id = da_rx.agent_id;
> +
> +        if ( i == n_agents )
> +            break;
> +
> +        i++;
> +    }
> +
> +    scmi_data.initialized = true;
> +    goto out;
> +
> +error:
> +    unmap_channel_memory(channel);
> +    free_channel_list();
> +out:
> +    free_shmem_regions(&addr_list);
> +    return ret == 0;
> +}
> +
> +static int scmi_domain_init(struct domain *d,
> +                           struct xen_arch_domainconfig *config)
> +{
> +    struct scmi_channel *channel;
> +    int ret;
> +
> +    if ( !scmi_data.initialized )
> +        return 0;
> +
> +    printk(XENLOG_INFO "scmi: domain_id = %d\n", d->domain_id);
> +
> +    channel = aquire_scmi_channel(d->domain_id);
> +    if ( IS_ERR_OR_NULL(channel) )
> +        return -ENOENT;
> +
> +#ifdef CONFIG_ARM_32
> +    printk(XENLOG_INFO
> +           "scmi: Aquire SCMI channel id = 0x%x , domain_id = %d paddr = 0x%llx\n",
> +           channel->chan_id, channel->domain_id, channel->paddr);
> +#else
> +    printk(XENLOG_INFO
> +           "scmi: Aquire SCMI channel id = 0x%x , domain_id = %d paddr = 0x%lx\n",
> +           channel->chan_id, channel->domain_id, channel->paddr);
> +#endif
> +
> +    if ( is_hardware_domain(d) )
> +    {
> +        ret = mem_permit_access(d, channel->paddr, PAGE_SIZE);
> +        if ( IS_ERR_VALUE(ret) )
> +            goto error;
> +
> +        ret = dt_update_domain_range(channel->paddr, PAGE_SIZE);
> +        if ( IS_ERR_VALUE(ret) )
> +        {
> +            int rc = mem_deny_access(d, channel->paddr, PAGE_SIZE);
> +            if ( rc )
> +                printk(XENLOG_ERR "Unable to mem_deny_access\n");
> +
> +            goto error;
> +        }
> +    }
> +
> +    d->arch.sci = channel;
> +    if ( config )
> +        config->arm_sci_agent_paddr = channel->paddr;
> +
> +    return 0;
> +error:
> +    relinquish_scmi_channel(channel);
> +
> +    return ret;
> +}
> +
> +static int scmi_add_device_by_devid(struct domain *d, uint32_t scmi_devid)
> +{
> +    struct scmi_channel *channel, *agent_channel;
> +    scmi_msg_header_t hdr;
> +    struct scmi_perms_tx {
> +        uint32_t agent_id;
> +        uint32_t device_id;
> +        uint32_t flags;
> +    } tx;
> +    struct rx_t {
> +        int32_t status;
> +        uint32_t attributes;
> +    } rx;
> +    int ret;
> +
> +    if ( !scmi_data.initialized )
> +        return 0;
> +
> +    printk(XENLOG_DEBUG "scmi: scmi_devid = %d\n", scmi_devid);
> +
> +    agent_channel = d->arch.sci;
> +    if ( IS_ERR_OR_NULL(agent_channel) )
> +        return PTR_ERR(agent_channel);
> +
> +    channel = get_channel_by_id(HYP_CHANNEL);
> +    if ( IS_ERR_OR_NULL(channel) )
> +        return PTR_ERR(channel);
> +
> +    hdr.id = SCMI_BASE_SET_DEVICE_PERMISSIONS;
> +    hdr.type = 0;
> +    hdr.protocol = SCMI_BASE_PROTOCOL;
> +
> +    tx.agent_id = agent_channel->agent_id;
> +    tx.device_id = scmi_devid;
> +    tx.flags = SCMI_ALLOW_ACCESS;
> +
> +    ret = do_smc_xfer(channel, &hdr, &tx, sizeof(tx), &rx, sizeof(&rx));
> +    if ( IS_ERR_VALUE(ret) )
> +        return ret;
> +
> +    ret = check_scmi_status(rx.status);
> +    if ( IS_ERR_VALUE(ret) )
> +        return ret;
> +
> +    return 0;
> +}
> +
> +static int scmi_add_dt_device(struct domain *d, struct dt_device_node *dev)
> +{
> +    uint32_t scmi_devid;
> +
> +    if ( (!scmi_data.initialized) || (!d->arch.sci) )
> +        return 0;
> +
> +    if ( !dt_property_read_u32(dev, "scmi_devid", &scmi_devid) )
> +        return 0;
> +
> +    printk(XENLOG_INFO "scmi: dt_node = %s\n", dt_node_full_name(dev));
> +
> +    return scmi_add_device_by_devid(d, scmi_devid);
> +}
> +
> +static int scmi_relinquish_resources(struct domain *d)
> +{
> +    int ret;
> +    struct scmi_channel *channel, *agent_channel;
> +    scmi_msg_header_t hdr;
> +    struct reset_agent_tx {
> +        uint32_t agent_id;
> +        uint32_t flags;
> +    } tx;
> +    uint32_t rx;
> +
> +    if ( !d->arch.sci )
> +        return 0;
> +
> +    agent_channel = d->arch.sci;
> +
> +    spin_lock(&agent_channel->lock);
> +    tx.agent_id = agent_channel->agent_id;
> +    spin_unlock(&agent_channel->lock);
> +
> +    channel = get_channel_by_id(HYP_CHANNEL);
> +    if ( !channel )
> +    {
> +        printk(XENLOG_ERR
> +               "scmi: Unable to get Hypervisor scmi channel for domain %d\n",
> +               d->domain_id);
> +        return -EINVAL;
> +    }
> +
> +    hdr.id = SCMI_BASE_RESET_AGENT_CONFIGURATION;
> +    hdr.type = 0;
> +    hdr.protocol = SCMI_BASE_PROTOCOL;
> +
> +    tx.flags = 0;
> +
> +    ret = do_smc_xfer(channel, &hdr, &tx, sizeof(tx), &rx, sizeof(rx));
> +    if ( ret )
> +        return ret;
> +
> +    ret = check_scmi_status(rx);
> +
> +    return ret;
> +}
> +
> +static void scmi_domain_destroy(struct domain *d)
> +{
> +    struct scmi_channel *channel;
> +
> +    if ( !d->arch.sci )
> +        return;
> +
> +    channel = d->arch.sci;
> +    spin_lock(&channel->lock);
> +
> +    relinquish_scmi_channel(channel);
> +    printk(XENLOG_DEBUG "scmi: Free domain %d\n", d->domain_id);
> +
> +    d->arch.sci = NULL;
> +
> +    mem_deny_access(d, channel->paddr, PAGE_SIZE);
> +    spin_unlock(&channel->lock);
> +}
> +
> +static bool scmi_handle_call(struct domain *d, void *args)
> +{
> +    bool res = false;
> +    struct scmi_channel *agent_channel;
> +    struct arm_smccc_res resp;
> +    struct cpu_user_regs *regs = args;
> +
> +    if ( !d->arch.sci )
> +        return false;
> +
> +    agent_channel = d->arch.sci;
> +    spin_lock(&agent_channel->lock);
> +
> +    if ( agent_channel->func_id != regs->r0 )
> +    {
> +        res = false;
> +        goto unlock;
> +    }
> +
> +    arm_smccc_smc(agent_channel->func_id, 0, 0, 0, 0, 0, 0,
> +                  agent_channel->chan_id, &resp);
> +
> +    set_user_reg(regs, 0, resp.a0);
> +    set_user_reg(regs, 1, resp.a1);
> +    set_user_reg(regs, 2, resp.a2);
> +    set_user_reg(regs, 3, resp.a3);
> +    res = true;
> +unlock:
> +    spin_unlock(&agent_channel->lock);
> +
> +    return res;
> +}
> +
> +static const struct dt_device_match scmi_smc_match[] __initconst =
> +{
> +    DT_MATCH_SCMI_SMC,
> +    { /* sentinel */ },
> +};
> +
> +static const struct sci_mediator_ops scmi_ops =
> +{
> +    .probe = scmi_probe,
> +    .domain_init = scmi_domain_init,
> +    .domain_destroy = scmi_domain_destroy,
> +    .add_dt_device = scmi_add_dt_device,
> +    .relinquish_resources = scmi_relinquish_resources,
> +    .handle_call = scmi_handle_call,
> +};
> +
> +REGISTER_SCI_MEDIATOR(scmi_smc, "SCMI-SMC", XEN_DOMCTL_CONFIG_ARM_SCI_SCMI_SMC,
> +                      scmi_smc_match, &scmi_ops);
> +
> +/*
> + * Local variables:
> + * mode: C
> + * c-file-style: "BSD"
> + * c-basic-offset: 4
> + * indent-tabs-mode: nil
> + * End:
> + */
> -- 
> 2.27.0


^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [RFC v2 5/8] xen/arm: introduce SCMI-SMC mediator driver
  2022-02-11  8:46   ` Bertrand Marquis
@ 2022-02-11 10:44     ` Oleksii Moisieiev
  2022-02-11 11:18       ` Bertrand Marquis
  0 siblings, 1 reply; 45+ messages in thread
From: Oleksii Moisieiev @ 2022-02-11 10:44 UTC (permalink / raw)
  To: Bertrand Marquis
  Cc: xen-devel, Stefano Stabellini, Julien Grall, Volodymyr Babchuk

Hi Bertrand,

On Fri, Feb 11, 2022 at 08:46:05AM +0000, Bertrand Marquis wrote:
> Hi Oleksii,
> 
> 
> > On 8 Feb 2022, at 18:00, Oleksii Moisieiev <Oleksii_Moisieiev@epam.com> wrote:
> > 
> > This is the implementation of SCI interface, called SCMI-SMC driver,
> > which works as the mediator between XEN Domains and Firmware (SCP, ATF etc).
> > This allows devices from the Domains to work with clocks, resets and
> > power-domains without access to CPG.
> > 
> > Originally, cpg should be passed to the domain so it can work with
> > power-domains/clocks/resets etc. Considering that cpg can't be split between
> > the Domains, we get the limitation that the devices, which are using
> > power-domains/clocks/resets etc, couldn't be split between the domains.
> > The solution is to move the power-domain/clock/resets etc to the
> > Firmware (such as SCP firmware or ATF) and provide interface for the
> > Domains. XEN should have an entity, caled SCI-Mediator, which is
> > responsible for messages redirection between Domains and Firmware and
> > for permission handling.
> > 
> > The following features are implemented:
> > - request SCMI channels from ATF and pass channels to Domains;
> > - set device permissions for Domains based on the Domain partial
> > device-tree. Devices with permissions are able to work with clocks,
> > resets and power-domains via SCMI;
> > - redirect scmi messages from Domains to ATF.
> 
> Before going more deeply in the code I would like to discuss the general
> design here and ask some questions to prevent to rework the code before
> we all agree that this is the right solution and that we want this in Xen.
> 
> First I want to point out that clock/reset/power virtualization is a problem
> on most applications using device pass-through and I am very glad that
> someone is looking into it.
> Also SCMI is the current standard existing for this so relying on it is a very
> good idea.
> 
> Latest version SCMI standard (DEN0056D v3.1) is defining some means
> to use SCMI on a virtualised system. In chapter 4.2.1, the standard
> recommends to set permissions per agent in the hypervisor so that a VM
> could later use the discovery protocol to detect the resources and use them.
> Using this kind of scenario the mediator in Xen would just configure the
> Permissions in the SCMI and would then rely on it to limit what is possible
> by who just by just assigning a channel to a VM.

> 
> In your current design (please correct me if I am wrong) you seem to fully
> rely on Xen and the FDT for discovery and permission.

In current implementation Xen is the trusted agent. And it's responsible
for permissions setting. During initialization it discovers agent and
set permissions by using BASE_SET_DEVICE_PERMISSIONS to the Dom0. When
new domain is created, Xen assigns agent id for this domain and request
resources, that are passed-through to this Domain.

I'm getting the follwing information from FDT:
1) Shared memory addressed, which should be used for agents. During
initialization I send BASE_DISCOVER_AGENT to each of this addresses and
receive agent_id. Xen is responsible for assigning agent_id for the
Domain. Then Xen intercept smc calls from the domain, set agent_id and
redirects it to the Firmware.

2) Devices, that are using SCMI. Those devices has clock/power/resets
etc related to scmi protocol (as it is done in Linux kernel)
and scmi_devid should be set. I'm currently preparing to send patch,
updating kernel bindings with this parameter to Linux kernel.
scmi_devid value should match device id, set in the Firmware.
dt example:
&usb0 {
    scmi_devid = <1>; // usb0 device id
    clocks = <&scmi_clock 1> // relays on clock with id 1
}

Xen requests permission for the device when device is attached to the
Domain during creation.

> Wouldn’t it be a better idea to use the protocol fully ?

Hm, I was thinking I am using the protocol fully. Did I miss something?

> Could we get rid of some of the FDT dependencies by using the discovery
> system of SCMI ?

I'm using FDT to get shmem regions for the channels. Then I send
BASE_DISCOVER_AGENT to each region and getting agent data. Did I use the
discovery system wrong?

> How is Linux doing this currently ? Is it relying on device tree to discover
>  the SCMI resources ?

Yes. Linux kernel has 2 nodes in the device-tree: arm,scmi-shmem, which
includes memory region for the communication and arm,scmi-smc node,
which describes all data related to scmi ( func_id, protocols etc)
Then the device nodes refer to the protocols by setting
clock/resets/power-domains etc. Please see the example above.
BASE_DISCOVER_AGENT is not used in Linux kernel.
The main idea was that scmi related changes to the device-tree are
common for virtualized and non virtualized systems. So the same FDT
configuration should work with of without Xen.

> 
> Also I understand that you rely on some entries to be declared in the device
> tree and also some support to be implemented in ATF or SCP. I checked in
> The boards I have access to and the device trees but none of this seem to
> be supported there. Could you tell which board/configuration/ATF you are
> using so that the implementation could be tested/validated ?
> 

We're currently have POC made for r8a77951-ulcb-kf and
r8a77961-salvator-xs boards. It's based on:
Linux-bsp kernel: 
git@github.com:renesas-rcar/linux-bsp.git
based on tag <rcar-5.0.0.rc4>

ATF: 
git@github.com:renesas-rcar/arm-trusted-firmware.git
based on branch <rcar_gen3_v2.5>

I can push those changes to Github, so you can review them.

Best regards,
Oleksii.

> 
> Regards
> Bertrand
> 
> 
> > 
> > Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@epam.com>
> > ---
> > xen/arch/arm/Kconfig        |   2 +
> > xen/arch/arm/sci/Kconfig    |  10 +
> > xen/arch/arm/sci/scmi_smc.c | 959 ++++++++++++++++++++++++++++++++++++
> > 3 files changed, 971 insertions(+)
> > create mode 100644 xen/arch/arm/sci/Kconfig
> > create mode 100644 xen/arch/arm/sci/scmi_smc.c
> > 
> > diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig
> > index ab07833582..3b0dfc57b6 100644
> > --- a/xen/arch/arm/Kconfig
> > +++ b/xen/arch/arm/Kconfig
> > @@ -123,6 +123,8 @@ config ARM_SCI
> > 	  support. It allows guests to control system resourcess via one of
> > 	  ARM_SCI mediators implemented in XEN.
> > 
> > +	source "arch/arm/sci/Kconfig"
> > +
> > endmenu
> > 
> > menu "ARM errata workaround via the alternative framework"
> > diff --git a/xen/arch/arm/sci/Kconfig b/xen/arch/arm/sci/Kconfig
> > new file mode 100644
> > index 0000000000..10b634d2ed
> > --- /dev/null
> > +++ b/xen/arch/arm/sci/Kconfig
> > @@ -0,0 +1,10 @@
> > +config SCMI_SMC
> > +	bool "Enable SCMI-SMC mediator driver"
> > +	default n
> > +	depends on ARM_SCI && HOST_DTB_EXPORT
> > +	---help---
> > +
> > +	Enables mediator in XEN to pass SCMI requests from Domains to ATF.
> > +	This feature allows drivers from Domains to work with System
> > +	Controllers (such as power,resets,clock etc.). SCP is used as transport
> > +	for communication.
> > diff --git a/xen/arch/arm/sci/scmi_smc.c b/xen/arch/arm/sci/scmi_smc.c
> > new file mode 100644
> > index 0000000000..103529dfab
> > --- /dev/null
> > +++ b/xen/arch/arm/sci/scmi_smc.c
> > @@ -0,0 +1,959 @@
> > +/*
> > + * xen/arch/arm/sci/scmi_smc.c
> > + *
> > + * SCMI mediator driver, using SCP as transport.
> > + *
> > + * Oleksii Moisieiev <oleksii_moisieiev@epam.com>
> > + * Copyright (C) 2021, EPAM Systems.
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License as published by
> > + * the Free Software Foundation; either version 2 of the License, or
> > + * (at your option) any later version.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > + * GNU General Public License for more details.
> > + */
> > +
> > +#include <asm/sci/sci.h>
> > +#include <asm/smccc.h>
> > +#include <asm/io.h>
> > +#include <xen/bitops.h>
> > +#include <xen/config.h>
> > +#include <xen/sched.h>
> > +#include <xen/device_tree.h>
> > +#include <xen/iocap.h>
> > +#include <xen/init.h>
> > +#include <xen/err.h>
> > +#include <xen/lib.h>
> > +#include <xen/list.h>
> > +#include <xen/mm.h>
> > +#include <xen/string.h>
> > +#include <xen/time.h>
> > +#include <xen/vmap.h>
> > +
> > +#define SCMI_BASE_PROTOCOL                  0x10
> > +#define SCMI_BASE_PROTOCOL_ATTIBUTES        0x1
> > +#define SCMI_BASE_SET_DEVICE_PERMISSIONS    0x9
> > +#define SCMI_BASE_RESET_AGENT_CONFIGURATION 0xB
> > +#define SCMI_BASE_DISCOVER_AGENT            0x7
> > +
> > +/* SCMI return codes. See section 4.1.4 of SCMI spec (DEN0056C) */
> > +#define SCMI_SUCCESS              0
> > +#define SCMI_NOT_SUPPORTED      (-1)
> > +#define SCMI_INVALID_PARAMETERS (-2)
> > +#define SCMI_DENIED             (-3)
> > +#define SCMI_NOT_FOUND          (-4)
> > +#define SCMI_OUT_OF_RANGE       (-5)
> > +#define SCMI_BUSY               (-6)
> > +#define SCMI_COMMS_ERROR        (-7)
> > +#define SCMI_GENERIC_ERROR      (-8)
> > +#define SCMI_HARDWARE_ERROR     (-9)
> > +#define SCMI_PROTOCOL_ERROR     (-10)
> > +
> > +#define DT_MATCH_SCMI_SMC DT_MATCH_COMPATIBLE("arm,scmi-smc")
> > +
> > +#define SCMI_SMC_ID                        "arm,smc-id"
> > +#define SCMI_SHARED_MEMORY                 "arm,scmi-shmem"
> > +#define SCMI_SHMEM                         "shmem"
> > +#define SCMI_SHMEM_MAPPED_SIZE             PAGE_SIZE
> > +
> > +#define HYP_CHANNEL                          0x0
> > +
> > +#define HDR_ID                             GENMASK(7,0)
> > +#define HDR_TYPE                           GENMASK(9, 8)
> > +#define HDR_PROTO                          GENMASK(17, 10)
> > +
> > +/* SCMI protocol, refer to section 4.2.2.2 (DEN0056C) */
> > +#define MSG_N_AGENTS_MASK                  GENMASK(15, 8)
> > +
> > +#define FIELD_GET(_mask, _reg)\
> > +    ((typeof(_mask))(((_reg) & (_mask)) >> (ffs64(_mask) - 1)))
> > +#define FIELD_PREP(_mask, _val)\
> > +    (((typeof(_mask))(_val) << (ffs64(_mask) - 1)) & (_mask))
> > +
> > +typedef struct scmi_msg_header {
> > +    uint8_t id;
> > +    uint8_t type;
> > +    uint8_t protocol;
> > +} scmi_msg_header_t;
> > +
> > +#define SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE   BIT(0, UL)
> > +#define SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR  BIT(1, UL)
> > +
> > +#define SCMI_ALLOW_ACCESS                   BIT(0, UL)
> > +
> > +struct scmi_shared_mem {
> > +    uint32_t reserved;
> > +    uint32_t channel_status;
> > +    uint32_t reserved1[2];
> > +    uint32_t flags;
> > +    uint32_t length;
> > +    uint32_t msg_header;
> > +    uint8_t msg_payload[];
> > +};
> > +
> > +struct dt_channel_addr {
> > +    u64 addr;
> > +    u64 size;
> > +    struct list_head list;
> > +};
> > +
> > +struct scmi_channel {
> > +    int chan_id;
> > +    int agent_id;
> > +    uint32_t func_id;
> > +    domid_t domain_id;
> > +    uint64_t paddr;
> > +    uint64_t len;
> > +    struct scmi_shared_mem *shmem;
> > +    spinlock_t lock;
> > +    struct list_head list;
> > +};
> > +
> > +struct scmi_data {
> > +    struct list_head channel_list;
> > +    spinlock_t channel_list_lock;
> > +    bool initialized;
> > +};
> > +
> > +static struct scmi_data scmi_data;
> > +
> > +
> > +/*
> > + * pack_scmi_header() - packs and returns 32-bit header
> > + *
> > + * @hdr: pointer to header containing all the information on message id,
> > + *    protocol id and type id.
> > + *
> > + * Return: 32-bit packed message header to be sent to the platform.
> > + */
> > +static inline uint32_t pack_scmi_header(scmi_msg_header_t *hdr)
> > +{
> > +    return FIELD_PREP(HDR_ID, hdr->id) |
> > +        FIELD_PREP(HDR_TYPE, hdr->type) |
> > +        FIELD_PREP(HDR_PROTO, hdr->protocol);
> > +}
> > +
> > +/*
> > + * unpack_scmi_header() - unpacks and records message and protocol id
> > + *
> > + * @msg_hdr: 32-bit packed message header sent from the platform
> > + * @hdr: pointer to header to fetch message and protocol id.
> > + */
> > +static inline void unpack_scmi_header(uint32_t msg_hdr, scmi_msg_header_t *hdr)
> > +{
> > +    hdr->id = FIELD_GET(HDR_ID, msg_hdr);
> > +    hdr->type = FIELD_GET(HDR_TYPE, msg_hdr);
> > +    hdr->protocol = FIELD_GET(HDR_PROTO, msg_hdr);
> > +}
> > +
> > +static inline int channel_is_free(struct scmi_channel *chan_info)
> > +{
> > +    return ( chan_info->shmem->channel_status
> > +            & SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE ) ? 0 : -EBUSY;
> > +}
> > +
> > +/*
> > + * Copy data from IO memory space to "real" memory space.
> > + */
> > +void __memcpy_fromio(void *to, const volatile void __iomem *from, size_t count)
> > +{
> > +    while (count && !IS_ALIGNED((unsigned long)from, 4)) {
> > +        *(u8 *)to = __raw_readb(from);
> > +        from++;
> > +        to++;
> > +        count--;
> > +    }
> > +
> > +    while (count >= 4) {
> > +        *(u32 *)to = __raw_readl(from);
> > +        from += 4;
> > +        to += 4;
> > +        count -= 4;
> > +    }
> > +
> > +    while (count) {
> > +        *(u8 *)to = __raw_readb(from);
> > +        from++;
> > +        to++;
> > +        count--;
> > +    }
> > +}
> > +
> > +/*
> > + * Copy data from "real" memory space to IO memory space.
> > + */
> > +void __memcpy_toio(volatile void __iomem *to, const void *from, size_t count)
> > +{
> > +    while (count && !IS_ALIGNED((unsigned long)to, 4)) {
> > +        __raw_writeb(*(u8 *)from, to);
> > +        from++;
> > +        to++;
> > +        count--;
> > +    }
> > +
> > +    while (count >= 4) {
> > +        __raw_writel(*(u32 *)from, to);
> > +        from += 4;
> > +        to += 4;
> > +        count -= 4;
> > +    }
> > +
> > +    while (count) {
> > +        __raw_writeb(*(u8 *)from, to);
> > +        from++;
> > +        to++;
> > +        count--;
> > +    }
> > +}
> > +
> > +static int send_smc_message(struct scmi_channel *chan_info,
> > +                            scmi_msg_header_t *hdr, void *data, int len)
> > +{
> > +    struct arm_smccc_res resp;
> > +    int ret;
> > +
> > +    if ( (len + sizeof(chan_info->shmem->msg_header)) >
> > +                         SCMI_SHMEM_MAPPED_SIZE )
> > +    {
> > +        printk(XENLOG_ERR
> > +               "scmi: Wrong size of smc message. Data is invalid\n");
> > +        return -EINVAL;
> > +    }
> > +
> > +    printk(XENLOG_DEBUG "scmi: status =%d len=%d\n",
> > +           chan_info->shmem->channel_status, len);
> > +    printk(XENLOG_DEBUG "scmi: header id = %d type = %d, proto = %d\n",
> > +           hdr->id, hdr->type, hdr->protocol);
> > +
> > +    ret = channel_is_free(chan_info);
> > +    if ( IS_ERR_VALUE(ret) )
> > +        return ret;
> > +
> > +    chan_info->shmem->channel_status = 0x0;
> > +    /* Writing 0x0 right now, but SCMI_SHMEM_FLAG_INTR_ENABLED can be set */
> > +    chan_info->shmem->flags = 0x0;
> > +    chan_info->shmem->length = sizeof(chan_info->shmem->msg_header) + len;
> > +    chan_info->shmem->msg_header = pack_scmi_header(hdr);
> > +
> > +    printk(XENLOG_DEBUG "scmi: Writing to shmem address %p\n",
> > +           chan_info->shmem);
> > +    if ( len > 0 && data )
> > +        __memcpy_toio((void *)(chan_info->shmem->msg_payload), data, len);
> > +
> > +    arm_smccc_smc(chan_info->func_id, 0, 0, 0, 0, 0, 0, chan_info->chan_id,
> > +                  &resp);
> > +
> > +    printk(XENLOG_DEBUG "scmi: scmccc_smc response %d\n", (int)(resp.a0));
> > +
> > +    if ( resp.a0 )
> > +        return -EOPNOTSUPP;
> > +
> > +    return 0;
> > +}
> > +
> > +static int check_scmi_status(int scmi_status)
> > +{
> > +    if ( scmi_status == SCMI_SUCCESS )
> > +        return 0;
> > +
> > +    printk(XENLOG_DEBUG "scmi: Error received: %d\n", scmi_status);
> > +
> > +    switch ( scmi_status )
> > +    {
> > +    case SCMI_NOT_SUPPORTED:
> > +        return -EOPNOTSUPP;
> > +    case SCMI_INVALID_PARAMETERS:
> > +        return -EINVAL;
> > +    case SCMI_DENIED:
> > +        return -EACCES;
> > +    case SCMI_NOT_FOUND:
> > +        return -ENOENT;
> > +    case SCMI_OUT_OF_RANGE:
> > +        return -ERANGE;
> > +    case SCMI_BUSY:
> > +        return -EBUSY;
> > +    case SCMI_COMMS_ERROR:
> > +        return -ENOTCONN;
> > +    case SCMI_GENERIC_ERROR:
> > +        return -EIO;
> > +    case SCMI_HARDWARE_ERROR:
> > +        return -ENXIO;
> > +    case SCMI_PROTOCOL_ERROR:
> > +        return -EBADMSG;
> > +    default:
> > +        return -EINVAL;
> > +    }
> > +}
> > +
> > +static int get_smc_response(struct scmi_channel *chan_info,
> > +                            scmi_msg_header_t *hdr, void *data, int len)
> > +{
> > +    int recv_len;
> > +    int ret;
> > +
> > +    printk(XENLOG_DEBUG "scmi: get smc responce msgid %d\n", hdr->id);
> > +
> > +    if ( len >= SCMI_SHMEM_MAPPED_SIZE - sizeof(chan_info->shmem) )
> > +    {
> > +        printk(XENLOG_ERR
> > +               "scmi: Wrong size of input smc message. Data may be invalid\n");
> > +        return -EINVAL;
> > +    }
> > +
> > +    ret = channel_is_free(chan_info);
> > +    if ( IS_ERR_VALUE(ret) )
> > +        return ret;
> > +
> > +    recv_len = chan_info->shmem->length - sizeof(chan_info->shmem->msg_header);
> > +
> > +    if ( recv_len < 0 )
> > +    {
> > +        printk(XENLOG_ERR
> > +               "scmi: Wrong size of smc message. Data may be invalid\n");
> > +        return -EINVAL;
> > +    }
> > +
> > +    if ( recv_len > len )
> > +    {
> > +        printk(XENLOG_ERR
> > +               "scmi: Not enough buffer for message %d, expecting %d\n",
> > +               recv_len, len);
> > +        return -EINVAL;
> > +    }
> > +
> > +    unpack_scmi_header(chan_info->shmem->msg_header, hdr);
> > +
> > +    if ( recv_len > 0 )
> > +    {
> > +        __memcpy_fromio(data, chan_info->shmem->msg_payload, recv_len);
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> > +static int do_smc_xfer(struct scmi_channel *channel, scmi_msg_header_t *hdr, void *tx_data, int tx_size,
> > +                       void *rx_data, int rx_size)
> > +{
> > +    int ret = 0;
> > +
> > +    ASSERT( channel && channel->shmem);
> > +
> > +    if ( !hdr )
> > +        return -EINVAL;
> > +
> > +    spin_lock(&channel->lock);
> > +
> > +    ret = send_smc_message(channel, hdr, tx_data, tx_size);
> > +    if ( ret )
> > +        goto clean;
> > +
> > +    ret = get_smc_response(channel, hdr, rx_data, rx_size);
> > +clean:
> > +    spin_unlock(&channel->lock);
> > +
> > +    return ret;
> > +}
> > +
> > +static struct scmi_channel *get_channel_by_id(uint8_t chan_id)
> > +{
> > +    struct scmi_channel *curr;
> > +    bool found = false;
> > +
> > +    spin_lock(&scmi_data.channel_list_lock);
> > +    list_for_each_entry(curr, &scmi_data.channel_list, list)
> > +    {
> > +        if ( curr->chan_id == chan_id )
> > +        {
> > +            found = true;
> > +            break;
> > +        }
> > +    }
> > +
> > +    spin_unlock(&scmi_data.channel_list_lock);
> > +    if ( found )
> > +        return curr;
> > +
> > +    return NULL;
> > +}
> > +
> > +static struct scmi_channel *aquire_scmi_channel(domid_t domain_id)
> > +{
> > +    struct scmi_channel *curr;
> > +    bool found = false;
> > +
> > +    ASSERT(domain_id != DOMID_INVALID && domain_id >= 0);
> > +
> > +    spin_lock(&scmi_data.channel_list_lock);
> > +    list_for_each_entry(curr, &scmi_data.channel_list, list)
> > +    {
> > +        if ( curr->domain_id == DOMID_INVALID )
> > +        {
> > +            curr->domain_id = domain_id;
> > +            found = true;
> > +            break;
> > +        }
> > +    }
> > +
> > +    spin_unlock(&scmi_data.channel_list_lock);
> > +    if ( found )
> > +        return curr;
> > +
> > +    return NULL;
> > +}
> > +
> > +static void relinquish_scmi_channel(struct scmi_channel *channel)
> > +{
> > +    ASSERT(channel != NULL);
> > +
> > +    spin_lock(&scmi_data.channel_list_lock);
> > +    channel->domain_id = DOMID_INVALID;
> > +    spin_unlock(&scmi_data.channel_list_lock);
> > +}
> > +
> > +static int map_channel_memory(struct scmi_channel *channel)
> > +{
> > +    ASSERT( channel && channel->paddr );
> > +    channel->shmem = ioremap_cache(channel->paddr, SCMI_SHMEM_MAPPED_SIZE);
> > +    if ( !channel->shmem )
> > +        return -ENOMEM;
> > +
> > +    channel->shmem->channel_status = SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE;
> > +    printk(XENLOG_DEBUG "scmi: Got shmem after vmap %p\n", channel->shmem);
> > +    return 0;
> > +}
> > +
> > +static void unmap_channel_memory(struct scmi_channel *channel)
> > +{
> > +    ASSERT( channel && channel->shmem );
> > +    iounmap(channel->shmem);
> > +    channel->shmem = NULL;
> > +}
> > +
> > +static struct scmi_channel *smc_create_channel(uint8_t chan_id,
> > +                                               uint32_t func_id, uint64_t addr)
> > +{
> > +    struct scmi_channel *channel;
> > +
> > +    channel = get_channel_by_id(chan_id);
> > +    if ( channel )
> > +        return ERR_PTR(EEXIST);
> > +
> > +    channel = xmalloc(struct scmi_channel);
> > +    if ( !channel )
> > +        return ERR_PTR(ENOMEM);
> > +
> > +    channel->chan_id = chan_id;
> > +    channel->func_id = func_id;
> > +    channel->domain_id = DOMID_INVALID;
> > +    channel->shmem = NULL;
> > +    channel->paddr = addr;
> > +    spin_lock_init(&channel->lock);
> > +    spin_lock(&scmi_data.channel_list_lock);
> > +    list_add(&channel->list, &scmi_data.channel_list);
> > +    spin_unlock(&scmi_data.channel_list_lock);
> > +    return channel;
> > +}
> > +
> > +static int mem_permit_access(struct domain *d, uint64_t addr, uint64_t len)
> > +{
> > +    return iomem_permit_access(d, paddr_to_pfn(addr),
> > +                paddr_to_pfn(PAGE_ALIGN(addr + len -1)));
> > +}
> > +
> > +static int mem_deny_access(struct domain *d, uint64_t addr,
> > +                                     uint64_t len)
> > +{
> > +    return iomem_deny_access(d, paddr_to_pfn(addr),
> > +                paddr_to_pfn(PAGE_ALIGN(addr + len -1)));
> > +}
> > +
> > +static int dt_update_domain_range(uint64_t addr, uint64_t size)
> > +{
> > +    struct dt_device_node *shmem_node;
> > +    __be32 *hw_reg;
> > +    const struct dt_property *pp;
> > +    uint32_t len;
> > +
> > +    shmem_node = dt_find_compatible_node(NULL, NULL, SCMI_SHARED_MEMORY);
> > +    if ( !shmem_node )
> > +    {
> > +        printk(XENLOG_ERR "scmi: Unable to find %s node in DT\n", SCMI_SHMEM);
> > +        return -EINVAL;
> > +    }
> > +
> > +    pp = dt_find_property(shmem_node, "reg", &len);
> > +    if ( !pp )
> > +    {
> > +        printk(XENLOG_ERR "scmi: Unable to find regs entry in shmem node\n");
> > +        return -ENOENT;
> > +    }
> > +
> > +    hw_reg = pp->value;
> > +    dt_set_range(&hw_reg, shmem_node, addr, size);
> > +
> > +    return 0;
> > +}
> > +
> > +static void free_channel_list(void)
> > +{
> > +    struct scmi_channel *curr, *_curr;
> > +
> > +    spin_lock(&scmi_data.channel_list_lock);
> > +    list_for_each_entry_safe (curr, _curr, &scmi_data.channel_list, list)
> > +    {
> > +        list_del(&curr->list);
> > +        xfree(curr);
> > +    }
> > +
> > +    spin_unlock(&scmi_data.channel_list_lock);
> > +}
> > +
> > +static struct dt_device_node *get_dt_node_from_property(
> > +                struct dt_device_node *node, const char * p_name)
> > +{
> > +    const __be32 *prop;
> > +
> > +    ASSERT( node );
> > +
> > +    prop = dt_get_property(node, p_name, NULL);
> > +    if ( !prop )
> > +        return ERR_PTR(-EINVAL);
> > +
> > +    return dt_find_node_by_phandle(be32_to_cpup(prop));
> > +}
> > +
> > +static int get_shmem_regions(struct list_head *head, u64 hyp_addr)
> > +{
> > +    struct dt_device_node *node;
> > +    int ret;
> > +    struct dt_channel_addr *lchan;
> > +    u64 laddr, lsize;
> > +
> > +    node = dt_find_compatible_node(NULL, NULL, SCMI_SHARED_MEMORY);
> > +    if ( !node )
> > +        return -ENOENT;
> > +
> > +    while ( node )
> > +    {
> > +        ret = dt_device_get_address(node, 0, &laddr, &lsize);
> > +        if ( ret )
> > +            return ret;
> > +
> > +        if ( laddr != hyp_addr )
> > +        {
> > +            lchan = xmalloc(struct dt_channel_addr);
> > +            if ( !lchan )
> > +                return -ENOMEM;
> > +            lchan->addr = laddr;
> > +            lchan->size = lsize;
> > +
> > +            list_add_tail(&lchan->list, head);
> > +        }
> > +
> > +        node = dt_find_compatible_node(node, NULL, SCMI_SHARED_MEMORY);
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> > +static int read_hyp_channel_addr(struct dt_device_node *scmi_node,
> > +                                 u64 *addr, u64 *size)
> > +{
> > +    struct dt_device_node *shmem_node;
> > +    shmem_node = get_dt_node_from_property(scmi_node, "shmem");
> > +    if ( IS_ERR_OR_NULL(shmem_node) )
> > +    {
> > +        printk(XENLOG_ERR
> > +               "scmi: Device tree error, can't parse reserved memory %ld\n",
> > +               PTR_ERR(shmem_node));
> > +        return PTR_ERR(shmem_node);
> > +    }
> > +
> > +    return dt_device_get_address(shmem_node, 0, addr, size);
> > +}
> > +
> > +static void free_shmem_regions(struct list_head *addr_list)
> > +{
> > +    struct dt_channel_addr *curr, *_curr;
> > +
> > +    list_for_each_entry_safe (curr, _curr, addr_list, list)
> > +    {
> > +        list_del(&curr->list);
> > +        xfree(curr);
> > +    }
> > +}
> > +
> > +static __init bool scmi_probe(struct dt_device_node *scmi_node)
> > +{
> > +    u64 addr, size;
> > +    int ret, i;
> > +    struct scmi_channel *channel, *agent_channel;
> > +    int n_agents;
> > +    scmi_msg_header_t hdr;
> > +    struct rx_t {
> > +        int32_t status;
> > +        uint32_t attributes;
> > +    } rx;
> > +    struct dt_channel_addr *entry;
> > +    struct list_head addr_list;
> > +
> > +    uint32_t func_id;
> > +
> > +    ASSERT(scmi_node != NULL);
> > +
> > +    INIT_LIST_HEAD(&scmi_data.channel_list);
> > +    spin_lock_init(&scmi_data.channel_list_lock);
> > +
> > +    if ( !dt_property_read_u32(scmi_node, SCMI_SMC_ID, &func_id) )
> > +    {
> > +        printk(XENLOG_ERR "scmi: Unable to read smc-id from DT\n");
> > +        return false;
> > +    }
> > +
> > +    ret = read_hyp_channel_addr(scmi_node, &addr, &size);
> > +    if ( IS_ERR_VALUE(ret) )
> > +        return false;
> > +
> > +    if ( !IS_ALIGNED(size, SCMI_SHMEM_MAPPED_SIZE) )
> > +    {
> > +        printk(XENLOG_ERR "scmi: Reserved memory is not aligned\n");
> > +        return false;
> > +    }
> > +
> > +    INIT_LIST_HEAD(&addr_list);
> > +
> > +    ret = get_shmem_regions(&addr_list, addr);
> > +    if ( IS_ERR_VALUE(ret) )
> > +        goto out;
> > +
> > +    channel = smc_create_channel(HYP_CHANNEL, func_id, addr);
> > +    if ( IS_ERR(channel) )
> > +        goto out;
> > +
> > +    ret = map_channel_memory(channel);
> > +    if ( ret )
> > +        goto out;
> > +
> > +    spin_lock(&scmi_data.channel_list_lock);
> > +    channel->domain_id = DOMID_XEN;
> > +    spin_unlock(&scmi_data.channel_list_lock);
> > +
> > +    hdr.id = SCMI_BASE_PROTOCOL_ATTIBUTES;
> > +    hdr.type = 0;
> > +    hdr.protocol = SCMI_BASE_PROTOCOL;
> > +
> > +    ret = do_smc_xfer(channel, &hdr, NULL, 0, &rx, sizeof(rx));
> > +    if ( ret )
> > +        goto error;
> > +
> > +    ret = check_scmi_status(rx.status);
> > +    if ( ret )
> > +        goto error;
> > +
> > +    n_agents = FIELD_GET(MSG_N_AGENTS_MASK, rx.attributes);
> > +    printk(XENLOG_DEBUG "scmi: Got agent count %d\n", n_agents);
> > +
> > +    i = 1;
> > +    list_for_each_entry(entry, &addr_list, list)
> > +    {
> > +        uint32_t tx_agent_id = 0xFFFFFFFF;
> > +        struct {
> > +            int32_t status;
> > +            uint32_t agent_id;
> > +            char name[16];
> > +        } da_rx;
> > +
> > +        agent_channel = smc_create_channel(i, func_id,
> > +                                           entry->addr);
> > +        if ( IS_ERR(agent_channel) )
> > +        {
> > +            ret = PTR_ERR(agent_channel);
> > +            goto error;
> > +        }
> > +
> > +        ret = map_channel_memory(agent_channel);
> > +        if ( ret )
> > +            goto error;
> > +
> > +        hdr.id = SCMI_BASE_DISCOVER_AGENT;
> > +        hdr.type = 0;
> > +        hdr.protocol = SCMI_BASE_PROTOCOL;
> > +
> > +        ret = do_smc_xfer(agent_channel, &hdr, &tx_agent_id,
> > +                          sizeof(tx_agent_id), &da_rx, sizeof(da_rx));
> > +        if ( ret )
> > +        {
> > +            unmap_channel_memory(agent_channel);
> > +            goto error;
> > +        }
> > +
> > +        unmap_channel_memory(agent_channel);
> > +
> > +        ret = check_scmi_status(da_rx.status);
> > +        if ( ret )
> > +            goto error;
> > +
> > +        printk(XENLOG_DEBUG "scmi: status=0x%x id=0x%x name=%s\n",
> > +                da_rx.status, da_rx.agent_id, da_rx.name);
> > +
> > +        agent_channel->agent_id = da_rx.agent_id;
> > +
> > +        if ( i == n_agents )
> > +            break;
> > +
> > +        i++;
> > +    }
> > +
> > +    scmi_data.initialized = true;
> > +    goto out;
> > +
> > +error:
> > +    unmap_channel_memory(channel);
> > +    free_channel_list();
> > +out:
> > +    free_shmem_regions(&addr_list);
> > +    return ret == 0;
> > +}
> > +
> > +static int scmi_domain_init(struct domain *d,
> > +                           struct xen_arch_domainconfig *config)
> > +{
> > +    struct scmi_channel *channel;
> > +    int ret;
> > +
> > +    if ( !scmi_data.initialized )
> > +        return 0;
> > +
> > +    printk(XENLOG_INFO "scmi: domain_id = %d\n", d->domain_id);
> > +
> > +    channel = aquire_scmi_channel(d->domain_id);
> > +    if ( IS_ERR_OR_NULL(channel) )
> > +        return -ENOENT;
> > +
> > +#ifdef CONFIG_ARM_32
> > +    printk(XENLOG_INFO
> > +           "scmi: Aquire SCMI channel id = 0x%x , domain_id = %d paddr = 0x%llx\n",
> > +           channel->chan_id, channel->domain_id, channel->paddr);
> > +#else
> > +    printk(XENLOG_INFO
> > +           "scmi: Aquire SCMI channel id = 0x%x , domain_id = %d paddr = 0x%lx\n",
> > +           channel->chan_id, channel->domain_id, channel->paddr);
> > +#endif
> > +
> > +    if ( is_hardware_domain(d) )
> > +    {
> > +        ret = mem_permit_access(d, channel->paddr, PAGE_SIZE);
> > +        if ( IS_ERR_VALUE(ret) )
> > +            goto error;
> > +
> > +        ret = dt_update_domain_range(channel->paddr, PAGE_SIZE);
> > +        if ( IS_ERR_VALUE(ret) )
> > +        {
> > +            int rc = mem_deny_access(d, channel->paddr, PAGE_SIZE);
> > +            if ( rc )
> > +                printk(XENLOG_ERR "Unable to mem_deny_access\n");
> > +
> > +            goto error;
> > +        }
> > +    }
> > +
> > +    d->arch.sci = channel;
> > +    if ( config )
> > +        config->arm_sci_agent_paddr = channel->paddr;
> > +
> > +    return 0;
> > +error:
> > +    relinquish_scmi_channel(channel);
> > +
> > +    return ret;
> > +}
> > +
> > +static int scmi_add_device_by_devid(struct domain *d, uint32_t scmi_devid)
> > +{
> > +    struct scmi_channel *channel, *agent_channel;
> > +    scmi_msg_header_t hdr;
> > +    struct scmi_perms_tx {
> > +        uint32_t agent_id;
> > +        uint32_t device_id;
> > +        uint32_t flags;
> > +    } tx;
> > +    struct rx_t {
> > +        int32_t status;
> > +        uint32_t attributes;
> > +    } rx;
> > +    int ret;
> > +
> > +    if ( !scmi_data.initialized )
> > +        return 0;
> > +
> > +    printk(XENLOG_DEBUG "scmi: scmi_devid = %d\n", scmi_devid);
> > +
> > +    agent_channel = d->arch.sci;
> > +    if ( IS_ERR_OR_NULL(agent_channel) )
> > +        return PTR_ERR(agent_channel);
> > +
> > +    channel = get_channel_by_id(HYP_CHANNEL);
> > +    if ( IS_ERR_OR_NULL(channel) )
> > +        return PTR_ERR(channel);
> > +
> > +    hdr.id = SCMI_BASE_SET_DEVICE_PERMISSIONS;
> > +    hdr.type = 0;
> > +    hdr.protocol = SCMI_BASE_PROTOCOL;
> > +
> > +    tx.agent_id = agent_channel->agent_id;
> > +    tx.device_id = scmi_devid;
> > +    tx.flags = SCMI_ALLOW_ACCESS;
> > +
> > +    ret = do_smc_xfer(channel, &hdr, &tx, sizeof(tx), &rx, sizeof(&rx));
> > +    if ( IS_ERR_VALUE(ret) )
> > +        return ret;
> > +
> > +    ret = check_scmi_status(rx.status);
> > +    if ( IS_ERR_VALUE(ret) )
> > +        return ret;
> > +
> > +    return 0;
> > +}
> > +
> > +static int scmi_add_dt_device(struct domain *d, struct dt_device_node *dev)
> > +{
> > +    uint32_t scmi_devid;
> > +
> > +    if ( (!scmi_data.initialized) || (!d->arch.sci) )
> > +        return 0;
> > +
> > +    if ( !dt_property_read_u32(dev, "scmi_devid", &scmi_devid) )
> > +        return 0;
> > +
> > +    printk(XENLOG_INFO "scmi: dt_node = %s\n", dt_node_full_name(dev));
> > +
> > +    return scmi_add_device_by_devid(d, scmi_devid);
> > +}
> > +
> > +static int scmi_relinquish_resources(struct domain *d)
> > +{
> > +    int ret;
> > +    struct scmi_channel *channel, *agent_channel;
> > +    scmi_msg_header_t hdr;
> > +    struct reset_agent_tx {
> > +        uint32_t agent_id;
> > +        uint32_t flags;
> > +    } tx;
> > +    uint32_t rx;
> > +
> > +    if ( !d->arch.sci )
> > +        return 0;
> > +
> > +    agent_channel = d->arch.sci;
> > +
> > +    spin_lock(&agent_channel->lock);
> > +    tx.agent_id = agent_channel->agent_id;
> > +    spin_unlock(&agent_channel->lock);
> > +
> > +    channel = get_channel_by_id(HYP_CHANNEL);
> > +    if ( !channel )
> > +    {
> > +        printk(XENLOG_ERR
> > +               "scmi: Unable to get Hypervisor scmi channel for domain %d\n",
> > +               d->domain_id);
> > +        return -EINVAL;
> > +    }
> > +
> > +    hdr.id = SCMI_BASE_RESET_AGENT_CONFIGURATION;
> > +    hdr.type = 0;
> > +    hdr.protocol = SCMI_BASE_PROTOCOL;
> > +
> > +    tx.flags = 0;
> > +
> > +    ret = do_smc_xfer(channel, &hdr, &tx, sizeof(tx), &rx, sizeof(rx));
> > +    if ( ret )
> > +        return ret;
> > +
> > +    ret = check_scmi_status(rx);
> > +
> > +    return ret;
> > +}
> > +
> > +static void scmi_domain_destroy(struct domain *d)
> > +{
> > +    struct scmi_channel *channel;
> > +
> > +    if ( !d->arch.sci )
> > +        return;
> > +
> > +    channel = d->arch.sci;
> > +    spin_lock(&channel->lock);
> > +
> > +    relinquish_scmi_channel(channel);
> > +    printk(XENLOG_DEBUG "scmi: Free domain %d\n", d->domain_id);
> > +
> > +    d->arch.sci = NULL;
> > +
> > +    mem_deny_access(d, channel->paddr, PAGE_SIZE);
> > +    spin_unlock(&channel->lock);
> > +}
> > +
> > +static bool scmi_handle_call(struct domain *d, void *args)
> > +{
> > +    bool res = false;
> > +    struct scmi_channel *agent_channel;
> > +    struct arm_smccc_res resp;
> > +    struct cpu_user_regs *regs = args;
> > +
> > +    if ( !d->arch.sci )
> > +        return false;
> > +
> > +    agent_channel = d->arch.sci;
> > +    spin_lock(&agent_channel->lock);
> > +
> > +    if ( agent_channel->func_id != regs->r0 )
> > +    {
> > +        res = false;
> > +        goto unlock;
> > +    }
> > +
> > +    arm_smccc_smc(agent_channel->func_id, 0, 0, 0, 0, 0, 0,
> > +                  agent_channel->chan_id, &resp);
> > +
> > +    set_user_reg(regs, 0, resp.a0);
> > +    set_user_reg(regs, 1, resp.a1);
> > +    set_user_reg(regs, 2, resp.a2);
> > +    set_user_reg(regs, 3, resp.a3);
> > +    res = true;
> > +unlock:
> > +    spin_unlock(&agent_channel->lock);
> > +
> > +    return res;
> > +}
> > +
> > +static const struct dt_device_match scmi_smc_match[] __initconst =
> > +{
> > +    DT_MATCH_SCMI_SMC,
> > +    { /* sentinel */ },
> > +};
> > +
> > +static const struct sci_mediator_ops scmi_ops =
> > +{
> > +    .probe = scmi_probe,
> > +    .domain_init = scmi_domain_init,
> > +    .domain_destroy = scmi_domain_destroy,
> > +    .add_dt_device = scmi_add_dt_device,
> > +    .relinquish_resources = scmi_relinquish_resources,
> > +    .handle_call = scmi_handle_call,
> > +};
> > +
> > +REGISTER_SCI_MEDIATOR(scmi_smc, "SCMI-SMC", XEN_DOMCTL_CONFIG_ARM_SCI_SCMI_SMC,
> > +                      scmi_smc_match, &scmi_ops);
> > +
> > +/*
> > + * Local variables:
> > + * mode: C
> > + * c-file-style: "BSD"
> > + * c-basic-offset: 4
> > + * indent-tabs-mode: nil
> > + * End:
> > + */
> > -- 
> > 2.27.0
> 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [RFC v2 5/8] xen/arm: introduce SCMI-SMC mediator driver
  2022-02-11 10:44     ` Oleksii Moisieiev
@ 2022-02-11 11:18       ` Bertrand Marquis
  2022-02-11 11:55         ` Oleksii Moisieiev
  2022-02-12 12:43         ` Julien Grall
  0 siblings, 2 replies; 45+ messages in thread
From: Bertrand Marquis @ 2022-02-11 11:18 UTC (permalink / raw)
  To: Oleksii Moisieiev
  Cc: xen-devel, Stefano Stabellini, Julien Grall, Volodymyr Babchuk

Hi Oleksii,


> On 11 Feb 2022, at 10:44, Oleksii Moisieiev <Oleksii_Moisieiev@epam.com> wrote:
> 
> Hi Bertrand,
> 
> On Fri, Feb 11, 2022 at 08:46:05AM +0000, Bertrand Marquis wrote:
>> Hi Oleksii,
>> 
>> 
>>> On 8 Feb 2022, at 18:00, Oleksii Moisieiev <Oleksii_Moisieiev@epam.com> wrote:
>>> 
>>> This is the implementation of SCI interface, called SCMI-SMC driver,
>>> which works as the mediator between XEN Domains and Firmware (SCP, ATF etc).
>>> This allows devices from the Domains to work with clocks, resets and
>>> power-domains without access to CPG.
>>> 
>>> Originally, cpg should be passed to the domain so it can work with
>>> power-domains/clocks/resets etc. Considering that cpg can't be split between
>>> the Domains, we get the limitation that the devices, which are using
>>> power-domains/clocks/resets etc, couldn't be split between the domains.
>>> The solution is to move the power-domain/clock/resets etc to the
>>> Firmware (such as SCP firmware or ATF) and provide interface for the
>>> Domains. XEN should have an entity, caled SCI-Mediator, which is
>>> responsible for messages redirection between Domains and Firmware and
>>> for permission handling.
>>> 
>>> The following features are implemented:
>>> - request SCMI channels from ATF and pass channels to Domains;
>>> - set device permissions for Domains based on the Domain partial
>>> device-tree. Devices with permissions are able to work with clocks,
>>> resets and power-domains via SCMI;
>>> - redirect scmi messages from Domains to ATF.
>> 
>> Before going more deeply in the code I would like to discuss the general
>> design here and ask some questions to prevent to rework the code before
>> we all agree that this is the right solution and that we want this in Xen.
>> 
>> First I want to point out that clock/reset/power virtualization is a problem
>> on most applications using device pass-through and I am very glad that
>> someone is looking into it.
>> Also SCMI is the current standard existing for this so relying on it is a very
>> good idea.
>> 
>> Latest version SCMI standard (DEN0056D v3.1) is defining some means
>> to use SCMI on a virtualised system. In chapter 4.2.1, the standard
>> recommends to set permissions per agent in the hypervisor so that a VM
>> could later use the discovery protocol to detect the resources and use them.
>> Using this kind of scenario the mediator in Xen would just configure the
>> Permissions in the SCMI and would then rely on it to limit what is possible
>> by who just by just assigning a channel to a VM.
> 
>> 
>> In your current design (please correct me if I am wrong) you seem to fully
>> rely on Xen and the FDT for discovery and permission.
> 
> In current implementation Xen is the trusted agent. And it's responsible
> for permissions setting. During initialization it discovers agent and
> set permissions by using BASE_SET_DEVICE_PERMISSIONS to the Dom0. When
> new domain is created, Xen assigns agent id for this domain and request
> resources, that are passed-through to this Domain.

Ok

> 
> I'm getting the follwing information from FDT:
> 1) Shared memory addressed, which should be used for agents. During
> initialization I send BASE_DISCOVER_AGENT to each of this addresses and
> receive agent_id. Xen is responsible for assigning agent_id for the
> Domain. Then Xen intercept smc calls from the domain, set agent_id and
> redirects it to the Firmware.

So Xen is setting the agent ID, no way for a guest to get access to something it
should with more check, am I right ?

> 
> 2) Devices, that are using SCMI. Those devices has clock/power/resets
> etc related to scmi protocol (as it is done in Linux kernel)
> and scmi_devid should be set. I'm currently preparing to send patch,
> updating kernel bindings with this parameter to Linux kernel.
> scmi_devid value should match device id, set in the Firmware.
> dt example:
> &usb0 {
>    scmi_devid = <1>; // usb0 device id
>    clocks = <&scmi_clock 1> // relays on clock with id 1
> }
> 
> Xen requests permission for the device when device is attached to the
> Domain during creation.

Without this, how is (if it is) the linux kernel using SCMI for power management ?

> 
>> Wouldn’t it be a better idea to use the protocol fully ?
> 
> Hm, I was thinking I am using the protocol fully. Did I miss something?

Sorry you seem to be, my understanding of your design was not right.

> 
>> Could we get rid of some of the FDT dependencies by using the discovery
>> system of SCMI ?
> 
> I'm using FDT to get shmem regions for the channels. Then I send
> BASE_DISCOVER_AGENT to each region and getting agent data. Did I use the
> discovery system wrong?

After more digging it seems you are. The link between scmi resource and device
is not possible to get automatically.

> 
>> How is Linux doing this currently ? Is it relying on device tree to discover
>> the SCMI resources ?
> 
> Yes. Linux kernel has 2 nodes in the device-tree: arm,scmi-shmem, which
> includes memory region for the communication and arm,scmi-smc node,
> which describes all data related to scmi ( func_id, protocols etc)
> Then the device nodes refer to the protocols by setting
> clock/resets/power-domains etc. Please see the example above.
> BASE_DISCOVER_AGENT is not used in Linux kernel.
> The main idea was that scmi related changes to the device-tree are
> common for virtualized and non virtualized systems. So the same FDT
> configuration should work with of without Xen.

So at this stage this is not supported in Linux and you plan to add support for it to.

> 
>> 
>> Also I understand that you rely on some entries to be declared in the device
>> tree and also some support to be implemented in ATF or SCP. I checked in
>> The boards I have access to and the device trees but none of this seem to
>> be supported there. Could you tell which board/configuration/ATF you are
>> using so that the implementation could be tested/validated ?
>> 
> 
> We're currently have POC made for r8a77951-ulcb-kf and
> r8a77961-salvator-xs boards. It's based on:
> Linux-bsp kernel: 
> git@github.com:renesas-rcar/linux-bsp.git
> based on tag <rcar-5.0.0.rc4>
> 
> ATF: 
> git@github.com:renesas-rcar/arm-trusted-firmware.git
> based on branch <rcar_gen3_v2.5>
> 
> I can push those changes to Github, so you can review them.

Do you plan to add support for other boards ?

Did you discuss more in general with the linux kernel guys to see if this
approach was agreed and will be adopted by other manufacturers ?

All in all I think this is a good idea but I fear that all this will actually only
be used by one board or one manufacturer and other might use a different
strategy, I would like to unrisk this before merging this in Xen.

@julien and Stefano: what is your view here ?

Cheers
Bertrand

> 
> Best regards,
> Oleksii.
> 
>> 
>> Regards
>> Bertrand
>> 
>> 
>>> 
>>> Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@epam.com>
>>> ---
>>> xen/arch/arm/Kconfig        |   2 +
>>> xen/arch/arm/sci/Kconfig    |  10 +
>>> xen/arch/arm/sci/scmi_smc.c | 959 ++++++++++++++++++++++++++++++++++++
>>> 3 files changed, 971 insertions(+)
>>> create mode 100644 xen/arch/arm/sci/Kconfig
>>> create mode 100644 xen/arch/arm/sci/scmi_smc.c
>>> 
>>> diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig
>>> index ab07833582..3b0dfc57b6 100644
>>> --- a/xen/arch/arm/Kconfig
>>> +++ b/xen/arch/arm/Kconfig
>>> @@ -123,6 +123,8 @@ config ARM_SCI
>>> 	  support. It allows guests to control system resourcess via one of
>>> 	  ARM_SCI mediators implemented in XEN.
>>> 
>>> +	source "arch/arm/sci/Kconfig"
>>> +
>>> endmenu
>>> 
>>> menu "ARM errata workaround via the alternative framework"
>>> diff --git a/xen/arch/arm/sci/Kconfig b/xen/arch/arm/sci/Kconfig
>>> new file mode 100644
>>> index 0000000000..10b634d2ed
>>> --- /dev/null
>>> +++ b/xen/arch/arm/sci/Kconfig
>>> @@ -0,0 +1,10 @@
>>> +config SCMI_SMC
>>> +	bool "Enable SCMI-SMC mediator driver"
>>> +	default n
>>> +	depends on ARM_SCI && HOST_DTB_EXPORT
>>> +	---help---
>>> +
>>> +	Enables mediator in XEN to pass SCMI requests from Domains to ATF.
>>> +	This feature allows drivers from Domains to work with System
>>> +	Controllers (such as power,resets,clock etc.). SCP is used as transport
>>> +	for communication.
>>> diff --git a/xen/arch/arm/sci/scmi_smc.c b/xen/arch/arm/sci/scmi_smc.c
>>> new file mode 100644
>>> index 0000000000..103529dfab
>>> --- /dev/null
>>> +++ b/xen/arch/arm/sci/scmi_smc.c
>>> @@ -0,0 +1,959 @@
>>> +/*
>>> + * xen/arch/arm/sci/scmi_smc.c
>>> + *
>>> + * SCMI mediator driver, using SCP as transport.
>>> + *
>>> + * Oleksii Moisieiev <oleksii_moisieiev@epam.com>
>>> + * Copyright (C) 2021, EPAM Systems.
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify
>>> + * it under the terms of the GNU General Public License as published by
>>> + * the Free Software Foundation; either version 2 of the License, or
>>> + * (at your option) any later version.
>>> + *
>>> + * This program is distributed in the hope that it will be useful,
>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>> + * GNU General Public License for more details.
>>> + */
>>> +
>>> +#include <asm/sci/sci.h>
>>> +#include <asm/smccc.h>
>>> +#include <asm/io.h>
>>> +#include <xen/bitops.h>
>>> +#include <xen/config.h>
>>> +#include <xen/sched.h>
>>> +#include <xen/device_tree.h>
>>> +#include <xen/iocap.h>
>>> +#include <xen/init.h>
>>> +#include <xen/err.h>
>>> +#include <xen/lib.h>
>>> +#include <xen/list.h>
>>> +#include <xen/mm.h>
>>> +#include <xen/string.h>
>>> +#include <xen/time.h>
>>> +#include <xen/vmap.h>
>>> +
>>> +#define SCMI_BASE_PROTOCOL                  0x10
>>> +#define SCMI_BASE_PROTOCOL_ATTIBUTES        0x1
>>> +#define SCMI_BASE_SET_DEVICE_PERMISSIONS    0x9
>>> +#define SCMI_BASE_RESET_AGENT_CONFIGURATION 0xB
>>> +#define SCMI_BASE_DISCOVER_AGENT            0x7
>>> +
>>> +/* SCMI return codes. See section 4.1.4 of SCMI spec (DEN0056C) */
>>> +#define SCMI_SUCCESS              0
>>> +#define SCMI_NOT_SUPPORTED      (-1)
>>> +#define SCMI_INVALID_PARAMETERS (-2)
>>> +#define SCMI_DENIED             (-3)
>>> +#define SCMI_NOT_FOUND          (-4)
>>> +#define SCMI_OUT_OF_RANGE       (-5)
>>> +#define SCMI_BUSY               (-6)
>>> +#define SCMI_COMMS_ERROR        (-7)
>>> +#define SCMI_GENERIC_ERROR      (-8)
>>> +#define SCMI_HARDWARE_ERROR     (-9)
>>> +#define SCMI_PROTOCOL_ERROR     (-10)
>>> +
>>> +#define DT_MATCH_SCMI_SMC DT_MATCH_COMPATIBLE("arm,scmi-smc")
>>> +
>>> +#define SCMI_SMC_ID                        "arm,smc-id"
>>> +#define SCMI_SHARED_MEMORY                 "arm,scmi-shmem"
>>> +#define SCMI_SHMEM                         "shmem"
>>> +#define SCMI_SHMEM_MAPPED_SIZE             PAGE_SIZE
>>> +
>>> +#define HYP_CHANNEL                          0x0
>>> +
>>> +#define HDR_ID                             GENMASK(7,0)
>>> +#define HDR_TYPE                           GENMASK(9, 8)
>>> +#define HDR_PROTO                          GENMASK(17, 10)
>>> +
>>> +/* SCMI protocol, refer to section 4.2.2.2 (DEN0056C) */
>>> +#define MSG_N_AGENTS_MASK                  GENMASK(15, 8)
>>> +
>>> +#define FIELD_GET(_mask, _reg)\
>>> +    ((typeof(_mask))(((_reg) & (_mask)) >> (ffs64(_mask) - 1)))
>>> +#define FIELD_PREP(_mask, _val)\
>>> +    (((typeof(_mask))(_val) << (ffs64(_mask) - 1)) & (_mask))
>>> +
>>> +typedef struct scmi_msg_header {
>>> +    uint8_t id;
>>> +    uint8_t type;
>>> +    uint8_t protocol;
>>> +} scmi_msg_header_t;
>>> +
>>> +#define SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE   BIT(0, UL)
>>> +#define SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR  BIT(1, UL)
>>> +
>>> +#define SCMI_ALLOW_ACCESS                   BIT(0, UL)
>>> +
>>> +struct scmi_shared_mem {
>>> +    uint32_t reserved;
>>> +    uint32_t channel_status;
>>> +    uint32_t reserved1[2];
>>> +    uint32_t flags;
>>> +    uint32_t length;
>>> +    uint32_t msg_header;
>>> +    uint8_t msg_payload[];
>>> +};
>>> +
>>> +struct dt_channel_addr {
>>> +    u64 addr;
>>> +    u64 size;
>>> +    struct list_head list;
>>> +};
>>> +
>>> +struct scmi_channel {
>>> +    int chan_id;
>>> +    int agent_id;
>>> +    uint32_t func_id;
>>> +    domid_t domain_id;
>>> +    uint64_t paddr;
>>> +    uint64_t len;
>>> +    struct scmi_shared_mem *shmem;
>>> +    spinlock_t lock;
>>> +    struct list_head list;
>>> +};
>>> +
>>> +struct scmi_data {
>>> +    struct list_head channel_list;
>>> +    spinlock_t channel_list_lock;
>>> +    bool initialized;
>>> +};
>>> +
>>> +static struct scmi_data scmi_data;
>>> +
>>> +
>>> +/*
>>> + * pack_scmi_header() - packs and returns 32-bit header
>>> + *
>>> + * @hdr: pointer to header containing all the information on message id,
>>> + *    protocol id and type id.
>>> + *
>>> + * Return: 32-bit packed message header to be sent to the platform.
>>> + */
>>> +static inline uint32_t pack_scmi_header(scmi_msg_header_t *hdr)
>>> +{
>>> +    return FIELD_PREP(HDR_ID, hdr->id) |
>>> +        FIELD_PREP(HDR_TYPE, hdr->type) |
>>> +        FIELD_PREP(HDR_PROTO, hdr->protocol);
>>> +}
>>> +
>>> +/*
>>> + * unpack_scmi_header() - unpacks and records message and protocol id
>>> + *
>>> + * @msg_hdr: 32-bit packed message header sent from the platform
>>> + * @hdr: pointer to header to fetch message and protocol id.
>>> + */
>>> +static inline void unpack_scmi_header(uint32_t msg_hdr, scmi_msg_header_t *hdr)
>>> +{
>>> +    hdr->id = FIELD_GET(HDR_ID, msg_hdr);
>>> +    hdr->type = FIELD_GET(HDR_TYPE, msg_hdr);
>>> +    hdr->protocol = FIELD_GET(HDR_PROTO, msg_hdr);
>>> +}
>>> +
>>> +static inline int channel_is_free(struct scmi_channel *chan_info)
>>> +{
>>> +    return ( chan_info->shmem->channel_status
>>> +            & SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE ) ? 0 : -EBUSY;
>>> +}
>>> +
>>> +/*
>>> + * Copy data from IO memory space to "real" memory space.
>>> + */
>>> +void __memcpy_fromio(void *to, const volatile void __iomem *from, size_t count)
>>> +{
>>> +    while (count && !IS_ALIGNED((unsigned long)from, 4)) {
>>> +        *(u8 *)to = __raw_readb(from);
>>> +        from++;
>>> +        to++;
>>> +        count--;
>>> +    }
>>> +
>>> +    while (count >= 4) {
>>> +        *(u32 *)to = __raw_readl(from);
>>> +        from += 4;
>>> +        to += 4;
>>> +        count -= 4;
>>> +    }
>>> +
>>> +    while (count) {
>>> +        *(u8 *)to = __raw_readb(from);
>>> +        from++;
>>> +        to++;
>>> +        count--;
>>> +    }
>>> +}
>>> +
>>> +/*
>>> + * Copy data from "real" memory space to IO memory space.
>>> + */
>>> +void __memcpy_toio(volatile void __iomem *to, const void *from, size_t count)
>>> +{
>>> +    while (count && !IS_ALIGNED((unsigned long)to, 4)) {
>>> +        __raw_writeb(*(u8 *)from, to);
>>> +        from++;
>>> +        to++;
>>> +        count--;
>>> +    }
>>> +
>>> +    while (count >= 4) {
>>> +        __raw_writel(*(u32 *)from, to);
>>> +        from += 4;
>>> +        to += 4;
>>> +        count -= 4;
>>> +    }
>>> +
>>> +    while (count) {
>>> +        __raw_writeb(*(u8 *)from, to);
>>> +        from++;
>>> +        to++;
>>> +        count--;
>>> +    }
>>> +}
>>> +
>>> +static int send_smc_message(struct scmi_channel *chan_info,
>>> +                            scmi_msg_header_t *hdr, void *data, int len)
>>> +{
>>> +    struct arm_smccc_res resp;
>>> +    int ret;
>>> +
>>> +    if ( (len + sizeof(chan_info->shmem->msg_header)) >
>>> +                         SCMI_SHMEM_MAPPED_SIZE )
>>> +    {
>>> +        printk(XENLOG_ERR
>>> +               "scmi: Wrong size of smc message. Data is invalid\n");
>>> +        return -EINVAL;
>>> +    }
>>> +
>>> +    printk(XENLOG_DEBUG "scmi: status =%d len=%d\n",
>>> +           chan_info->shmem->channel_status, len);
>>> +    printk(XENLOG_DEBUG "scmi: header id = %d type = %d, proto = %d\n",
>>> +           hdr->id, hdr->type, hdr->protocol);
>>> +
>>> +    ret = channel_is_free(chan_info);
>>> +    if ( IS_ERR_VALUE(ret) )
>>> +        return ret;
>>> +
>>> +    chan_info->shmem->channel_status = 0x0;
>>> +    /* Writing 0x0 right now, but SCMI_SHMEM_FLAG_INTR_ENABLED can be set */
>>> +    chan_info->shmem->flags = 0x0;
>>> +    chan_info->shmem->length = sizeof(chan_info->shmem->msg_header) + len;
>>> +    chan_info->shmem->msg_header = pack_scmi_header(hdr);
>>> +
>>> +    printk(XENLOG_DEBUG "scmi: Writing to shmem address %p\n",
>>> +           chan_info->shmem);
>>> +    if ( len > 0 && data )
>>> +        __memcpy_toio((void *)(chan_info->shmem->msg_payload), data, len);
>>> +
>>> +    arm_smccc_smc(chan_info->func_id, 0, 0, 0, 0, 0, 0, chan_info->chan_id,
>>> +                  &resp);
>>> +
>>> +    printk(XENLOG_DEBUG "scmi: scmccc_smc response %d\n", (int)(resp.a0));
>>> +
>>> +    if ( resp.a0 )
>>> +        return -EOPNOTSUPP;
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +static int check_scmi_status(int scmi_status)
>>> +{
>>> +    if ( scmi_status == SCMI_SUCCESS )
>>> +        return 0;
>>> +
>>> +    printk(XENLOG_DEBUG "scmi: Error received: %d\n", scmi_status);
>>> +
>>> +    switch ( scmi_status )
>>> +    {
>>> +    case SCMI_NOT_SUPPORTED:
>>> +        return -EOPNOTSUPP;
>>> +    case SCMI_INVALID_PARAMETERS:
>>> +        return -EINVAL;
>>> +    case SCMI_DENIED:
>>> +        return -EACCES;
>>> +    case SCMI_NOT_FOUND:
>>> +        return -ENOENT;
>>> +    case SCMI_OUT_OF_RANGE:
>>> +        return -ERANGE;
>>> +    case SCMI_BUSY:
>>> +        return -EBUSY;
>>> +    case SCMI_COMMS_ERROR:
>>> +        return -ENOTCONN;
>>> +    case SCMI_GENERIC_ERROR:
>>> +        return -EIO;
>>> +    case SCMI_HARDWARE_ERROR:
>>> +        return -ENXIO;
>>> +    case SCMI_PROTOCOL_ERROR:
>>> +        return -EBADMSG;
>>> +    default:
>>> +        return -EINVAL;
>>> +    }
>>> +}
>>> +
>>> +static int get_smc_response(struct scmi_channel *chan_info,
>>> +                            scmi_msg_header_t *hdr, void *data, int len)
>>> +{
>>> +    int recv_len;
>>> +    int ret;
>>> +
>>> +    printk(XENLOG_DEBUG "scmi: get smc responce msgid %d\n", hdr->id);
>>> +
>>> +    if ( len >= SCMI_SHMEM_MAPPED_SIZE - sizeof(chan_info->shmem) )
>>> +    {
>>> +        printk(XENLOG_ERR
>>> +               "scmi: Wrong size of input smc message. Data may be invalid\n");
>>> +        return -EINVAL;
>>> +    }
>>> +
>>> +    ret = channel_is_free(chan_info);
>>> +    if ( IS_ERR_VALUE(ret) )
>>> +        return ret;
>>> +
>>> +    recv_len = chan_info->shmem->length - sizeof(chan_info->shmem->msg_header);
>>> +
>>> +    if ( recv_len < 0 )
>>> +    {
>>> +        printk(XENLOG_ERR
>>> +               "scmi: Wrong size of smc message. Data may be invalid\n");
>>> +        return -EINVAL;
>>> +    }
>>> +
>>> +    if ( recv_len > len )
>>> +    {
>>> +        printk(XENLOG_ERR
>>> +               "scmi: Not enough buffer for message %d, expecting %d\n",
>>> +               recv_len, len);
>>> +        return -EINVAL;
>>> +    }
>>> +
>>> +    unpack_scmi_header(chan_info->shmem->msg_header, hdr);
>>> +
>>> +    if ( recv_len > 0 )
>>> +    {
>>> +        __memcpy_fromio(data, chan_info->shmem->msg_payload, recv_len);
>>> +    }
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +static int do_smc_xfer(struct scmi_channel *channel, scmi_msg_header_t *hdr, void *tx_data, int tx_size,
>>> +                       void *rx_data, int rx_size)
>>> +{
>>> +    int ret = 0;
>>> +
>>> +    ASSERT( channel && channel->shmem);
>>> +
>>> +    if ( !hdr )
>>> +        return -EINVAL;
>>> +
>>> +    spin_lock(&channel->lock);
>>> +
>>> +    ret = send_smc_message(channel, hdr, tx_data, tx_size);
>>> +    if ( ret )
>>> +        goto clean;
>>> +
>>> +    ret = get_smc_response(channel, hdr, rx_data, rx_size);
>>> +clean:
>>> +    spin_unlock(&channel->lock);
>>> +
>>> +    return ret;
>>> +}
>>> +
>>> +static struct scmi_channel *get_channel_by_id(uint8_t chan_id)
>>> +{
>>> +    struct scmi_channel *curr;
>>> +    bool found = false;
>>> +
>>> +    spin_lock(&scmi_data.channel_list_lock);
>>> +    list_for_each_entry(curr, &scmi_data.channel_list, list)
>>> +    {
>>> +        if ( curr->chan_id == chan_id )
>>> +        {
>>> +            found = true;
>>> +            break;
>>> +        }
>>> +    }
>>> +
>>> +    spin_unlock(&scmi_data.channel_list_lock);
>>> +    if ( found )
>>> +        return curr;
>>> +
>>> +    return NULL;
>>> +}
>>> +
>>> +static struct scmi_channel *aquire_scmi_channel(domid_t domain_id)
>>> +{
>>> +    struct scmi_channel *curr;
>>> +    bool found = false;
>>> +
>>> +    ASSERT(domain_id != DOMID_INVALID && domain_id >= 0);
>>> +
>>> +    spin_lock(&scmi_data.channel_list_lock);
>>> +    list_for_each_entry(curr, &scmi_data.channel_list, list)
>>> +    {
>>> +        if ( curr->domain_id == DOMID_INVALID )
>>> +        {
>>> +            curr->domain_id = domain_id;
>>> +            found = true;
>>> +            break;
>>> +        }
>>> +    }
>>> +
>>> +    spin_unlock(&scmi_data.channel_list_lock);
>>> +    if ( found )
>>> +        return curr;
>>> +
>>> +    return NULL;
>>> +}
>>> +
>>> +static void relinquish_scmi_channel(struct scmi_channel *channel)
>>> +{
>>> +    ASSERT(channel != NULL);
>>> +
>>> +    spin_lock(&scmi_data.channel_list_lock);
>>> +    channel->domain_id = DOMID_INVALID;
>>> +    spin_unlock(&scmi_data.channel_list_lock);
>>> +}
>>> +
>>> +static int map_channel_memory(struct scmi_channel *channel)
>>> +{
>>> +    ASSERT( channel && channel->paddr );
>>> +    channel->shmem = ioremap_cache(channel->paddr, SCMI_SHMEM_MAPPED_SIZE);
>>> +    if ( !channel->shmem )
>>> +        return -ENOMEM;
>>> +
>>> +    channel->shmem->channel_status = SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE;
>>> +    printk(XENLOG_DEBUG "scmi: Got shmem after vmap %p\n", channel->shmem);
>>> +    return 0;
>>> +}
>>> +
>>> +static void unmap_channel_memory(struct scmi_channel *channel)
>>> +{
>>> +    ASSERT( channel && channel->shmem );
>>> +    iounmap(channel->shmem);
>>> +    channel->shmem = NULL;
>>> +}
>>> +
>>> +static struct scmi_channel *smc_create_channel(uint8_t chan_id,
>>> +                                               uint32_t func_id, uint64_t addr)
>>> +{
>>> +    struct scmi_channel *channel;
>>> +
>>> +    channel = get_channel_by_id(chan_id);
>>> +    if ( channel )
>>> +        return ERR_PTR(EEXIST);
>>> +
>>> +    channel = xmalloc(struct scmi_channel);
>>> +    if ( !channel )
>>> +        return ERR_PTR(ENOMEM);
>>> +
>>> +    channel->chan_id = chan_id;
>>> +    channel->func_id = func_id;
>>> +    channel->domain_id = DOMID_INVALID;
>>> +    channel->shmem = NULL;
>>> +    channel->paddr = addr;
>>> +    spin_lock_init(&channel->lock);
>>> +    spin_lock(&scmi_data.channel_list_lock);
>>> +    list_add(&channel->list, &scmi_data.channel_list);
>>> +    spin_unlock(&scmi_data.channel_list_lock);
>>> +    return channel;
>>> +}
>>> +
>>> +static int mem_permit_access(struct domain *d, uint64_t addr, uint64_t len)
>>> +{
>>> +    return iomem_permit_access(d, paddr_to_pfn(addr),
>>> +                paddr_to_pfn(PAGE_ALIGN(addr + len -1)));
>>> +}
>>> +
>>> +static int mem_deny_access(struct domain *d, uint64_t addr,
>>> +                                     uint64_t len)
>>> +{
>>> +    return iomem_deny_access(d, paddr_to_pfn(addr),
>>> +                paddr_to_pfn(PAGE_ALIGN(addr + len -1)));
>>> +}
>>> +
>>> +static int dt_update_domain_range(uint64_t addr, uint64_t size)
>>> +{
>>> +    struct dt_device_node *shmem_node;
>>> +    __be32 *hw_reg;
>>> +    const struct dt_property *pp;
>>> +    uint32_t len;
>>> +
>>> +    shmem_node = dt_find_compatible_node(NULL, NULL, SCMI_SHARED_MEMORY);
>>> +    if ( !shmem_node )
>>> +    {
>>> +        printk(XENLOG_ERR "scmi: Unable to find %s node in DT\n", SCMI_SHMEM);
>>> +        return -EINVAL;
>>> +    }
>>> +
>>> +    pp = dt_find_property(shmem_node, "reg", &len);
>>> +    if ( !pp )
>>> +    {
>>> +        printk(XENLOG_ERR "scmi: Unable to find regs entry in shmem node\n");
>>> +        return -ENOENT;
>>> +    }
>>> +
>>> +    hw_reg = pp->value;
>>> +    dt_set_range(&hw_reg, shmem_node, addr, size);
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +static void free_channel_list(void)
>>> +{
>>> +    struct scmi_channel *curr, *_curr;
>>> +
>>> +    spin_lock(&scmi_data.channel_list_lock);
>>> +    list_for_each_entry_safe (curr, _curr, &scmi_data.channel_list, list)
>>> +    {
>>> +        list_del(&curr->list);
>>> +        xfree(curr);
>>> +    }
>>> +
>>> +    spin_unlock(&scmi_data.channel_list_lock);
>>> +}
>>> +
>>> +static struct dt_device_node *get_dt_node_from_property(
>>> +                struct dt_device_node *node, const char * p_name)
>>> +{
>>> +    const __be32 *prop;
>>> +
>>> +    ASSERT( node );
>>> +
>>> +    prop = dt_get_property(node, p_name, NULL);
>>> +    if ( !prop )
>>> +        return ERR_PTR(-EINVAL);
>>> +
>>> +    return dt_find_node_by_phandle(be32_to_cpup(prop));
>>> +}
>>> +
>>> +static int get_shmem_regions(struct list_head *head, u64 hyp_addr)
>>> +{
>>> +    struct dt_device_node *node;
>>> +    int ret;
>>> +    struct dt_channel_addr *lchan;
>>> +    u64 laddr, lsize;
>>> +
>>> +    node = dt_find_compatible_node(NULL, NULL, SCMI_SHARED_MEMORY);
>>> +    if ( !node )
>>> +        return -ENOENT;
>>> +
>>> +    while ( node )
>>> +    {
>>> +        ret = dt_device_get_address(node, 0, &laddr, &lsize);
>>> +        if ( ret )
>>> +            return ret;
>>> +
>>> +        if ( laddr != hyp_addr )
>>> +        {
>>> +            lchan = xmalloc(struct dt_channel_addr);
>>> +            if ( !lchan )
>>> +                return -ENOMEM;
>>> +            lchan->addr = laddr;
>>> +            lchan->size = lsize;
>>> +
>>> +            list_add_tail(&lchan->list, head);
>>> +        }
>>> +
>>> +        node = dt_find_compatible_node(node, NULL, SCMI_SHARED_MEMORY);
>>> +    }
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +static int read_hyp_channel_addr(struct dt_device_node *scmi_node,
>>> +                                 u64 *addr, u64 *size)
>>> +{
>>> +    struct dt_device_node *shmem_node;
>>> +    shmem_node = get_dt_node_from_property(scmi_node, "shmem");
>>> +    if ( IS_ERR_OR_NULL(shmem_node) )
>>> +    {
>>> +        printk(XENLOG_ERR
>>> +               "scmi: Device tree error, can't parse reserved memory %ld\n",
>>> +               PTR_ERR(shmem_node));
>>> +        return PTR_ERR(shmem_node);
>>> +    }
>>> +
>>> +    return dt_device_get_address(shmem_node, 0, addr, size);
>>> +}
>>> +
>>> +static void free_shmem_regions(struct list_head *addr_list)
>>> +{
>>> +    struct dt_channel_addr *curr, *_curr;
>>> +
>>> +    list_for_each_entry_safe (curr, _curr, addr_list, list)
>>> +    {
>>> +        list_del(&curr->list);
>>> +        xfree(curr);
>>> +    }
>>> +}
>>> +
>>> +static __init bool scmi_probe(struct dt_device_node *scmi_node)
>>> +{
>>> +    u64 addr, size;
>>> +    int ret, i;
>>> +    struct scmi_channel *channel, *agent_channel;
>>> +    int n_agents;
>>> +    scmi_msg_header_t hdr;
>>> +    struct rx_t {
>>> +        int32_t status;
>>> +        uint32_t attributes;
>>> +    } rx;
>>> +    struct dt_channel_addr *entry;
>>> +    struct list_head addr_list;
>>> +
>>> +    uint32_t func_id;
>>> +
>>> +    ASSERT(scmi_node != NULL);
>>> +
>>> +    INIT_LIST_HEAD(&scmi_data.channel_list);
>>> +    spin_lock_init(&scmi_data.channel_list_lock);
>>> +
>>> +    if ( !dt_property_read_u32(scmi_node, SCMI_SMC_ID, &func_id) )
>>> +    {
>>> +        printk(XENLOG_ERR "scmi: Unable to read smc-id from DT\n");
>>> +        return false;
>>> +    }
>>> +
>>> +    ret = read_hyp_channel_addr(scmi_node, &addr, &size);
>>> +    if ( IS_ERR_VALUE(ret) )
>>> +        return false;
>>> +
>>> +    if ( !IS_ALIGNED(size, SCMI_SHMEM_MAPPED_SIZE) )
>>> +    {
>>> +        printk(XENLOG_ERR "scmi: Reserved memory is not aligned\n");
>>> +        return false;
>>> +    }
>>> +
>>> +    INIT_LIST_HEAD(&addr_list);
>>> +
>>> +    ret = get_shmem_regions(&addr_list, addr);
>>> +    if ( IS_ERR_VALUE(ret) )
>>> +        goto out;
>>> +
>>> +    channel = smc_create_channel(HYP_CHANNEL, func_id, addr);
>>> +    if ( IS_ERR(channel) )
>>> +        goto out;
>>> +
>>> +    ret = map_channel_memory(channel);
>>> +    if ( ret )
>>> +        goto out;
>>> +
>>> +    spin_lock(&scmi_data.channel_list_lock);
>>> +    channel->domain_id = DOMID_XEN;
>>> +    spin_unlock(&scmi_data.channel_list_lock);
>>> +
>>> +    hdr.id = SCMI_BASE_PROTOCOL_ATTIBUTES;
>>> +    hdr.type = 0;
>>> +    hdr.protocol = SCMI_BASE_PROTOCOL;
>>> +
>>> +    ret = do_smc_xfer(channel, &hdr, NULL, 0, &rx, sizeof(rx));
>>> +    if ( ret )
>>> +        goto error;
>>> +
>>> +    ret = check_scmi_status(rx.status);
>>> +    if ( ret )
>>> +        goto error;
>>> +
>>> +    n_agents = FIELD_GET(MSG_N_AGENTS_MASK, rx.attributes);
>>> +    printk(XENLOG_DEBUG "scmi: Got agent count %d\n", n_agents);
>>> +
>>> +    i = 1;
>>> +    list_for_each_entry(entry, &addr_list, list)
>>> +    {
>>> +        uint32_t tx_agent_id = 0xFFFFFFFF;
>>> +        struct {
>>> +            int32_t status;
>>> +            uint32_t agent_id;
>>> +            char name[16];
>>> +        } da_rx;
>>> +
>>> +        agent_channel = smc_create_channel(i, func_id,
>>> +                                           entry->addr);
>>> +        if ( IS_ERR(agent_channel) )
>>> +        {
>>> +            ret = PTR_ERR(agent_channel);
>>> +            goto error;
>>> +        }
>>> +
>>> +        ret = map_channel_memory(agent_channel);
>>> +        if ( ret )
>>> +            goto error;
>>> +
>>> +        hdr.id = SCMI_BASE_DISCOVER_AGENT;
>>> +        hdr.type = 0;
>>> +        hdr.protocol = SCMI_BASE_PROTOCOL;
>>> +
>>> +        ret = do_smc_xfer(agent_channel, &hdr, &tx_agent_id,
>>> +                          sizeof(tx_agent_id), &da_rx, sizeof(da_rx));
>>> +        if ( ret )
>>> +        {
>>> +            unmap_channel_memory(agent_channel);
>>> +            goto error;
>>> +        }
>>> +
>>> +        unmap_channel_memory(agent_channel);
>>> +
>>> +        ret = check_scmi_status(da_rx.status);
>>> +        if ( ret )
>>> +            goto error;
>>> +
>>> +        printk(XENLOG_DEBUG "scmi: status=0x%x id=0x%x name=%s\n",
>>> +                da_rx.status, da_rx.agent_id, da_rx.name);
>>> +
>>> +        agent_channel->agent_id = da_rx.agent_id;
>>> +
>>> +        if ( i == n_agents )
>>> +            break;
>>> +
>>> +        i++;
>>> +    }
>>> +
>>> +    scmi_data.initialized = true;
>>> +    goto out;
>>> +
>>> +error:
>>> +    unmap_channel_memory(channel);
>>> +    free_channel_list();
>>> +out:
>>> +    free_shmem_regions(&addr_list);
>>> +    return ret == 0;
>>> +}
>>> +
>>> +static int scmi_domain_init(struct domain *d,
>>> +                           struct xen_arch_domainconfig *config)
>>> +{
>>> +    struct scmi_channel *channel;
>>> +    int ret;
>>> +
>>> +    if ( !scmi_data.initialized )
>>> +        return 0;
>>> +
>>> +    printk(XENLOG_INFO "scmi: domain_id = %d\n", d->domain_id);
>>> +
>>> +    channel = aquire_scmi_channel(d->domain_id);
>>> +    if ( IS_ERR_OR_NULL(channel) )
>>> +        return -ENOENT;
>>> +
>>> +#ifdef CONFIG_ARM_32
>>> +    printk(XENLOG_INFO
>>> +           "scmi: Aquire SCMI channel id = 0x%x , domain_id = %d paddr = 0x%llx\n",
>>> +           channel->chan_id, channel->domain_id, channel->paddr);
>>> +#else
>>> +    printk(XENLOG_INFO
>>> +           "scmi: Aquire SCMI channel id = 0x%x , domain_id = %d paddr = 0x%lx\n",
>>> +           channel->chan_id, channel->domain_id, channel->paddr);
>>> +#endif
>>> +
>>> +    if ( is_hardware_domain(d) )
>>> +    {
>>> +        ret = mem_permit_access(d, channel->paddr, PAGE_SIZE);
>>> +        if ( IS_ERR_VALUE(ret) )
>>> +            goto error;
>>> +
>>> +        ret = dt_update_domain_range(channel->paddr, PAGE_SIZE);
>>> +        if ( IS_ERR_VALUE(ret) )
>>> +        {
>>> +            int rc = mem_deny_access(d, channel->paddr, PAGE_SIZE);
>>> +            if ( rc )
>>> +                printk(XENLOG_ERR "Unable to mem_deny_access\n");
>>> +
>>> +            goto error;
>>> +        }
>>> +    }
>>> +
>>> +    d->arch.sci = channel;
>>> +    if ( config )
>>> +        config->arm_sci_agent_paddr = channel->paddr;
>>> +
>>> +    return 0;
>>> +error:
>>> +    relinquish_scmi_channel(channel);
>>> +
>>> +    return ret;
>>> +}
>>> +
>>> +static int scmi_add_device_by_devid(struct domain *d, uint32_t scmi_devid)
>>> +{
>>> +    struct scmi_channel *channel, *agent_channel;
>>> +    scmi_msg_header_t hdr;
>>> +    struct scmi_perms_tx {
>>> +        uint32_t agent_id;
>>> +        uint32_t device_id;
>>> +        uint32_t flags;
>>> +    } tx;
>>> +    struct rx_t {
>>> +        int32_t status;
>>> +        uint32_t attributes;
>>> +    } rx;
>>> +    int ret;
>>> +
>>> +    if ( !scmi_data.initialized )
>>> +        return 0;
>>> +
>>> +    printk(XENLOG_DEBUG "scmi: scmi_devid = %d\n", scmi_devid);
>>> +
>>> +    agent_channel = d->arch.sci;
>>> +    if ( IS_ERR_OR_NULL(agent_channel) )
>>> +        return PTR_ERR(agent_channel);
>>> +
>>> +    channel = get_channel_by_id(HYP_CHANNEL);
>>> +    if ( IS_ERR_OR_NULL(channel) )
>>> +        return PTR_ERR(channel);
>>> +
>>> +    hdr.id = SCMI_BASE_SET_DEVICE_PERMISSIONS;
>>> +    hdr.type = 0;
>>> +    hdr.protocol = SCMI_BASE_PROTOCOL;
>>> +
>>> +    tx.agent_id = agent_channel->agent_id;
>>> +    tx.device_id = scmi_devid;
>>> +    tx.flags = SCMI_ALLOW_ACCESS;
>>> +
>>> +    ret = do_smc_xfer(channel, &hdr, &tx, sizeof(tx), &rx, sizeof(&rx));
>>> +    if ( IS_ERR_VALUE(ret) )
>>> +        return ret;
>>> +
>>> +    ret = check_scmi_status(rx.status);
>>> +    if ( IS_ERR_VALUE(ret) )
>>> +        return ret;
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +static int scmi_add_dt_device(struct domain *d, struct dt_device_node *dev)
>>> +{
>>> +    uint32_t scmi_devid;
>>> +
>>> +    if ( (!scmi_data.initialized) || (!d->arch.sci) )
>>> +        return 0;
>>> +
>>> +    if ( !dt_property_read_u32(dev, "scmi_devid", &scmi_devid) )
>>> +        return 0;
>>> +
>>> +    printk(XENLOG_INFO "scmi: dt_node = %s\n", dt_node_full_name(dev));
>>> +
>>> +    return scmi_add_device_by_devid(d, scmi_devid);
>>> +}
>>> +
>>> +static int scmi_relinquish_resources(struct domain *d)
>>> +{
>>> +    int ret;
>>> +    struct scmi_channel *channel, *agent_channel;
>>> +    scmi_msg_header_t hdr;
>>> +    struct reset_agent_tx {
>>> +        uint32_t agent_id;
>>> +        uint32_t flags;
>>> +    } tx;
>>> +    uint32_t rx;
>>> +
>>> +    if ( !d->arch.sci )
>>> +        return 0;
>>> +
>>> +    agent_channel = d->arch.sci;
>>> +
>>> +    spin_lock(&agent_channel->lock);
>>> +    tx.agent_id = agent_channel->agent_id;
>>> +    spin_unlock(&agent_channel->lock);
>>> +
>>> +    channel = get_channel_by_id(HYP_CHANNEL);
>>> +    if ( !channel )
>>> +    {
>>> +        printk(XENLOG_ERR
>>> +               "scmi: Unable to get Hypervisor scmi channel for domain %d\n",
>>> +               d->domain_id);
>>> +        return -EINVAL;
>>> +    }
>>> +
>>> +    hdr.id = SCMI_BASE_RESET_AGENT_CONFIGURATION;
>>> +    hdr.type = 0;
>>> +    hdr.protocol = SCMI_BASE_PROTOCOL;
>>> +
>>> +    tx.flags = 0;
>>> +
>>> +    ret = do_smc_xfer(channel, &hdr, &tx, sizeof(tx), &rx, sizeof(rx));
>>> +    if ( ret )
>>> +        return ret;
>>> +
>>> +    ret = check_scmi_status(rx);
>>> +
>>> +    return ret;
>>> +}
>>> +
>>> +static void scmi_domain_destroy(struct domain *d)
>>> +{
>>> +    struct scmi_channel *channel;
>>> +
>>> +    if ( !d->arch.sci )
>>> +        return;
>>> +
>>> +    channel = d->arch.sci;
>>> +    spin_lock(&channel->lock);
>>> +
>>> +    relinquish_scmi_channel(channel);
>>> +    printk(XENLOG_DEBUG "scmi: Free domain %d\n", d->domain_id);
>>> +
>>> +    d->arch.sci = NULL;
>>> +
>>> +    mem_deny_access(d, channel->paddr, PAGE_SIZE);
>>> +    spin_unlock(&channel->lock);
>>> +}
>>> +
>>> +static bool scmi_handle_call(struct domain *d, void *args)
>>> +{
>>> +    bool res = false;
>>> +    struct scmi_channel *agent_channel;
>>> +    struct arm_smccc_res resp;
>>> +    struct cpu_user_regs *regs = args;
>>> +
>>> +    if ( !d->arch.sci )
>>> +        return false;
>>> +
>>> +    agent_channel = d->arch.sci;
>>> +    spin_lock(&agent_channel->lock);
>>> +
>>> +    if ( agent_channel->func_id != regs->r0 )
>>> +    {
>>> +        res = false;
>>> +        goto unlock;
>>> +    }
>>> +
>>> +    arm_smccc_smc(agent_channel->func_id, 0, 0, 0, 0, 0, 0,
>>> +                  agent_channel->chan_id, &resp);
>>> +
>>> +    set_user_reg(regs, 0, resp.a0);
>>> +    set_user_reg(regs, 1, resp.a1);
>>> +    set_user_reg(regs, 2, resp.a2);
>>> +    set_user_reg(regs, 3, resp.a3);
>>> +    res = true;
>>> +unlock:
>>> +    spin_unlock(&agent_channel->lock);
>>> +
>>> +    return res;
>>> +}
>>> +
>>> +static const struct dt_device_match scmi_smc_match[] __initconst =
>>> +{
>>> +    DT_MATCH_SCMI_SMC,
>>> +    { /* sentinel */ },
>>> +};
>>> +
>>> +static const struct sci_mediator_ops scmi_ops =
>>> +{
>>> +    .probe = scmi_probe,
>>> +    .domain_init = scmi_domain_init,
>>> +    .domain_destroy = scmi_domain_destroy,
>>> +    .add_dt_device = scmi_add_dt_device,
>>> +    .relinquish_resources = scmi_relinquish_resources,
>>> +    .handle_call = scmi_handle_call,
>>> +};
>>> +
>>> +REGISTER_SCI_MEDIATOR(scmi_smc, "SCMI-SMC", XEN_DOMCTL_CONFIG_ARM_SCI_SCMI_SMC,
>>> +                      scmi_smc_match, &scmi_ops);
>>> +
>>> +/*
>>> + * Local variables:
>>> + * mode: C
>>> + * c-file-style: "BSD"
>>> + * c-basic-offset: 4
>>> + * indent-tabs-mode: nil
>>> + * End:
>>> + */
>>> -- 
>>> 2.27.0


^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [RFC v2 5/8] xen/arm: introduce SCMI-SMC mediator driver
  2022-02-11 11:18       ` Bertrand Marquis
@ 2022-02-11 11:55         ` Oleksii Moisieiev
  2022-02-11 23:35           ` Stefano Stabellini
  2022-02-12 12:43         ` Julien Grall
  1 sibling, 1 reply; 45+ messages in thread
From: Oleksii Moisieiev @ 2022-02-11 11:55 UTC (permalink / raw)
  To: Bertrand Marquis
  Cc: xen-devel, Stefano Stabellini, Julien Grall, Volodymyr Babchuk

On Fri, Feb 11, 2022 at 11:18:47AM +0000, Bertrand Marquis wrote:
> Hi Oleksii,
> 
> 
> > On 11 Feb 2022, at 10:44, Oleksii Moisieiev <Oleksii_Moisieiev@epam.com> wrote:
> > 
> > Hi Bertrand,
> > 
> > On Fri, Feb 11, 2022 at 08:46:05AM +0000, Bertrand Marquis wrote:
> >> Hi Oleksii,
> >> 
> >> 
> >>> On 8 Feb 2022, at 18:00, Oleksii Moisieiev <Oleksii_Moisieiev@epam.com> wrote:
> >>> 
> >>> This is the implementation of SCI interface, called SCMI-SMC driver,
> >>> which works as the mediator between XEN Domains and Firmware (SCP, ATF etc).
> >>> This allows devices from the Domains to work with clocks, resets and
> >>> power-domains without access to CPG.
> >>> 
> >>> Originally, cpg should be passed to the domain so it can work with
> >>> power-domains/clocks/resets etc. Considering that cpg can't be split between
> >>> the Domains, we get the limitation that the devices, which are using
> >>> power-domains/clocks/resets etc, couldn't be split between the domains.
> >>> The solution is to move the power-domain/clock/resets etc to the
> >>> Firmware (such as SCP firmware or ATF) and provide interface for the
> >>> Domains. XEN should have an entity, caled SCI-Mediator, which is
> >>> responsible for messages redirection between Domains and Firmware and
> >>> for permission handling.
> >>> 
> >>> The following features are implemented:
> >>> - request SCMI channels from ATF and pass channels to Domains;
> >>> - set device permissions for Domains based on the Domain partial
> >>> device-tree. Devices with permissions are able to work with clocks,
> >>> resets and power-domains via SCMI;
> >>> - redirect scmi messages from Domains to ATF.
> >> 
> >> Before going more deeply in the code I would like to discuss the general
> >> design here and ask some questions to prevent to rework the code before
> >> we all agree that this is the right solution and that we want this in Xen.
> >> 
> >> First I want to point out that clock/reset/power virtualization is a problem
> >> on most applications using device pass-through and I am very glad that
> >> someone is looking into it.
> >> Also SCMI is the current standard existing for this so relying on it is a very
> >> good idea.
> >> 
> >> Latest version SCMI standard (DEN0056D v3.1) is defining some means
> >> to use SCMI on a virtualised system. In chapter 4.2.1, the standard
> >> recommends to set permissions per agent in the hypervisor so that a VM
> >> could later use the discovery protocol to detect the resources and use them.
> >> Using this kind of scenario the mediator in Xen would just configure the
> >> Permissions in the SCMI and would then rely on it to limit what is possible
> >> by who just by just assigning a channel to a VM.
> > 
> >> 
> >> In your current design (please correct me if I am wrong) you seem to fully
> >> rely on Xen and the FDT for discovery and permission.
> > 
> > In current implementation Xen is the trusted agent. And it's responsible
> > for permissions setting. During initialization it discovers agent and
> > set permissions by using BASE_SET_DEVICE_PERMISSIONS to the Dom0. When
> > new domain is created, Xen assigns agent id for this domain and request
> > resources, that are passed-through to this Domain.
> 
> Ok
> 
> > 
> > I'm getting the follwing information from FDT:
> > 1) Shared memory addressed, which should be used for agents. During
> > initialization I send BASE_DISCOVER_AGENT to each of this addresses and
> > receive agent_id. Xen is responsible for assigning agent_id for the
> > Domain. Then Xen intercept smc calls from the domain, set agent_id and
> > redirects it to the Firmware.
> 
> So Xen is setting the agent ID, no way for a guest to get access to something it
> should with more check, am I right ?
> 

Yes. Xen is the only entity, which is trusted. So it's responsible for
setting permissions and assigning agent_id. Guest get's an access only
for the devices it's allowed to.

> > 
> > 2) Devices, that are using SCMI. Those devices has clock/power/resets
> > etc related to scmi protocol (as it is done in Linux kernel)
> > and scmi_devid should be set. I'm currently preparing to send patch,
> > updating kernel bindings with this parameter to Linux kernel.
> > scmi_devid value should match device id, set in the Firmware.
> > dt example:
> > &usb0 {
> >    scmi_devid = <1>; // usb0 device id
> >    clocks = <&scmi_clock 1> // relays on clock with id 1
> > }
> > 
> > Xen requests permission for the device when device is attached to the
> > Domain during creation.
> 
> Without this, how is (if it is) the linux kernel using SCMI for power management ?

Here is how it should be desribed in FDT: 
/
{
    firmware {
        scmi {
            arm,smc-id = <0x82000002>;
            scmi_power: protocol@11 {
                reg = <0x11>;
                #power-domain-cells = <1>;
            };
            ...
            scmi_clock: protocol@14 {
            ...
            scmi_reset: protocol@16 {
            ...
        };
    };
};

&avb {
    scmi_devid = <0>; // Matches Etherned device_id in Firmware
    clocks = <&scmi_clock 0>;
    power-domains = <&scmi_power 0>;
    resets = <&scmi_reset 0>;
};

In the provided case devid equals to reset, clock and power-domain id,
but this is conicidence. Each clock/power-domain/reset parameter can
have more than one entity.
Also - no changes was done to linux kernel scmi drivers.

> 
> > 
> >> Wouldn’t it be a better idea to use the protocol fully ?
> > 
> > Hm, I was thinking I am using the protocol fully. Did I miss something?
> 
> Sorry you seem to be, my understanding of your design was not right.
> 
> > 
> >> Could we get rid of some of the FDT dependencies by using the discovery
> >> system of SCMI ?
> > 
> > I'm using FDT to get shmem regions for the channels. Then I send
> > BASE_DISCOVER_AGENT to each region and getting agent data. Did I use the
> > discovery system wrong?
> 
> After more digging it seems you are. The link between scmi resource and device
> is not possible to get automatically.
> 
> > 
> >> How is Linux doing this currently ? Is it relying on device tree to discover
> >> the SCMI resources ?
> > 
> > Yes. Linux kernel has 2 nodes in the device-tree: arm,scmi-shmem, which
> > includes memory region for the communication and arm,scmi-smc node,
> > which describes all data related to scmi ( func_id, protocols etc)
> > Then the device nodes refer to the protocols by setting
> > clock/resets/power-domains etc. Please see the example above.
> > BASE_DISCOVER_AGENT is not used in Linux kernel.
> > The main idea was that scmi related changes to the device-tree are
> > common for virtualized and non virtualized systems. So the same FDT
> > configuration should work with of without Xen.
> 
> So at this stage this is not supported in Linux and you plan to add support for it to.
> 

Yes. That's correct. I've already prepared patch which should update
linux kernel device-tree bindings.

> > 
> >> 
> >> Also I understand that you rely on some entries to be declared in the device
> >> tree and also some support to be implemented in ATF or SCP. I checked in
> >> The boards I have access to and the device trees but none of this seem to
> >> be supported there. Could you tell which board/configuration/ATF you are
> >> using so that the implementation could be tested/validated ?
> >> 
> > 
> > We're currently have POC made for r8a77951-ulcb-kf and
> > r8a77961-salvator-xs boards. It's based on:
> > Linux-bsp kernel: 
> > git@github.com:renesas-rcar/linux-bsp.git
> > based on tag <rcar-5.0.0.rc4>
> > 
> > ATF: 
> > git@github.com:renesas-rcar/arm-trusted-firmware.git
> > based on branch <rcar_gen3_v2.5>
> > 
> > I can push those changes to Github, so you can review them
> 
> Do you plan to add support for other boards ?
> 

Right now we're working only with r8a77951 and r8a77961 boards.

> Did you discuss more in general with the linux kernel guys to see if this
> approach was agreed and will be adopted by other manufacturers ?

I didn't. I've contacted Sudeep Holla <sudeep.holla@arm.com>, who is the
maintainer of the SCMI protocol drivers. Waiting for the response.

Also we proposed to add Pinctl support to SCMI specification. It was
agreed and should be added to SCMI protocol in SCMIv3.2 (due end-2022/early 2023).

> 
> All in all I think this is a good idea but I fear that all this will actually only
> be used by one board or one manufacturer and other might use a different
> strategy, I would like to unrisk this before merging this in Xen.

The main idea was to make Xen SCMI mediator completely transparent from
the Domain point of view. So there is no Xen specific changes should be
done to OS pinctrl drivers to work through SCMI.

This means that all platforms, that already using SCMI can work with it
in virtualized system.

Also the advantage is that the devices, passed-through the
Domains, which doesn't have an access to CPG, can access to
clocks/resets and power-domains. We already have Pinctl protocol POC, so
the devices from different Domains can access pins either.

--
Oleksii.
> 
> @julien and Stefano: what is your view here ?
> 
> Cheers
> Bertrand
> 
> > 
> > Best regards,
> > Oleksii.
> > 
> >> 
> >> Regards
> >> Bertrand
> >> 
> >> 
> >>> 
> >>> Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@epam.com>
> >>> ---
> >>> xen/arch/arm/Kconfig        |   2 +
> >>> xen/arch/arm/sci/Kconfig    |  10 +
> >>> xen/arch/arm/sci/scmi_smc.c | 959 ++++++++++++++++++++++++++++++++++++
> >>> 3 files changed, 971 insertions(+)
> >>> create mode 100644 xen/arch/arm/sci/Kconfig
> >>> create mode 100644 xen/arch/arm/sci/scmi_smc.c
> >>> 
> >>> diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig
> >>> index ab07833582..3b0dfc57b6 100644
> >>> --- a/xen/arch/arm/Kconfig
> >>> +++ b/xen/arch/arm/Kconfig
> >>> @@ -123,6 +123,8 @@ config ARM_SCI
> >>> 	  support. It allows guests to control system resourcess via one of
> >>> 	  ARM_SCI mediators implemented in XEN.
> >>> 
> >>> +	source "arch/arm/sci/Kconfig"
> >>> +
> >>> endmenu
> >>> 
> >>> menu "ARM errata workaround via the alternative framework"
> >>> diff --git a/xen/arch/arm/sci/Kconfig b/xen/arch/arm/sci/Kconfig
> >>> new file mode 100644
> >>> index 0000000000..10b634d2ed
> >>> --- /dev/null
> >>> +++ b/xen/arch/arm/sci/Kconfig
> >>> @@ -0,0 +1,10 @@
> >>> +config SCMI_SMC
> >>> +	bool "Enable SCMI-SMC mediator driver"
> >>> +	default n
> >>> +	depends on ARM_SCI && HOST_DTB_EXPORT
> >>> +	---help---
> >>> +
> >>> +	Enables mediator in XEN to pass SCMI requests from Domains to ATF.
> >>> +	This feature allows drivers from Domains to work with System
> >>> +	Controllers (such as power,resets,clock etc.). SCP is used as transport
> >>> +	for communication.
> >>> diff --git a/xen/arch/arm/sci/scmi_smc.c b/xen/arch/arm/sci/scmi_smc.c
> >>> new file mode 100644
> >>> index 0000000000..103529dfab
> >>> --- /dev/null
> >>> +++ b/xen/arch/arm/sci/scmi_smc.c
> >>> @@ -0,0 +1,959 @@
> >>> +/*
> >>> + * xen/arch/arm/sci/scmi_smc.c
> >>> + *
> >>> + * SCMI mediator driver, using SCP as transport.
> >>> + *
> >>> + * Oleksii Moisieiev <oleksii_moisieiev@epam.com>
> >>> + * Copyright (C) 2021, EPAM Systems.
> >>> + *
> >>> + * This program is free software; you can redistribute it and/or modify
> >>> + * it under the terms of the GNU General Public License as published by
> >>> + * the Free Software Foundation; either version 2 of the License, or
> >>> + * (at your option) any later version.
> >>> + *
> >>> + * This program is distributed in the hope that it will be useful,
> >>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> >>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> >>> + * GNU General Public License for more details.
> >>> + */
> >>> +
> >>> +#include <asm/sci/sci.h>
> >>> +#include <asm/smccc.h>
> >>> +#include <asm/io.h>
> >>> +#include <xen/bitops.h>
> >>> +#include <xen/config.h>
> >>> +#include <xen/sched.h>
> >>> +#include <xen/device_tree.h>
> >>> +#include <xen/iocap.h>
> >>> +#include <xen/init.h>
> >>> +#include <xen/err.h>
> >>> +#include <xen/lib.h>
> >>> +#include <xen/list.h>
> >>> +#include <xen/mm.h>
> >>> +#include <xen/string.h>
> >>> +#include <xen/time.h>
> >>> +#include <xen/vmap.h>
> >>> +
> >>> +#define SCMI_BASE_PROTOCOL                  0x10
> >>> +#define SCMI_BASE_PROTOCOL_ATTIBUTES        0x1
> >>> +#define SCMI_BASE_SET_DEVICE_PERMISSIONS    0x9
> >>> +#define SCMI_BASE_RESET_AGENT_CONFIGURATION 0xB
> >>> +#define SCMI_BASE_DISCOVER_AGENT            0x7
> >>> +
> >>> +/* SCMI return codes. See section 4.1.4 of SCMI spec (DEN0056C) */
> >>> +#define SCMI_SUCCESS              0
> >>> +#define SCMI_NOT_SUPPORTED      (-1)
> >>> +#define SCMI_INVALID_PARAMETERS (-2)
> >>> +#define SCMI_DENIED             (-3)
> >>> +#define SCMI_NOT_FOUND          (-4)
> >>> +#define SCMI_OUT_OF_RANGE       (-5)
> >>> +#define SCMI_BUSY               (-6)
> >>> +#define SCMI_COMMS_ERROR        (-7)
> >>> +#define SCMI_GENERIC_ERROR      (-8)
> >>> +#define SCMI_HARDWARE_ERROR     (-9)
> >>> +#define SCMI_PROTOCOL_ERROR     (-10)
> >>> +
> >>> +#define DT_MATCH_SCMI_SMC DT_MATCH_COMPATIBLE("arm,scmi-smc")
> >>> +
> >>> +#define SCMI_SMC_ID                        "arm,smc-id"
> >>> +#define SCMI_SHARED_MEMORY                 "arm,scmi-shmem"
> >>> +#define SCMI_SHMEM                         "shmem"
> >>> +#define SCMI_SHMEM_MAPPED_SIZE             PAGE_SIZE
> >>> +
> >>> +#define HYP_CHANNEL                          0x0
> >>> +
> >>> +#define HDR_ID                             GENMASK(7,0)
> >>> +#define HDR_TYPE                           GENMASK(9, 8)
> >>> +#define HDR_PROTO                          GENMASK(17, 10)
> >>> +
> >>> +/* SCMI protocol, refer to section 4.2.2.2 (DEN0056C) */
> >>> +#define MSG_N_AGENTS_MASK                  GENMASK(15, 8)
> >>> +
> >>> +#define FIELD_GET(_mask, _reg)\
> >>> +    ((typeof(_mask))(((_reg) & (_mask)) >> (ffs64(_mask) - 1)))
> >>> +#define FIELD_PREP(_mask, _val)\
> >>> +    (((typeof(_mask))(_val) << (ffs64(_mask) - 1)) & (_mask))
> >>> +
> >>> +typedef struct scmi_msg_header {
> >>> +    uint8_t id;
> >>> +    uint8_t type;
> >>> +    uint8_t protocol;
> >>> +} scmi_msg_header_t;
> >>> +
> >>> +#define SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE   BIT(0, UL)
> >>> +#define SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR  BIT(1, UL)
> >>> +
> >>> +#define SCMI_ALLOW_ACCESS                   BIT(0, UL)
> >>> +
> >>> +struct scmi_shared_mem {
> >>> +    uint32_t reserved;
> >>> +    uint32_t channel_status;
> >>> +    uint32_t reserved1[2];
> >>> +    uint32_t flags;
> >>> +    uint32_t length;
> >>> +    uint32_t msg_header;
> >>> +    uint8_t msg_payload[];
> >>> +};
> >>> +
> >>> +struct dt_channel_addr {
> >>> +    u64 addr;
> >>> +    u64 size;
> >>> +    struct list_head list;
> >>> +};
> >>> +
> >>> +struct scmi_channel {
> >>> +    int chan_id;
> >>> +    int agent_id;
> >>> +    uint32_t func_id;
> >>> +    domid_t domain_id;
> >>> +    uint64_t paddr;
> >>> +    uint64_t len;
> >>> +    struct scmi_shared_mem *shmem;
> >>> +    spinlock_t lock;
> >>> +    struct list_head list;
> >>> +};
> >>> +
> >>> +struct scmi_data {
> >>> +    struct list_head channel_list;
> >>> +    spinlock_t channel_list_lock;
> >>> +    bool initialized;
> >>> +};
> >>> +
> >>> +static struct scmi_data scmi_data;
> >>> +
> >>> +
> >>> +/*
> >>> + * pack_scmi_header() - packs and returns 32-bit header
> >>> + *
> >>> + * @hdr: pointer to header containing all the information on message id,
> >>> + *    protocol id and type id.
> >>> + *
> >>> + * Return: 32-bit packed message header to be sent to the platform.
> >>> + */
> >>> +static inline uint32_t pack_scmi_header(scmi_msg_header_t *hdr)
> >>> +{
> >>> +    return FIELD_PREP(HDR_ID, hdr->id) |
> >>> +        FIELD_PREP(HDR_TYPE, hdr->type) |
> >>> +        FIELD_PREP(HDR_PROTO, hdr->protocol);
> >>> +}
> >>> +
> >>> +/*
> >>> + * unpack_scmi_header() - unpacks and records message and protocol id
> >>> + *
> >>> + * @msg_hdr: 32-bit packed message header sent from the platform
> >>> + * @hdr: pointer to header to fetch message and protocol id.
> >>> + */
> >>> +static inline void unpack_scmi_header(uint32_t msg_hdr, scmi_msg_header_t *hdr)
> >>> +{
> >>> +    hdr->id = FIELD_GET(HDR_ID, msg_hdr);
> >>> +    hdr->type = FIELD_GET(HDR_TYPE, msg_hdr);
> >>> +    hdr->protocol = FIELD_GET(HDR_PROTO, msg_hdr);
> >>> +}
> >>> +
> >>> +static inline int channel_is_free(struct scmi_channel *chan_info)
> >>> +{
> >>> +    return ( chan_info->shmem->channel_status
> >>> +            & SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE ) ? 0 : -EBUSY;
> >>> +}
> >>> +
> >>> +/*
> >>> + * Copy data from IO memory space to "real" memory space.
> >>> + */
> >>> +void __memcpy_fromio(void *to, const volatile void __iomem *from, size_t count)
> >>> +{
> >>> +    while (count && !IS_ALIGNED((unsigned long)from, 4)) {
> >>> +        *(u8 *)to = __raw_readb(from);
> >>> +        from++;
> >>> +        to++;
> >>> +        count--;
> >>> +    }
> >>> +
> >>> +    while (count >= 4) {
> >>> +        *(u32 *)to = __raw_readl(from);
> >>> +        from += 4;
> >>> +        to += 4;
> >>> +        count -= 4;
> >>> +    }
> >>> +
> >>> +    while (count) {
> >>> +        *(u8 *)to = __raw_readb(from);
> >>> +        from++;
> >>> +        to++;
> >>> +        count--;
> >>> +    }
> >>> +}
> >>> +
> >>> +/*
> >>> + * Copy data from "real" memory space to IO memory space.
> >>> + */
> >>> +void __memcpy_toio(volatile void __iomem *to, const void *from, size_t count)
> >>> +{
> >>> +    while (count && !IS_ALIGNED((unsigned long)to, 4)) {
> >>> +        __raw_writeb(*(u8 *)from, to);
> >>> +        from++;
> >>> +        to++;
> >>> +        count--;
> >>> +    }
> >>> +
> >>> +    while (count >= 4) {
> >>> +        __raw_writel(*(u32 *)from, to);
> >>> +        from += 4;
> >>> +        to += 4;
> >>> +        count -= 4;
> >>> +    }
> >>> +
> >>> +    while (count) {
> >>> +        __raw_writeb(*(u8 *)from, to);
> >>> +        from++;
> >>> +        to++;
> >>> +        count--;
> >>> +    }
> >>> +}
> >>> +
> >>> +static int send_smc_message(struct scmi_channel *chan_info,
> >>> +                            scmi_msg_header_t *hdr, void *data, int len)
> >>> +{
> >>> +    struct arm_smccc_res resp;
> >>> +    int ret;
> >>> +
> >>> +    if ( (len + sizeof(chan_info->shmem->msg_header)) >
> >>> +                         SCMI_SHMEM_MAPPED_SIZE )
> >>> +    {
> >>> +        printk(XENLOG_ERR
> >>> +               "scmi: Wrong size of smc message. Data is invalid\n");
> >>> +        return -EINVAL;
> >>> +    }
> >>> +
> >>> +    printk(XENLOG_DEBUG "scmi: status =%d len=%d\n",
> >>> +           chan_info->shmem->channel_status, len);
> >>> +    printk(XENLOG_DEBUG "scmi: header id = %d type = %d, proto = %d\n",
> >>> +           hdr->id, hdr->type, hdr->protocol);
> >>> +
> >>> +    ret = channel_is_free(chan_info);
> >>> +    if ( IS_ERR_VALUE(ret) )
> >>> +        return ret;
> >>> +
> >>> +    chan_info->shmem->channel_status = 0x0;
> >>> +    /* Writing 0x0 right now, but SCMI_SHMEM_FLAG_INTR_ENABLED can be set */
> >>> +    chan_info->shmem->flags = 0x0;
> >>> +    chan_info->shmem->length = sizeof(chan_info->shmem->msg_header) + len;
> >>> +    chan_info->shmem->msg_header = pack_scmi_header(hdr);
> >>> +
> >>> +    printk(XENLOG_DEBUG "scmi: Writing to shmem address %p\n",
> >>> +           chan_info->shmem);
> >>> +    if ( len > 0 && data )
> >>> +        __memcpy_toio((void *)(chan_info->shmem->msg_payload), data, len);
> >>> +
> >>> +    arm_smccc_smc(chan_info->func_id, 0, 0, 0, 0, 0, 0, chan_info->chan_id,
> >>> +                  &resp);
> >>> +
> >>> +    printk(XENLOG_DEBUG "scmi: scmccc_smc response %d\n", (int)(resp.a0));
> >>> +
> >>> +    if ( resp.a0 )
> >>> +        return -EOPNOTSUPP;
> >>> +
> >>> +    return 0;
> >>> +}
> >>> +
> >>> +static int check_scmi_status(int scmi_status)
> >>> +{
> >>> +    if ( scmi_status == SCMI_SUCCESS )
> >>> +        return 0;
> >>> +
> >>> +    printk(XENLOG_DEBUG "scmi: Error received: %d\n", scmi_status);
> >>> +
> >>> +    switch ( scmi_status )
> >>> +    {
> >>> +    case SCMI_NOT_SUPPORTED:
> >>> +        return -EOPNOTSUPP;
> >>> +    case SCMI_INVALID_PARAMETERS:
> >>> +        return -EINVAL;
> >>> +    case SCMI_DENIED:
> >>> +        return -EACCES;
> >>> +    case SCMI_NOT_FOUND:
> >>> +        return -ENOENT;
> >>> +    case SCMI_OUT_OF_RANGE:
> >>> +        return -ERANGE;
> >>> +    case SCMI_BUSY:
> >>> +        return -EBUSY;
> >>> +    case SCMI_COMMS_ERROR:
> >>> +        return -ENOTCONN;
> >>> +    case SCMI_GENERIC_ERROR:
> >>> +        return -EIO;
> >>> +    case SCMI_HARDWARE_ERROR:
> >>> +        return -ENXIO;
> >>> +    case SCMI_PROTOCOL_ERROR:
> >>> +        return -EBADMSG;
> >>> +    default:
> >>> +        return -EINVAL;
> >>> +    }
> >>> +}
> >>> +
> >>> +static int get_smc_response(struct scmi_channel *chan_info,
> >>> +                            scmi_msg_header_t *hdr, void *data, int len)
> >>> +{
> >>> +    int recv_len;
> >>> +    int ret;
> >>> +
> >>> +    printk(XENLOG_DEBUG "scmi: get smc responce msgid %d\n", hdr->id);
> >>> +
> >>> +    if ( len >= SCMI_SHMEM_MAPPED_SIZE - sizeof(chan_info->shmem) )
> >>> +    {
> >>> +        printk(XENLOG_ERR
> >>> +               "scmi: Wrong size of input smc message. Data may be invalid\n");
> >>> +        return -EINVAL;
> >>> +    }
> >>> +
> >>> +    ret = channel_is_free(chan_info);
> >>> +    if ( IS_ERR_VALUE(ret) )
> >>> +        return ret;
> >>> +
> >>> +    recv_len = chan_info->shmem->length - sizeof(chan_info->shmem->msg_header);
> >>> +
> >>> +    if ( recv_len < 0 )
> >>> +    {
> >>> +        printk(XENLOG_ERR
> >>> +               "scmi: Wrong size of smc message. Data may be invalid\n");
> >>> +        return -EINVAL;
> >>> +    }
> >>> +
> >>> +    if ( recv_len > len )
> >>> +    {
> >>> +        printk(XENLOG_ERR
> >>> +               "scmi: Not enough buffer for message %d, expecting %d\n",
> >>> +               recv_len, len);
> >>> +        return -EINVAL;
> >>> +    }
> >>> +
> >>> +    unpack_scmi_header(chan_info->shmem->msg_header, hdr);
> >>> +
> >>> +    if ( recv_len > 0 )
> >>> +    {
> >>> +        __memcpy_fromio(data, chan_info->shmem->msg_payload, recv_len);
> >>> +    }
> >>> +
> >>> +    return 0;
> >>> +}
> >>> +
> >>> +static int do_smc_xfer(struct scmi_channel *channel, scmi_msg_header_t *hdr, void *tx_data, int tx_size,
> >>> +                       void *rx_data, int rx_size)
> >>> +{
> >>> +    int ret = 0;
> >>> +
> >>> +    ASSERT( channel && channel->shmem);
> >>> +
> >>> +    if ( !hdr )
> >>> +        return -EINVAL;
> >>> +
> >>> +    spin_lock(&channel->lock);
> >>> +
> >>> +    ret = send_smc_message(channel, hdr, tx_data, tx_size);
> >>> +    if ( ret )
> >>> +        goto clean;
> >>> +
> >>> +    ret = get_smc_response(channel, hdr, rx_data, rx_size);
> >>> +clean:
> >>> +    spin_unlock(&channel->lock);
> >>> +
> >>> +    return ret;
> >>> +}
> >>> +
> >>> +static struct scmi_channel *get_channel_by_id(uint8_t chan_id)
> >>> +{
> >>> +    struct scmi_channel *curr;
> >>> +    bool found = false;
> >>> +
> >>> +    spin_lock(&scmi_data.channel_list_lock);
> >>> +    list_for_each_entry(curr, &scmi_data.channel_list, list)
> >>> +    {
> >>> +        if ( curr->chan_id == chan_id )
> >>> +        {
> >>> +            found = true;
> >>> +            break;
> >>> +        }
> >>> +    }
> >>> +
> >>> +    spin_unlock(&scmi_data.channel_list_lock);
> >>> +    if ( found )
> >>> +        return curr;
> >>> +
> >>> +    return NULL;
> >>> +}
> >>> +
> >>> +static struct scmi_channel *aquire_scmi_channel(domid_t domain_id)
> >>> +{
> >>> +    struct scmi_channel *curr;
> >>> +    bool found = false;
> >>> +
> >>> +    ASSERT(domain_id != DOMID_INVALID && domain_id >= 0);
> >>> +
> >>> +    spin_lock(&scmi_data.channel_list_lock);
> >>> +    list_for_each_entry(curr, &scmi_data.channel_list, list)
> >>> +    {
> >>> +        if ( curr->domain_id == DOMID_INVALID )
> >>> +        {
> >>> +            curr->domain_id = domain_id;
> >>> +            found = true;
> >>> +            break;
> >>> +        }
> >>> +    }
> >>> +
> >>> +    spin_unlock(&scmi_data.channel_list_lock);
> >>> +    if ( found )
> >>> +        return curr;
> >>> +
> >>> +    return NULL;
> >>> +}
> >>> +
> >>> +static void relinquish_scmi_channel(struct scmi_channel *channel)
> >>> +{
> >>> +    ASSERT(channel != NULL);
> >>> +
> >>> +    spin_lock(&scmi_data.channel_list_lock);
> >>> +    channel->domain_id = DOMID_INVALID;
> >>> +    spin_unlock(&scmi_data.channel_list_lock);
> >>> +}
> >>> +
> >>> +static int map_channel_memory(struct scmi_channel *channel)
> >>> +{
> >>> +    ASSERT( channel && channel->paddr );
> >>> +    channel->shmem = ioremap_cache(channel->paddr, SCMI_SHMEM_MAPPED_SIZE);
> >>> +    if ( !channel->shmem )
> >>> +        return -ENOMEM;
> >>> +
> >>> +    channel->shmem->channel_status = SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE;
> >>> +    printk(XENLOG_DEBUG "scmi: Got shmem after vmap %p\n", channel->shmem);
> >>> +    return 0;
> >>> +}
> >>> +
> >>> +static void unmap_channel_memory(struct scmi_channel *channel)
> >>> +{
> >>> +    ASSERT( channel && channel->shmem );
> >>> +    iounmap(channel->shmem);
> >>> +    channel->shmem = NULL;
> >>> +}
> >>> +
> >>> +static struct scmi_channel *smc_create_channel(uint8_t chan_id,
> >>> +                                               uint32_t func_id, uint64_t addr)
> >>> +{
> >>> +    struct scmi_channel *channel;
> >>> +
> >>> +    channel = get_channel_by_id(chan_id);
> >>> +    if ( channel )
> >>> +        return ERR_PTR(EEXIST);
> >>> +
> >>> +    channel = xmalloc(struct scmi_channel);
> >>> +    if ( !channel )
> >>> +        return ERR_PTR(ENOMEM);
> >>> +
> >>> +    channel->chan_id = chan_id;
> >>> +    channel->func_id = func_id;
> >>> +    channel->domain_id = DOMID_INVALID;
> >>> +    channel->shmem = NULL;
> >>> +    channel->paddr = addr;
> >>> +    spin_lock_init(&channel->lock);
> >>> +    spin_lock(&scmi_data.channel_list_lock);
> >>> +    list_add(&channel->list, &scmi_data.channel_list);
> >>> +    spin_unlock(&scmi_data.channel_list_lock);
> >>> +    return channel;
> >>> +}
> >>> +
> >>> +static int mem_permit_access(struct domain *d, uint64_t addr, uint64_t len)
> >>> +{
> >>> +    return iomem_permit_access(d, paddr_to_pfn(addr),
> >>> +                paddr_to_pfn(PAGE_ALIGN(addr + len -1)));
> >>> +}
> >>> +
> >>> +static int mem_deny_access(struct domain *d, uint64_t addr,
> >>> +                                     uint64_t len)
> >>> +{
> >>> +    return iomem_deny_access(d, paddr_to_pfn(addr),
> >>> +                paddr_to_pfn(PAGE_ALIGN(addr + len -1)));
> >>> +}
> >>> +
> >>> +static int dt_update_domain_range(uint64_t addr, uint64_t size)
> >>> +{
> >>> +    struct dt_device_node *shmem_node;
> >>> +    __be32 *hw_reg;
> >>> +    const struct dt_property *pp;
> >>> +    uint32_t len;
> >>> +
> >>> +    shmem_node = dt_find_compatible_node(NULL, NULL, SCMI_SHARED_MEMORY);
> >>> +    if ( !shmem_node )
> >>> +    {
> >>> +        printk(XENLOG_ERR "scmi: Unable to find %s node in DT\n", SCMI_SHMEM);
> >>> +        return -EINVAL;
> >>> +    }
> >>> +
> >>> +    pp = dt_find_property(shmem_node, "reg", &len);
> >>> +    if ( !pp )
> >>> +    {
> >>> +        printk(XENLOG_ERR "scmi: Unable to find regs entry in shmem node\n");
> >>> +        return -ENOENT;
> >>> +    }
> >>> +
> >>> +    hw_reg = pp->value;
> >>> +    dt_set_range(&hw_reg, shmem_node, addr, size);
> >>> +
> >>> +    return 0;
> >>> +}
> >>> +
> >>> +static void free_channel_list(void)
> >>> +{
> >>> +    struct scmi_channel *curr, *_curr;
> >>> +
> >>> +    spin_lock(&scmi_data.channel_list_lock);
> >>> +    list_for_each_entry_safe (curr, _curr, &scmi_data.channel_list, list)
> >>> +    {
> >>> +        list_del(&curr->list);
> >>> +        xfree(curr);
> >>> +    }
> >>> +
> >>> +    spin_unlock(&scmi_data.channel_list_lock);
> >>> +}
> >>> +
> >>> +static struct dt_device_node *get_dt_node_from_property(
> >>> +                struct dt_device_node *node, const char * p_name)
> >>> +{
> >>> +    const __be32 *prop;
> >>> +
> >>> +    ASSERT( node );
> >>> +
> >>> +    prop = dt_get_property(node, p_name, NULL);
> >>> +    if ( !prop )
> >>> +        return ERR_PTR(-EINVAL);
> >>> +
> >>> +    return dt_find_node_by_phandle(be32_to_cpup(prop));
> >>> +}
> >>> +
> >>> +static int get_shmem_regions(struct list_head *head, u64 hyp_addr)
> >>> +{
> >>> +    struct dt_device_node *node;
> >>> +    int ret;
> >>> +    struct dt_channel_addr *lchan;
> >>> +    u64 laddr, lsize;
> >>> +
> >>> +    node = dt_find_compatible_node(NULL, NULL, SCMI_SHARED_MEMORY);
> >>> +    if ( !node )
> >>> +        return -ENOENT;
> >>> +
> >>> +    while ( node )
> >>> +    {
> >>> +        ret = dt_device_get_address(node, 0, &laddr, &lsize);
> >>> +        if ( ret )
> >>> +            return ret;
> >>> +
> >>> +        if ( laddr != hyp_addr )
> >>> +        {
> >>> +            lchan = xmalloc(struct dt_channel_addr);
> >>> +            if ( !lchan )
> >>> +                return -ENOMEM;
> >>> +            lchan->addr = laddr;
> >>> +            lchan->size = lsize;
> >>> +
> >>> +            list_add_tail(&lchan->list, head);
> >>> +        }
> >>> +
> >>> +        node = dt_find_compatible_node(node, NULL, SCMI_SHARED_MEMORY);
> >>> +    }
> >>> +
> >>> +    return 0;
> >>> +}
> >>> +
> >>> +static int read_hyp_channel_addr(struct dt_device_node *scmi_node,
> >>> +                                 u64 *addr, u64 *size)
> >>> +{
> >>> +    struct dt_device_node *shmem_node;
> >>> +    shmem_node = get_dt_node_from_property(scmi_node, "shmem");
> >>> +    if ( IS_ERR_OR_NULL(shmem_node) )
> >>> +    {
> >>> +        printk(XENLOG_ERR
> >>> +               "scmi: Device tree error, can't parse reserved memory %ld\n",
> >>> +               PTR_ERR(shmem_node));
> >>> +        return PTR_ERR(shmem_node);
> >>> +    }
> >>> +
> >>> +    return dt_device_get_address(shmem_node, 0, addr, size);
> >>> +}
> >>> +
> >>> +static void free_shmem_regions(struct list_head *addr_list)
> >>> +{
> >>> +    struct dt_channel_addr *curr, *_curr;
> >>> +
> >>> +    list_for_each_entry_safe (curr, _curr, addr_list, list)
> >>> +    {
> >>> +        list_del(&curr->list);
> >>> +        xfree(curr);
> >>> +    }
> >>> +}
> >>> +
> >>> +static __init bool scmi_probe(struct dt_device_node *scmi_node)
> >>> +{
> >>> +    u64 addr, size;
> >>> +    int ret, i;
> >>> +    struct scmi_channel *channel, *agent_channel;
> >>> +    int n_agents;
> >>> +    scmi_msg_header_t hdr;
> >>> +    struct rx_t {
> >>> +        int32_t status;
> >>> +        uint32_t attributes;
> >>> +    } rx;
> >>> +    struct dt_channel_addr *entry;
> >>> +    struct list_head addr_list;
> >>> +
> >>> +    uint32_t func_id;
> >>> +
> >>> +    ASSERT(scmi_node != NULL);
> >>> +
> >>> +    INIT_LIST_HEAD(&scmi_data.channel_list);
> >>> +    spin_lock_init(&scmi_data.channel_list_lock);
> >>> +
> >>> +    if ( !dt_property_read_u32(scmi_node, SCMI_SMC_ID, &func_id) )
> >>> +    {
> >>> +        printk(XENLOG_ERR "scmi: Unable to read smc-id from DT\n");
> >>> +        return false;
> >>> +    }
> >>> +
> >>> +    ret = read_hyp_channel_addr(scmi_node, &addr, &size);
> >>> +    if ( IS_ERR_VALUE(ret) )
> >>> +        return false;
> >>> +
> >>> +    if ( !IS_ALIGNED(size, SCMI_SHMEM_MAPPED_SIZE) )
> >>> +    {
> >>> +        printk(XENLOG_ERR "scmi: Reserved memory is not aligned\n");
> >>> +        return false;
> >>> +    }
> >>> +
> >>> +    INIT_LIST_HEAD(&addr_list);
> >>> +
> >>> +    ret = get_shmem_regions(&addr_list, addr);
> >>> +    if ( IS_ERR_VALUE(ret) )
> >>> +        goto out;
> >>> +
> >>> +    channel = smc_create_channel(HYP_CHANNEL, func_id, addr);
> >>> +    if ( IS_ERR(channel) )
> >>> +        goto out;
> >>> +
> >>> +    ret = map_channel_memory(channel);
> >>> +    if ( ret )
> >>> +        goto out;
> >>> +
> >>> +    spin_lock(&scmi_data.channel_list_lock);
> >>> +    channel->domain_id = DOMID_XEN;
> >>> +    spin_unlock(&scmi_data.channel_list_lock);
> >>> +
> >>> +    hdr.id = SCMI_BASE_PROTOCOL_ATTIBUTES;
> >>> +    hdr.type = 0;
> >>> +    hdr.protocol = SCMI_BASE_PROTOCOL;
> >>> +
> >>> +    ret = do_smc_xfer(channel, &hdr, NULL, 0, &rx, sizeof(rx));
> >>> +    if ( ret )
> >>> +        goto error;
> >>> +
> >>> +    ret = check_scmi_status(rx.status);
> >>> +    if ( ret )
> >>> +        goto error;
> >>> +
> >>> +    n_agents = FIELD_GET(MSG_N_AGENTS_MASK, rx.attributes);
> >>> +    printk(XENLOG_DEBUG "scmi: Got agent count %d\n", n_agents);
> >>> +
> >>> +    i = 1;
> >>> +    list_for_each_entry(entry, &addr_list, list)
> >>> +    {
> >>> +        uint32_t tx_agent_id = 0xFFFFFFFF;
> >>> +        struct {
> >>> +            int32_t status;
> >>> +            uint32_t agent_id;
> >>> +            char name[16];
> >>> +        } da_rx;
> >>> +
> >>> +        agent_channel = smc_create_channel(i, func_id,
> >>> +                                           entry->addr);
> >>> +        if ( IS_ERR(agent_channel) )
> >>> +        {
> >>> +            ret = PTR_ERR(agent_channel);
> >>> +            goto error;
> >>> +        }
> >>> +
> >>> +        ret = map_channel_memory(agent_channel);
> >>> +        if ( ret )
> >>> +            goto error;
> >>> +
> >>> +        hdr.id = SCMI_BASE_DISCOVER_AGENT;
> >>> +        hdr.type = 0;
> >>> +        hdr.protocol = SCMI_BASE_PROTOCOL;
> >>> +
> >>> +        ret = do_smc_xfer(agent_channel, &hdr, &tx_agent_id,
> >>> +                          sizeof(tx_agent_id), &da_rx, sizeof(da_rx));
> >>> +        if ( ret )
> >>> +        {
> >>> +            unmap_channel_memory(agent_channel);
> >>> +            goto error;
> >>> +        }
> >>> +
> >>> +        unmap_channel_memory(agent_channel);
> >>> +
> >>> +        ret = check_scmi_status(da_rx.status);
> >>> +        if ( ret )
> >>> +            goto error;
> >>> +
> >>> +        printk(XENLOG_DEBUG "scmi: status=0x%x id=0x%x name=%s\n",
> >>> +                da_rx.status, da_rx.agent_id, da_rx.name);
> >>> +
> >>> +        agent_channel->agent_id = da_rx.agent_id;
> >>> +
> >>> +        if ( i == n_agents )
> >>> +            break;
> >>> +
> >>> +        i++;
> >>> +    }
> >>> +
> >>> +    scmi_data.initialized = true;
> >>> +    goto out;
> >>> +
> >>> +error:
> >>> +    unmap_channel_memory(channel);
> >>> +    free_channel_list();
> >>> +out:
> >>> +    free_shmem_regions(&addr_list);
> >>> +    return ret == 0;
> >>> +}
> >>> +
> >>> +static int scmi_domain_init(struct domain *d,
> >>> +                           struct xen_arch_domainconfig *config)
> >>> +{
> >>> +    struct scmi_channel *channel;
> >>> +    int ret;
> >>> +
> >>> +    if ( !scmi_data.initialized )
> >>> +        return 0;
> >>> +
> >>> +    printk(XENLOG_INFO "scmi: domain_id = %d\n", d->domain_id);
> >>> +
> >>> +    channel = aquire_scmi_channel(d->domain_id);
> >>> +    if ( IS_ERR_OR_NULL(channel) )
> >>> +        return -ENOENT;
> >>> +
> >>> +#ifdef CONFIG_ARM_32
> >>> +    printk(XENLOG_INFO
> >>> +           "scmi: Aquire SCMI channel id = 0x%x , domain_id = %d paddr = 0x%llx\n",
> >>> +           channel->chan_id, channel->domain_id, channel->paddr);
> >>> +#else
> >>> +    printk(XENLOG_INFO
> >>> +           "scmi: Aquire SCMI channel id = 0x%x , domain_id = %d paddr = 0x%lx\n",
> >>> +           channel->chan_id, channel->domain_id, channel->paddr);
> >>> +#endif
> >>> +
> >>> +    if ( is_hardware_domain(d) )
> >>> +    {
> >>> +        ret = mem_permit_access(d, channel->paddr, PAGE_SIZE);
> >>> +        if ( IS_ERR_VALUE(ret) )
> >>> +            goto error;
> >>> +
> >>> +        ret = dt_update_domain_range(channel->paddr, PAGE_SIZE);
> >>> +        if ( IS_ERR_VALUE(ret) )
> >>> +        {
> >>> +            int rc = mem_deny_access(d, channel->paddr, PAGE_SIZE);
> >>> +            if ( rc )
> >>> +                printk(XENLOG_ERR "Unable to mem_deny_access\n");
> >>> +
> >>> +            goto error;
> >>> +        }
> >>> +    }
> >>> +
> >>> +    d->arch.sci = channel;
> >>> +    if ( config )
> >>> +        config->arm_sci_agent_paddr = channel->paddr;
> >>> +
> >>> +    return 0;
> >>> +error:
> >>> +    relinquish_scmi_channel(channel);
> >>> +
> >>> +    return ret;
> >>> +}
> >>> +
> >>> +static int scmi_add_device_by_devid(struct domain *d, uint32_t scmi_devid)
> >>> +{
> >>> +    struct scmi_channel *channel, *agent_channel;
> >>> +    scmi_msg_header_t hdr;
> >>> +    struct scmi_perms_tx {
> >>> +        uint32_t agent_id;
> >>> +        uint32_t device_id;
> >>> +        uint32_t flags;
> >>> +    } tx;
> >>> +    struct rx_t {
> >>> +        int32_t status;
> >>> +        uint32_t attributes;
> >>> +    } rx;
> >>> +    int ret;
> >>> +
> >>> +    if ( !scmi_data.initialized )
> >>> +        return 0;
> >>> +
> >>> +    printk(XENLOG_DEBUG "scmi: scmi_devid = %d\n", scmi_devid);
> >>> +
> >>> +    agent_channel = d->arch.sci;
> >>> +    if ( IS_ERR_OR_NULL(agent_channel) )
> >>> +        return PTR_ERR(agent_channel);
> >>> +
> >>> +    channel = get_channel_by_id(HYP_CHANNEL);
> >>> +    if ( IS_ERR_OR_NULL(channel) )
> >>> +        return PTR_ERR(channel);
> >>> +
> >>> +    hdr.id = SCMI_BASE_SET_DEVICE_PERMISSIONS;
> >>> +    hdr.type = 0;
> >>> +    hdr.protocol = SCMI_BASE_PROTOCOL;
> >>> +
> >>> +    tx.agent_id = agent_channel->agent_id;
> >>> +    tx.device_id = scmi_devid;
> >>> +    tx.flags = SCMI_ALLOW_ACCESS;
> >>> +
> >>> +    ret = do_smc_xfer(channel, &hdr, &tx, sizeof(tx), &rx, sizeof(&rx));
> >>> +    if ( IS_ERR_VALUE(ret) )
> >>> +        return ret;
> >>> +
> >>> +    ret = check_scmi_status(rx.status);
> >>> +    if ( IS_ERR_VALUE(ret) )
> >>> +        return ret;
> >>> +
> >>> +    return 0;
> >>> +}
> >>> +
> >>> +static int scmi_add_dt_device(struct domain *d, struct dt_device_node *dev)
> >>> +{
> >>> +    uint32_t scmi_devid;
> >>> +
> >>> +    if ( (!scmi_data.initialized) || (!d->arch.sci) )
> >>> +        return 0;
> >>> +
> >>> +    if ( !dt_property_read_u32(dev, "scmi_devid", &scmi_devid) )
> >>> +        return 0;
> >>> +
> >>> +    printk(XENLOG_INFO "scmi: dt_node = %s\n", dt_node_full_name(dev));
> >>> +
> >>> +    return scmi_add_device_by_devid(d, scmi_devid);
> >>> +}
> >>> +
> >>> +static int scmi_relinquish_resources(struct domain *d)
> >>> +{
> >>> +    int ret;
> >>> +    struct scmi_channel *channel, *agent_channel;
> >>> +    scmi_msg_header_t hdr;
> >>> +    struct reset_agent_tx {
> >>> +        uint32_t agent_id;
> >>> +        uint32_t flags;
> >>> +    } tx;
> >>> +    uint32_t rx;
> >>> +
> >>> +    if ( !d->arch.sci )
> >>> +        return 0;
> >>> +
> >>> +    agent_channel = d->arch.sci;
> >>> +
> >>> +    spin_lock(&agent_channel->lock);
> >>> +    tx.agent_id = agent_channel->agent_id;
> >>> +    spin_unlock(&agent_channel->lock);
> >>> +
> >>> +    channel = get_channel_by_id(HYP_CHANNEL);
> >>> +    if ( !channel )
> >>> +    {
> >>> +        printk(XENLOG_ERR
> >>> +               "scmi: Unable to get Hypervisor scmi channel for domain %d\n",
> >>> +               d->domain_id);
> >>> +        return -EINVAL;
> >>> +    }
> >>> +
> >>> +    hdr.id = SCMI_BASE_RESET_AGENT_CONFIGURATION;
> >>> +    hdr.type = 0;
> >>> +    hdr.protocol = SCMI_BASE_PROTOCOL;
> >>> +
> >>> +    tx.flags = 0;
> >>> +
> >>> +    ret = do_smc_xfer(channel, &hdr, &tx, sizeof(tx), &rx, sizeof(rx));
> >>> +    if ( ret )
> >>> +        return ret;
> >>> +
> >>> +    ret = check_scmi_status(rx);
> >>> +
> >>> +    return ret;
> >>> +}
> >>> +
> >>> +static void scmi_domain_destroy(struct domain *d)
> >>> +{
> >>> +    struct scmi_channel *channel;
> >>> +
> >>> +    if ( !d->arch.sci )
> >>> +        return;
> >>> +
> >>> +    channel = d->arch.sci;
> >>> +    spin_lock(&channel->lock);
> >>> +
> >>> +    relinquish_scmi_channel(channel);
> >>> +    printk(XENLOG_DEBUG "scmi: Free domain %d\n", d->domain_id);
> >>> +
> >>> +    d->arch.sci = NULL;
> >>> +
> >>> +    mem_deny_access(d, channel->paddr, PAGE_SIZE);
> >>> +    spin_unlock(&channel->lock);
> >>> +}
> >>> +
> >>> +static bool scmi_handle_call(struct domain *d, void *args)
> >>> +{
> >>> +    bool res = false;
> >>> +    struct scmi_channel *agent_channel;
> >>> +    struct arm_smccc_res resp;
> >>> +    struct cpu_user_regs *regs = args;
> >>> +
> >>> +    if ( !d->arch.sci )
> >>> +        return false;
> >>> +
> >>> +    agent_channel = d->arch.sci;
> >>> +    spin_lock(&agent_channel->lock);
> >>> +
> >>> +    if ( agent_channel->func_id != regs->r0 )
> >>> +    {
> >>> +        res = false;
> >>> +        goto unlock;
> >>> +    }
> >>> +
> >>> +    arm_smccc_smc(agent_channel->func_id, 0, 0, 0, 0, 0, 0,
> >>> +                  agent_channel->chan_id, &resp);
> >>> +
> >>> +    set_user_reg(regs, 0, resp.a0);
> >>> +    set_user_reg(regs, 1, resp.a1);
> >>> +    set_user_reg(regs, 2, resp.a2);
> >>> +    set_user_reg(regs, 3, resp.a3);
> >>> +    res = true;
> >>> +unlock:
> >>> +    spin_unlock(&agent_channel->lock);
> >>> +
> >>> +    return res;
> >>> +}
> >>> +
> >>> +static const struct dt_device_match scmi_smc_match[] __initconst =
> >>> +{
> >>> +    DT_MATCH_SCMI_SMC,
> >>> +    { /* sentinel */ },
> >>> +};
> >>> +
> >>> +static const struct sci_mediator_ops scmi_ops =
> >>> +{
> >>> +    .probe = scmi_probe,
> >>> +    .domain_init = scmi_domain_init,
> >>> +    .domain_destroy = scmi_domain_destroy,
> >>> +    .add_dt_device = scmi_add_dt_device,
> >>> +    .relinquish_resources = scmi_relinquish_resources,
> >>> +    .handle_call = scmi_handle_call,
> >>> +};
> >>> +
> >>> +REGISTER_SCI_MEDIATOR(scmi_smc, "SCMI-SMC", XEN_DOMCTL_CONFIG_ARM_SCI_SCMI_SMC,
> >>> +                      scmi_smc_match, &scmi_ops);
> >>> +
> >>> +/*
> >>> + * Local variables:
> >>> + * mode: C
> >>> + * c-file-style: "BSD"
> >>> + * c-basic-offset: 4
> >>> + * indent-tabs-mode: nil
> >>> + * End:
> >>> + */
> >>> -- 
> >>> 2.27.0
> 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [RFC v2 1/8] xen/hypfs: support fo nested dynamic hypfs nodes
  2022-02-11  8:16     ` Oleksii Moisieiev
@ 2022-02-11 13:28       ` Juergen Gross
  2022-02-11 13:32         ` Oleksii Moisieiev
  0 siblings, 1 reply; 45+ messages in thread
From: Juergen Gross @ 2022-02-11 13:28 UTC (permalink / raw)
  To: Oleksii Moisieiev; +Cc: xen-devel


[-- Attachment #1.1.1: Type: text/plain, Size: 4037 bytes --]

On 11.02.22 09:16, Oleksii Moisieiev wrote:
> Hi Juergen,
> 
> On Thu, Feb 10, 2022 at 08:34:08AM +0100, Juergen Gross wrote:
>> On 08.02.22 19:00, Oleksii Moisieiev wrote:
>>
> 
>>> Add new api:
>>> - hypfs_read_dyndir_entry
>>> - hypfs_gen_dyndir_entry
>>> which are the extension of the dynamic hypfs nodes support, presented in
>>> 0b3b53be8cf226d947a79c2535a9efbb2dd7bc38.
>>> This allows nested dynamic nodes to be added. Also input parameter is
>>> hypfs_entry, so properties can also be generated dynamically.
>>>
>>> Generating mixed list of dirs and properties is also supported.
>>> Same as to the dynamic hypfs nodes, this is anchored in percpu pointer,
>>> which can be retriewed on any level of the dynamic entries.
>>> This handle should be allocated on enter() callback and released on
>>> exit() callback. When using nested dynamic dirs and properties handle
>>> should be allocated on the first enter() call and released on the last
>>> exit() call.
>>>
>>> Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@epam.com>

...

>>> diff --git a/xen/include/xen/hypfs.h b/xen/include/xen/hypfs.h
>>> index e9d4c2555b..5d2728b963 100644
>>> --- a/xen/include/xen/hypfs.h
>>> +++ b/xen/include/xen/hypfs.h
>>> @@ -79,8 +79,8 @@ struct hypfs_entry_dir {
>>>    struct hypfs_dyndir_id {
>>
>> Please rename to struct hypfs_dyndir.
> 
> Ok, thanks.
> 
>>
>>>        struct hypfs_entry_dir dir;             /* Modified copy of template. */
>>>        struct hypfs_funcs funcs;               /* Dynamic functions. */
>>> -    const struct hypfs_entry_dir *template; /* Template used. */
>>> -#define HYPFS_DYNDIR_ID_NAMELEN 12
>>> +    const struct hypfs_entry *template; /* Template used. */
>>> +#define HYPFS_DYNDIR_ID_NAMELEN 32
>>>        char name[HYPFS_DYNDIR_ID_NAMELEN];     /* Name of hypfs entry. */
>>>        unsigned int id;                        /* Numerical id. */
>>
>> What about the following change instead:
>>
>> -    const struct hypfs_entry_dir *template; /* Template used. */
>> -#define HYPFS_DYNDIR_ID_NAMELEN 12
>> -    char name[HYPFS_DYNDIR_ID_NAMELEN];     /* Name of hypfs entry. */
>> -
>> -    unsigned int id;                        /* Numerical id. */
>> -    void *data;                             /* Data associated with id. */
>> +    const struct hypfs_entry *template;  /* Template used. */
>> +    union {
>> +#define HYPFS_DYNDIR_NAMELEN    32
>> +        char name[HYPFS_DYNDIR_NAMELEN]; /* Name of hypfs entry. */
>> +        struct {
>> +#define HYPFS_DYNDIR_ID_NAMELEN 12
>> +            char name[HYPFS_DYNDIR_ID_NAMELEN]; /* Name of id entry. */
>> +            unsigned int id;                    /* Numerical id. */
>> +        } id;
>> +    };
>> +    void*data;                          /* Data associated with entry. */
>>
> 
> I'm not sure I see the benefit from this union. The only one I see is
> that struct hypds_dyndir will be smaller by sizeof(unsigned int).
> Could you explain please?

My main concern is that it is not obvious to a user that the
numerical id is needed only for a special case. Putting it into
the union makes this much more clear.

> 
> Also what do you think about the following change:
> -    char name[HYPFS_DYNDIR_ID_NAMELEN];     /* Name of hypfs entry. */
> -
> -    unsigned int id;                        /* Numerical id. */
> -    void *data;                             /* Data associated with id. */
> +    char name[HYPFS_DYNDIR_ID_NAMELEN];     /* Name of hypfs entry. */
> +
> +    unsigned int id;                        /* Numerical id. */
> +    union {
> +       const void *content;
> +       void *data;                             /* Data associated with id. */
> +    }
> This change is similar to the hypfs_entry_leaf. In this case we can
> store const pointer for read-only entries and use data when write access
> is needed?

Sure, if you need that.

> 
> PS: I will address all your comments in v3.

Thanks,


Juergen

[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 3149 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 495 bytes --]

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [RFC v2 1/8] xen/hypfs: support fo nested dynamic hypfs nodes
  2022-02-11 13:28       ` Juergen Gross
@ 2022-02-11 13:32         ` Oleksii Moisieiev
  0 siblings, 0 replies; 45+ messages in thread
From: Oleksii Moisieiev @ 2022-02-11 13:32 UTC (permalink / raw)
  To: Juergen Gross; +Cc: xen-devel

On Fri, Feb 11, 2022 at 02:28:49PM +0100, Juergen Gross wrote:
> On 11.02.22 09:16, Oleksii Moisieiev wrote:
> > Hi Juergen,
> > 
> > On Thu, Feb 10, 2022 at 08:34:08AM +0100, Juergen Gross wrote:
> > > On 08.02.22 19:00, Oleksii Moisieiev wrote:
> > > 
> > 
> > > > Add new api:
> > > > - hypfs_read_dyndir_entry
> > > > - hypfs_gen_dyndir_entry
> > > > which are the extension of the dynamic hypfs nodes support, presented in
> > > > 0b3b53be8cf226d947a79c2535a9efbb2dd7bc38.
> > > > This allows nested dynamic nodes to be added. Also input parameter is
> > > > hypfs_entry, so properties can also be generated dynamically.
> > > > 
> > > > Generating mixed list of dirs and properties is also supported.
> > > > Same as to the dynamic hypfs nodes, this is anchored in percpu pointer,
> > > > which can be retriewed on any level of the dynamic entries.
> > > > This handle should be allocated on enter() callback and released on
> > > > exit() callback. When using nested dynamic dirs and properties handle
> > > > should be allocated on the first enter() call and released on the last
> > > > exit() call.
> > > > 
> > > > Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@epam.com>
> 
> ...
> 
> > > > diff --git a/xen/include/xen/hypfs.h b/xen/include/xen/hypfs.h
> > > > index e9d4c2555b..5d2728b963 100644
> > > > --- a/xen/include/xen/hypfs.h
> > > > +++ b/xen/include/xen/hypfs.h
> > > > @@ -79,8 +79,8 @@ struct hypfs_entry_dir {
> > > >    struct hypfs_dyndir_id {
> > > 
> > > Please rename to struct hypfs_dyndir.
> > 
> > Ok, thanks.
> > 
> > > 
> > > >        struct hypfs_entry_dir dir;             /* Modified copy of template. */
> > > >        struct hypfs_funcs funcs;               /* Dynamic functions. */
> > > > -    const struct hypfs_entry_dir *template; /* Template used. */
> > > > -#define HYPFS_DYNDIR_ID_NAMELEN 12
> > > > +    const struct hypfs_entry *template; /* Template used. */
> > > > +#define HYPFS_DYNDIR_ID_NAMELEN 32
> > > >        char name[HYPFS_DYNDIR_ID_NAMELEN];     /* Name of hypfs entry. */
> > > >        unsigned int id;                        /* Numerical id. */
> > > 
> > > What about the following change instead:
> > > 
> > > -    const struct hypfs_entry_dir *template; /* Template used. */
> > > -#define HYPFS_DYNDIR_ID_NAMELEN 12
> > > -    char name[HYPFS_DYNDIR_ID_NAMELEN];     /* Name of hypfs entry. */
> > > -
> > > -    unsigned int id;                        /* Numerical id. */
> > > -    void *data;                             /* Data associated with id. */
> > > +    const struct hypfs_entry *template;  /* Template used. */
> > > +    union {
> > > +#define HYPFS_DYNDIR_NAMELEN    32
> > > +        char name[HYPFS_DYNDIR_NAMELEN]; /* Name of hypfs entry. */
> > > +        struct {
> > > +#define HYPFS_DYNDIR_ID_NAMELEN 12
> > > +            char name[HYPFS_DYNDIR_ID_NAMELEN]; /* Name of id entry. */
> > > +            unsigned int id;                    /* Numerical id. */
> > > +        } id;
> > > +    };
> > > +    void*data;                          /* Data associated with entry. */
> > > 
> > 
> > I'm not sure I see the benefit from this union. The only one I see is
> > that struct hypds_dyndir will be smaller by sizeof(unsigned int).
> > Could you explain please?
> 
> My main concern is that it is not obvious to a user that the
> numerical id is needed only for a special case. Putting it into
> the union makes this much more clear.
> 

This make sense. I'll make this union. Thanks.

> > 
> > Also what do you think about the following change:
> > -    char name[HYPFS_DYNDIR_ID_NAMELEN];     /* Name of hypfs entry. */
> > -
> > -    unsigned int id;                        /* Numerical id. */
> > -    void *data;                             /* Data associated with id. */
> > +    char name[HYPFS_DYNDIR_ID_NAMELEN];     /* Name of hypfs entry. */
> > +
> > +    unsigned int id;                        /* Numerical id. */
> > +    union {
> > +       const void *content;
> > +       void *data;                             /* Data associated with id. */
> > +    }
> > This change is similar to the hypfs_entry_leaf. In this case we can
> > store const pointer for read-only entries and use data when write access
> > is needed?
> 
> Sure, if you need that.

Thanks I will do this as well.

Best regards,
Oleksii
> 
> > 
> > PS: I will address all your comments in v3.
> 
> Thanks,
> 
> 
> Juergen






^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [RFC v2 5/8] xen/arm: introduce SCMI-SMC mediator driver
  2022-02-11 11:55         ` Oleksii Moisieiev
@ 2022-02-11 23:35           ` Stefano Stabellini
  0 siblings, 0 replies; 45+ messages in thread
From: Stefano Stabellini @ 2022-02-11 23:35 UTC (permalink / raw)
  To: Oleksii Moisieiev
  Cc: Bertrand Marquis, xen-devel, Stefano Stabellini, Julien Grall,
	Volodymyr Babchuk

[-- Attachment #1: Type: text/plain, Size: 10121 bytes --]

On Fri, 11 Feb 2022, Oleksii Moisieiev wrote:
> On Fri, Feb 11, 2022 at 11:18:47AM +0000, Bertrand Marquis wrote:
> > Hi Oleksii,
> > 
> > 
> > > On 11 Feb 2022, at 10:44, Oleksii Moisieiev <Oleksii_Moisieiev@epam.com> wrote:
> > > 
> > > Hi Bertrand,
> > > 
> > > On Fri, Feb 11, 2022 at 08:46:05AM +0000, Bertrand Marquis wrote:
> > >> Hi Oleksii,
> > >> 
> > >> 
> > >>> On 8 Feb 2022, at 18:00, Oleksii Moisieiev <Oleksii_Moisieiev@epam.com> wrote:
> > >>> 
> > >>> This is the implementation of SCI interface, called SCMI-SMC driver,
> > >>> which works as the mediator between XEN Domains and Firmware (SCP, ATF etc).
> > >>> This allows devices from the Domains to work with clocks, resets and
> > >>> power-domains without access to CPG.
> > >>> 
> > >>> Originally, cpg should be passed to the domain so it can work with
> > >>> power-domains/clocks/resets etc. Considering that cpg can't be split between
> > >>> the Domains, we get the limitation that the devices, which are using
> > >>> power-domains/clocks/resets etc, couldn't be split between the domains.
> > >>> The solution is to move the power-domain/clock/resets etc to the
> > >>> Firmware (such as SCP firmware or ATF) and provide interface for the
> > >>> Domains. XEN should have an entity, caled SCI-Mediator, which is
> > >>> responsible for messages redirection between Domains and Firmware and
> > >>> for permission handling.
> > >>> 
> > >>> The following features are implemented:
> > >>> - request SCMI channels from ATF and pass channels to Domains;
> > >>> - set device permissions for Domains based on the Domain partial
> > >>> device-tree. Devices with permissions are able to work with clocks,
> > >>> resets and power-domains via SCMI;
> > >>> - redirect scmi messages from Domains to ATF.
> > >> 
> > >> Before going more deeply in the code I would like to discuss the general
> > >> design here and ask some questions to prevent to rework the code before
> > >> we all agree that this is the right solution and that we want this in Xen.
> > >> 
> > >> First I want to point out that clock/reset/power virtualization is a problem
> > >> on most applications using device pass-through and I am very glad that
> > >> someone is looking into it.
> > >> Also SCMI is the current standard existing for this so relying on it is a very
> > >> good idea.
> > >> 
> > >> Latest version SCMI standard (DEN0056D v3.1) is defining some means
> > >> to use SCMI on a virtualised system. In chapter 4.2.1, the standard
> > >> recommends to set permissions per agent in the hypervisor so that a VM
> > >> could later use the discovery protocol to detect the resources and use them.
> > >> Using this kind of scenario the mediator in Xen would just configure the
> > >> Permissions in the SCMI and would then rely on it to limit what is possible
> > >> by who just by just assigning a channel to a VM.
> > > 
> > >> 
> > >> In your current design (please correct me if I am wrong) you seem to fully
> > >> rely on Xen and the FDT for discovery and permission.
> > > 
> > > In current implementation Xen is the trusted agent. And it's responsible
> > > for permissions setting. During initialization it discovers agent and
> > > set permissions by using BASE_SET_DEVICE_PERMISSIONS to the Dom0. When
> > > new domain is created, Xen assigns agent id for this domain and request
> > > resources, that are passed-through to this Domain.
> > 
> > Ok
> > 
> > > 
> > > I'm getting the follwing information from FDT:
> > > 1) Shared memory addressed, which should be used for agents. During
> > > initialization I send BASE_DISCOVER_AGENT to each of this addresses and
> > > receive agent_id. Xen is responsible for assigning agent_id for the
> > > Domain. Then Xen intercept smc calls from the domain, set agent_id and
> > > redirects it to the Firmware.
> > 
> > So Xen is setting the agent ID, no way for a guest to get access to something it
> > should with more check, am I right ?
> > 
> 
> Yes. Xen is the only entity, which is trusted. So it's responsible for
> setting permissions and assigning agent_id. Guest get's an access only
> for the devices it's allowed to.
> 
> > > 
> > > 2) Devices, that are using SCMI. Those devices has clock/power/resets
> > > etc related to scmi protocol (as it is done in Linux kernel)
> > > and scmi_devid should be set. I'm currently preparing to send patch,
> > > updating kernel bindings with this parameter to Linux kernel.
> > > scmi_devid value should match device id, set in the Firmware.
> > > dt example:
> > > &usb0 {
> > >    scmi_devid = <1>; // usb0 device id
> > >    clocks = <&scmi_clock 1> // relays on clock with id 1
> > > }
> > > 
> > > Xen requests permission for the device when device is attached to the
> > > Domain during creation.
> > 
> > Without this, how is (if it is) the linux kernel using SCMI for power management ?
> 
> Here is how it should be desribed in FDT: 
> /
> {
>     firmware {
>         scmi {
>             arm,smc-id = <0x82000002>;
>             scmi_power: protocol@11 {
>                 reg = <0x11>;
>                 #power-domain-cells = <1>;
>             };
>             ...
>             scmi_clock: protocol@14 {
>             ...
>             scmi_reset: protocol@16 {
>             ...
>         };
>     };
> };
> 
> &avb {
>     scmi_devid = <0>; // Matches Etherned device_id in Firmware
>     clocks = <&scmi_clock 0>;
>     power-domains = <&scmi_power 0>;
>     resets = <&scmi_reset 0>;
> };
> 
> In the provided case devid equals to reset, clock and power-domain id,
> but this is conicidence. Each clock/power-domain/reset parameter can
> have more than one entity.
> Also - no changes was done to linux kernel scmi drivers.
> 
> > 
> > > 
> > >> Wouldn’t it be a better idea to use the protocol fully ?
> > > 
> > > Hm, I was thinking I am using the protocol fully. Did I miss something?
> > 
> > Sorry you seem to be, my understanding of your design was not right.
> > 
> > > 
> > >> Could we get rid of some of the FDT dependencies by using the discovery
> > >> system of SCMI ?
> > > 
> > > I'm using FDT to get shmem regions for the channels. Then I send
> > > BASE_DISCOVER_AGENT to each region and getting agent data. Did I use the
> > > discovery system wrong?
> > 
> > After more digging it seems you are. The link between scmi resource and device
> > is not possible to get automatically.
> > 
> > > 
> > >> How is Linux doing this currently ? Is it relying on device tree to discover
> > >> the SCMI resources ?
> > > 
> > > Yes. Linux kernel has 2 nodes in the device-tree: arm,scmi-shmem, which
> > > includes memory region for the communication and arm,scmi-smc node,
> > > which describes all data related to scmi ( func_id, protocols etc)
> > > Then the device nodes refer to the protocols by setting
> > > clock/resets/power-domains etc. Please see the example above.
> > > BASE_DISCOVER_AGENT is not used in Linux kernel.
> > > The main idea was that scmi related changes to the device-tree are
> > > common for virtualized and non virtualized systems. So the same FDT
> > > configuration should work with of without Xen.
> > 
> > So at this stage this is not supported in Linux and you plan to add support for it to.
> > 
> 
> Yes. That's correct. I've already prepared patch which should update
> linux kernel device-tree bindings.
> 
> > > 
> > >> 
> > >> Also I understand that you rely on some entries to be declared in the device
> > >> tree and also some support to be implemented in ATF or SCP. I checked in
> > >> The boards I have access to and the device trees but none of this seem to
> > >> be supported there. Could you tell which board/configuration/ATF you are
> > >> using so that the implementation could be tested/validated ?
> > >> 
> > > 
> > > We're currently have POC made for r8a77951-ulcb-kf and
> > > r8a77961-salvator-xs boards. It's based on:
> > > Linux-bsp kernel: 
> > > git@github.com:renesas-rcar/linux-bsp.git
> > > based on tag <rcar-5.0.0.rc4>
> > > 
> > > ATF: 
> > > git@github.com:renesas-rcar/arm-trusted-firmware.git
> > > based on branch <rcar_gen3_v2.5>
> > > 
> > > I can push those changes to Github, so you can review them
> > 
> > Do you plan to add support for other boards ?
> > 
> 
> Right now we're working only with r8a77951 and r8a77961 boards.
> 
> > Did you discuss more in general with the linux kernel guys to see if this
> > approach was agreed and will be adopted by other manufacturers ?
> 
> I didn't. I've contacted Sudeep Holla <sudeep.holla@arm.com>, who is the
> maintainer of the SCMI protocol drivers. Waiting for the response.
> 
> Also we proposed to add Pinctl support to SCMI specification. It was
> agreed and should be added to SCMI protocol in SCMIv3.2 (due end-2022/early 2023).
> 
> > 
> > All in all I think this is a good idea but I fear that all this will actually only
> > be used by one board or one manufacturer and other might use a different
> > strategy, I would like to unrisk this before merging this in Xen.
> 
> The main idea was to make Xen SCMI mediator completely transparent from
> the Domain point of view. So there is no Xen specific changes should be
> done to OS pinctrl drivers to work through SCMI.
> 
> This means that all platforms, that already using SCMI can work with it
> in virtualized system.

I like this statement. The aim of this series should not be just one
board, but it should be able to easily support any board with an SCMI
interface. For it to work, any changes to device tree interfaces should
be done in upstream device tree
(linux.git/Documentation/devicetree/bindings and/or devicetree.org).

Xilinx doesn't make use of SCMI yet. We are currently using an older
firmware interface called EEMI. EEMI and SCMI are not the same but they
are somewhat similar.

From my experience with this kind of interfaces, I think Oleksii's
design is the right way to go. There are some important details to
review, like the device tree interfaces at the host level and domU
level, and the memory mapping of the channels; we need to be very
careful about those details. But overall I think it is the right
design.

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [RFC v2 5/8] xen/arm: introduce SCMI-SMC mediator driver
  2022-02-11 11:18       ` Bertrand Marquis
  2022-02-11 11:55         ` Oleksii Moisieiev
@ 2022-02-12 12:43         ` Julien Grall
  2022-02-14 11:13           ` Oleksii Moisieiev
  1 sibling, 1 reply; 45+ messages in thread
From: Julien Grall @ 2022-02-12 12:43 UTC (permalink / raw)
  To: Bertrand Marquis, Oleksii Moisieiev
  Cc: xen-devel, Stefano Stabellini, Volodymyr Babchuk

Hi,

On 11/02/2022 11:18, Bertrand Marquis wrote:
> Do you plan to add support for other boards ?
> 
> Did you discuss more in general with the linux kernel guys to see if this
> approach was agreed and will be adopted by other manufacturers ?
> 
> All in all I think this is a good idea but I fear that all this will actually only
> be used by one board or one manufacturer and other might use a different
> strategy, I would like to unrisk this before merging this in Xen.

In the past we merged code that would only benefits one vendor (i.e. 
EEMI). That said, this was a vendor specific protocol. I believe the 
situation is different here because the spec is meant to be generic.

> @julien and Stefano: what is your view here ?

I share the same concerns as you. I think we need to make sure all the 
pieces we rely on (e.g. firmware, DT bindings) have been agreed before 
we can merge such code in Xen.

The first step is to have all the pieces available in public so they can 
be reviewed and tested together.

Oleksii, on a separate e-mail, you said you made change for ATF. How 
much of those changes was related to support for Xen? If they are some, 
then I think they should be upstreamed first.

Cheers,

-- 
Julien Grall


^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [RFC v2 5/8] xen/arm: introduce SCMI-SMC mediator driver
  2022-02-12 12:43         ` Julien Grall
@ 2022-02-14 11:13           ` Oleksii Moisieiev
  2022-02-14 11:27             ` Bertrand Marquis
  0 siblings, 1 reply; 45+ messages in thread
From: Oleksii Moisieiev @ 2022-02-14 11:13 UTC (permalink / raw)
  To: Julien Grall
  Cc: Bertrand Marquis, xen-devel, Stefano Stabellini, Volodymyr Babchuk

Hi Julien,

On Sat, Feb 12, 2022 at 12:43:56PM +0000, Julien Grall wrote:
> Hi,
> 
> On 11/02/2022 11:18, Bertrand Marquis wrote:
> > Do you plan to add support for other boards ?
> > 
> > Did you discuss more in general with the linux kernel guys to see if this
> > approach was agreed and will be adopted by other manufacturers ?
> > 
> > All in all I think this is a good idea but I fear that all this will actually only
> > be used by one board or one manufacturer and other might use a different
> > strategy, I would like to unrisk this before merging this in Xen.
> 
> In the past we merged code that would only benefits one vendor (i.e. EEMI).
> That said, this was a vendor specific protocol. I believe the situation is
> different here because the spec is meant to be generic.
> 
> > @julien and Stefano: what is your view here ?
> 
> I share the same concerns as you. I think we need to make sure all the
> pieces we rely on (e.g. firmware, DT bindings) have been agreed before we
> can merge such code in Xen.
> 
> The first step is to have all the pieces available in public so they can be
> reviewed and tested together.
> 
> Oleksii, on a separate e-mail, you said you made change for ATF. How much of
> those changes was related to support for Xen? If they are some, then I think
> they should be upstreamed first.
> 

Let me share changes, that were done to AT-F and Linux kernel
device-tree in terms of the SCMI mediator POC.
Changes to the Linux kernel:
https://github.com/oleksiimoisieiev/arm-trusted-firmware/pull/4
Based on renesas-rcar linux-bsp, branch v5.10/rcar-5.0.0.rc5

Changes to AT-F:
https://github.com/oleksiimoisieiev/linux-bsp/pull/3
Based on renesas-rcar/arm-trusted-firmware branch rcar_gen3_v2.5.

All changes that were done are not Xen specific. Given AT-F changes are
the implementation of the SCMI feature using SMC as transport. All
changes were done accoding to the DEN0056C [0] and DEN0028D [1].

We pass channel_id via SMC to the Firmware on r7 bits [15:0] (See Section
4.1 of [1]). Then Firmware converts channel_id to agent_id. Channel_id can't be
equal to agent_id in our case, because, according to the 4.2.2.8 of [0]
- agent_id 0 is reserved to identify platform itself.


[0] https://developer.arm.com/documentation/den0056/latest
[1] https://developer.arm.com/documentation/den0028/latest

Best regards,
Oleksii.

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [RFC v2 5/8] xen/arm: introduce SCMI-SMC mediator driver
  2022-02-14 11:13           ` Oleksii Moisieiev
@ 2022-02-14 11:27             ` Bertrand Marquis
  2022-02-14 11:51               ` Oleksii Moisieiev
  0 siblings, 1 reply; 45+ messages in thread
From: Bertrand Marquis @ 2022-02-14 11:27 UTC (permalink / raw)
  To: Oleksii Moisieiev
  Cc: Julien Grall, xen-devel, Stefano Stabellini, Volodymyr Babchuk

Hi Oleksii,

> On 14 Feb 2022, at 11:13, Oleksii Moisieiev <Oleksii_Moisieiev@epam.com> wrote:
> 
> Hi Julien,
> 
> On Sat, Feb 12, 2022 at 12:43:56PM +0000, Julien Grall wrote:
>> Hi,
>> 
>> On 11/02/2022 11:18, Bertrand Marquis wrote:
>>> Do you plan to add support for other boards ?
>>> 
>>> Did you discuss more in general with the linux kernel guys to see if this
>>> approach was agreed and will be adopted by other manufacturers ?
>>> 
>>> All in all I think this is a good idea but I fear that all this will actually only
>>> be used by one board or one manufacturer and other might use a different
>>> strategy, I would like to unrisk this before merging this in Xen.
>> 
>> In the past we merged code that would only benefits one vendor (i.e. EEMI).
>> That said, this was a vendor specific protocol. I believe the situation is
>> different here because the spec is meant to be generic.
>> 
>>> @julien and Stefano: what is your view here ?
>> 
>> I share the same concerns as you. I think we need to make sure all the
>> pieces we rely on (e.g. firmware, DT bindings) have been agreed before we
>> can merge such code in Xen.
>> 
>> The first step is to have all the pieces available in public so they can be
>> reviewed and tested together.
>> 
>> Oleksii, on a separate e-mail, you said you made change for ATF. How much of
>> those changes was related to support for Xen? If they are some, then I think
>> they should be upstreamed first.
>> 
> 
> Let me share changes, that were done to AT-F and Linux kernel
> device-tree in terms of the SCMI mediator POC.
> Changes to the Linux kernel:
> https://github.com/oleksiimoisieiev/arm-trusted-firmware/pull/4
> Based on renesas-rcar linux-bsp, branch v5.10/rcar-5.0.0.rc5
> 
> Changes to AT-F:
> https://github.com/oleksiimoisieiev/linux-bsp/pull/3
> Based on renesas-rcar/arm-trusted-firmware branch rcar_gen3_v2.5.

You inverted the links but thanks this is really useful.

Did you push the ATF changes to mainstream ATF or discuss those with
the maintainers ?

The strategy overall is nice but we need to make sure this is accepted and
 merged by all parties (ATF and Linux) to make sure the support for this will
not only be available in Xen and for one board.

I will try to get in touch with the SCMI linux driver maintainer at arm to get his view.

Regards
Bertrand

> 
> All changes that were done are not Xen specific. Given AT-F changes are
> the implementation of the SCMI feature using SMC as transport. All
> changes were done accoding to the DEN0056C [0] and DEN0028D [1].
> 
> We pass channel_id via SMC to the Firmware on r7 bits [15:0] (See Section
> 4.1 of [1]). Then Firmware converts channel_id to agent_id. Channel_id can't be
> equal to agent_id in our case, because, according to the 4.2.2.8 of [0]
> - agent_id 0 is reserved to identify platform itself.
> 
> 
> [0] https://developer.arm.com/documentation/den0056/latest
> [1] https://developer.arm.com/documentation/den0028/latest
> 
> Best regards,
> Oleksii.



^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [RFC v2 5/8] xen/arm: introduce SCMI-SMC mediator driver
  2022-02-14 11:27             ` Bertrand Marquis
@ 2022-02-14 11:51               ` Oleksii Moisieiev
  2022-02-14 22:05                 ` Stefano Stabellini
  0 siblings, 1 reply; 45+ messages in thread
From: Oleksii Moisieiev @ 2022-02-14 11:51 UTC (permalink / raw)
  To: Bertrand Marquis
  Cc: Julien Grall, xen-devel, Stefano Stabellini, Volodymyr Babchuk

Hi Bertrand,

On Mon, Feb 14, 2022 at 11:27:21AM +0000, Bertrand Marquis wrote:
> Hi Oleksii,
> 
> > On 14 Feb 2022, at 11:13, Oleksii Moisieiev <Oleksii_Moisieiev@epam.com> wrote:
> > 
> > Hi Julien,
> > 
> > On Sat, Feb 12, 2022 at 12:43:56PM +0000, Julien Grall wrote:
> >> Hi,
> >> 
> >> On 11/02/2022 11:18, Bertrand Marquis wrote:
> >>> Do you plan to add support for other boards ?
> >>> 
> >>> Did you discuss more in general with the linux kernel guys to see if this
> >>> approach was agreed and will be adopted by other manufacturers ?
> >>> 
> >>> All in all I think this is a good idea but I fear that all this will actually only
> >>> be used by one board or one manufacturer and other might use a different
> >>> strategy, I would like to unrisk this before merging this in Xen.
> >> 
> >> In the past we merged code that would only benefits one vendor (i.e. EEMI).
> >> That said, this was a vendor specific protocol. I believe the situation is
> >> different here because the spec is meant to be generic.
> >> 
> >>> @julien and Stefano: what is your view here ?
> >> 
> >> I share the same concerns as you. I think we need to make sure all the
> >> pieces we rely on (e.g. firmware, DT bindings) have been agreed before we
> >> can merge such code in Xen.
> >> 
> >> The first step is to have all the pieces available in public so they can be
> >> reviewed and tested together.
> >> 
> >> Oleksii, on a separate e-mail, you said you made change for ATF. How much of
> >> those changes was related to support for Xen? If they are some, then I think
> >> they should be upstreamed first.
> >> 
> > 
> > Let me share changes, that were done to AT-F and Linux kernel
> > device-tree in terms of the SCMI mediator POC.
> > Changes to the Linux kernel:
> > https://urldefense.com/v3/__https://github.com/oleksiimoisieiev/arm-trusted-firmware/pull/4__;!!GF_29dbcQIUBPA!je9Cu0n0498Yn76OLWjxxVaB7jWJtyWycHX0YARezTnc7aYHpGRJ8tSxHqIC0fTMUUSV$ [github[.]com]
> > Based on renesas-rcar linux-bsp, branch v5.10/rcar-5.0.0.rc5
> > 
> > Changes to AT-F:
> > https://urldefense.com/v3/__https://github.com/oleksiimoisieiev/linux-bsp/pull/3__;!!GF_29dbcQIUBPA!je9Cu0n0498Yn76OLWjxxVaB7jWJtyWycHX0YARezTnc7aYHpGRJ8tSxHqIC0eDKS3ge$ [github[.]com]
> > Based on renesas-rcar/arm-trusted-firmware branch rcar_gen3_v2.5.
> 
> You inverted the links but thanks this is really useful.
> 

That's strange. Links looks good from xen.markmail.org interface.

> Did you push the ATF changes to mainstream ATF or discuss those with
> the maintainers ?

No. We did changes in ATF as a proof of concept.

> 
> The strategy overall is nice but we need to make sure this is accepted and
>  merged by all parties (ATF and Linux) to make sure the support for this will
> not only be available in Xen and for one board.

I've prepared patch to Linux kernel, which is introducing scmi_devid
binding, needed to set device permissions via SCMI. I've contacted
Sudeep Holla <sudeep.holla@arm.com>, who is the maintainer of the SCMI protocol
drivers. Waiting for the response.

Changes to ATF are not Xen specific and were done in terms of POC. We do
not have plans to upstream those changes right now.

> 
> I will try to get in touch with the SCMI linux driver maintainer at arm to get his view.
> 

Thanks.

Best regards,
Oleksii.

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [RFC v2 5/8] xen/arm: introduce SCMI-SMC mediator driver
  2022-02-14 11:51               ` Oleksii Moisieiev
@ 2022-02-14 22:05                 ` Stefano Stabellini
  2022-02-16 17:41                   ` Oleksii Moisieiev
  0 siblings, 1 reply; 45+ messages in thread
From: Stefano Stabellini @ 2022-02-14 22:05 UTC (permalink / raw)
  To: Oleksii Moisieiev
  Cc: Bertrand Marquis, Julien Grall, xen-devel, Stefano Stabellini,
	Volodymyr Babchuk

On Mon, 14 Feb 2022, Oleksii Moisieiev wrote:
> Hi Bertrand,
> 
> On Mon, Feb 14, 2022 at 11:27:21AM +0000, Bertrand Marquis wrote:
> > Hi Oleksii,
> > 
> > > On 14 Feb 2022, at 11:13, Oleksii Moisieiev <Oleksii_Moisieiev@epam.com> wrote:
> > > 
> > > Hi Julien,
> > > 
> > > On Sat, Feb 12, 2022 at 12:43:56PM +0000, Julien Grall wrote:
> > >> Hi,
> > >> 
> > >> On 11/02/2022 11:18, Bertrand Marquis wrote:
> > >>> Do you plan to add support for other boards ?
> > >>> 
> > >>> Did you discuss more in general with the linux kernel guys to see if this
> > >>> approach was agreed and will be adopted by other manufacturers ?
> > >>> 
> > >>> All in all I think this is a good idea but I fear that all this will actually only
> > >>> be used by one board or one manufacturer and other might use a different
> > >>> strategy, I would like to unrisk this before merging this in Xen.
> > >> 
> > >> In the past we merged code that would only benefits one vendor (i.e. EEMI).
> > >> That said, this was a vendor specific protocol. I believe the situation is
> > >> different here because the spec is meant to be generic.
> > >> 
> > >>> @julien and Stefano: what is your view here ?
> > >> 
> > >> I share the same concerns as you. I think we need to make sure all the
> > >> pieces we rely on (e.g. firmware, DT bindings) have been agreed before we
> > >> can merge such code in Xen.
> > >> 
> > >> The first step is to have all the pieces available in public so they can be
> > >> reviewed and tested together.
> > >>
> > >> Oleksii, on a separate e-mail, you said you made change for ATF. How much of
> > >> those changes was related to support for Xen? If they are some, then I think
> > >> they should be upstreamed first.
> > >> 
> > > 
> > > Let me share changes, that were done to AT-F and Linux kernel
> > > device-tree in terms of the SCMI mediator POC.
> > > Changes to the Linux kernel:
> > > https://urldefense.com/v3/__https://github.com/oleksiimoisieiev/arm-trusted-firmware/pull/4__;!!GF_29dbcQIUBPA!je9Cu0n0498Yn76OLWjxxVaB7jWJtyWycHX0YARezTnc7aYHpGRJ8tSxHqIC0fTMUUSV$ [github[.]com]
> > > Based on renesas-rcar linux-bsp, branch v5.10/rcar-5.0.0.rc5
> > > 
> > > Changes to AT-F:
> > > https://urldefense.com/v3/__https://github.com/oleksiimoisieiev/linux-bsp/pull/3__;!!GF_29dbcQIUBPA!je9Cu0n0498Yn76OLWjxxVaB7jWJtyWycHX0YARezTnc7aYHpGRJ8tSxHqIC0eDKS3ge$ [github[.]com]
> > > Based on renesas-rcar/arm-trusted-firmware branch rcar_gen3_v2.5.
> > 
> > You inverted the links but thanks this is really useful.
> > 
> 
> That's strange. Links looks good from xen.markmail.org interface.
> 
> > Did you push the ATF changes to mainstream ATF or discuss those with
> > the maintainers ?
> 
> No. We did changes in ATF as a proof of concept.
> 
> > 
> > The strategy overall is nice but we need to make sure this is accepted and
> >  merged by all parties (ATF and Linux) to make sure the support for this will
> > not only be available in Xen and for one board.

+1


> I've prepared patch to Linux kernel, which is introducing scmi_devid
> binding, needed to set device permissions via SCMI. I've contacted
> Sudeep Holla <sudeep.holla@arm.com>, who is the maintainer of the SCMI protocol
> drivers. Waiting for the response.
> 
> Changes to ATF are not Xen specific and were done in terms of POC. We do
> not have plans to upstream those changes right now.

If this work relies on a new interface in ATF, and the interface is not
vendor-specific, then at least the interface (if not the code) should be
reviewed and accepted by ATF.

Otherwise we risk ending up with an upstream SCMI implementation in Xen
that cannot be used anywhere, except the PoC. To make things worse, this
could happen:

- we upstream the SCMI mediator to Xen
- we upstream any required changes to Linux
- ATF rejects the SCMI-related interface changes
- ATF comes up with a difference interface

At this point we would have to deprecate the implementation in Xen. It
might also be difficult to do so due to versioning issues. We would
need to be able to detect which version of ATF we are running on, to
distinguish the ATF PoC version that works with the old interface from
the new ATF version that supports a different interface.

To avoid this kind of issues we typically expect that all relevant
communities agree on the public interfaces before upstreaming the code.


^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [RFC v2 5/8] xen/arm: introduce SCMI-SMC mediator driver
  2022-02-14 22:05                 ` Stefano Stabellini
@ 2022-02-16 17:41                   ` Oleksii Moisieiev
  0 siblings, 0 replies; 45+ messages in thread
From: Oleksii Moisieiev @ 2022-02-16 17:41 UTC (permalink / raw)
  To: Stefano Stabellini
  Cc: Bertrand Marquis, Julien Grall, xen-devel, Volodymyr Babchuk

Hi Stefano,

On Mon, Feb 14, 2022 at 02:05:18PM -0800, Stefano Stabellini wrote:
> On Mon, 14 Feb 2022, Oleksii Moisieiev wrote:
> > Hi Bertrand,
> > 
> > On Mon, Feb 14, 2022 at 11:27:21AM +0000, Bertrand Marquis wrote:
> > > Hi Oleksii,
> > > 
> > > > On 14 Feb 2022, at 11:13, Oleksii Moisieiev <Oleksii_Moisieiev@epam.com> wrote:
> > > > 
> > > > Hi Julien,
> > > > 
> > > > On Sat, Feb 12, 2022 at 12:43:56PM +0000, Julien Grall wrote:
> > > >> Hi,
> > > >> 
> > > >> On 11/02/2022 11:18, Bertrand Marquis wrote:
> > > >>> Do you plan to add support for other boards ?
> > > >>> 
> > > >>> Did you discuss more in general with the linux kernel guys to see if this
> > > >>> approach was agreed and will be adopted by other manufacturers ?
> > > >>> 
> > > >>> All in all I think this is a good idea but I fear that all this will actually only
> > > >>> be used by one board or one manufacturer and other might use a different
> > > >>> strategy, I would like to unrisk this before merging this in Xen.
> > > >> 
> > > >> In the past we merged code that would only benefits one vendor (i.e. EEMI).
> > > >> That said, this was a vendor specific protocol. I believe the situation is
> > > >> different here because the spec is meant to be generic.
> > > >> 
> > > >>> @julien and Stefano: what is your view here ?
> > > >> 
> > > >> I share the same concerns as you. I think we need to make sure all the
> > > >> pieces we rely on (e.g. firmware, DT bindings) have been agreed before we
> > > >> can merge such code in Xen.
> > > >> 
> > > >> The first step is to have all the pieces available in public so they can be
> > > >> reviewed and tested together.
> > > >>
> > > >> Oleksii, on a separate e-mail, you said you made change for ATF. How much of
> > > >> those changes was related to support for Xen? If they are some, then I think
> > > >> they should be upstreamed first.
> > > >> 
> > > > 
> > > > Let me share changes, that were done to AT-F and Linux kernel
> > > > device-tree in terms of the SCMI mediator POC.
> > > > Changes to the Linux kernel:
> > > > https://urldefense.com/v3/__https://github.com/oleksiimoisieiev/arm-trusted-firmware/pull/4__;!!GF_29dbcQIUBPA!je9Cu0n0498Yn76OLWjxxVaB7jWJtyWycHX0YARezTnc7aYHpGRJ8tSxHqIC0fTMUUSV$ [github[.]com]
> > > > Based on renesas-rcar linux-bsp, branch v5.10/rcar-5.0.0.rc5
> > > > 
> > > > Changes to AT-F:
> > > > https://urldefense.com/v3/__https://github.com/oleksiimoisieiev/linux-bsp/pull/3__;!!GF_29dbcQIUBPA!je9Cu0n0498Yn76OLWjxxVaB7jWJtyWycHX0YARezTnc7aYHpGRJ8tSxHqIC0eDKS3ge$ [github[.]com]
> > > > Based on renesas-rcar/arm-trusted-firmware branch rcar_gen3_v2.5.
> > > 
> > > You inverted the links but thanks this is really useful.
> > > 
> > 
> > That's strange. Links looks good from xen.markmail.org interface.
> > 
> > > Did you push the ATF changes to mainstream ATF or discuss those with
> > > the maintainers ?
> > 
> > No. We did changes in ATF as a proof of concept.
> > 
> > > 
> > > The strategy overall is nice but we need to make sure this is accepted and
> > >  merged by all parties (ATF and Linux) to make sure the support for this will
> > > not only be available in Xen and for one board.
> 
> +1
> 
> 
> > I've prepared patch to Linux kernel, which is introducing scmi_devid
> > binding, needed to set device permissions via SCMI. I've contacted
> > Sudeep Holla <sudeep.holla@arm.com>, who is the maintainer of the SCMI protocol
> > drivers. Waiting for the response.
> > 
> > Changes to ATF are not Xen specific and were done in terms of POC. We do
> > not have plans to upstream those changes right now.
> 
> If this work relies on a new interface in ATF, and the interface is not
> vendor-specific, then at least the interface (if not the code) should be
> reviewed and accepted by ATF.
> 
> Otherwise we risk ending up with an upstream SCMI implementation in Xen
> that cannot be used anywhere, except the PoC. To make things worse, this
> could happen:
> 
> - we upstream the SCMI mediator to Xen
> - we upstream any required changes to Linux
> - ATF rejects the SCMI-related interface changes
> - ATF comes up with a difference interface
> 
> At this point we would have to deprecate the implementation in Xen. It
> might also be difficult to do so due to versioning issues. We would
> need to be able to detect which version of ATF we are running on, to
> distinguish the ATF PoC version that works with the old interface from
> the new ATF version that supports a different interface.
> 
> To avoid this kind of issues we typically expect that all relevant
> communities agree on the public interfaces before upstreaming the code.

That's sound reasonable.
I'll contact with AT-F maintainers. Maybe I'll be able to upstream SCMI
to AT-F.
Also I hope I'll be able to contact Linux kernel SCMI maintainers and
discuss device-tree structure.

Best regards,
Oleksii

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [RFC v2 6/8] tools/arm: Introduce force_assign_without_iommu option to xl.cfg
  2022-02-08 18:00 ` [RFC v2 6/8] tools/arm: Introduce force_assign_without_iommu option to xl.cfg Oleksii Moisieiev
@ 2022-02-17 14:52   ` Anthony PERARD
  2022-02-18  8:19     ` Oleksii Moisieiev
  2022-02-17 15:20   ` Julien Grall
  2022-06-03 13:43   ` Jan Beulich
  2 siblings, 1 reply; 45+ messages in thread
From: Anthony PERARD @ 2022-02-17 14:52 UTC (permalink / raw)
  To: Oleksii Moisieiev
  Cc: xen-devel, Wei Liu, Andrew Cooper, George Dunlap, Jan Beulich,
	Julien Grall, Stefano Stabellini, Nick Rosbrook, Juergen Gross,
	Paul Durrant

On Tue, Feb 08, 2022 at 06:00:12PM +0000, Oleksii Moisieiev wrote:
> If set, Xen is allowed to assign the devices even if they are not under
> IOMMU.
> Can be confugired from dom.cfg in the following format:
> force_assign_without_iommu = 1
> 
> This parameter has the same purpose as xen,force-assign-without-iommu
> property in dom0less archtecture.
> 
> Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@epam.com>
> ---
> diff --git a/tools/libs/light/libxl_types.idl b/tools/libs/light/libxl_types.idl
> index 2a42da2f7d..1080966c33 100644
> --- a/tools/libs/light/libxl_types.idl
> +++ b/tools/libs/light/libxl_types.idl
> @@ -564,6 +564,7 @@ libxl_domain_build_info = Struct("domain_build_info",[
>      ("apic",             libxl_defbool),
>      ("dm_restrict",      libxl_defbool),
>      ("tee",              libxl_tee_type),
> +    ("force_assign_without_iommu", libxl_defbool),

As you are making changes to libxl's API, could you add a LIBXL_HAVE_*
macro in "tools/include/libxl.h", they are plenty of example there about
adding new fields in "libxl_domain_build_info".

Thanks,

-- 
Anthony PERARD


^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [RFC v2 6/8] tools/arm: Introduce force_assign_without_iommu option to xl.cfg
  2022-02-08 18:00 ` [RFC v2 6/8] tools/arm: Introduce force_assign_without_iommu option to xl.cfg Oleksii Moisieiev
  2022-02-17 14:52   ` Anthony PERARD
@ 2022-02-17 15:20   ` Julien Grall
  2022-02-18  9:16     ` Oleksii Moisieiev
  2022-06-03 13:43   ` Jan Beulich
  2 siblings, 1 reply; 45+ messages in thread
From: Julien Grall @ 2022-02-17 15:20 UTC (permalink / raw)
  To: Oleksii Moisieiev, xen-devel
  Cc: Wei Liu, Andrew Cooper, George Dunlap, Jan Beulich,
	Stefano Stabellini, Nick Rosbrook, Anthony PERARD, Juergen Gross,
	Paul Durrant

Hi,

On 08/02/2022 18:00, Oleksii Moisieiev wrote:
> If set, Xen is allowed to assign the devices even if they are not under
> IOMMU.

I think you mean "not protected by an IOMMU".

> Can be confugired from dom.cfg in the following format:

s/confugired/configured/

> force_assign_without_iommu = 1
> 
> This parameter has the same purpose as xen,force-assign-without-iommu
> property in dom0less archtecture.

s/archtecture/architecture/

> 
> Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@epam.com>
> ---
>   docs/man/xl.cfg.5.pod.in              |  9 +++++++++
>   tools/golang/xenlight/helpers.gen.go  |  5 +++++
>   tools/golang/xenlight/types.gen.go    |  1 +
>   tools/libs/light/libxl_arm.c          |  3 +++
>   tools/libs/light/libxl_types.idl      |  1 +
>   tools/xl/xl_parse.c                   |  3 +++
>   xen/common/domain.c                   |  2 +-
>   xen/drivers/passthrough/device_tree.c | 19 +++++++++++++++++--
>   xen/drivers/passthrough/iommu.c       |  5 ++++-
>   xen/include/public/domctl.h           |  5 ++++-
>   xen/include/xen/iommu.h               |  3 +++
>   11 files changed, 51 insertions(+), 5 deletions(-)
> 
> diff --git a/docs/man/xl.cfg.5.pod.in b/docs/man/xl.cfg.5.pod.in
> index b98d161398..ddf82cb3bc 100644
> --- a/docs/man/xl.cfg.5.pod.in
> +++ b/docs/man/xl.cfg.5.pod.in
> @@ -1614,6 +1614,15 @@ This feature is a B<technology preview>.
>   
>   =back
>   
> +=over 4
> +
> +=item B<force_assign_without_iommu=BOOLEAN>
> +
> +If set, Xen allows to assign a devices even if it is not behind an IOMMU.
> +This renders your platform *unsafe* if the device is DMA-capable.

I agree this is going to be unsafe. But the more important bit here is 
this is not going to work because the guest has no way to translate a 
GFN to an MFN.

Your guest will need to be direct map to make it usable. So I would add 
that this will *not* work with DMA-capable devices.

Also, can you explain in the commit message why you want to allow this 
setup?

>       xlu_cfg_get_defbool(config, "xend_suspend_evtchn_compat",
> diff --git a/xen/common/domain.c b/xen/common/domain.c
> index 093bb4403f..f1f19bf711 100644
> --- a/xen/common/domain.c
> +++ b/xen/common/domain.c
> @@ -512,7 +512,7 @@ static int sanitise_domain_config(struct xen_domctl_createdomain *config)
>   
>       if ( iommu )
>       {
> -        if ( config->iommu_opts & ~XEN_DOMCTL_IOMMU_no_sharept )
> +        if ( config->iommu_opts >> XEN_DOMCTL_IOMMU_MAX )

XEN_DOMCTL_IOMMU_MAX will be defined as:

(1U << _XEN_DOMCTL_IOMMU_force_iommu)

This means the shift will do the wrong thing. However, AFAICT, this new 
option will only be supported by Arm and likely only for platform device 
for the time being.

That said, I am not convinced this flag should be per-domain in Xen. 
Instead, I think it would be better to pass the flag via the device 
assign domctl.

>           {
>               dprintk(XENLOG_INFO, "Unknown IOMMU options %#x\n",
>                       config->iommu_opts);
> diff --git a/xen/drivers/passthrough/device_tree.c b/xen/drivers/passthrough/device_tree.c
> index 98f2aa0dad..103608dec1 100644
> --- a/xen/drivers/passthrough/device_tree.c
> +++ b/xen/drivers/passthrough/device_tree.c
> @@ -198,6 +198,7 @@ int iommu_do_dt_domctl(struct xen_domctl *domctl, struct domain *d,
>   {
>       int ret;
>       struct dt_device_node *dev;
> +    struct domain_iommu *hd = dom_iommu(d);
>   
>       switch ( domctl->cmd )
>       {
> @@ -238,6 +239,16 @@ int iommu_do_dt_domctl(struct xen_domctl *domctl, struct domain *d,
>               return -EINVAL;
>   
>           ret = iommu_add_dt_device(dev);
> +
> +        /*
> +         * iommu_add_dt_device returns 1 if iommu is disabled or device don't
> +         * have iommus property
> +         */
> +        if ( (ret == 1) && (hd->force_assign_iommu) ) {
> +            ret = -ENOSYS;
> +            break;
> +        }
> +
>           if ( ret < 0 )
>           {
>               printk(XENLOG_G_ERR "Failed to add %s to the IOMMU\n",
> @@ -275,10 +286,14 @@ int iommu_do_dt_domctl(struct xen_domctl *domctl, struct domain *d,
>   
>           ret = iommu_deassign_dt_device(d, dev);
>   
> -        if ( ret )
> -            printk(XENLOG_G_ERR "XEN_DOMCTL_assign_dt_device: assign \"%s\""
> +        if ( ret ) {
> +            if ( hd->force_assign_iommu )
> +                ret = -ENOSYS;
> +            else
> +                printk(XENLOG_G_ERR "XEN_DOMCTL_assign_dt_device: assign \"%s\""
>                      " to dom%u failed (%d)\n",
>                      dt_node_full_name(dev), d->domain_id, ret);
> +        }
>           break;
>   
>       default:
> diff --git a/xen/drivers/passthrough/iommu.c b/xen/drivers/passthrough/iommu.c
> index 6334370109..216a9058c0 100644
> --- a/xen/drivers/passthrough/iommu.c
> +++ b/xen/drivers/passthrough/iommu.c
> @@ -193,6 +193,8 @@ int iommu_domain_init(struct domain *d, unsigned int opts)
>       hd->node = NUMA_NO_NODE;
>   #endif
>   
> +    hd->force_assign_iommu = opts & XEN_DOMCTL_IOMMU_force_iommu;
> +
>       ret = arch_iommu_domain_init(d);
>       if ( ret )
>           return ret;
> @@ -534,6 +536,7 @@ int iommu_do_domctl(
>   {
>       int ret = -ENODEV;
>   
> +

Spurious change.

>       if ( !is_iommu_enabled(d) )

Should not this check be updated to check force_assign?

>           return -EOPNOTSUPP;
>   
> @@ -542,7 +545,7 @@ int iommu_do_domctl(
>   #endif
>   
>   #ifdef CONFIG_HAS_DEVICE_TREE
> -    if ( ret == -ENODEV )
> +    if ( ret == -ENOSYS )

AFAICT, none of the code (including callee) before ret have been 
modified. So why are you modifying the check here?

>           ret = iommu_do_dt_domctl(domctl, d, u_domctl);
>   #endif
>   
> diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
> index b85e6170b0..bf5f8c5b6b 100644
> --- a/xen/include/public/domctl.h
> +++ b/xen/include/public/domctl.h
> @@ -81,8 +81,11 @@ struct xen_domctl_createdomain {
>   #define _XEN_DOMCTL_IOMMU_no_sharept  0
>   #define XEN_DOMCTL_IOMMU_no_sharept   (1U << _XEN_DOMCTL_IOMMU_no_sharept)
>   
> +#define _XEN_DOMCTL_IOMMU_force_iommu 1
> +#define XEN_DOMCTL_IOMMU_force_iommu  (1U << _XEN_DOMCTL_IOMMU_force_iommu)
> +
>   /* Max XEN_DOMCTL_IOMMU_* constant.  Used for ABI checking. */
> -#define XEN_DOMCTL_IOMMU_MAX XEN_DOMCTL_IOMMU_no_sharept
> +#define XEN_DOMCTL_IOMMU_MAX XEN_DOMCTL_IOMMU_force_iommu
>   
>       uint32_t iommu_opts;
>   
> diff --git a/xen/include/xen/iommu.h b/xen/include/xen/iommu.h
> index 6b2cdffa4a..a9cf2334af 100644
> --- a/xen/include/xen/iommu.h
> +++ b/xen/include/xen/iommu.h
> @@ -330,6 +330,9 @@ struct domain_iommu {
>        * necessarily imply this is true.
>        */
>       bool need_sync;
> +
> +    /* Do not return error if the device without iommu is assigned */
> +    bool force_assign_iommu;
>   };
>   
>   #define dom_iommu(d)              (&(d)->iommu)

Cheers,

-- 
Julien Grall


^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [RFC v2 6/8] tools/arm: Introduce force_assign_without_iommu option to xl.cfg
  2022-02-17 14:52   ` Anthony PERARD
@ 2022-02-18  8:19     ` Oleksii Moisieiev
  0 siblings, 0 replies; 45+ messages in thread
From: Oleksii Moisieiev @ 2022-02-18  8:19 UTC (permalink / raw)
  To: Anthony PERARD
  Cc: xen-devel, Wei Liu, Andrew Cooper, George Dunlap, Jan Beulich,
	Julien Grall, Stefano Stabellini, Nick Rosbrook, Juergen Gross,
	Paul Durrant

Hi Anthony,

On Thu, Feb 17, 2022 at 02:52:44PM +0000, Anthony PERARD wrote:
> On Tue, Feb 08, 2022 at 06:00:12PM +0000, Oleksii Moisieiev wrote:
> > If set, Xen is allowed to assign the devices even if they are not under
> > IOMMU.
> > Can be confugired from dom.cfg in the following format:
> > force_assign_without_iommu = 1
> > 
> > This parameter has the same purpose as xen,force-assign-without-iommu
> > property in dom0less archtecture.
> > 
> > Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@epam.com>
> > ---
> > diff --git a/tools/libs/light/libxl_types.idl b/tools/libs/light/libxl_types.idl
> > index 2a42da2f7d..1080966c33 100644
> > --- a/tools/libs/light/libxl_types.idl
> > +++ b/tools/libs/light/libxl_types.idl
> > @@ -564,6 +564,7 @@ libxl_domain_build_info = Struct("domain_build_info",[
> >      ("apic",             libxl_defbool),
> >      ("dm_restrict",      libxl_defbool),
> >      ("tee",              libxl_tee_type),
> > +    ("force_assign_without_iommu", libxl_defbool),
> 
> As you are making changes to libxl's API, could you add a LIBXL_HAVE_*
> macro in "tools/include/libxl.h", they are plenty of example there about
> adding new fields in "libxl_domain_build_info".

Sure, I will add it in v3.

--
Oleksii.

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [RFC v2 6/8] tools/arm: Introduce force_assign_without_iommu option to xl.cfg
  2022-02-17 15:20   ` Julien Grall
@ 2022-02-18  9:16     ` Oleksii Moisieiev
  2022-02-18 10:17       ` Julien Grall
  0 siblings, 1 reply; 45+ messages in thread
From: Oleksii Moisieiev @ 2022-02-18  9:16 UTC (permalink / raw)
  To: Julien Grall
  Cc: xen-devel, Wei Liu, Andrew Cooper, George Dunlap, Jan Beulich,
	Stefano Stabellini, Nick Rosbrook, Anthony PERARD, Juergen Gross,
	Paul Durrant

Hi Julien,

On Thu, Feb 17, 2022 at 03:20:36PM +0000, Julien Grall wrote:
> Hi,
> 
> On 08/02/2022 18:00, Oleksii Moisieiev wrote:
> > If set, Xen is allowed to assign the devices even if they are not under
> > IOMMU.
> 
> I think you mean "not protected by an IOMMU".

Yes. Thanks.
> 
> > Can be confugired from dom.cfg in the following format:
> 
> s/confugired/configured/
> 
> > force_assign_without_iommu = 1
> > 
> > This parameter has the same purpose as xen,force-assign-without-iommu
> > property in dom0less archtecture.
> 
> s/archtecture/architecture/
> 
Shame on me :(. I'll fix that.
> > 
> > Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@epam.com>
> > ---
> >   docs/man/xl.cfg.5.pod.in              |  9 +++++++++
> >   tools/golang/xenlight/helpers.gen.go  |  5 +++++
> >   tools/golang/xenlight/types.gen.go    |  1 +
> >   tools/libs/light/libxl_arm.c          |  3 +++
> >   tools/libs/light/libxl_types.idl      |  1 +
> >   tools/xl/xl_parse.c                   |  3 +++
> >   xen/common/domain.c                   |  2 +-
> >   xen/drivers/passthrough/device_tree.c | 19 +++++++++++++++++--
> >   xen/drivers/passthrough/iommu.c       |  5 ++++-
> >   xen/include/public/domctl.h           |  5 ++++-
> >   xen/include/xen/iommu.h               |  3 +++
> >   11 files changed, 51 insertions(+), 5 deletions(-)
> > 
> > diff --git a/docs/man/xl.cfg.5.pod.in b/docs/man/xl.cfg.5.pod.in
> > index b98d161398..ddf82cb3bc 100644
> > --- a/docs/man/xl.cfg.5.pod.in
> > +++ b/docs/man/xl.cfg.5.pod.in
> > @@ -1614,6 +1614,15 @@ This feature is a B<technology preview>.
> >   =back
> > +=over 4
> > +
> > +=item B<force_assign_without_iommu=BOOLEAN>
> > +
> > +If set, Xen allows to assign a devices even if it is not behind an IOMMU.
> > +This renders your platform *unsafe* if the device is DMA-capable.
> 
> I agree this is going to be unsafe. But the more important bit here is this
> is not going to work because the guest has no way to translate a GFN to an
> MFN.
> 
> Your guest will need to be direct map to make it usable. So I would add that
> this will *not* work with DMA-capable devices.
> 
> Also, can you explain in the commit message why you want to allow this
> setup?

Ok, I will update the commit message.

> 
> >       xlu_cfg_get_defbool(config, "xend_suspend_evtchn_compat",
> > diff --git a/xen/common/domain.c b/xen/common/domain.c
> > index 093bb4403f..f1f19bf711 100644
> > --- a/xen/common/domain.c
> > +++ b/xen/common/domain.c
> > @@ -512,7 +512,7 @@ static int sanitise_domain_config(struct xen_domctl_createdomain *config)
> >       if ( iommu )
> >       {
> > -        if ( config->iommu_opts & ~XEN_DOMCTL_IOMMU_no_sharept )
> > +        if ( config->iommu_opts >> XEN_DOMCTL_IOMMU_MAX )
> 
> XEN_DOMCTL_IOMMU_MAX will be defined as:
> 
> (1U << _XEN_DOMCTL_IOMMU_force_iommu)
> 
> This means the shift will do the wrong thing. However, AFAICT, this new
> option will only be supported by Arm and likely only for platform device for
> the time being.

Thanks, I will fix that.

> 
> That said, I am not convinced this flag should be per-domain in Xen.
> Instead, I think it would be better to pass the flag via the device assign
> domctl.

Do you mean that it's better to set this flag per device, not per
domain? This will require setting this flag for each device which should
require either changing the dtdev format in dom.cfg or setting
xen,force-assign-without-iommu in partial device-tree.

Both of those ways will complicate the configuration. As was mentioned
before, we don't want to make domain configuration more complicated.
What do you think about that?


> 
> >           {
> >               dprintk(XENLOG_INFO, "Unknown IOMMU options %#x\n",
> >                       config->iommu_opts);
> > diff --git a/xen/drivers/passthrough/device_tree.c b/xen/drivers/passthrough/device_tree.c
> > index 98f2aa0dad..103608dec1 100644
> > --- a/xen/drivers/passthrough/device_tree.c
> > +++ b/xen/drivers/passthrough/device_tree.c
> > @@ -198,6 +198,7 @@ int iommu_do_dt_domctl(struct xen_domctl *domctl, struct domain *d,
> >   {
> >       int ret;
> >       struct dt_device_node *dev;
> > +    struct domain_iommu *hd = dom_iommu(d);
> >       switch ( domctl->cmd )
> >       {
> > @@ -238,6 +239,16 @@ int iommu_do_dt_domctl(struct xen_domctl *domctl, struct domain *d,
> >               return -EINVAL;
> >           ret = iommu_add_dt_device(dev);
> > +
> > +        /*
> > +         * iommu_add_dt_device returns 1 if iommu is disabled or device don't
> > +         * have iommus property
> > +         */
> > +        if ( (ret == 1) && (hd->force_assign_iommu) ) {
> > +            ret = -ENOSYS;
> > +            break;
> > +        }
> > +
> >           if ( ret < 0 )
> >           {
> >               printk(XENLOG_G_ERR "Failed to add %s to the IOMMU\n",
> > @@ -275,10 +286,14 @@ int iommu_do_dt_domctl(struct xen_domctl *domctl, struct domain *d,
> >           ret = iommu_deassign_dt_device(d, dev);
> > -        if ( ret )
> > -            printk(XENLOG_G_ERR "XEN_DOMCTL_assign_dt_device: assign \"%s\""
> > +        if ( ret ) {
> > +            if ( hd->force_assign_iommu )
> > +                ret = -ENOSYS;
> > +            else
> > +                printk(XENLOG_G_ERR "XEN_DOMCTL_assign_dt_device: assign \"%s\""
> >                      " to dom%u failed (%d)\n",
> >                      dt_node_full_name(dev), d->domain_id, ret);
> > +        }
> >           break;
> >       default:
> > diff --git a/xen/drivers/passthrough/iommu.c b/xen/drivers/passthrough/iommu.c
> > index 6334370109..216a9058c0 100644
> > --- a/xen/drivers/passthrough/iommu.c
> > +++ b/xen/drivers/passthrough/iommu.c
> > @@ -193,6 +193,8 @@ int iommu_domain_init(struct domain *d, unsigned int opts)
> >       hd->node = NUMA_NO_NODE;
> >   #endif
> > +    hd->force_assign_iommu = opts & XEN_DOMCTL_IOMMU_force_iommu;
> > +
> >       ret = arch_iommu_domain_init(d);
> >       if ( ret )
> >           return ret;
> > @@ -534,6 +536,7 @@ int iommu_do_domctl(
> >   {
> >       int ret = -ENODEV;
> > +
> 
> Spurious change.

I'll remove this.

> 
> >       if ( !is_iommu_enabled(d) )
> 
> Should not this check be updated to check force_assign?

That's a good point. I'll take a look on it.

> 
> >           return -EOPNOTSUPP;
> > @@ -542,7 +545,7 @@ int iommu_do_domctl(
> >   #endif
> >   #ifdef CONFIG_HAS_DEVICE_TREE
> > -    if ( ret == -ENODEV )
> > +    if ( ret == -ENOSYS )
> 
> AFAICT, none of the code (including callee) before ret have been modified.
> So why are you modifying the check here?
>

Because this check will fail if we have CONFIG_HAS_DEVICE_TREE define,
but do not have CONFIG_HAS_PCI and iommu_do_dt_domctl will not be
called.
Same thing if switch/case inside iommu_do_pci_domctl go to default and
return -ENOSYS. This part looked strange for me. But I will definitely
go through this part once again.

Or maybe I've misinterpreted this part? 

> >           ret = iommu_do_dt_domctl(domctl, d, u_domctl);
> >   #endif
> > diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
> > index b85e6170b0..bf5f8c5b6b 100644
> > --- a/xen/include/public/domctl.h
> > +++ b/xen/include/public/domctl.h
> > @@ -81,8 +81,11 @@ struct xen_domctl_createdomain {
> >   #define _XEN_DOMCTL_IOMMU_no_sharept  0
> >   #define XEN_DOMCTL_IOMMU_no_sharept   (1U << _XEN_DOMCTL_IOMMU_no_sharept)
> > +#define _XEN_DOMCTL_IOMMU_force_iommu 1
> > +#define XEN_DOMCTL_IOMMU_force_iommu  (1U << _XEN_DOMCTL_IOMMU_force_iommu)
> > +
> >   /* Max XEN_DOMCTL_IOMMU_* constant.  Used for ABI checking. */
> > -#define XEN_DOMCTL_IOMMU_MAX XEN_DOMCTL_IOMMU_no_sharept
> > +#define XEN_DOMCTL_IOMMU_MAX XEN_DOMCTL_IOMMU_force_iommu
> >       uint32_t iommu_opts;
> > diff --git a/xen/include/xen/iommu.h b/xen/include/xen/iommu.h
> > index 6b2cdffa4a..a9cf2334af 100644
> > --- a/xen/include/xen/iommu.h
> > +++ b/xen/include/xen/iommu.h
> > @@ -330,6 +330,9 @@ struct domain_iommu {
> >        * necessarily imply this is true.
> >        */
> >       bool need_sync;
> > +
> > +    /* Do not return error if the device without iommu is assigned */
> > +    bool force_assign_iommu;
> >   };
> >   #define dom_iommu(d)              (&(d)->iommu)
> 
> Cheers,
> 
> -- 
> Julien Grall

Also I've posted a task on AT-F Phabricator asking about the feedback
about my SCMI implementation.
Link: https://developer.trustedfirmware.org/T985
Hope I'll be able to start a discussion and get an implementation, which
is approved by AT-F.

Best regards,
Oleksii.

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [RFC v2 6/8] tools/arm: Introduce force_assign_without_iommu option to xl.cfg
  2022-02-18  9:16     ` Oleksii Moisieiev
@ 2022-02-18 10:17       ` Julien Grall
  2022-02-21 18:39         ` Oleksii Moisieiev
  0 siblings, 1 reply; 45+ messages in thread
From: Julien Grall @ 2022-02-18 10:17 UTC (permalink / raw)
  To: Oleksii Moisieiev
  Cc: xen-devel, Wei Liu, Andrew Cooper, George Dunlap, Jan Beulich,
	Stefano Stabellini, Nick Rosbrook, Anthony PERARD, Juergen Gross,
	Paul Durrant



On 18/02/2022 09:16, Oleksii Moisieiev wrote:
> Hi Julien,

Hi Oleksii,

> On Thu, Feb 17, 2022 at 03:20:36PM +0000, Julien Grall wrote:
>>>        xlu_cfg_get_defbool(config, "xend_suspend_evtchn_compat",
>>> diff --git a/xen/common/domain.c b/xen/common/domain.c
>>> index 093bb4403f..f1f19bf711 100644
>>> --- a/xen/common/domain.c
>>> +++ b/xen/common/domain.c
>>> @@ -512,7 +512,7 @@ static int sanitise_domain_config(struct xen_domctl_createdomain *config)
>>>        if ( iommu )
>>>        {
>>> -        if ( config->iommu_opts & ~XEN_DOMCTL_IOMMU_no_sharept )
>>> +        if ( config->iommu_opts >> XEN_DOMCTL_IOMMU_MAX )
>>
>> XEN_DOMCTL_IOMMU_MAX will be defined as:
>>
>> (1U << _XEN_DOMCTL_IOMMU_force_iommu)
>>
>> This means the shift will do the wrong thing. However, AFAICT, this new
>> option will only be supported by Arm and likely only for platform device for
>> the time being.
> 
> Thanks, I will fix that.
> 
>>
>> That said, I am not convinced this flag should be per-domain in Xen.
>> Instead, I think it would be better to pass the flag via the device assign
>> domctl.
> 
> Do you mean that it's better to set this flag per device, not per
> domain? > This will require setting this flag for each device which should
> require either changing the dtdev format in dom.cfg or setting
> xen,force-assign-without-iommu in partial device-tree.
> 
> Both of those ways will complicate the configuration. As was mentioned
> before, we don't want to make domain configuration more complicated.
> What do you think about that?

We have two interfaces here:
   1) User -> tools
   2) tools -> Xen

We can chose different policy for each interface.

For the tools -> Xen interface, I think this should be per device 
(similar to XEN_DOMCTL_DEV_RDM_RELAXED).

For the User -> tools, I am open to discussion. One advantage with per 
device is the user explicitely vet each device. So it is harder to 
passthrough a device wrongly.

But I agree this also complicates the interface. What do other thinks?

>>
>>>            return -EOPNOTSUPP;
>>> @@ -542,7 +545,7 @@ int iommu_do_domctl(
>>>    #endif
>>>    #ifdef CONFIG_HAS_DEVICE_TREE
>>> -    if ( ret == -ENODEV )
>>> +    if ( ret == -ENOSYS )
>>
>> AFAICT, none of the code (including callee) before ret have been modified.
>> So why are you modifying the check here?
>>
> 
> Because this check will fail if we have CONFIG_HAS_DEVICE_TREE define,
> but do not have CONFIG_HAS_PCI and iommu_do_dt_domctl will not be
> called.

Below the implementation of iommu_do_domctl() on staging:

int iommu_do_domctl(
     struct xen_domctl *domctl, struct domain *d,
     XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl)
{
     int ret = -ENODEV;

     if ( !is_iommu_enabled(d) )
         return -EOPNOTSUPP;

#ifdef CONFIG_HAS_PCI
     ret = iommu_do_pci_domctl(domctl, d, u_domctl);
#endif

#ifdef CONFIG_HAS_DEVICE_TREE
     if ( ret == -ENODEV )
         ret = iommu_do_dt_domctl(domctl, d, u_domctl);
#endif

     return ret;
}

'ret' is initialized to -ENODEV. So for !CONFIG_HAS_PCI, then ret will 
not be changed. Therefore the current check is correct.

AFAICT, your patch is setting 'ret' so I don't expect any change here.

> Same thing if switch/case inside iommu_do_pci_domctl go to default and
> return -ENOSYS. This part looked strange for me. But I will definitely
> go through this part once again.
We use the same sub-op to assign/deassign a PCI and "DT" device. So we 
are not interested in -ENOSYS but -ENODEV that would be returned by the 
checks:

if ( domct->u.assign_device.dev != XEN_DOMCTL_DEV_PCI )

At the moment, there are no sub-op specific to "DT" device. So it is not 
necessary for us to check -ENOSYS yet.

I haven't looked at the rest of the series to see if we need it. But if 
we do, then I think the check should be extended in the patch that 
requires it.

Cheers,

-- 
Julien Grall


^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [RFC v2 6/8] tools/arm: Introduce force_assign_without_iommu option to xl.cfg
  2022-02-18 10:17       ` Julien Grall
@ 2022-02-21 18:39         ` Oleksii Moisieiev
  0 siblings, 0 replies; 45+ messages in thread
From: Oleksii Moisieiev @ 2022-02-21 18:39 UTC (permalink / raw)
  To: Julien Grall
  Cc: xen-devel, Wei Liu, Andrew Cooper, George Dunlap, Jan Beulich,
	Stefano Stabellini, Nick Rosbrook, Anthony PERARD, Juergen Gross,
	Paul Durrant

Hi Julien,

On Fri, Feb 18, 2022 at 10:17:33AM +0000, Julien Grall wrote:
> 
> 
> On 18/02/2022 09:16, Oleksii Moisieiev wrote:
> > Hi Julien,
> 
> Hi Oleksii,
> 
> > On Thu, Feb 17, 2022 at 03:20:36PM +0000, Julien Grall wrote:
> > > >        xlu_cfg_get_defbool(config, "xend_suspend_evtchn_compat",
> > > > diff --git a/xen/common/domain.c b/xen/common/domain.c
> > > > index 093bb4403f..f1f19bf711 100644
> > > > --- a/xen/common/domain.c
> > > > +++ b/xen/common/domain.c
> > > > @@ -512,7 +512,7 @@ static int sanitise_domain_config(struct xen_domctl_createdomain *config)
> > > >        if ( iommu )
> > > >        {
> > > > -        if ( config->iommu_opts & ~XEN_DOMCTL_IOMMU_no_sharept )
> > > > +        if ( config->iommu_opts >> XEN_DOMCTL_IOMMU_MAX )
> > > 
> > > XEN_DOMCTL_IOMMU_MAX will be defined as:
> > > 
> > > (1U << _XEN_DOMCTL_IOMMU_force_iommu)
> > > 
> > > This means the shift will do the wrong thing. However, AFAICT, this new
> > > option will only be supported by Arm and likely only for platform device for
> > > the time being.
> > 
> > Thanks, I will fix that.
> > 
> > > 
> > > That said, I am not convinced this flag should be per-domain in Xen.
> > > Instead, I think it would be better to pass the flag via the device assign
> > > domctl.
> > 
> > Do you mean that it's better to set this flag per device, not per
> > domain? > This will require setting this flag for each device which should
> > require either changing the dtdev format in dom.cfg or setting
> > xen,force-assign-without-iommu in partial device-tree.
> > 
> > Both of those ways will complicate the configuration. As was mentioned
> > before, we don't want to make domain configuration more complicated.
> > What do you think about that?
> 
> We have two interfaces here:
>   1) User -> tools
>   2) tools -> Xen
> 
> We can chose different policy for each interface.
> 
> For the tools -> Xen interface, I think this should be per device (similar
> to XEN_DOMCTL_DEV_RDM_RELAXED).
> 
> For the User -> tools, I am open to discussion. One advantage with per
> device is the user explicitely vet each device. So it is harder to
> passthrough a device wrongly.
> 
> But I agree this also complicates the interface. What do other thinks?
> 

I see the following ways of User -> tools format:

a) Set force_assign_without_iommu = 1 in dom.cfg
b) Update dtdev format add force_iommu parameter, so dtdev will look
like this:
dtdev = [
    "/soc/dma-controller@e6700000",
    "/soc/gpio@e6055000,force_iommu",
    ...
]
c)...

Tools -> Xen possible ways:

d) Set force_assign_without_iommu to domain globally
e) Pass force_assign_without_iommu via device-assign domctl.

a) + d) is what we have in the patch series.

I think a) + e) can work for now so we will have an interface to make
force_assign_without_iommu per device in future.

What do you think about it?

> > > 
> > > >            return -EOPNOTSUPP;
> > > > @@ -542,7 +545,7 @@ int iommu_do_domctl(
> > > >    #endif
> > > >    #ifdef CONFIG_HAS_DEVICE_TREE
> > > > -    if ( ret == -ENODEV )
> > > > +    if ( ret == -ENOSYS )
> > > 
> > > AFAICT, none of the code (including callee) before ret have been modified.
> > > So why are you modifying the check here?
> > > 
> > 
> > Because this check will fail if we have CONFIG_HAS_DEVICE_TREE define,
> > but do not have CONFIG_HAS_PCI and iommu_do_dt_domctl will not be
> > called.
> 
> Below the implementation of iommu_do_domctl() on staging:
> 
> int iommu_do_domctl(
>     struct xen_domctl *domctl, struct domain *d,
>     XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl)
> {
>     int ret = -ENODEV;
> 
>     if ( !is_iommu_enabled(d) )
>         return -EOPNOTSUPP;
> 
> #ifdef CONFIG_HAS_PCI
>     ret = iommu_do_pci_domctl(domctl, d, u_domctl);
> #endif
> 
> #ifdef CONFIG_HAS_DEVICE_TREE
>     if ( ret == -ENODEV )
>         ret = iommu_do_dt_domctl(domctl, d, u_domctl);
> #endif
> 
>     return ret;
> }
> 
> 'ret' is initialized to -ENODEV. So for !CONFIG_HAS_PCI, then ret will not
> be changed. Therefore the current check is correct.
> 
> AFAICT, your patch is setting 'ret' so I don't expect any change here.
> 
> > Same thing if switch/case inside iommu_do_pci_domctl go to default and
> > return -ENOSYS. This part looked strange for me. But I will definitely
> > go through this part once again.
> We use the same sub-op to assign/deassign a PCI and "DT" device. So we are
> not interested in -ENOSYS but -ENODEV that would be returned by the checks:
> 
> if ( domct->u.assign_device.dev != XEN_DOMCTL_DEV_PCI )
> 
> At the moment, there are no sub-op specific to "DT" device. So it is not
> necessary for us to check -ENOSYS yet.
> 
> I haven't looked at the rest of the series to see if we need it. But if we
> do, then I think the check should be extended in the patch that requires it.
> 

Thank you for the comment. I will refactor this code.

Also I wanted to share with you some thoughts about using SMC client_id
field to pass agent_id to the SCMI.
Posted question regarding this approach to trustedfirmware
phabricator [0].

I've found that ATF already has multiagent approach implemented for
stm32mp1 platform, see plat/st/stm32mp1/include/stm32mp1_smc.h [1].
It uses 2 funcids hardcoded for AGENT0 and AGENT1:
STM32_SIP_SMC_SCMI_AGENT0       0x82002000
STM32_SIP_SMC_SCMI_AGENT1       0x82002001

I think this approach will be very promising for SCI mediator.

Firmware defines a range of func_ids, let's say from 0x82000010 to 0x82000020,
where 0x82000010 is the base func_id for trusted agent. This func_id is
set in arm,scmi-smc node in Xen device-tree.

During startup Xen requests agent configuration and calculate func_id for
each channel the following way:

<Base Func_ID> + <channel_id>

Calculated func_id should be assigned to the Domain by setting it as
arm,scmi-id in arm,scmi-smc node. So for the Domain Xen will generate
the following nodes:

scmi {
   compatible = "arm,scmi-smc";
   arm,smc-id = <calculated func_id>;
   ...
   shmem = <&shmem_node>
}; 

shmem_node {
  compatible = "arm,scmi-shmem";
  ...
};

In this case each domain will get unique func_id to send SCMI commands.

I see the following advantages of this approach:
1) There is no need for Xen to intercept SMC requests. All requests from
agents will go directly to the Firmware, which can calculate agent_id
from func_id. This mean that there is no need for scmi_handle_call
function.
2) This approach already implemented for stm32mp1 board so it's more
likely to be accepted.

Another thing I want to discuss is how Xen should handle scmi related
nodes from xen device-tree.
Currently Xen device-tree includes arm,scmi-smc node and a list of
scmi-shmem nodes for the channels:
scmi {
   compatible = "arm,scmi-smc";
   ...
};

sram@0x53ff0000 {
    compatible = "mmio-sram";
    ...
    cpu_scp_shm: scp-shmem@0x0 {
        compatible = "arm,scmi-shmem";
        ...
    };
    scp-shmem@0x1000 {
        ...
    };

    ...

    scp-shmem@0xF000 {
        ...
    };

};

We do not want all of this nodes to be present in Dom0.
I suggest to set xen,passthrough for all this nodes to ensure that Dom0
will not get information about other channels and generate nodes
arm,scmi-shmem and arm,scmi-smc for Dom0.
I think this approach will be more secure.

What do you think about both suggested approaches?

[0] https://developer.trustedfirmware.org/T985
[1] https://review.trustedfirmware.org/TF-A/trusted-firmware-a

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [RFC v2 6/8] tools/arm: Introduce force_assign_without_iommu option to xl.cfg
  2022-02-08 18:00 ` [RFC v2 6/8] tools/arm: Introduce force_assign_without_iommu option to xl.cfg Oleksii Moisieiev
  2022-02-17 14:52   ` Anthony PERARD
  2022-02-17 15:20   ` Julien Grall
@ 2022-06-03 13:43   ` Jan Beulich
  2 siblings, 0 replies; 45+ messages in thread
From: Jan Beulich @ 2022-06-03 13:43 UTC (permalink / raw)
  To: Oleksii Moisieiev
  Cc: Wei Liu, Andrew Cooper, xen-devel, George Dunlap, Julien Grall,
	Stefano Stabellini, Nick Rosbrook, Anthony PERARD, Juergen Gross,
	Paul Durrant

On 08.02.2022 19:00, Oleksii Moisieiev wrote:
> --- a/xen/common/domain.c
> +++ b/xen/common/domain.c
> @@ -512,7 +512,7 @@ static int sanitise_domain_config(struct xen_domctl_createdomain *config)
>  
>      if ( iommu )
>      {
> -        if ( config->iommu_opts & ~XEN_DOMCTL_IOMMU_no_sharept )
> +        if ( config->iommu_opts >> XEN_DOMCTL_IOMMU_MAX )
>          {
>              dprintk(XENLOG_INFO, "Unknown IOMMU options %#x\n",
>                      config->iommu_opts);

While in common code this is perhaps okay, the new bit wants rejecting
(or also implementing) for x86.

> @@ -534,6 +536,7 @@ int iommu_do_domctl(
>  {
>      int ret = -ENODEV;
>  
> +
>      if ( !is_iommu_enabled(d) )
>          return -EOPNOTSUPP;

Please don't.

> @@ -542,7 +545,7 @@ int iommu_do_domctl(
>  #endif
>  
>  #ifdef CONFIG_HAS_DEVICE_TREE
> -    if ( ret == -ENODEV )
> +    if ( ret == -ENOSYS )
>          ret = iommu_do_dt_domctl(domctl, d, u_domctl);
>  #endif

Why?

Jan



^ permalink raw reply	[flat|nested] 45+ messages in thread

end of thread, other threads:[~2022-06-03 13:44 UTC | newest]

Thread overview: 45+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-02-08 18:00 [RFC v2 0/8] Introduce SCI-mediator feature Oleksii Moisieiev
2022-02-08 18:00 ` [RFC v2 1/8] xen/hypfs: support fo nested dynamic hypfs nodes Oleksii Moisieiev
2022-02-10  7:34   ` Juergen Gross
2022-02-11  8:16     ` Oleksii Moisieiev
2022-02-11 13:28       ` Juergen Gross
2022-02-11 13:32         ` Oleksii Moisieiev
2022-02-08 18:00 ` [RFC v2 2/8] libs: libxenhypfs - handle blob properties Oleksii Moisieiev
2022-02-09 13:47   ` Oleksandr Andrushchenko
2022-02-09 14:01     ` Jan Beulich
2022-02-09 14:04       ` Oleksandr Andrushchenko
2022-02-09 14:04   ` Juergen Gross
2022-02-08 18:00 ` [RFC v2 3/8] xen/arm: Export host device-tree to hypfs Oleksii Moisieiev
2022-02-08 18:26   ` Julien Grall
2022-02-09 10:20     ` Oleksii Moisieiev
2022-02-09 12:17       ` Julien Grall
2022-02-09 14:17         ` Oleksii Moisieiev
2022-02-09 18:51         ` Oleksii Moisieiev
2022-02-09 19:34           ` Julien Grall
2022-02-10  9:38             ` Oleksii Moisieiev
2022-02-09 14:03     ` Juergen Gross
2022-02-08 18:00 ` [RFC v2 4/8] xen/arm: add generic SCI mediator framework Oleksii Moisieiev
2022-02-08 18:00 ` [RFC v2 5/8] xen/arm: introduce SCMI-SMC mediator driver Oleksii Moisieiev
2022-02-09 15:02   ` Oleksandr Andrushchenko
2022-02-09 15:23     ` Julien Grall
2022-02-11  8:46   ` Bertrand Marquis
2022-02-11 10:44     ` Oleksii Moisieiev
2022-02-11 11:18       ` Bertrand Marquis
2022-02-11 11:55         ` Oleksii Moisieiev
2022-02-11 23:35           ` Stefano Stabellini
2022-02-12 12:43         ` Julien Grall
2022-02-14 11:13           ` Oleksii Moisieiev
2022-02-14 11:27             ` Bertrand Marquis
2022-02-14 11:51               ` Oleksii Moisieiev
2022-02-14 22:05                 ` Stefano Stabellini
2022-02-16 17:41                   ` Oleksii Moisieiev
2022-02-08 18:00 ` [RFC v2 6/8] tools/arm: Introduce force_assign_without_iommu option to xl.cfg Oleksii Moisieiev
2022-02-17 14:52   ` Anthony PERARD
2022-02-18  8:19     ` Oleksii Moisieiev
2022-02-17 15:20   ` Julien Grall
2022-02-18  9:16     ` Oleksii Moisieiev
2022-02-18 10:17       ` Julien Grall
2022-02-21 18:39         ` Oleksii Moisieiev
2022-06-03 13:43   ` Jan Beulich
2022-02-08 18:00 ` [RFC v2 7/8] tools/arm: add "arm_sci" " Oleksii Moisieiev
2022-02-08 18:00 ` [RFC v2 8/8] xen/arm: add SCI mediator support for DomUs Oleksii Moisieiev

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.