From nobody Sat Jul 25 20:10:34 2026 Received: from BL0PR03CU003.outbound.protection.outlook.com (mail-eastusazon11012063.outbound.protection.outlook.com [52.101.53.63]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 86F1543F8C5 for ; Tue, 14 Jul 2026 09:22:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.53.63 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784020935; cv=fail; b=UxFywZZRNA4/dB3Is/1GiQL5793tAHWua6xZg6q+RGpnplsaBnysNBV5bcOejzuABIxD5GnEojMFUXsXCl7R/P4GEl1ygFhj4iPivQWcBoknkApEkjetShl6ZpvjFRr9tHfDwmnLauA3avCglz8e4JAz9Txk7O0BI3ULUbcHeA8= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784020935; c=relaxed/simple; bh=oNcFNGNtxfWFnQ2fhCE3z9iZC4g1xBzP5cHqcPIb1NA=; h=From:To:Cc:Subject:Date:Message-ID:Content-Type:MIME-Version; b=qW5VtOt2GVTEHcHFZpza6Yo8AqXBB+hqi44jLNRYPW0pasRH010LTKLxcs+YBUb2gm9bwYvL5zhfY1MViV77DDSDc6uMPV9jQNwKrgkbCfqlXeo0f53D2iiuJi9MK1b8hXUO4KIwiP7vxUTOU4d6q0g767wersIceKzETXE00vs= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=altera.com; spf=pass smtp.mailfrom=altera.com; dkim=pass (2048-bit key) header.d=altera.com header.i=@altera.com header.b=NPRg2Y5N; arc=fail smtp.client-ip=52.101.53.63 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=altera.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=altera.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=altera.com header.i=@altera.com header.b="NPRg2Y5N" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=tqvmAbNqgGOBBjPMdqeLYCi+F7AMhy2dfMbLcrxUU1BbBc129gRxrM9qiL85jrbVD6ALpzUT3pDA9zBCbEyP+phW/KM5ROHWdajfWdztOgM9IkBn6A5iRIcu0a8iVexG9CxDVbXsGfotUZcA8RVzvBMkCNpTuTl7XeuJ7hkG7eNFhcaFUOjv5qshZlp1LAUXVOcGKfJZYMD/xwHOpEqUeJMSgJ69CN6V3Hl2LoAlUBmhNyvR1R5VMCVNsFm2tzN29vcGEkZYjane0N6DOH/JORXOvvXJnU0c2SMwNU7+WQgryOyX8pE9ptD/qfG/PAiLdsNs2vlI75pgAU3upKwsQQ== 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=AkPpCYSwaTxJg9Z/yk2WrgdpvCXJYDgVD3BN/nvsLiw=; b=mTUbWqSUxOMlV2/m6zlb4Ppky/srqPFaMAqv55geAQGWZ2JovK9j8uFpd5xVlvihAVUaKFx69CeL/lXNe2O4hEU5nB9eilOjwUf7mmfUBteLgoGdYYJpw8P50qIoRC5J4ZOOJ1G3NkBj6YPFwT2+JKt7iJjckEoas7BIy4XD99UQnbGYiuq1h8dI1cKYmdqbr/vqx3litnqO2bGCXC9PTQoGpupX+/G5djKH/qN2S0rGjv2QOzJRtWMlb+/e57+ZwwESqojQPJRgrPvb6FAS5RhUw8G8Gln8+p8ik83wUbgNNZJSegAwfQoIHLnvrPRvlVN1GH3tB4d9xEESzkFsZA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=altera.com; dmarc=pass action=none header.from=altera.com; dkim=pass header.d=altera.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=altera.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=AkPpCYSwaTxJg9Z/yk2WrgdpvCXJYDgVD3BN/nvsLiw=; b=NPRg2Y5NJODKQU/EwAU6uPghZPHlhmtFScpXln5DT0G9/CWCe3SDV/4LYVNhfanUrFB8A8gp2e24zp37jdTxeOFQApMtf2m7areVYFxLa5CdkgOQ3JdFwbNA8pP/HuWxognDNRLj+0fqjvTm12w2jdtX7R21gcUCBm552P8P7gJgSUSvqo6Y6NBjegdItas4AETiJGqNGvecVQnhkaicuFKkhHrKCvO5VekUrJ4+4E+IYIVIHeXD6R3sB5e9R7W3LGMyTv2D7z5mUmU46y8MdKPQi33lXt6yoTs09RZN5xAEoknrOxZB7HMcnRnRDOwq9jfOYgpDCZdr94eTOoZLlw== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=altera.com; Received: from DM8PR03MB6230.namprd03.prod.outlook.com (2603:10b6:8:3c::13) by PH0PR03MB5863.namprd03.prod.outlook.com (2603:10b6:510:39::22) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.223.10; Tue, 14 Jul 2026 09:22:08 +0000 Received: from DM8PR03MB6230.namprd03.prod.outlook.com ([fe80::abad:9d80:7a13:9542]) by DM8PR03MB6230.namprd03.prod.outlook.com ([fe80::abad:9d80:7a13:9542%3]) with mapi id 15.21.0223.008; Tue, 14 Jul 2026 09:22:08 +0000 From: Adrian Ng Ho Yin To: Dinh Nguyen , linux-kernel@vger.kernel.org Cc: Adrian Ng Ho Yin Subject: [PATCH v2] firmware: stratix10-svc: add PSCI secondary CPU offline on warm reboot for agilex and stratix10 Date: Tue, 14 Jul 2026 17:16:13 +0800 Message-ID: X-Mailer: git-send-email 2.49.GIT Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: SI1PR02CA0037.apcprd02.prod.outlook.com (2603:1096:4:1f6::13) To DM8PR03MB6230.namprd03.prod.outlook.com (2603:10b6:8:3c::13) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DM8PR03MB6230:EE_|PH0PR03MB5863:EE_ X-MS-Office365-Filtering-Correlation-Id: bff19a0c-185b-4a5c-dbab-08dee18960a9 X-MS-Exchange-AtpMessageProperties: SA X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|23010399003|1800799024|366016|376014|55112099003|18002099003|6133799003|5023799004|11063799006|56012099006; X-Microsoft-Antispam-Message-Info: 9eeLEPhZ93+4UdGYYSLubtHCTJBAM/yAB9FPRuwdhLS3MkZsvQMICPnuDQzToTK5KKEezWELPKuk0mN/cpnPiJAd9RjEtgGOCsEDjA5FfL9B+XmH9G/30HdVNIh/nqknwwDIa8qX3uJBke2ms4VYdRLv4UGgZtnahUAVgoWN8rerOIYWlx5z6jt6jr6WiWoEIWZex3ckiFr2Mr/Ckv9Nd+T/VbAFOhc93GesMHtZQcsU46tnMVR5y3EuLEmNknrxncXg9CsrCxLIEiiPb3EUONQ6Aht8UAJ2g9MbXZmHLh/JIXoLoIOC5zpj2LQTRruqcKFR/ybPsemdkH3gcZc4nhj0B1+Ee3pTTlX3+1r17GGCTh87itIjDixoRWT/+mKMC75apUqkqSea0TxJA7pSvs+8nHx3SdWfAJJXvyzB2PXTa+H7LOMFOTSzE6ftTMhIuoEbjDaBVx+IXA/UIE7O6PqEjb9HibMOY3eqa/YX1P64LOffzql2TP6iMBWReGwckkg5oQsFYiJnm6vxElDh3GQQY5dEY7FxU75LGZ03VTfv4xT3zgSIrleCQlgWOKHFCZvin/goNBm/yjr9n/ZXFdiQN8/Nl2XXmxnlFSVrYoInZGdE7JzpKJeltnK1Gh9JhCZ/uN4kcUjLKdrrHoYezHzlJ6jHaz7Koa3U7H5BRFo= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:DM8PR03MB6230.namprd03.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(23010399003)(1800799024)(366016)(376014)(55112099003)(18002099003)(6133799003)(5023799004)(11063799006)(56012099006);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?HYnltxEntT1ogGB7TSjGptFPPhPTZGkj9qnMDEzIWvWTPa0HeTX5zHSCDVmA?= =?us-ascii?Q?av6o25ZFHEHPbw0sLt9/Tnp64BWYWc0MlBX8d49uMaTxDlJc6jk6Y2DPnYQh?= =?us-ascii?Q?8WeBC53ADy9/jfCPNLUUQYAMPg0jx9r8cPkW174FU4ot3mQOqwuXMcRzOA5F?= =?us-ascii?Q?i8i7iKve5F0UNQB2NRqhkA15PvYGP5AQAQFAbMZgqD3NFwQKycmZ+GTx9mf5?= =?us-ascii?Q?UxFPcbfYzlN2WfZvYX20qV3vVOgw2OLdcVduE2Mbf4p4TwOadikoctvOL13s?= =?us-ascii?Q?4G1ElPKHXakFGgV6a5SJBeGSkb/6/zroyzJ3ZmdBvBPVZlekaJVlgn1DQJpr?= =?us-ascii?Q?JR9V0u04oxPrItmmWzl3UHrySaYBcdswXdt1sqZca+yI0LdUKh+g4eSFlt7O?= =?us-ascii?Q?eMIdQ3GloBLKo3FJNFr+jXyaN3Mq1Y3askfd2QeFTPGOG7zaNSvwFFjK7JC0?= =?us-ascii?Q?rB0PmougkxMvQgtS5BR55dBCPDWnHNsUkur5O97JBmCExvwTFFU1S2o4fHSq?= =?us-ascii?Q?wCRA/d9juJ9YoGJp8MU0NdQbtW96lYMSglt5frYBgMiEAxxZ6qj/fV/byOkw?= =?us-ascii?Q?WEKTwZ7OpyKHV+iI/qUCnqESfile/VYLgTLfRovYG/4JibXOMHyDyFqrOwZm?= =?us-ascii?Q?cipyfSRfSHSIw6Ftp+xag+pmEZR+/aKQTGyQeb5V4WuP2xw+kFodsrtyiKNS?= =?us-ascii?Q?e14i+sC55+l80eVVAUODNKHt2qiO8xeR3aixB+9OVyC589JTOstSwoL5DdCR?= =?us-ascii?Q?nvqQ5KpD8zc6BkFiJmfTmhiKKvXurBHlNAzMMKf0xcjuFttf4uJEXt2+vw1v?= =?us-ascii?Q?pjOZdq0mOAM4jV8uzWCic+l1wllvutdl+LJRRPer5S/KK302rHkWAJHcN8fA?= =?us-ascii?Q?4VRL9IoVMSfMlE1KK7CekxZxjiKbmJC2ebcVqx+adm6iUkngAYEUh87Bpk9s?= =?us-ascii?Q?OAuzFR0031w0PuL+S14BoukdxYfofCZ9Y55wQDAoTp61lfgihGd+DxrX/jSZ?= =?us-ascii?Q?v7UwNyEBOMDQzbvA0kDJxAS+pH50sJhSj+p690+8h+AhC+f/8k+w7n3Yp6w+?= =?us-ascii?Q?FW7FIKY0kX3eD7sUuYEDxAy9w1O/AzL1gu4pZhx+ZiUn9XxFmvYWHNGC7AqB?= =?us-ascii?Q?E9XZzU6PgnOuQLXlLT1Gwv9L+SXHKJoWkDNAHhXD3CSQ5JXovWrJsbx/IMG8?= =?us-ascii?Q?1mcEL0hvUtzsOas1t9+7wKiHjq104V1jxWbDoVIQzSLcGA7cPcb4MkgADDRW?= =?us-ascii?Q?y9sQN81bqmzqrvoIXp80c8/3MPZYdbOctROc/l/yjzBtyDbxPQ3gChk5FwmV?= =?us-ascii?Q?ePSj5+EJZ3PHH9bvmwTJ+bxpORyCKMB/bikh8wuNYxcLaTsEmcTcMZdgprhU?= =?us-ascii?Q?ZspfkJik0f7Qj4Xe7E/NixjqFPivQbePJWp7iXoVs5YtqT+fTZEZNtLgYdVP?= =?us-ascii?Q?H8wjDf0xIK9RHmKM0BVsrsiY1wnVtcH0ZfeHnqXvO/cSZaMySHgiiWNFtGFc?= =?us-ascii?Q?1mmBzY/1vFl37QH6xCqeWkZjmzXL1uACKYFQ4fA4jLtcuKXYiBBLYLPe8hJj?= =?us-ascii?Q?Gt9NvYF2+lK+UhOHFttryJjS/5wgK5Pjh+jPs7BqdMi7rCLrQ7n2MTMwJTHK?= =?us-ascii?Q?PYZl8a41OZlD7FewQI3SxhAP+IFWLuVqaISsGplhMScRPUHYzi5iseePIPOr?= =?us-ascii?Q?O1sOfLQR6Vuyw86lG9S6e4MQWGA9Fe9S2cGzMR2l6a3VzvgimzTq5vo17hPI?= =?us-ascii?Q?RRDz44XbDpQoDg8jxW8HMBQWzvsuD+Y=3D?= X-OriginatorOrg: altera.com X-MS-Exchange-CrossTenant-Network-Message-Id: bff19a0c-185b-4a5c-dbab-08dee18960a9 X-MS-Exchange-CrossTenant-AuthSource: DM8PR03MB6230.namprd03.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 14 Jul 2026 09:22:08.4190 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: fbd72e03-d4a5-4110-adce-614d51f2077a X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: 3A48NwHyCW+SHAlr5TBwZdYMFgcn24RbzU7lO1czAfI6XY0ZleMLAnkt7S/FeqMTeQ9j0cqC9W+qUpJWRPMxMHbON16Wmt01RTQNfSslE/w= X-MS-Exchange-Transport-CrossTenantHeadersStamped: PH0PR03MB5863 Content-Type: text/plain; charset="utf-8" On Agilex7 and Stratix10 SoCs, secondary CPUs must be offlined before a warm reboot to ensure a clean PSCI state. Register a reboot notifier that calls remove_cpu() on each secondary CPU when SYS_RESTART is triggered in REBOOT_WARM mode. A snapshot of cpu_online_mask is taken before the loop since remove_cpu() modifies the mask as CPUs go down. CPU 0 is excluded as it is typically not hotpluggable. Failures are logged and the loop continues so the reboot is not blocked by a single CPU that refuses to offline. The of_device_id table carries a per-compatible pdata flag to enable the notifier only on platforms that need it; Agilex5 leaves the flag unset. The notifier is unregistered at the start of remove(), before async channel teardown, to prevent a reboot notification from racing with driver shutdown. Signed-off-by: Adrian Ng Ho Yin --- changelog: v1 -> v2: - Drop workqueue fan-out: remove_cpu() serialises on device_hotplug_lock internally so concurrent workers provided no parallelism. Replace with a single sequential loop over a cpumask snapshot. - Fix CPU identity bug: get_cpu()/put_cpu() did not prevent task migration and the notifier can run on any CPU before migrate_to_reboot_cpu(). Exclude CPU 0 (typically not hotpluggable) and offline everything else. - Fix pre-count race: the two-loop atomic pre-count had a window where a concurrent hotplug event could cause dec_and_test() to fire prematurely. Eliminated entirely along with the completion and timeout. - Replace of_device_is_compatible() checks with a stratix10_svc_pdata struct carried in of_device_id.data, retrieved via of_device_get_match_da= ta(). - Move psci_cpu_off_teardown() to the top of stratix10_svc_drv_remove(), before async channel teardown, to close the race where a warm-reboot notification could fire while the driver is being dismantled. --- drivers/firmware/stratix10-svc.c | 88 ++++++++++++++++++++++++++++++-- 1 file changed, 85 insertions(+), 3 deletions(-) diff --git a/drivers/firmware/stratix10-svc.c b/drivers/firmware/stratix10-= svc.c index de938ab2db0b..e10550237ea1 100644 --- a/drivers/firmware/stratix10-svc.c +++ b/drivers/firmware/stratix10-svc.c @@ -24,6 +24,10 @@ #include #include #include +#include +#include +#include +#include =20 /** * SVC_NUM_DATA_IN_FIFO - number of struct stratix10_svc_data in the FIFO @@ -96,6 +100,14 @@ #define STRATIX10_GET_SDM_STATUS_CODE(status) \ (FIELD_GET(STRATIX10_SDM_STATUS_MASK, status)) =20 +struct stratix10_svc_pdata { + bool needs_psci_cpu_off; +}; + +static const struct stratix10_svc_pdata psci_cpu_off_pdata =3D { + .needs_psci_cpu_off =3D true, +}; + typedef void (svc_invoke_fn)(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, @@ -280,6 +292,7 @@ struct stratix10_svc_chan { * @svc: manages the list of client svc drivers * @sdm_lock: only allows a single command single response to SDM * @actrl: async control structure + * @psci_reboot_nb: reboot notifier for PSCI secondary CPU offlining * @chans: array of service channels * * This struct is used to create communication channels for service client= s, to @@ -296,6 +309,7 @@ struct stratix10_svc_controller { struct stratix10_svc *svc; struct mutex sdm_lock; struct stratix10_async_ctrl actrl; + struct notifier_block psci_reboot_nb; struct stratix10_svc_chan chans[] __counted_by(num_chans); }; =20 @@ -1981,9 +1995,60 @@ void stratix10_svc_free_memory(struct stratix10_svc_= chan *chan, void *kaddr) } EXPORT_SYMBOL_GPL(stratix10_svc_free_memory); =20 +static void psci_offline_secondary_cpus(struct stratix10_svc_controller *c= trl) +{ + cpumask_var_t mask; + int cpu, ret; + + if (!alloc_cpumask_var(&mask, GFP_KERNEL)) + return; + + /* + * Snapshot cpu_online_mask before the loop; remove_cpu() modifies it + * as each CPU is brought down. Always preserve CPU 0 (boot CPU) to + * run the reboot. + */ + cpumask_copy(mask, cpu_online_mask); + cpumask_clear_cpu(0, mask); + + /* + * Offlining is best-effort: if a CPU refuses to go down we log the + * error and continue so the remaining secondaries are still attempted + * and the warm reboot can proceed. + */ + for_each_cpu(cpu, mask) { + ret =3D remove_cpu(cpu); + if (ret) + pr_err("psci_cpu_off: failed to offline CPU%d: %d\n", + cpu, ret); + } + + free_cpumask_var(mask); +} + +static int psci_cpu_off_reboot_notifier(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct stratix10_svc_controller *ctrl =3D + container_of(nb, struct stratix10_svc_controller, psci_reboot_nb); + + if (reboot_mode !=3D REBOOT_WARM) + return NOTIFY_DONE; + + if (action =3D=3D SYS_RESTART) + psci_offline_secondary_cpus(ctrl); + + return NOTIFY_OK; +} + +static void psci_cpu_off_teardown(struct stratix10_svc_controller *ctrl) +{ + unregister_reboot_notifier(&ctrl->psci_reboot_nb); +} + static const struct of_device_id stratix10_svc_drv_match[] =3D { - {.compatible =3D "intel,stratix10-svc"}, - {.compatible =3D "intel,agilex-svc"}, + { .compatible =3D "intel,stratix10-svc", .data =3D &psci_cpu_off_pdata }, + { .compatible =3D "intel,agilex-svc", .data =3D &psci_cpu_off_pdata }, {}, }; =20 @@ -2001,6 +2066,7 @@ static int stratix10_svc_drv_probe(struct platform_de= vice *pdev) struct gen_pool *genpool; struct stratix10_svc_sh_memory *sh_memory; struct stratix10_svc *svc =3D NULL; + const struct stratix10_svc_pdata *pdata =3D of_device_get_match_data(dev); =20 svc_invoke_fn *invoke_fn; size_t fifo_size; @@ -2040,13 +2106,25 @@ static int stratix10_svc_drv_probe(struct platform_= device *pdev) INIT_LIST_HEAD(&controller->node); init_completion(&controller->complete_status); =20 + if (pdata && pdata->needs_psci_cpu_off) { + controller->psci_reboot_nb.notifier_call =3D + psci_cpu_off_reboot_notifier; + controller->psci_reboot_nb.priority =3D INT_MAX; + + ret =3D register_reboot_notifier(&controller->psci_reboot_nb); + if (ret) { + dev_err(dev, "failed to register reboot notifier: %d\n", ret); + goto err_destroy_pool; + } + } + ret =3D stratix10_svc_async_init(controller); if (ret =3D=3D -EOPNOTSUPP) { dev_info(dev, "Intel Service Layer Driver Initialized (sync-only mode)\n= "); } else if (ret) { dev_dbg(dev, "Intel Service Layer Driver: Error on stratix10_svc_async_i= nit %d\n", ret); - goto err_destroy_pool; + goto err_free_notifier; } else { dev_info(dev, "Intel Service Layer Driver Initialized\n"); } @@ -2110,6 +2188,8 @@ static int stratix10_svc_drv_probe(struct platform_de= vice *pdev) while (i--) kfifo_free(&controller->chans[i].svc_fifo); stratix10_svc_async_exit(controller); +err_free_notifier: + psci_cpu_off_teardown(controller); err_destroy_pool: gen_pool_destroy(genpool); =20 @@ -2122,6 +2202,8 @@ static void stratix10_svc_drv_remove(struct platform_= device *pdev) struct stratix10_svc_controller *ctrl =3D platform_get_drvdata(pdev); struct stratix10_svc *svc =3D ctrl->svc; =20 + psci_cpu_off_teardown(ctrl); + stratix10_svc_async_exit(ctrl); =20 of_platform_depopulate(ctrl->dev); --=20 2.49.GIT