From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (prime256v1) server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A05A460A2609 for ; Fri, 23 Oct 2026 01:57:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key, unprotected) header.d=epam.com header.i=@epam.com header.a=rsa-sha256 header.s=selector1 header.b=TmDWYDvJ Received: from list by lists.xenproject.org with outflank-mailman.1458761.1670807 (Exim 4.92) (envelope-from ) id 1xK4WK-0002pz-Id; Fri, 23 Oct 2026 01:56:36 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 1458761.1670807; Fri, 23 Oct 2026 01:56:36 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1xK4WK-0002ps-Fo; Fri, 23 Oct 2026 01:56:36 +0000 Received: by outflank-mailman (input) for mailman id 1458761; Fri, 23 Oct 2026 01:56:34 +0000 Received: from mx.expurgate.net ([195.190.135.20]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1xK4WI-0002pm-9u for xen-devel@lists.xenproject.org; Fri, 23 Oct 2026 01:56:34 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1xK4WH-00FAa2-J5 for xen-devel@lists.xenproject.org; Fri, 23 Oct 2026 03:56:33 +0200 Received: from [10.42.69.12] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 6adabe21-8faa-0a2a0a5109dd-0a2a450ca4f0-20 for ; Fri, 23 Oct 2026 03:56:33 +0200 Received: from [40.107.159.82] (helo=OSPPR02CU001.outbound.protection.outlook.com) by tlsNG-d25034.mxtls.expurgate.net with ESMTPS (eXpurgate 4.57.1) (envelope-from ) id 6adabed1-f479-0a2a450c0019-286b9f52683f-3 for ; Fri, 23 Oct 2026 03:56:33 +0200 Received: from VE1PR03MB6078.eurprd03.prod.outlook.com (2603:10a6:803:113::29) by MMZPR03MB647648.eurprd03.prod.outlook.com (2603:10a6:190:4c::15) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.546.15; Fri, 23 Oct 2026 01:56:29 +0000 Received: from VE1PR03MB6078.eurprd03.prod.outlook.com ([fe80::4722:b91:9b24:ee48]) by VE1PR03MB6078.eurprd03.prod.outlook.com ([fe80::4722:b91:9b24:ee48%4]) with mapi id 15.21.0546.012; Fri, 23 Oct 2026 01:56:28 +0000 X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Post: List-Help: List-Subscribe: , Precedence: list Sender: "Xen-devel" Authentication-Results: eu.smtp.expurgate.cloud; dkim=pass header.s=selector1 header.d=epam.com header.i="@epam.com" header.h="From:Date:Subject:Message-ID:Content-Type:MIME-Version:x-ms-exchange-senderadcheck" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=GBt/SnjZ1NLSllOyb4MD36w7ZZLJAVstzU6JQllkjkcAnjqruW8WBzKTL5va3ItYznNV6+OSZkjcpCFjxQD5Sj9P105fum8YOLC7UOGcxO4dREyRDgOapJAc3jMVoLzcGwaHQCFA6agxyda8l4KvvzyOmIW63N6mAdPAIs5/BLOlEXkEd9Jp0M17Xk2quviTTyQlMe9jGCVFCk9jvTFIBm/9dyZRrDEMWRfk1Fo8RtPx3FbdKwh0AAL2hGeiOrTyllIhl7HtHP1QL3y4lEf2JIRIb5L3869KGEgjtDRO+9ulQfgE3Pmt+l5oZIFqwl66muW/sNoEdf8PODQBLd6kSA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; 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=NzgvpxZwGof/EUUXE22kj+bYNxRo0NQ6DPaedQuJZYs=; b=bXScgLgqW2NTszhQnEbdlEFyOOmNyaramKJgEob/Ah4PKoN+Jgl5CbeEFJiRRVUcqpC2Z/8uNGt9++zZ6rGmeh/mddD1etrrG2Y/mSn1pkd9ILD3122uLMVb5YQ8hAj4TVweFAPYhzQKfVbA0IlOB+ltok9DgSHh0RcUhJVNt5nljl8Oihg8fQN2t6l1foKdPREU65OnwTRlXNHGuP4REqoZVakt4z4wy36BopDBtQci9EaoGRlgFq8guL2ylALKDxEge7UAktWCMB+nt0aXf8AEu/XrYq2tSsupblZeMtGre3yIoEawDKQTJhdXWx83TngCitOJGLtIM0SKMGT/YA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=epam.com; dmarc=pass action=none header.from=epam.com; dkim=pass header.d=epam.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=epam.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=NzgvpxZwGof/EUUXE22kj+bYNxRo0NQ6DPaedQuJZYs=; b=TmDWYDvJ8tVAB9rTp0XqpaeyEFb6C1UjizgUlDIeZsz1A1BlKrBryujqDwrXNXKuVQKDSLWtHVSsE+cIXv0PqoX5a81BaS8DWOtxxTW8nm0Cg3h0qlFE5Ty7UKwZ3B7RKHDtq2/3Q/VnhHjxHq7+hJsqG/6RvuY4YeJI4hrxkfirLLLlJJv2hD6mHJHC8jo4bbHhSwxGpkj2/cKtbyGhGbde/gkCyH3O8gwx30Nsf84wavA2O5LKsjPv/6Txuo0iRDEB5mi0yYpDg5ZQ+A5m38UuygqQOiKWNXd3tUQGUykm1yktIe8yPqZ62W0KMQvE0ciGAq0ZhqVosuJvIsZ40w== From: Volodymyr Babchuk To: Oleksii Moisieiev CC: "xen-devel@lists.xenproject.org" , Andrew Cooper , Anthony PERARD , Bertrand Marquis , Jan Beulich , Juergen Gross , Julien Grall , Michal Orzel , =?iso-8859-1?Q?Roger_Pau_Monn=E9?= , Stefano Stabellini , Grygorii Strashko Subject: Re: [PATCH v14 4/6] xen/arm: scmi: introduce SCI SCMI SMC multi-agent driver Thread-Topic: [PATCH v14 4/6] xen/arm: scmi: introduce SCI SCMI SMC multi-agent driver Thread-Index: AQHdYG8UqIf/0AA9cU2/foNeomddPw== Date: Fri, 23 Oct 2026 01:56:28 +0000 Message-ID: <87mrs5tc1g.fsf@epam.com> References: In-Reply-To: (Oleksii Moisieiev's message of "Tue, 20 Oct 2026 08:43:20 +0000") Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: user-agent: mu4e 1.14.3; emacs 30.2 authentication-results: mx.microsoft.com 1; dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=epam.com; x-ms-publictraffictype: Email x-ms-traffictypediagnostic: VE1PR03MB6078:EE_|MMZPR03MB647648:EE_ x-ms-office365-filtering-correlation-id: 139f6820-f35d-453b-f364-08df30a8da72 x-ms-exchange-senderadcheck: 1 x-ms-exchange-antispam-relay: 0 x-microsoft-antispam: BCL:0;ARA:13230040|7416014|376014|366016|42112799006|1800799024|23010399003|261022105027099003|260925021311599003|261022075727099003|260925021911599003|56012099006|261009223027099003|260925022911599003|4143699003|11063799006|38070700021|261021133027099003|261021123027099003|261021130227099003|261021121427099003|261021135927099003|10067099003|18002099003|22082099003|6133799003|261022115727099003|4133799003|3023799007|261022113327099003; x-microsoft-antispam-message-info: QvDFjY9Abfq0sOl54miuIrJX7P0Yh42wo4EK+J/KRKjnctzp6qjBUcdY1nAIk2OCm39q8ItMoeCG/B9U4Z8qxnS2AmT6f/7u/wzm3/gPfwOKIFdGqd/fclxTjbEeqlD3tx7HbcNAIxaidL2SstU1V7AIlAr5QcWJomLR8A7K6/qA6VfLl3zGSkE4EuUqHFbDqonDUYiPZ1aBo8+tISnfc78R2yJ2uXIONbp3v40ICgl26QhdBEIFsiX70Fy8S+K4piNpsxYF0qsKagfwZ+CpMoEvumoz4L9xB5CyiFd/HZJOzGbIt0h6KhrxOxJ47du+xS8XYu/VSHqdk85gvRdT781Jv/OFq+uFniIFSgcEl+h+x1oZ9GJSXtv6l2C7xVjjMPnQ/vuBqGI7XPjBExNhOlLjMHSKTwEDGt+knSYpjhrTzrC6XuHOsX3jAI/FZsuBwYDJ50aaVN0PPAaeRrng4VTMqZLVMq3aQ+4p32B+hBTavf+cdsofNongS0DDAvVu7FdaXTk2mFQauDag+zeKcM6QwNGMOMgluQfbd/RSNZRBbNSiBQt6qGZ+xAv3jCP53jGjdsJUGgbZVhlHH1ddtkbGGuEsGQctVYBq8i4Xkytp9HI1cEmAFrKj0bscgoWqqGSGaU2/FQXvH/KCTfCKoEiOvk3pxHNrlLunTgrpGo8= x-forefront-antispam-report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:VE1PR03MB6078.eurprd03.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(7416014)(376014)(366016)(42112799006)(1800799024)(23010399003)(261022105027099003)(260925021311599003)(261022075727099003)(260925021911599003)(56012099006)(261009223027099003)(260925022911599003)(4143699003)(11063799006)(38070700021)(261021133027099003)(261021123027099003)(261021130227099003)(261021121427099003)(261021135927099003)(10067099003)(18002099003)(22082099003)(6133799003)(261022115727099003)(4133799003)(3023799007)(261022113327099003);DIR:OUT;SFP:1102; x-ms-exchange-antispam-messagedata-chunkcount: 1 x-ms-exchange-antispam-messagedata-0: =?iso-8859-1?Q?J74lhKX56EnvlZNZv20YH8euuuYQEC6EfGt1/l2ZpdZEGJBw+I3BcAQCqG?= =?iso-8859-1?Q?nADirY2Fmi9EVlSRzCxvOrP68qXKDt7nW+lRPa2j63wDu+E1pWz8ld8ykk?= =?iso-8859-1?Q?P7iYxSUgbDfaTitUM/5DuJJ+MeHkvS696XXCIGIHDdl9xS83p+SPRfMjZp?= =?iso-8859-1?Q?bJ3Wt1JGmhHcGLlAJDqiZXdGBdx/lXt3QlP1bg6ceKRnNqK5qJzy2C93fv?= =?iso-8859-1?Q?2aods7SRF3Frpl3MRBtZmYIN8VMiFgvCiqRXkD52Uc3l4Scy3aGeppvHKQ?= =?iso-8859-1?Q?AiNc2wrrzNgzQSfPfXDzd7esZ/h054MUdO+D8CltFlclumr8BCfc/VKP5b?= =?iso-8859-1?Q?kC2kXbOJAAZmxWl3OUZbdsNS2ejFnxxq1jdepINnvVA8ohegh+rVcS2HnV?= =?iso-8859-1?Q?TzyAxhHZevZn5QK0YweqG6zmuwyIPif6A21U2W2CnE9gZqFFI/xrXVEQMm?= =?iso-8859-1?Q?S7AtgfpXwQjFT834SZIM9WpEmRCZD9z8f34dPCYwFF0zvsA9MlD2ybmMI3?= =?iso-8859-1?Q?ygpJtk2LXkFVZypgd9j68s+NP4a6wK4EcPwACagtL6ekwtPRHYZOn8QziM?= =?iso-8859-1?Q?36cvnow34c/RWWOKgQe5TWYl+/YGtUbXWpGQMYKB2CM/WmWmXFs6H5K3bp?= =?iso-8859-1?Q?25fJORLpSYzPcAHsyTqsZN5IrmFny103YQXYryuPM5el+UP0vF9Tsb11vT?= =?iso-8859-1?Q?5+3xMWYqFnANyezi1lfFBU9XNROYxNClGzOqiJ9dc28w8xA+3FoPy9tMxa?= =?iso-8859-1?Q?NkpLb2qdga+9mKayMfUntlZp5dRphQiegPxmjwYbGa6lniUfTkGPGb/OOS?= =?iso-8859-1?Q?fW3djk5m3tKksOXJTaOdM0dmEXWjL2GDXfas0vbSe/k02g1N+2+MCURcFg?= =?iso-8859-1?Q?yDMdGMHcu5IDuBsWPnMqGHIPCJbWhWxkqfqfvXrXCT0yWmzkSWeFi8XdQR?= =?iso-8859-1?Q?JRJzw9BqpWbmEeXHQx/cO5dVGcqyI5zOBPjW+u1fYvkAkBo90i7KAlJda1?= =?iso-8859-1?Q?GMODGZ3BqY/KTc2u0UGJhY/3JzanYJXdBMlIUXskK78EGeDsnwAilrNdWV?= =?iso-8859-1?Q?PU7JCg2d3XqYiMzyTGdYbQrgmOCry8gKijrROoeyP/Zy4OsK/jiUgGfYAw?= =?iso-8859-1?Q?VXRBkFrX8ompbPTv8zj4Ed/nfRS0cyU4bZ1tSPWRq+ZD17FQtH5lrRXghX?= =?iso-8859-1?Q?1tsbhAuUrXtccX5QBzwtVlG+H3F6ZurTyKRZqroONfmwCjydM9VdtComx3?= =?iso-8859-1?Q?vxGMGG2mLDcttGG6hytaYfauhNT61OgQabJumKJoTwvZJe9BLiPsE/pQ6E?= =?iso-8859-1?Q?BKqQjzxTEgHegoBp/v1BI9/ds575nAx/r+shhrZkpxSAIPFoGAKKDk7Z6t?= =?iso-8859-1?Q?nQNKyiNSZ+88I/gItbB7d8HtB2ziE0LjQQfog4vb3Jg52nntMAOKzIeQ5O?= =?iso-8859-1?Q?NIv/0u+ZJGLjMNqKRiTN0+bGLZp2pdw/Rkn1mDDHXz4LYDucs8HiNlsyVv?= =?iso-8859-1?Q?Lee9XrF2LWGxehVkVDlTboOionmh2z/9MKs6GLDiA6n9TvHIrsChyHLmyV?= =?iso-8859-1?Q?IaSXJ0b1NzjDtCXOEiClCulSkQkhVeapg66Nf7nrWFvIJE9dGdNzGMXvMW?= =?iso-8859-1?Q?zqQPQ0AlgnhnF15ycy0tIUEuysEOmDucQuL5b34suuewQvFbYdnrh93EPC?= =?iso-8859-1?Q?NI+wKOXxgWiq+A30JXs1l59C1XxFsN6lmxz78CUddkil5h28hpkHEKc4fY?= =?iso-8859-1?Q?WQPEpRyVqUEPNuxcKQ12GxhPt+Ub2toH+mVQjt2FTKPXWdGrS97BQZpx/Q?= =?iso-8859-1?Q?ms0o5G1+UwTpuRPsIS3jqV0HTou6liM=3D?= Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable X-Archived-By: MIME-Version: 1.0 X-OriginatorOrg: epam.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-AuthSource: VE1PR03MB6078.eurprd03.prod.outlook.com X-MS-Exchange-CrossTenant-Network-Message-Id: 139f6820-f35d-453b-f364-08df30a8da72 X-MS-Exchange-CrossTenant-originalarrivaltime: 23 Oct 2026 01:56:28.7205 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: b41b72d0-4e9f-4c26-8a69-f949f367c91d X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-MS-Exchange-CrossTenant-userprincipalname: FTeKH5hekYy6tDj32+S6oovGK00eVlYRmmd+kujJq6fSJJXXI4FAfBL5kKT9buDBp0qD/eEJ8FItCWS1LCmbOPMIKXMyomE03YZ8WuGye9Y= X-MS-Exchange-Transport-CrossTenantHeadersStamped: MMZPR03MB647648 X-purgate-ID: tlsNG-d25034/1792720593-5073F9FB-85E95DCF/0/0 X-purgate-type: clean X-purgate-size: 74405 X-Spam-Status: No, score=-20.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI, MENTIONS_GIT_HOSTING,SPF_HELO_PASS,SPF_PASS,UNPARSEABLE_RELAY autolearn=ham autolearn_force=no version=4.0.1 X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-26) on aws-us-west-2-korg-listserv-alma10-1 Hi Oleksii, Oleksii Moisieiev writes: > This patch introduces SCI driver to support for ARM EL3 Trusted Firmware-= A > (TF-A) which provides SCMI interface with multi-agent support, as shown > below. > > +-----------------------------------------+ > | | > | EL3 TF-A SCMI | > +-------+--+-------+--+-------+--+-------++ > |shmem1 | |shmem0 | |shmem2 | |shmemX | > +-----+-+ +---+---+ +--+----+ +---+---+ > smc-id1 | | | | > agent1 | | | | > +-----v--------+---------+-----------+----+ > | | | | | > | | | | | > +--------------+---------+-----------+----+ > smc-id0 | smc-id2| smc-idX| > agent0 | agent2 | agentX | > | | | > +----v---+ +--v-----+ +--v-----+ > | | | | | | > | Dom0 | | Dom1 | | DomX | > | | | | | | > | | | | | | > +--------+ +--------+ +--------+ > > The EL3 SCMI multi-agent firmware is expected to provide SCMI SMC shared > memory transport for every Agent in the system. > > The SCMI Agent transport channel defined by pair: > - smc-id: SMC id used for Doorbell > - shmem: shared memory for messages transfer, Xen page > aligned. Shared memory is mapped with the following flags: > MT_DEVICE_nGnRE. > > The following SCMI Agents are expected to be defined by SCMI FW to enable= SCMI > multi-agent functionality under Xen: > - Xen management agent: trusted agents that accesses to the Base Protocol > commands to configure agent specific permissions > - OSPM VM agents: non-trusted agent, one for each Guest domain which is > allowed direct HW access. At least one OSPM VM agent has to be provided > by FW if HW is handled only by Dom0 or Driver Domain. > > The EL3 SCMI FW is expected to implement following Base protocol messages= : > - BASE_DISCOVER_AGENT (required for Xen and secondary agents without reg) > - BASE_RESET_AGENT_CONFIGURATION (optional) > - BASE_SET_DEVICE_PERMISSIONS (optional) > > The driver binds to the arm,scmi-smc management node inside a Xen-specifi= c > container compatible with xen,sci under /chosen/xen. Other SCMI nodes, > including the host /firmware/scmi, are ignored by the mediator. > > Describe secondary agents as xen,scmi-agent children of an agents node > inside the same container. The agents node uses #address-cells =3D <1> an= d > `#size-cells =3D <0>`. Each child provides arm,smc-id and a single shmem = phandle. > The optional single-cell reg property supplies the SCMI agent ID (0..254)= . > When reg is absent, Xen discovers the ID using BASE_DISCOVER_AGENT on tha= t > channel. Use agent@ for an explicit ID, and a node name without a uni= t > address for discovery. Disabled agent nodes are ignored; at least one > enabled secondary agent is required. > > Resolve discovered IDs before adding channels to the list, so duplicate > IDs are rejected consistently, including clashes with Xen's management > agent. Explicit IDs avoid mapping and probing secondary channels during > initialization. Xen always discovers its own management agent ID. > > Keep shared-memory nodes under xen_scmi_config and leave the platform's > existing /firmware/scmi and host OSPM shared-memory node unchanged. Chann= el > nodes describe locations, rather than reserve memory: if firmware buffers > occupy system RAM, the platform DT must reserve the whole firmware-owned > range in /reserved-memory before Xen boots. A single reservation may cove= r > multiple channels, including unused ones. SRAM outside system RAM does > not require a RAM reservation. Channel nodes need not be moved into > /reserved-memory. > > For example: > > / { > #address-cells =3D <2>; > #size-cells =3D <2>; > > scmi_shm_0: sram@47ff0000 { > compatible =3D "arm,scmi-shmem"; > reg =3D <0x0 0x47ff0000 0x0 0x1000>; > }; > > firmware { > scmi: scmi { > compatible =3D "arm,scmi-smc"; > arm,smc-id =3D <0x82000002>; > #address-cells =3D <1>; > #size-cells =3D <0>; > shmem =3D <&scmi_shm_0>; > }; > }; > > chosen { > #address-cells =3D <2>; > #size-cells =3D <2>; > ranges; > > xen { > #address-cells =3D <2>; > #size-cells =3D <2>; > ranges; > > xen_scmi_config { > compatible =3D "xen,sci"; > #address-cells =3D <2>; > #size-cells =3D <2>; > ranges; > xen,dom0-sci-agent-id =3D <0>; > > /* Xen management channel */ > scmi_shm_1: sram@47ff1000 { > compatible =3D "arm,scmi-shmem"; > reg =3D <0x0 0x47ff1000 0x0 0x1000>; > }; > > scmi_shm_2: sram@47ff2000 { > compatible =3D "arm,scmi-shmem"; > reg =3D <0x0 0x47ff2000 0x0 0x1000>; > }; > > scmi_shm_3: sram@47ff3000 { > compatible =3D "arm,scmi-shmem"; > reg =3D <0x0 0x47ff3000 0x0 0x1000>; > }; > > scmi_xen: scmi { > compatible =3D "arm,scmi-smc"; > arm,smc-id =3D <0x82000003>; > #address-cells =3D <1>; > #size-cells =3D <0>; > #access-controller-cells =3D <1>; > shmem =3D <&scmi_shm_1>; > }; > > agents { > #address-cells =3D <1>; > #size-cells =3D <0>; > > agent@0 { > compatible =3D "xen,scmi-agent"; > reg =3D <0>; > arm,smc-id =3D <0x82000002>; > shmem =3D <&scmi_shm_0>; > }; > > agent@2 { > compatible =3D "xen,scmi-agent"; > reg =3D <2>; > arm,smc-id =3D <0x82000004>; > shmem =3D <&scmi_shm_2>; > }; > > agent@3 { > compatible =3D "xen,scmi-agent"; > reg =3D <3>; > arm,smc-id =3D <0x82000005>; > shmem =3D <&scmi_shm_3>; > }; > }; > }; > }; > }; > }; > > To discover a secondary agent ID instead, omit reg from its node: > > agent-domu { > compatible =3D "xen,scmi-agent"; > arm,smc-id =3D <0x82000004>; > shmem =3D <&scmi_shm_2>; > }; > > The agents child nodes replace the former scmi-secondary-agents list and > `#scmi-secondary-agents-cells` property. The xen,sci subtree is omitted f= rom > Dom0's DT; the host OSPM channel is passed through when SCMI is enabled > for Dom0. Full configuration and domain examples are included in the > binding documentation and the hypervisor guide in patch 6. > > SMC ID Configuration and SCMI Connection Compatibility: > > The configuration allows the same device tree to work for both baremetal > Linux and Linux Dom0. This is achieved because: > > - Baremetal Linux uses: func_id 0x82000002, scmi-shmem 0x47ff0000 > - Dom0 Linux uses: func_id 0x82000002, scmi-shmem 0x47ff0000 > - Xen management uses: func_id 0x82000003, scmi-shmem 0x47ff1000 > > This works because the privileged SCMI connection in EL3 firmware is not > tied exclusively to func_id 0x82000002. The EL3 firmware supports multipl= e > SCMI agents with different SMC IDs and shared memory regions. Each agent > (Dom0 via 0x82000002, Xen via 0x82000003, other domains via additional > func_ids) has an independent communication channel to the firmware. > > The key distinction is that Xen's management channel (0x82000003) is used > for privileged operations like agent configuration and device permissions > (BASE_SET_DEVICE_PERMISSIONS, BASE_RESET_AGENT_CONFIGURATION), while Dom0= 's > channel (0x82000002) is used for standard SCMI protocol operations (power= , > clock, sensor management, etc.). The firmware enforces different permissi= on > levels for each agent based on their agent_id, not the SMC ID. > > Therefore, there is no conflict: Linux Dom0 retains its standard SCMI > connection for hardware management, while Xen uses its separate privilege= d > channel for mediating access between multiple domains. > > - It implements the SCI subsystem interface required for configuring and > enabling SCMI functionality for Dom0/hwdom and Guest domains. To enable > SCMI functionality for domain it has to be configured with unique support= ed > SCMI Agent_id and use corresponding SCMI SMC shared memory transport > [smc-id, shmem] defined for this SCMI Agent_id. > - Once Xen domain is configured it can communicate with EL3 SCMI FW: > -- zero-copy, the guest domain puts SCMI message in shmem; > -- the guest triggers SMC exception with smc-id (doorbell); > -- the Xen driver catches exception, do checks and synchronously forwar= ds > it to EL3 FW. > - the Xen driver sends BASE_RESET_AGENT_CONFIGURATION message to Xen > management agent channel on domain destroy event. This allows to reset > resources used by domain and so implement use-case like domain reboot. > > Dom0 Enable SCMI SMC: > - set xen,dom0-sci-agent-id=3D under the xen,sci container in > the Host DT. If the property is absent, SCMI is disabled for Dom0 > and all SCMI nodes are removed from the Dom0 DT. The driver updates > the Dom0 DT SCMI node "arm,smc-id" value and fixes up the shmem > node according to the assigned agent_id. > > - pass dom0=3Dsci-agent-id=3D in Xen command line. if not prov= ided > SCMI will be disabled for Dom0 and all SCMI nodes removed from Dom0 DT= . > The driver updates Dom0 DT SCMI node "arm,smc-id" value and fix up shm= em > node according to assigned agent_id. > > Guest domains enable SCMI SMC: > - xl.cfg: add configuration option as below > > arm_sci =3D "type=3Dscmi_smc_multiagent,agent_id=3D2" > > - xl.cfg: enable access to the "arm,scmi-shmem" which should > correspond assigned agent_id for the domain, for example: > > iomem =3D [ > "47ff2,1@22001", > ] > > - DT: add SCMI nodes to the Driver domain partial device tree as in the > below example. The "arm,smc-id" should correspond assigned agent_id > for the domain: > > passthrough { > scmi_shm_0: sram@22001000 { > compatible =3D "arm,scmi-shmem"; > reg =3D <0x0 0x22001000 0x0 0x1000>; > }; > > firmware { > compatible =3D "simple-bus"; > scmi: scmi { > compatible =3D "arm,scmi-smc"; > arm,smc-id =3D <0x82000004>; > shmem =3D <&scmi_shm_0>; > ... > } > } > } > > SCMI "4.2.1.1 Device specific access control" > > The XEN SCI SCMI SMC multi-agent driver performs "access-controller" > provider function in case EL3 SCMI FW implements SCMI "4.2.1.1 Device > specific access control" and provides the BASE_SET_DEVICE_PERMISSIONS > command to configure the devices that an agents have access to. > The DT SCMI node should "#access-controller-cells=3D<1>" property and DT > devices should be bound to the Xen SCMI. > > &i2c1 { > access-controllers =3D <&scmi 0>; > }; > > The Dom0 and dom0less domains DT devices will be processed > automatically through sci_assign_dt_device() call, but to assign SCMI > devices from toolstack the xl.cfg:"dtdev" property > shall be used: > > dtdev =3D [ > "/soc/i2c@e6508000", > ] > > xl.cfg:dtdev will contain all nodes which are under SCMI > management (not only those which are behind IOMMU). > > Additionally, this patch adds documentation for the pre-existing > scmi-smc-passthrough command line option, which was previously > undocumented. > > [0] https://developer.arm.com/documentation/den0056 > [1] https://web.git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.gi= t/tree/Documentation/devicetree/bindings/firmware/arm,scmi.yaml > [2] https://web.git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.gi= t/tree/Documentation/devicetree/bindings/access-controllers/access-controll= ers.yaml > > Signed-off-by: Grygorii Strashko > Signed-off-by: Oleksii Moisieiev > --- > > Changes in v14: > - replace the flat secondary-agent list and its cell-count property with > xen,scmi-agent child nodes under agents, using reg for an optional ID > - scope secondary-agent parsing to the management channel's xen,sci conta= iner > - resolve discovered IDs before insertion and reject duplicate or invalid= IDs > - validate shared-memory phandles, addresses and nonzero page-aligned siz= es > - retain shared-memory nodes under xen_scmi_config and document platform > reservations separately, following the review discussion > - update binding examples and commit description for the child-node forma= t > - match the const-qualified SCI domain_sanitise_config callback interface > > Changes in v13: > - fix typo in commit description > > Changes in v12: > - rebase to the latest staging > - return EINVAL if xen,sci_type=3Dscmi_smc_multiagent was set but > CONFIG_SCMI_SMC_MA not set > - put arm_sci_agent_id after v8r_el1_msa and before pad to preserve > order. Reduced pad from uint16_t to uint8_t to fill the gap (was 2 > bytes before adding arm_sci_agent_id and left only 1, so used uint8_t > to preserve structure size) > - fix scmi_handle_call to use arm_smccc_guest_smc helper function > - update send_smc_message function to use new format of > arm_smccc_1_1_smc > - guard the Dom0 SCMI agent id setup in create_dom0() and MA related > funcitons with CONFIG_SCMI_SMC_MA > - fix the xen_scmi_config example in booting.txt, which placed properties > after subnodes and was rejected by dtc with "Properties must precede > subnodes" > > Changes in v10: > - Fix tabs in MAINTAINERS file > - remove duplicate SPDX tag from scmi-shmem.c > - add cast to ARM_SMCCC_INVALID_PARAMETER to settle the sign since > ARM_SMCCC_INVALID_PARAMETER is -3 which is part of the spec and resp > is the default smccc call structure. > - update free_channel_list. Add spinlock to avoid race condition and > a comment with a description of the function work > - preserve error of smc_create_channel in scmi_probe > - check scmi shmem address alignment as wel as it is done for size > - check for d->arch.sci_data !=3D NULL in scmi_handle_call > - use SCMI_SHMEM_MAPPED size for iomem_permit_access > - change len type to unsigned in shmem_{get|put}_message > - rename shmem_channel_is_free to shmem_channel_status > - add comment about skipping message status when getting message response > - Set correct agent_id ranges for dom0less and a toolstack. Agent_id 0 > is not binded for dom0 so can be reused. Also mentioned that > UINT8_MAX (255) is treated as invalid agent_id. > - Split hypervisor and toolstack changes into separate commits > - move init list and spin init after initial checks in probe call > - fix typo in comments > - clean resources when sci_register returns an error. > > Changes in v9: > - sort and refactor MAINTAINERS enties > - remove Spurious changes > - add extra check to avoid ASSERT when calling unmap_channel_memory > from assign device method > - set correct tx flag to SCMI_BASE_AGENT_PERMISSIONS_RESET when > freeing resources. Flag should be set to 1 according to the > section 4.2.2.12 [0]. > - fix dt node copmaring > - moved channel->shmem check from ASSERT in unmap_memory_channel to > "if" statement. This will prevent firing ASSERT if > unmap_channel_memory was called twice on the same channel. > > Changes in v8: > - update xen_scmi func_id in commit description > - updated documentation with the new DT format > - updated opt_dom0_scmi_agent_id setting to avoid it to be equal > SCMI_AGENT_ID_INVALID. > - changed SCMI_AGENT_ID_INVALID from 0xff to UINT8_MAX which makes > code more clear showing that UINT8_MAX is theated like invalid > agent_id and couldn't be used. Also excluded SCMI_AGENT_ID_INVALID > from acceptable value range > - remove outdated xen,config property ignore, added xen,sci compatible > to skip_matches in handle_node > - add documentation for pre-existing scmi-smc-passthrough command line > option in alphabetically correct location (in 's' section) > - add note to commit description about documentation for previously > undocumented scmi-smc-passthrough > - Fix SMC IDs in DT examples (Xen management uses 0x82000003, Dom0 uses 0= x82000002) > - Add explicit note explaining why Dom0 and Xen channels do not conflict > - Document dom0less multi-agent configuration example (xen,sci_type / xen= ,sci-agent-id) > - Add scmi_xen node to agent-discovery example with #scmi-secondary-agent= s-cells =3D 2 > - Drop dom0=3Dsci-agent-id command line handling; Dom0 SCMI is now enable= d via > xen,dom0-sci-agent-id in the xen,sci DT container > - Refresh docs and examples to mention the DT property instead of the cmd= line option > > Changes in v7: > - rework scmi nodes for xen to match on compatible string instead of > the direct path > > Changes in v6: > - updated scmi-shmem to use io.h from generic location > - update scmi_agent_id parameter to be provided inside dom0=3D parameter > list and have the following format "dom0=3Dsci-agent-id=3D0" > This change was done as a response for Stefano comment and > requires a lot of code changes, but produces much cleaner solution > that's why I've added it to the code. > - fix file comments and return codes > - fix lenght checks in shmem_{get,put}_message to use offsetof > - remove len member from scmi_channel structure as it is not used > - set scmi-secondary-agents property to be mandatory since if no > secondary agents were provided then there is no sence to enable scmi > when no secondary agents are populated to the Domains > - update documentation in booting.txt, added xen_scmi node to the > example > - adjust d->arch.sci_enabled value in scmi_domain_destroy > - fix lock management in smc_create_channel call > - avoid extra map_channel_memory command for Xen management channel > because collect_agent_id call unmaps memory if DOMID_XEN is not > set. So for Xen management channel we can init domain_id ad DOMID_XEN > before calling collect_agent_id so memory shouldn't be unmapped. > > Changes in v5: > - fix device-tree example format in booting.txt, added ";" after "}". > - update define in scmi-proto.h > - update define in scmi-shmem.h file > - scmi_assign_device - do not ignore -EOPNOTSUPP return > code of the do_smc_xfer > - remove overwriting agent_channel->agent_id after > SCMI_BASE_DISCOVER_AGENT call > - add multi-agent files to the MAINTAINERS > - add SCMI multi-agent description to the SUPPORT.md > - handle ARM_SMCCC_INVALID_PARAMETER return code and return -EINVAL > for smc call > - updated collect_agents function. Set agent_id parameter as optional > in scmi-secondary-agents device-tree property > - introduce "#scmi-secondary-agents-cells" parameter to set if > agent_id was provided > - reanme xen,scmi-secondary-agents property to scmi-secondary-agents > - move memcpu_toio/fromio for the generic place > - update Xen to get management channel from /chosen/xen,config node > - get hypervisor channnel from node instead of using hardcoded > - update handling scmi and shmem nodes for the domain > - Set multi-agent driver to support only Arm64 > > Changes in v4: > - toolstack comments from Anthony PERARD > - added dom0less support > - added doc for "xen,scmi-secondary-agents" > > MAINTAINERS | 1 + > SUPPORT.md | 11 + > docs/misc/arm/device-tree/booting.txt | 195 +++++ > xen/arch/arm/dom0less-build.c | 17 + > xen/arch/arm/domain_build.c | 43 ++ > xen/arch/arm/firmware/Kconfig | 12 + > xen/arch/arm/firmware/Makefile | 1 + > xen/arch/arm/firmware/scmi-proto.h | 164 ++++ > xen/arch/arm/firmware/scmi-shmem.c | 118 +++ > xen/arch/arm/firmware/scmi-shmem.h | 45 ++ > xen/arch/arm/firmware/scmi-smc-multiagent.c | 792 ++++++++++++++++++++ > xen/include/public/arch-arm.h | 5 +- > 12 files changed, 1403 insertions(+), 1 deletion(-) > create mode 100644 xen/arch/arm/firmware/scmi-proto.h > create mode 100644 xen/arch/arm/firmware/scmi-shmem.c > create mode 100644 xen/arch/arm/firmware/scmi-shmem.h > create mode 100644 xen/arch/arm/firmware/scmi-smc-multiagent.c > > diff --git a/MAINTAINERS b/MAINTAINERS > index c60afc93a5..cd6d1243bd 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -534,6 +534,7 @@ SCI MEDIATORS > R: Oleksii Moisieiev > S: Supported > F: xen/arch/arm/firmware/sci.c > +F: xen/arch/arm/firmware/scmi-*.[ch] > F: xen/arch/arm/include/asm/firmware/sci.h > > SEABIOS UPSTREAM > diff --git a/SUPPORT.md b/SUPPORT.md > index eb07332462..dc41a6b2f3 100644 > --- a/SUPPORT.md > +++ b/SUPPORT.md > @@ -972,6 +972,17 @@ by hwdom. Some platforms use SCMI for access to syst= em-level resources. > > Status: Supported > > +### Arm: SCMI SMC multi-agent support > + > +Enable support for the multi-agent configuration of the EL3 Firmware, wh= ich > +allows Xen to provide an SCMI interface to the Domains. > +Xen manages access permissions to the HW resources and provides an SCMI = interface > +to the Domains. Each Domain is represented as a separate Agent, which ca= n > +communicate with EL3 Firmware using a dedicated shared memory region, an= d > +notifications are passed through by Xen. > + > + Status, ARM64: Tech Preview > + > ### ARM: Guest PSCI support > > Emulated PSCI interface exposed to guests. We support all mandatory > diff --git a/docs/misc/arm/device-tree/booting.txt b/docs/misc/arm/device= -tree/booting.txt > index 3787d2e2b6..178f2493d8 100644 > --- a/docs/misc/arm/device-tree/booting.txt > +++ b/docs/misc/arm/device-tree/booting.txt > @@ -331,6 +331,21 @@ with the following properties: > Should be used together with scmi-smc-passthrough Xen command line > option. > > + - "scmi_smc_multiagent" > + > + Enables ARM SCMI SMC multi-agent support for the guest by enabling S= CMI over > + SMC calls forwarding from domain to the EL3 firmware (like ARM > + Trusted Firmware-A) with a multi SCMI OSPM agent support. > + The SCMI agent_id should be specified for the guest with "xen,sci-ag= ent-id" > + property. > + > +- "xen,sci-agent-id" > + > + Specifies ARM SCMI agent id for the guest. This option is mandatory = if the > + SCMI SMC "scmi_smc_multiagent" support is enabled for the guest. The= agent ids > + of guest must be unique and in the range [0..254]. UINT8_MAX (255) i= s > + treated as invalid. > + > - v8r_el1_msa > > A string property specifying whether, on Armv8-R systems at EL1, a d= omain > @@ -847,3 +862,183 @@ The automatically allocated static shared memory wi= ll get mapped at > 0x80000000 in DomU1 guest physical address space, and at 0x90000000 in D= omU2 > guest physical address space. DomU1 is explicitly defined as the owner d= omain, > and DomU2 is the borrower domain. > + > +SCMI SMC multi-agent support > +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D > + > +For enabling the ARM SCMI SMC multi-agent support (enabled by CONFIG_SCM= I_SMC_MA) > +the Xen specific SCMI Agent's configuration shall be provided in the Hos= t DT > +according to the SCMI compliant EL3 Firmware specification with ARM SMC/= HVC > +transport. The SCMI configuration must live under the Xen SCMI container > +"xen,sci" beneath "/chosen" (for example "/chosen/xen/xen_scmi_config/sc= mi"). The > +Xen SCMI mediator will bind only to the "arm,scmi-smc" node that is a ch= ild of > +this "xen,sci" container; any other "arm,scmi-smc" nodes (for example un= der > +"/firmware") are ignored to avoid stealing the host's SCMI OSPM instance= . > + > +- agents > + > + Required child of the xen,sci container. Describes the secondary SCM= I > + agents available for assignment to domains. Set #address-cells =3D <= 1> > + and #size-cells =3D <0> in this node. At least one enabled child wit= h > + compatible =3D "xen,scmi-agent" is required. Each such child has: > + > + - reg: Optional single-cell SCMI agent ID in the range 0..254. When > + present, name the node agent@, with the unit address in hexade= cimal. > + When absent, use a name without a unit address; Xen discovers the = ID > + using BASE_DISCOVER_AGENT on that channel. A malformed reg is reje= cted. > + - arm,smc-id: Required SMC function ID for this agent's doorbell. > + - shmem: Required single phandle to an arm,scmi-shmem node. Its addr= ess > + and nonzero size must be Xen page aligned. > + > + Agent IDs must be unique, including IDs returned by discovery, and m= ust > + not identify Xen's management agent. Children marked disabled are ig= nored. > + The management arm,scmi-smc node remains a sibling of agents, direct= ly > + under xen,sci. > + > +- xen,dom0-sci-agent-id > + > + Optional. Specifies the Dom0/hwdom SCMI agent_id inside the ``xen,sc= i`` > + container. When provided, Dom0 will be configured for SCMI multi-age= nt > + support; when omitted, SCMI remains disabled for Dom0. The selected > + agent's ``func_id`` and shared-memory region must match the host > + ``/firmware/scmi`` channel passed to Dom0. > + > +The shared-memory nodes may remain inside xen_scmi_config, while the > +platform's existing /firmware/scmi and its shared-memory node stay uncha= nged. > +Shared-memory nodes describe channel locations; they do not reserve RAM. > +If the channel buffers occupy system RAM, the platform DT must reserve t= he > +whole firmware-owned range in /reserved-memory before Xen boots. One > +reservation may cover several channels, including channels not listed in > +this configuration. SRAM outside system RAM does not require a RAM > +reservation. Moving the channel nodes into /reserved-memory is not requi= red. > + > +As an example: > + > +/ { > + #address-cells =3D <2>; > + #size-cells =3D <2>; > + > + scmi_shm_0: sram@47ff0000 { > + compatible =3D "arm,scmi-shmem"; > + reg =3D <0x0 0x47ff0000 0x0 0x1000>; > + }; > + > + firmware { > + scmi: scmi { > + compatible =3D "arm,scmi-smc"; > + arm,smc-id =3D <0x82000002>; > + #address-cells =3D <1>; > + #size-cells =3D <0>; > + shmem =3D <&scmi_shm_0>; > + }; > + }; > + > + chosen { > + #address-cells =3D <2>; > + #size-cells =3D <2>; > + ranges; > + > + xen { > + #address-cells =3D <2>; > + #size-cells =3D <2>; > + ranges; > + > + xen_scmi_config { > + compatible =3D "xen,sci"; > + #address-cells =3D <2>; > + #size-cells =3D <2>; > + ranges; > + xen,dom0-sci-agent-id =3D <0>; /* dom0 agent id */ > + > + /* Xen management channel */ > + scmi_shm_1: sram@47ff1000 { > + compatible =3D "arm,scmi-shmem"; > + reg =3D <0x0 0x47ff1000 0x0 0x1000>; > + }; > + > + scmi_shm_2: sram@47ff2000 { > + compatible =3D "arm,scmi-shmem"; > + reg =3D <0x0 0x47ff2000 0x0 0x1000>; > + }; > + > + scmi_shm_3: sram@47ff3000 { > + compatible =3D "arm,scmi-shmem"; > + reg =3D <0x0 0x47ff3000 0x0 0x1000>; > + }; > + > + scmi_xen: scmi { > + compatible =3D "arm,scmi-smc"; /* Xen management age= nt func_id */ > + arm,smc-id =3D <0x82000003>; > + #address-cells =3D <1>; > + #size-cells =3D <0>; > + #access-controller-cells =3D <1>; > + shmem =3D <&scmi_shm_1>; /* Xen management agent shm= em */ > + }; > + > + agents { > + #address-cells =3D <1>; > + #size-cells =3D <0>; > + > + agent@0 { > + compatible =3D "xen,scmi-agent"; > + reg =3D <0>; > + arm,smc-id =3D <0x82000002>; > + shmem =3D <&scmi_shm_0>; > + }; > + > + agent@2 { > + compatible =3D "xen,scmi-agent"; > + reg =3D <2>; > + arm,smc-id =3D <0x82000004>; > + shmem =3D <&scmi_shm_2>; > + }; > + > + agent@3 { > + compatible =3D "xen,scmi-agent"; > + reg =3D <3>; > + arm,smc-id =3D <0x82000005>; > + shmem =3D <&scmi_shm_3>; > + }; > + }; > + }; > + }; > + }; > +}; > + > +This keeps the host OSPM channel (SMC 0x82000002, shmem 0x47ff0000) sepa= rate > +from Xen's privileged management channel (SMC 0x82000003, shmem 0x47ff10= 00). > +The xen,sci subtree is omitted from Dom0's device tree. > + > +To discover a secondary agent ID, omit reg from its node. For example, > +replace only agent@2 above with: > + > +agent-domu { > + compatible =3D "xen,scmi-agent"; > + arm,smc-id =3D <0x82000004>; > + shmem =3D <&scmi_shm_2>; > +}; > + > +BASE_DISCOVER_AGENT is required on secondary channels only when reg is > +omitted. Xen always uses it to discover its management agent ID. Providi= ng > +reg avoids mapping and probing the secondary channel during initializati= on. > +The scmi-secondary-agents and #scmi-secondary-agents-cells properties us= ed > +by earlier versions are replaced by the agents child nodes. > + > +Dom0less example (multi-agent) > +------------------------------- > + > +Use the same Xen SCMI configuration as above. Remove xen,dom0-sci-agent-= id > +if Dom0 does not use SCMI. Add xen,sci_type and xen,sci-agent-id to the > +predefined guest's node under /chosen: > + > +chosen { > + xen,domain@1 { > + compatible =3D "xen,domain"; > + xen,sci_type =3D "scmi_smc_multiagent"; > + xen,sci-agent-id =3D <2>; > + /* Additional domain properties (memory, cpus, kernels, etc.) */ > + }; > +}; > + > +The guest's partial DT and shared-memory mapping must use the SMC functi= on > +ID and shared-memory channel associated with agent 2 in the agents node. > diff --git a/xen/arch/arm/dom0less-build.c b/xen/arch/arm/dom0less-build.= c > index 7bbb2eafb6..01c2a5ce52 100644 > --- a/xen/arch/arm/dom0less-build.c > +++ b/xen/arch/arm/dom0less-build.c > @@ -293,6 +293,23 @@ static int __init domu_dt_sci_parse(struct dt_device= _node *node, > > d_cfg->arch.arm_sci_type =3D XEN_DOMCTL_CONFIG_ARM_SCI_SCMI_SMC; > } > + else if ( !strcmp(sci_type, "scmi_smc_multiagent") ) > + { > + uint32_t agent_id =3D 0; > + > + if ( !IS_ENABLED(CONFIG_SCMI_SMC_MA) ) > + { > + printk(XENLOG_ERR "xen,sci_type=3Dscmi_smc_multiagent reques= ted, but CONFIG_SCMI_SMC_MA not set\n"); > + return -EINVAL; > + } > + > + if ( !dt_property_read_u32(node, "xen,sci-agent-id", &agent_id) = || > + agent_id >=3D UINT8_MAX ) > + return -EINVAL; > + > + d_cfg->arch.arm_sci_type =3D XEN_DOMCTL_CONFIG_ARM_SCI_SCMI_SMC_= MA; > + d_cfg->arch.arm_sci_agent_id =3D agent_id; > + } > else > { > printk(XENLOG_ERR "xen,sci_type in not valid (%s) for domain %s\= n", > diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c > index 72f6f7539a..5d42cdf6af 100644 > --- a/xen/arch/arm/domain_build.c > +++ b/xen/arch/arm/domain_build.c > @@ -88,6 +88,39 @@ int __init parse_arch_dom0_param(const char *s, const = char *e) > return -EINVAL; > } > > +#ifdef CONFIG_SCMI_SMC_MA > +/* SCMI agent ID for dom0 obtained from xen,sci container */ > +#define SCMI_AGENT_ID_INVALID UINT8_MAX > + > +static uint8_t __init get_dom0_scmi_agent_id(void) > +{ > + const struct dt_device_node *config_node; > + u32 val; > + const struct dt_property *prop; > + > + config_node =3D dt_find_compatible_node(NULL, NULL, "xen,sci"); > + if ( !config_node ) > + return SCMI_AGENT_ID_INVALID; > + > + prop =3D dt_find_property(config_node, "xen,dom0-sci-agent-id", NULL= ); > + if ( !prop ) > + return SCMI_AGENT_ID_INVALID; > + > + if ( !dt_property_read_u32(config_node, "xen,dom0-sci-agent-id", &va= l) ) > + return SCMI_AGENT_ID_INVALID; > + > + if ( val >=3D SCMI_AGENT_ID_INVALID ) > + { > + printk(XENLOG_WARNING > + "Invalid xen,dom0-sci-agent-id=3D%u, SCMI disabled for Dom0= \n", > + val); > + return SCMI_AGENT_ID_INVALID; > + } > + > + return val; > +} > +#endif /* CONFIG_SCMI_SMC_MA */ > + > /* Override macros from asm/page.h to make them work with mfn_t */ > #undef virt_to_mfn > #define virt_to_mfn(va) _mfn(__virt_to_mfn(va)) > @@ -1480,6 +1513,7 @@ static int __init handle_node(struct domain *d, str= uct kernel_info *kinfo, > DT_MATCH_TYPE("memory"), > /* The memory mapped timer is not supported by Xen. */ > DT_MATCH_COMPATIBLE("arm,armv7-timer-mem"), > + DT_MATCH_COMPATIBLE("xen,sci"), > { /* sentinel */ }, > }; > static const struct dt_device_match timer_matches[] __initconst =3D > @@ -1975,6 +2009,15 @@ void __init create_dom0(void) > dom0_cfg.arch.tee_type =3D tee_get_type(); > dom0_cfg.max_vcpus =3D dom0_max_vcpus(); > > +#ifdef CONFIG_SCMI_SMC_MA > + /* Set up SCMI agent ID if provided in the xen,sci container */ > + dom0_cfg.arch.arm_sci_agent_id =3D get_dom0_scmi_agent_id(); > + dom0_cfg.arch.arm_sci_type =3D (dom0_cfg.arch.arm_sci_agent_id !=3D > + SCMI_AGENT_ID_INVALID) ? > + XEN_DOMCTL_CONFIG_ARM_SCI_SCMI_SMC_MA : > + XEN_DOMCTL_CONFIG_ARM_SCI_NONE; > +#endif > + > if ( iommu_enabled ) > dom0_cfg.flags |=3D XEN_DOMCTL_CDF_iommu; > > diff --git a/xen/arch/arm/firmware/Kconfig b/xen/arch/arm/firmware/Kconfi= g > index 5c5f0880c4..972cd9b173 100644 > --- a/xen/arch/arm/firmware/Kconfig > +++ b/xen/arch/arm/firmware/Kconfig > @@ -29,6 +29,18 @@ config SCMI_SMC > driver domain. > Use with EL3 firmware which supports only single SCMI OSPM agent. > > +config SCMI_SMC_MA > + bool "Enable ARM SCMI SMC multi-agent driver" > + depends on ARM_64 > + select ARM_SCI > + help > + Enables SCMI SMC/HVC multi-agent in XEN to pass SCMI requests fro= m Domains > + to EL3 firmware (TF-A) which supports multi-agent feature. > + This feature allows to enable SCMI per Domain using unique SCMI a= gent_id, > + so Domain is identified by EL3 firmware as an SCMI Agent and can = access > + allowed platform resources through dedicated SMC/HVC Shared memor= y based > + transport. > + > endchoice > > endmenu > diff --git a/xen/arch/arm/firmware/Makefile b/xen/arch/arm/firmware/Makef= ile > index 71bdefc24a..37927e690e 100644 > --- a/xen/arch/arm/firmware/Makefile > +++ b/xen/arch/arm/firmware/Makefile > @@ -1,2 +1,3 @@ > obj-$(CONFIG_ARM_SCI) +=3D sci.o > obj-$(CONFIG_SCMI_SMC) +=3D scmi-smc.o > +obj-$(CONFIG_SCMI_SMC_MA) +=3D scmi-shmem.o scmi-smc-multiagent.o > diff --git a/xen/arch/arm/firmware/scmi-proto.h b/xen/arch/arm/firmware/s= cmi-proto.h > new file mode 100644 > index 0000000000..49f63cfc0a > --- /dev/null > +++ b/xen/arch/arm/firmware/scmi-proto.h > @@ -0,0 +1,164 @@ > +/* SPDX-License-Identifier: GPL-2.0-only */ > +/* > + * Arm System Control and Management Interface definitions > + * Version 3.0 (DEN0056C) > + * > + * Copyright (c) 2025 EPAM Systems > + */ > + > +#ifndef ARM_FIRMWARE_SCMI_PROTO_H_ > +#define ARM_FIRMWARE_SCMI_PROTO_H_ > + > +#include > + > +#define SCMI_SHORT_NAME_MAX_SIZE 16 > + > +/* SCMI status codes. See section 4.1.4 */ > +#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) > + > +/* Protocol IDs */ > +#define SCMI_BASE_PROTOCOL 0x10 > + > +/* Base protocol message IDs */ > +#define SCMI_BASE_PROTOCOL_VERSION 0x0 > +#define SCMI_BASE_PROTOCOL_ATTIBUTES 0x1 > +#define SCMI_BASE_PROTOCOL_MESSAGE_ATTRIBUTES 0x2 > +#define SCMI_BASE_DISCOVER_AGENT 0x7 > +#define SCMI_BASE_SET_DEVICE_PERMISSIONS 0x9 > +#define SCMI_BASE_RESET_AGENT_CONFIGURATION 0xB > + > +typedef struct scmi_msg_header { > + uint8_t id; > + uint8_t type; > + uint8_t protocol; > + uint32_t status; > +} scmi_msg_header_t; > + > +/* Table 2 Message header format */ > +#define SCMI_HDR_ID GENMASK(7, 0) > +#define SCMI_HDR_TYPE GENMASK(9, 8) > +#define SCMI_HDR_PROTO GENMASK(17, 10) > + > +#define SCMI_FIELD_GET(_mask, _reg) = \ > + ((typeof(_mask))(((_reg) & (_mask)) >> (ffs64(_mask) - 1))) > +#define SCMI_FIELD_PREP(_mask, _val) = \ > + (((typeof(_mask))(_val) << (ffs64(_mask) - 1)) & (_mask)) > + > +static inline uint32_t pack_scmi_header(scmi_msg_header_t *hdr) > +{ > + return SCMI_FIELD_PREP(SCMI_HDR_ID, hdr->id) | > + SCMI_FIELD_PREP(SCMI_HDR_TYPE, hdr->type) | > + SCMI_FIELD_PREP(SCMI_HDR_PROTO, hdr->protocol); > +} > + > +static inline void unpack_scmi_header(uint32_t msg_hdr, scmi_msg_header_= t *hdr) > +{ > + hdr->id =3D SCMI_FIELD_GET(SCMI_HDR_ID, msg_hdr); > + hdr->type =3D SCMI_FIELD_GET(SCMI_HDR_TYPE, msg_hdr); > + hdr->protocol =3D SCMI_FIELD_GET(SCMI_HDR_PROTO, msg_hdr); > +} > + > +static inline int scmi_to_xen_errno(int scmi_status) > +{ > + if ( scmi_status =3D=3D SCMI_SUCCESS ) > + return 0; > + > + 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; > + } > +} > + > +/* PROTOCOL_VERSION */ > +#define SCMI_VERSION_MINOR GENMASK(15, 0) > +#define SCMI_VERSION_MAJOR GENMASK(31, 16) > + > +struct scmi_msg_prot_version_p2a { > + uint32_t version; > +} __packed; > + > +/* BASE PROTOCOL_ATTRIBUTES */ > +#define SCMI_BASE_ATTR_NUM_PROTO GENMASK(7, 0) > +#define SCMI_BASE_ATTR_NUM_AGENT GENMASK(15, 8) > + > +struct scmi_msg_base_attributes_p2a { > + uint32_t attributes; > +} __packed; > + > +/* > + * BASE_DISCOVER_AGENT > + */ > +#define SCMI_BASE_AGENT_ID_OWN 0xFFFFFFFF > + > +struct scmi_msg_base_discover_agent_a2p { > + uint32_t agent_id; > +} __packed; > + > +struct scmi_msg_base_discover_agent_p2a { > + uint32_t agent_id; > + char name[SCMI_SHORT_NAME_MAX_SIZE]; > +} __packed; > + > +/* > + * BASE_SET_DEVICE_PERMISSIONS > + */ > +#define SCMI_BASE_DEVICE_ACCESS_ALLOW BIT(0, UL) > + > +struct scmi_msg_base_set_device_permissions_a2p { > + uint32_t agent_id; > + uint32_t device_id; > + uint32_t flags; > +} __packed; > + > +/* > + * BASE_RESET_AGENT_CONFIGURATION > + */ > +#define SCMI_BASE_AGENT_PERMISSIONS_RESET BIT(0, UL) > + > +struct scmi_msg_base_reset_agent_cfg_a2p { > + uint32_t agent_id; > + uint32_t flags; > +} __packed; > + > +#endif /* ARM_FIRMWARE_SCMI_PROTO_H_ */ > + > +/* > + * Local variables: > + * mode: C > + * c-file-style: "BSD" > + * c-basic-offset: 4 > + * tab-width: 4 > + * indent-tabs-mode: nil > + * End: > + */ > diff --git a/xen/arch/arm/firmware/scmi-shmem.c b/xen/arch/arm/firmware/s= cmi-shmem.c > new file mode 100644 > index 0000000000..e36745a85e > --- /dev/null > +++ b/xen/arch/arm/firmware/scmi-shmem.c > @@ -0,0 +1,118 @@ > +/* SPDX-License-Identifier: GPL-2.0-only */ > +/* > + * SMC/HVC shmem transport implementation used by > + * SCI SCMI multi-agent driver. > + * > + * Oleksii Moisieiev > + * Copyright (c) 2025 EPAM Systems > + */ > + > +#include > +#include > +#include > + > +#include "scmi-proto.h" > +#include "scmi-shmem.h" > + > +static inline int > +shmem_channel_status(const volatile struct scmi_shared_mem __iomem *shme= m) > +{ > + return (readl(&shmem->channel_status) & > + SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE) ? 0 : -EBUSY; > +} > + > +int shmem_put_message(volatile struct scmi_shared_mem __iomem *shmem, > + scmi_msg_header_t *hdr, void *data, unsigned int l= en) > +{ > + int ret; > + > + if ( (len + offsetof(struct scmi_shared_mem, msg_payload)) > > + SCMI_SHMEM_MAPPED_SIZE ) > + { > + printk(XENLOG_ERR "scmi: Wrong size of smc message. Data is inva= lid\n"); "of the SMC message". Also, looks like it is over 80 characters. > + return -EINVAL; > + } > + > + ret =3D shmem_channel_status(shmem); > + if ( ret ) > + return ret; > + > + writel_relaxed(0x0, &shmem->channel_status); > + /* Writing 0x0 right now, but "shmem"_FLAG_INTR_ENABLED can be set *= / > + writel_relaxed(0x0, &shmem->flags); > + writel_relaxed(sizeof(shmem->msg_header) + len, &shmem->length); > + writel(pack_scmi_header(hdr), &shmem->msg_header); Why do you mix writel() and writel_relaxed() here? > + > + if ( len > 0 && data ) > + memcpy_toio(shmem->msg_payload, data, len); > + > + return 0; > +} > + > +int shmem_get_response(const volatile struct scmi_shared_mem __iomem *sh= mem, > + scmi_msg_header_t *hdr, void *data, unsigned int = len) > +{ > + int recv_len; > + int ret; > + /* > + * First word of msg_payload carries the returned status; exclude it= from > + * recv_len so only the protocol payload is copied back to the calle= r. > + */ > + int pad =3D sizeof(hdr->status); > + > + if ( len >=3D SCMI_SHMEM_MAPPED_SIZE - > + offsetof(struct scmi_shared_mem, msg_payload) ) > + { > + printk(XENLOG_ERR > + "scmi: Wrong size of input smc message. Data may be inval= id\n"); "of the input SMC message" > + return -EINVAL; > + } > + > + ret =3D shmem_channel_status(shmem); > + if ( ret ) > + return ret; > + > + recv_len =3D readl(&shmem->length) - sizeof(shmem->msg_header); > + > + if ( recv_len < 0 ) > + { > + printk(XENLOG_ERR > + "scmi: Wrong size of smc message. Data may be invalid\n")= ; "of the SMC message" Also, I am wondering if you really need to print this error messages in the first place. > + return -EINVAL; > + } > + > + unpack_scmi_header(readl(&shmem->msg_header), hdr); > + > + hdr->status =3D readl(&shmem->msg_payload); > + recv_len =3D recv_len > pad ? recv_len - pad : 0; > + > + ret =3D scmi_to_xen_errno(hdr->status); > + if ( ret ) > + { > + printk(XENLOG_DEBUG "scmi: Error received: %d\n", ret); > + return ret; > + } > + > + if ( recv_len > len ) > + { > + printk(XENLOG_ERR > + "scmi: Not enough buffer for message %d, expecting %d\n", > + recv_len, len); > + return -EINVAL; > + } > + > + if ( recv_len > 0 ) > + memcpy_fromio(data, shmem->msg_payload + pad, recv_len); > + > + return 0; > +} > + > +/* > + * Local variables: > + * mode: C > + * c-file-style: "BSD" > + * c-basic-offset: 4 > + * tab-width: 4 > + * indent-tabs-mode: nil > + * End: > + */ > diff --git a/xen/arch/arm/firmware/scmi-shmem.h b/xen/arch/arm/firmware/s= cmi-shmem.h > new file mode 100644 > index 0000000000..722263aa77 > --- /dev/null > +++ b/xen/arch/arm/firmware/scmi-shmem.h > @@ -0,0 +1,45 @@ > +/* SPDX-License-Identifier: GPL-2.0-only */ > +/* > + * Arm System Control and Management Interface definitions > + * Version 3.0 (DEN0056C) > + * Shared Memory based Transport > + * > + * Copyright (c) 2024 EPAM Systems > + */ > + > +#ifndef ARM_FIRMWARE_SCMI_SHMEM_H_ > +#define ARM_FIRMWARE_SCMI_SHMEM_H_ > + > +#include > + > +#define SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE BIT(0, UL) > +#define SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR BIT(1, 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[]; > +}; Should it be __packed? > + > +#define SCMI_SHMEM_MAPPED_SIZE PAGE_SIZE > + > +int shmem_put_message(volatile struct scmi_shared_mem __iomem *shmem, I am not sure if volatile makes sense here, taking into account that this is __iomem anyway. Also, shmem_put_message sounds to generic... Maybe scmi_put_message? > + scmi_msg_header_t *hdr, void *data, unsigned int l= en); > + > +int shmem_get_response(const volatile struct scmi_shared_mem __iomem *sh= mem, > + scmi_msg_header_t *hdr, void *data, unsigned int = len); Basically the same comments as for previous one. > +#endif /* ARM_FIRMWARE_SCMI_SHMEM_H_ */ > + > +/* > + * Local variables: > + * mode: C > + * c-file-style: "BSD" > + * c-basic-offset: 4 > + * tab-width: 4 > + * indent-tabs-mode: nil > + * End: > + */ > diff --git a/xen/arch/arm/firmware/scmi-smc-multiagent.c b/xen/arch/arm/f= irmware/scmi-smc-multiagent.c > new file mode 100644 > index 0000000000..6c46f6cd36 > --- /dev/null > +++ b/xen/arch/arm/firmware/scmi-smc-multiagent.c > @@ -0,0 +1,792 @@ > +/* SPDX-License-Identifier: GPL-2.0-only */ > +/* > + * SCI SCMI multi-agent driver, using SMC/HVC shmem as transport. > + * > + * Oleksii Moisieiev > + * Copyright (c) 2025 EPAM Systems > + */ > + > +#include > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > + > +#include "scmi-proto.h" > +#include "scmi-shmem.h" > + > +struct scmi_channel { > + uint32_t agent_id; If all agent_ids large than UINT8_MAX are invalid, why do you need uint32_t here? > + uint32_t func_id; > + domid_t domain_id; > + uint64_t paddr; paddr_t > + struct scmi_shared_mem __iomem *shmem; > + spinlock_t lock; > + struct list_head list; > +}; > + > +struct scmi_data { > + struct list_head channel_list; > + spinlock_t channel_list_lock; > + uint32_t func_id; > + bool initialized; > + uint32_t shmem_phandle; > + uint32_t hyp_channel_agent_id; > + struct dt_device_node *dt_dev; > +}; > + > +static struct scmi_data scmi_data; > + > +static bool scmi_is_under_xen_sci(const struct dt_device_node *node) > +{ > + const struct dt_device_node *p; > + > + for ( p =3D node->parent; p; p =3D p->parent ) > + if ( dt_device_is_compatible(p, "xen,sci") ) > + return true; > + > + return false; > +} > + > +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; > + > + ret =3D shmem_put_message(chan_info->shmem, hdr, data, len); > + if ( ret ) > + return ret; > + > + resp =3D arm_smccc_1_1_smc(chan_info->func_id, 0, 0, 0, 0, 0, 0, 0); > + > + if ( resp.a0 =3D=3D (unsigned long)ARM_SMCCC_INVALID_PARAMETER ) > + return -EINVAL; > + > + if ( resp.a0 ) > + return -EOPNOTSUPP; > + > + return 0; > +} > + > +static int do_smc_xfer(struct scmi_channel *chan_info, scmi_msg_header_t= *hdr, > + void *tx_data, int tx_size, void *rx_data, int rx= _size) > +{ > + int ret =3D 0; > + > + ASSERT(chan_info && chan_info->shmem); > + > + if ( !hdr ) > + return -EINVAL; > + > + spin_lock(&chan_info->lock); > + > + printk(XENLOG_DEBUG > + "scmi: agent_id =3D %d msg_id =3D %x type =3D %d, proto =3D %= x\n", > + chan_info->agent_id, hdr->id, hdr->type, hdr->protocol); > + > + ret =3D send_smc_message(chan_info, hdr, tx_data, tx_size); > + if ( ret ) > + goto clean; > + > + ret =3D shmem_get_response(chan_info->shmem, hdr, rx_data, rx_size); > + > +clean: > + printk(XENLOG_DEBUG > + "scmi: get smc response agent_id =3D %d msg_id =3D %x proto = =3D %x res=3D%d\n", > + chan_info->agent_id, hdr->id, hdr->protocol, ret); You will print this even if send_smc_message() fails. I think it should go before "clean:" label. Also, maybe "cleanup:" ? > + > + spin_unlock(&chan_info->lock); > + > + return ret; > +} > + > +static struct scmi_channel *get_channel_by_id(uint32_t agent_id) > +{ > + struct scmi_channel *curr; > + bool found =3D false; > + > + spin_lock(&scmi_data.channel_list_lock); > + list_for_each_entry(curr, &scmi_data.channel_list, list) > + { > + if ( curr->agent_id =3D=3D agent_id ) > + { > + found =3D true; > + break; > + } > + } > + > + spin_unlock(&scmi_data.channel_list_lock); > + if ( found ) > + return curr; > + > + return NULL; > +} > + > +static struct scmi_channel *acquire_scmi_channel(struct domain *d, > + uint32_t agent_id) > +{ > + struct scmi_channel *curr; > + struct scmi_channel *ret =3D ERR_PTR(-ENOENT); > + > + spin_lock(&scmi_data.channel_list_lock); > + list_for_each_entry(curr, &scmi_data.channel_list, list) > + { > + if ( curr->agent_id =3D=3D agent_id ) > + { > + if ( curr->domain_id !=3D DOMID_INVALID ) > + { > + ret =3D ERR_PTR(-EEXIST); > + break; > + } > + > + curr->domain_id =3D d->domain_id; > + ret =3D curr; > + break; > + } > + } > + > + spin_unlock(&scmi_data.channel_list_lock); > + > + return ret; > +} > + > +static void relinquish_scmi_channel(struct scmi_channel *channel) > +{ > + ASSERT(channel !=3D NULL); > + > + spin_lock(&scmi_data.channel_list_lock); > + channel->domain_id =3D DOMID_INVALID; > + spin_unlock(&scmi_data.channel_list_lock); > +} > + > +static int map_channel_memory(struct scmi_channel *channel) > +{ > + ASSERT(channel && channel->paddr); > + channel->shmem =3D ioremap_nocache(channel->paddr, SCMI_SHMEM_MAPPED= _SIZE); > + if ( !channel->shmem ) > + return -ENOMEM; > + > + channel->shmem->channel_status =3D SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE= ; > + printk(XENLOG_DEBUG "scmi: Got shmem %lx after vmap %p\n", channel->= paddr, You will need proper format, not "%lx" for channel->paddr > + channel->shmem); > + > + return 0; > +} > + > +static void unmap_channel_memory(struct scmi_channel *channel) > +{ > + ASSERT(channel); > + > + if ( !channel->shmem ) > + return; > + > + iounmap(channel->shmem); > + channel->shmem =3D NULL; > +} > + > +static struct scmi_channel *smc_create_channel(uint32_t agent_id, > + uint32_t func_id, uint64_= t addr) > +{ > + struct scmi_channel *channel, *curr; > + > + spin_lock(&scmi_data.channel_list_lock); > + > + /* Check if channel already exists while holding the lock */ > + list_for_each_entry(curr, &scmi_data.channel_list, list) > + { > + if ( curr->agent_id =3D=3D agent_id ) > + { > + spin_unlock(&scmi_data.channel_list_lock); > + return ERR_PTR(-EEXIST); > + } > + } > + > + channel =3D xmalloc(struct scmi_channel); > + if ( !channel ) > + { > + spin_unlock(&scmi_data.channel_list_lock); > + return ERR_PTR(-ENOMEM); > + } > + > + spin_lock_init(&channel->lock); > + channel->agent_id =3D agent_id; > + channel->func_id =3D func_id; > + channel->domain_id =3D DOMID_INVALID; > + channel->shmem =3D NULL; > + channel->paddr =3D addr; > + list_add_tail(&channel->list, &scmi_data.channel_list); > + > + spin_unlock(&scmi_data.channel_list_lock); > + return channel; > +} > + > +static void free_channel_list(void) > +{ > + struct scmi_channel *curr, *_curr; > + /* > + * Called only on the __init error path, before any runtime users ex= ist, Then you can put this function into __init as well > + * so no other thread is iterating channel_list. Keep the lock for t= he > + * whole drain for clarity and to avoid misleading readers about pos= sible > + * concurrent access. > + */ > + 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 int __init > +scmi_dt_read_channel_addr(struct dt_device_node *scmi_node, u64 *addr, > + u64 *size) > +{ > + struct dt_device_node *shmem_node; > + uint32_t phandle; > + int ret; > + > + ret =3D dt_property_read_variable_u32_array(scmi_node, "shmem", &pha= ndle, > + 1, 1); > + if ( ret < 0 ) > + return ret; > + > + shmem_node =3D dt_find_node_by_phandle(phandle); > + if ( !shmem_node || > + !dt_device_is_compatible(shmem_node, "arm,scmi-shmem") ) > + return -EINVAL; > + > + ret =3D dt_device_get_address(shmem_node, 0, addr, size); > + if ( ret ) > + return ret; > + > + if ( !*size || !IS_ALIGNED(*size, SCMI_SHMEM_MAPPED_SIZE) || > + !IS_ALIGNED(*addr, SCMI_SHMEM_MAPPED_SIZE) ) > + { > + printk(XENLOG_ERR "scmi: invalid shmem range for %s\n", > + scmi_node->full_name); > + return -EINVAL; > + } > + > + return 0; > +} > + > +/* > + * Handle Dom0 SCMI specific DT nodes > + * > + * Make a decision on copying SCMI specific nodes into Dom0 device tree. > + * For SCMI multi-agent case: > + * - shmem nodes will not be copied and generated instead if SCMI > + * is enabled for Dom0 > + * - scmi node will be copied if SCMI is enabled for Dom0 > + */ > +static bool scmi_dt_handle_node(struct domain *d, struct dt_device_node = *node) Also __init? > +{ > + static const struct dt_device_match shmem_matches[] __initconst =3D = { > + DT_MATCH_COMPATIBLE("arm,scmi-shmem"), > + { /* sentinel */ }, > + }; > + static const struct dt_device_match scmi_matches[] __initconst =3D { > + DT_MATCH_PATH("/firmware/scmi"), > + { /* sentinel */ }, > + }; > + > + if ( !scmi_data.initialized ) > + return false; > + > + /* skip scmi shmem node for dom0 if scmi not enabled */ > + if ( dt_match_node(shmem_matches, node) && !sci_domain_is_enabled(d)= ) > + { > + dt_dprintk(" Skip scmi shmem node\n"); > + return true; > + } > + > + /* drop scmi if not enabled */ > + if ( dt_match_node(scmi_matches, node) && !sci_domain_is_enabled(d) = ) > + { > + dt_dprintk(" Skip scmi node\n"); > + return true; > + } > + > + return false; > +} > + > +static int scmi_assign_device(uint32_t agent_id, uint32_t device_id, > + uint32_t flags) > +{ > + struct scmi_msg_base_set_device_permissions_a2p tx; > + struct scmi_channel *channel; > + scmi_msg_header_t hdr; > + > + channel =3D get_channel_by_id(scmi_data.hyp_channel_agent_id); > + if ( !channel ) > + return -EINVAL; > + > + hdr.id =3D SCMI_BASE_SET_DEVICE_PERMISSIONS; > + hdr.type =3D 0; > + hdr.protocol =3D SCMI_BASE_PROTOCOL; > + > + tx.agent_id =3D agent_id; > + tx.device_id =3D device_id; > + tx.flags =3D flags; > + > + return do_smc_xfer(channel, &hdr, &tx, sizeof(tx), NULL, 0); > +} > + > +static int scmi_dt_assign_device(struct domain *d, > + struct dt_phandle_args *ac_spec) > +{ > + struct scmi_channel *agent_channel; > + uint32_t scmi_device_id =3D ac_spec->args[0]; > + int ret; > + > + if ( !d->arch.sci_data ) > + return 0; > + > + /* The access-controllers is specified for DT dev, but it's not a SC= MI */ > + if ( !scmi_data.dt_dev || > + !dt_node_path_is_equal(ac_spec->np, scmi_data.dt_dev->full_name= ) ) > + return 0; > + > + agent_channel =3D d->arch.sci_data; > + > + spin_lock(&agent_channel->lock); > + > + ret =3D scmi_assign_device(agent_channel->agent_id, scmi_device_id, > + SCMI_BASE_DEVICE_ACCESS_ALLOW); > + if ( ret ) > + { > + printk(XENLOG_ERR > + "scmi: could not assign dev for %pd agent:%d dev_id:%u (%= d)", > + d, agent_channel->agent_id, scmi_device_id, ret); > + } > + > + spin_unlock(&agent_channel->lock); > + return ret; > +} > + > +static int collect_agent_id(struct scmi_channel *agent_channel) > +{ > + int ret; > + scmi_msg_header_t hdr; > + struct scmi_msg_base_discover_agent_p2a da_rx; > + struct scmi_msg_base_discover_agent_a2p da_tx; > + > + ret =3D map_channel_memory(agent_channel); > + if ( ret ) > + return ret; > + > + hdr.id =3D SCMI_BASE_DISCOVER_AGENT; > + hdr.type =3D 0; > + hdr.protocol =3D SCMI_BASE_PROTOCOL; > + > + da_tx.agent_id =3D agent_channel->agent_id; > + > + ret =3D do_smc_xfer(agent_channel, &hdr, &da_tx, sizeof(da_tx), &da_= rx, > + sizeof(da_rx)); > + if ( agent_channel->domain_id !=3D DOMID_XEN ) > + unmap_channel_memory(agent_channel); > + if ( ret ) On error, Xen's channel will be mapped still. Is this intended behaviour? > + return ret; > + > + printk(XENLOG_DEBUG "id=3D0x%x name=3D%s\n", da_rx.agent_id, da_rx.n= ame); > + agent_channel->agent_id =3D da_rx.agent_id; > + return 0; > +} > + > +static int __init collect_agents(struct dt_device_node *scmi_node) > +{ > + struct dt_device_node *agents, *node; > + unsigned int count =3D 0; > + > + /* Use the configuration containing this management channel. */ > + for ( agents =3D scmi_node->parent; agents; agents =3D agents->paren= t ) > + if ( dt_device_is_compatible(agents, "xen,sci") ) > + break; > + > + ASSERT(agents); > + > + dt_for_each_child_node(agents, node) > + if ( dt_node_name_is_equal(node, "agents") ) > + break; > + > + if ( !node ) > + { > + printk(XENLOG_ERR "scmi: missing agents node\n"); > + return -EINVAL; > + } > + agents =3D node; > + > + if ( dt_child_n_addr_cells(agents) !=3D 1 || > + dt_child_n_size_cells(agents) !=3D 0 ) > + return -EINVAL; > + > + dt_for_each_child_node(agents, node) > + { > + struct scmi_channel agent =3D { > + .agent_id =3D SCMI_BASE_AGENT_ID_OWN, > + .domain_id =3D DOMID_INVALID, > + }; > + struct scmi_channel *channel; > + bool discover; > + uint32_t len; > + u64 size; uint64_t > + int ret; > + > + if ( !dt_device_is_compatible(node, "xen,scmi-agent") || > + !dt_device_is_available(node) ) > + continue; > + > + discover =3D !dt_find_property(node, "reg", &len); > + if ( !discover ) > + { > + if ( len !=3D sizeof(uint32_t) || > + !dt_property_read_u32(node, "reg", &agent.agent_id) ) > + return -EINVAL; > + } > + > + if ( !dt_property_read_u32(node, "arm,smc-id", &agent.func_id) ) > + return -EINVAL; > + > + ret =3D scmi_dt_read_channel_addr(node, &agent.paddr, &size); > + if ( ret ) > + return ret; > + > + if ( discover ) > + { > + /* Resolve the ID before inserting it into the channel list.= */ > + spin_lock_init(&agent.lock); > + ret =3D collect_agent_id(&agent); > + if ( ret ) > + return ret; > + } > + > + /* Guest configurations encode agent IDs in an eight-bit field. = */ > + if ( agent.agent_id >=3D UINT8_MAX ) > + return -EINVAL; > + > + channel =3D smc_create_channel(agent.agent_id, agent.func_id, > + agent.paddr); > + if ( IS_ERR(channel) ) > + { > + printk(XENLOG_ERR "scmi: Could not create channel for %s: %l= d\n", > + node->full_name, PTR_ERR(channel)); > + return PTR_ERR(channel); > + } > + > + count++; > + printk(XENLOG_DEBUG "scmi: Agent %u SMC %X addr %lx\n", > + agent.agent_id, agent.func_id, (unsigned long)agent.paddr= ); Why cast to unsigned long? > + } > + > + return count ? 0 : -EINVAL; > +} > + > +static int scmi_domain_init(struct domain *d, > + struct xen_domctl_createdomain *config) > +{ > + struct scmi_channel *channel; > + int ret; > + > + if ( !scmi_data.initialized ) > + return 0; > + > + /* > + * SCMI support is configured via: > + * - For dom0: xen,dom0-sci-agent-id property under the xen,sci cont= ainer > + * - For dom0less: xen,sci-agent-id in the domain node > + * The config->arch.arm_sci_type and config->arch.arm_sci_agent_id > + * are already set by domain_build.c or dom0less-build.c > + */ > + > + if ( config->arch.arm_sci_type =3D=3D XEN_DOMCTL_CONFIG_ARM_SCI_NONE= ) > + return 0; > + > + channel =3D acquire_scmi_channel(d, config->arch.arm_sci_agent_id); > + if ( IS_ERR(channel) ) > + { > + printk(XENLOG_ERR > + "scmi: Failed to acquire SCMI channel for agent_id %u: %l= d\n", > + config->arch.arm_sci_agent_id, PTR_ERR(channel)); > + return PTR_ERR(channel); > + } > + > + printk(XENLOG_INFO > + "scmi: Acquire channel id =3D 0x%x, domain_id =3D %d paddr = =3D 0x%lx\n", > + channel->agent_id, channel->domain_id, channel->paddr); > + > + /* > + * Dom0 (if present) needs to have an access to the guest memory ran= ge > + * to satisfy iomem_access_permitted() check in XEN_DOMCTL_iomem_per= mission > + * domctl. > + */ > + if ( hardware_domain && !is_hardware_domain(d) ) > + { > + ret =3D iomem_permit_access(hardware_domain, paddr_to_pfn(channe= l->paddr), > + paddr_to_pfn(channel->paddr + > + SCMI_SHMEM_MAPPED_SIZE - 1)); > + if ( ret ) > + goto error; > + } > + > + d->arch.sci_data =3D channel; > + d->arch.sci_enabled =3D true; > + > + return 0; > + > +error: > + relinquish_scmi_channel(channel); > + return ret; > +} > + > +int scmi_domain_sanitise_config(const struct xen_domctl_createdomain *co= nfig) > +{ > + if ( config->arch.arm_sci_type !=3D XEN_DOMCTL_CONFIG_ARM_SCI_NONE &= & > + config->arch.arm_sci_type !=3D XEN_DOMCTL_CONFIG_ARM_SCI_SCMI_S= MC_MA ) > + { > + dprintk(XENLOG_INFO, "scmi: Unsupported ARM_SCI type\n"); > + return -EINVAL; > + } > + > + return 0; > +} > + > +static int scmi_relinquish_resources(struct domain *d) > +{ > + int ret; > + struct scmi_channel *channel, *agent_channel; > + scmi_msg_header_t hdr; > + struct scmi_msg_base_reset_agent_cfg_a2p tx; > + > + if ( !d->arch.sci_data ) > + return 0; > + > + agent_channel =3D d->arch.sci_data; > + > + spin_lock(&agent_channel->lock); > + tx.agent_id =3D agent_channel->agent_id; > + spin_unlock(&agent_channel->lock); > + > + channel =3D get_channel_by_id(scmi_data.hyp_channel_agent_id); > + if ( !channel ) > + { > + printk(XENLOG_ERR > + "scmi: Unable to get Hypervisor scmi channel for domain %= d\n", > + d->domain_id); > + return -EINVAL; > + } > + > + hdr.id =3D SCMI_BASE_RESET_AGENT_CONFIGURATION; > + hdr.type =3D 0; > + hdr.protocol =3D SCMI_BASE_PROTOCOL; > + > + tx.flags =3D SCMI_BASE_AGENT_PERMISSIONS_RESET; > + > + ret =3D do_smc_xfer(channel, &hdr, &tx, sizeof(tx), NULL, 0); > + if ( ret =3D=3D -EOPNOTSUPP ) > + return 0; > + > + return ret; > +} > + > +static void scmi_domain_destroy(struct domain *d) > +{ > + struct scmi_channel *channel; > + > + if ( !d->arch.sci_data ) > + return; > + > + channel =3D d->arch.sci_data; > + spin_lock(&channel->lock); > + > + relinquish_scmi_channel(channel); > + printk(XENLOG_DEBUG "scmi: Free domain %d\n", d->domain_id); You can use "%pd" > + > + d->arch.sci_data =3D NULL; > + d->arch.sci_enabled =3D false; > + > + spin_unlock(&channel->lock); > +} > + > +static bool scmi_handle_call(struct cpu_user_regs *regs) > +{ > + uint32_t fid =3D (uint32_t)get_user_reg(regs, 0); > + struct scmi_channel *agent_channel; > + struct domain *d =3D current->domain; > + bool res =3D false; > + > + if ( (!sci_domain_is_enabled(d)) || (!d->arch.sci_data) ) > + return false; > + > + agent_channel =3D d->arch.sci_data; > + spin_lock(&agent_channel->lock); > + > + if ( agent_channel->func_id !=3D fid ) > + { > + res =3D false; > + goto unlock; > + } > + > + arm_smccc_guest_smc(regs); > + res =3D true; > +unlock: > + spin_unlock(&agent_channel->lock); > + > + return res; > +} > + > +static const struct sci_mediator_ops scmi_ops =3D { > + .domain_init =3D scmi_domain_init, > + .domain_destroy =3D scmi_domain_destroy, > + .relinquish_resources =3D scmi_relinquish_resources, > + .handle_call =3D scmi_handle_call, > + .dom0_dt_handle_node =3D scmi_dt_handle_node, > + .domain_sanitise_config =3D scmi_domain_sanitise_config, > + .assign_dt_device =3D scmi_dt_assign_device, > +}; > + > +static int __init scmi_check_smccc_ver(void) > +{ > + if ( smccc_ver < ARM_SMCCC_VERSION_1_1 ) > + { > + printk(XENLOG_WARNING > + "scmi: No SMCCC 1.1 support, SCMI calls forwarding disabl= ed\n"); > + return -ENOSYS; > + } > + > + return 0; > +} > + > +static int __init scmi_dt_hyp_channel_read(struct dt_device_node *scmi_n= ode, > + struct scmi_data *scmi_data, > + u64 *addr) > +{ > + u64 size; > + > + if ( !dt_property_read_u32(scmi_node, "arm,smc-id", &scmi_data->func= _id) ) > + { > + printk(XENLOG_ERR "scmi: unable to read smc-id from DT\n"); > + return -ENOENT; > + } > + > + return scmi_dt_read_channel_addr(scmi_node, addr, &size); > +} > + > +static __init int scmi_probe(struct dt_device_node *scmi_node, const voi= d *data) > +{ > + u64 addr; > + int ret; > + struct scmi_channel *channel; > + unsigned int n_agents; > + scmi_msg_header_t hdr; > + struct scmi_msg_base_attributes_p2a rx; > + > + ASSERT(scmi_node !=3D NULL); > + > + /* > + * Only bind to the SCMI node provided by Xen under the xen,sci cont= ainer > + * (e.g. /chosen/xen/xen_scmi_config/scmi). This avoids binding to f= irmware > + * SCMI nodes that belong to the host OSPM and keeps the mediator sc= oped to > + * Xen-provided configuration only. > + */ > + if ( !scmi_is_under_xen_sci(scmi_node) ) > + return -ENODEV; > + > + if ( !acpi_disabled ) > + { > + printk(XENLOG_WARNING "scmi: is not supported when using ACPI\n"= ); > + return -EINVAL; > + } > + > + ret =3D scmi_check_smccc_ver(); > + if ( ret ) > + return ret; > + > + ret =3D scmi_dt_hyp_channel_read(scmi_node, &scmi_data, &addr); > + if ( ret ) > + return ret; > + > + INIT_LIST_HEAD(&scmi_data.channel_list); > + spin_lock_init(&scmi_data.channel_list_lock); > + > + scmi_data.dt_dev =3D scmi_node; > + > + channel =3D smc_create_channel(SCMI_BASE_AGENT_ID_OWN, scmi_data.fun= c_id, addr); > + if ( IS_ERR(channel) ) > + { > + ret =3D PTR_ERR(channel); > + goto out; > + } > + > + /* Mark as Xen management channel before collecting agent ID */ > + channel->domain_id =3D DOMID_XEN; > + > + /* Request agent id for Xen management channel */ > + ret =3D collect_agent_id(channel); > + if ( ret ) > + goto error; > + > + /* Save the agent id for Xen management channel */ > + scmi_data.hyp_channel_agent_id =3D channel->agent_id; > + > + hdr.id =3D SCMI_BASE_PROTOCOL_ATTIBUTES; > + hdr.type =3D 0; > + hdr.protocol =3D SCMI_BASE_PROTOCOL; > + > + ret =3D do_smc_xfer(channel, &hdr, NULL, 0, &rx, sizeof(rx)); > + if ( ret ) > + goto error; > + > + n_agents =3D SCMI_FIELD_GET(SCMI_BASE_ATTR_NUM_AGENT, rx.attributes)= ; > + printk(XENLOG_DEBUG "scmi: Got agent count %d\n", n_agents); > + ret =3D collect_agents(scmi_node); > + if ( ret ) > + goto error; > + > + ret =3D sci_register(&scmi_ops); > + if ( ret ) > + { > + printk(XENLOG_ERR "SCMI: mediator already registered (ret =3D %d= )\n", > + ret); > + goto error; > + } > + > + scmi_data.initialized =3D true; > + goto out; > + > +error: > + unmap_channel_memory(channel); > + free_channel_list(); > +out: > + return ret; > +} > + > +static const struct dt_device_match scmi_smc_match[] __initconst =3D { > + DT_MATCH_COMPATIBLE("arm,scmi-smc"), > + { /* sentinel */ }, > +}; > + > +DT_DEVICE_START(scmi_smc_ma, "SCMI SMC MEDIATOR", DEVICE_FIRMWARE) > + .dt_match =3D scmi_smc_match, > + .init =3D scmi_probe, > +DT_DEVICE_END > + > +/* > + * Local variables: > + * mode: C > + * c-file-style: "BSD" > + * c-basic-offset: 4 > + * tab-width: 4 > + * indent-tabs-mode: nil > + * End: > + */ > diff --git a/xen/include/public/arch-arm.h b/xen/include/public/arch-arm.= h > index 14d51e0746..722c2d2e3a 100644 > --- a/xen/include/public/arch-arm.h > +++ b/xen/include/public/arch-arm.h > @@ -329,6 +329,7 @@ DEFINE_XEN_GUEST_HANDLE(vcpu_guest_context_t); > > #define XEN_DOMCTL_CONFIG_ARM_SCI_NONE 0 > #define XEN_DOMCTL_CONFIG_ARM_SCI_SCMI_SMC 1 > +#define XEN_DOMCTL_CONFIG_ARM_SCI_SCMI_SMC_MA 2 > > #define XEN_DOMCTL_CONFIG_ARM_V8R_EL1_MSA_NONE 0 > #define XEN_DOMCTL_CONFIG_ARM_V8R_EL1_MSA_PMSA 1 > @@ -347,7 +348,9 @@ struct xen_arch_domainconfig { > uint8_t arm_sci_type; > /* IN */ > uint8_t v8r_el1_msa; > - uint16_t pad; > + /* IN */ > + uint8_t arm_sci_agent_id; > + uint8_t pad; > }; > #endif /* __XEN__ || __XEN_TOOLS__ */ -- WBR, Volodymyr