[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [RFC v2 5/8] xen/arm: introduce SCMI-SMC mediator driver


  • To: Oleksii Moisieiev <Oleksii_Moisieiev@xxxxxxxx>
  • From: Bertrand Marquis <Bertrand.Marquis@xxxxxxx>
  • Date: Fri, 11 Feb 2022 11:18:47 +0000
  • Accept-language: en-GB, en-US
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=none; dmarc=none; dkim=none; arc=none
  • Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=AQ1kbdgRgQY1DbM0npjKQIudIjlSMj0GSZFre9YsSgw=; b=Eh/UC38XBEWkzXBvCPRb+6iG5oL3yZXtFZfnAhfoLKmXj38iku/LleBsdnr2oaNe2Xb5Tt2iXY50usfbl+1aLF3N/tCVlA1/C9HUQghdVtkogTYvjy0O5mcxxq7erjYmmaeD1OVFBOXEWt0qxxxK3e/GAydk4RzPyetdJQ1SSIDqcGnVMt6coDKe/ojv1DhYww4VmG0poaXVOZCGl4w/O9EH6WRD3jcZ63MRY844aEPamA/VMVWsKoVx5hmXsBJ7+jnaeD+1PiJJwgUSGuEM1lUitz/amdDCKIGGtuear8w+LpAimLroA3WQs2VwOv8BGkjhTDHClx1RwYjM41da0A==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=Qk6uQeUXY1qAEQ1qqd2pjOyIoWuM1ADgzLzvR7SbHYMIO1H0M9qPkw3Qapg+PA8Tair8K1esrYf2Eijj7cEg6xaVmYDfpXlwKhZcn58SRe4Ne99ajDL4bRLjSA1NttQnfCja2+R7oTUrqnykIlBl0GdJQCSF09+ppaEWVlJaabpsSQcVYJR9F4+3m8G1+xBvwT99Iz/xPkZS7b3zER/1sriqeR5AZY2hv5Dbz9eritOLSUldub6ivHrr3DNBMiCeFjYSRuMBD+Y1m7MgjZinf10edJSSSYyhP0O5tHGTeEpIu/FgaKlpjgO6X/GL+hB/lChrBYl6eyrjbE5atLs38w==
  • Authentication-results-original: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=arm.com;
  • Cc: "xen-devel@xxxxxxxxxxxxxxxxxxxx" <xen-devel@xxxxxxxxxxxxxxxxxxxx>, Stefano Stabellini <sstabellini@xxxxxxxxxx>, Julien Grall <julien@xxxxxxx>, Volodymyr Babchuk <Volodymyr_Babchuk@xxxxxxxx>
  • Delivery-date: Fri, 11 Feb 2022 11:19:20 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>
  • Nodisclaimer: true
  • Original-authentication-results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=arm.com;
  • Thread-index: AQHYHRW24Dmb0qV8ZkqAv39Pf6/nVayODW6AgAAg+ICAAAmzAA==
  • Thread-topic: [RFC v2 5/8] xen/arm: introduce SCMI-SMC mediator driver

Hi Oleksii,


> On 11 Feb 2022, at 10:44, Oleksii Moisieiev <Oleksii_Moisieiev@xxxxxxxx> 
> 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@xxxxxxxx> 
>>> 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@xxxxxxxxxx:renesas-rcar/linux-bsp.git
> based on tag <rcar-5.0.0.rc4>
> 
> ATF: 
> git@xxxxxxxxxx: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@xxxxxxxx>
>>> ---
>>> 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@xxxxxxxx>
>>> + * 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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.