From nobody Sat Dec 27 17:01:13 2025 Received: from refb01.tmes.trendmicro.eu (refb01.tmes.trendmicro.eu [18.185.115.53]) (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 38548F9DC for ; Mon, 18 Dec 2023 07:41:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=opensynergy.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=opensynergy.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=opensynergy.com header.i=@opensynergy.com header.b="PbudoPQx" Received: from 104.47.7.168_.trendmicro.com (unknown [172.21.9.90]) by refb01.tmes.trendmicro.eu (Postfix) with ESMTPS id 62EDF10B1DA81 for ; Mon, 18 Dec 2023 07:40:52 +0000 (UTC) Received: from 104.47.7.168_.trendmicro.com (unknown [172.21.176.220]) by repost01.tmes.trendmicro.eu (Postfix) with SMTP id AD04A10000D15; Mon, 18 Dec 2023 07:40:44 +0000 (UTC) X-TM-MAIL-RECEIVED-TIME: 1702885244.389000 X-TM-MAIL-UUID: 7319bebd-f98c-4a63-9f7f-b6213c472697 Received: from DEU01-BE0-obe.outbound.protection.outlook.com (unknown [104.47.7.168]) by repre01.tmes.trendmicro.eu (Trend Micro Email Security) with ESMTPS id 5F2B910000E3D; Mon, 18 Dec 2023 07:40:44 +0000 (UTC) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=NKeIKqsSVh1KQl9IiKqrReUw5Y1LM/xVDYU/Kq7FUlyuKvp37jh17k87RUAYo+q7lX5p6lHceS9U+r0kF+9W3X01yumsFNYC2owxUCoj3i+BC9yLwmXBKCJSpS7K+w2IW+mpQP/CugZWiwoHCtYXb5HYt5d1QOfi4H3r45wbuPNvi/TMA5Fq5uBLvn9AgKFSKQAqfXfy2NSl0d2DvmRSgS8adzgjyW/IG4mDoEPHD57cW49Br0vw/ppYiPZZneW8flcZMyCXKFazVVA7Dz0R36mEibLeSbAFNY5fSwvcBOWaGXXHDeGwe41wJPjYYzFVkOBOSO8qy6iD9jEh7J5qpA== 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=jpOCaZgwPahm/fdWdeYRxx7ypc4rKVKfdFAHasjtZ8s=; b=YN6JNtJa6Gisoj2i0s5Flu6rw3QzhUDedPl30LcVgebhHLHaYjgTS+bY9TbQr/maPRKHFaABH6vbAlKuIKZgNWkn79ROID3lyAbR2GKm235ifYeLYsPs+v2v8C1oz8d/bWbohHVhzORUUgaUPGEphXGQB7rBkb8VLNsUmRhYnyf3zo4ehnZwhF6BmFedHv+mZAgNbXKO8ZwoIrt++qLfildCEyAIqRFILRoJvZPt17qBPQPjkjzosCS1gYxweLNNOgJBgkqxRCl1btHJBdfecFtYs1Z8j+xi8W5hpztUeLVtrj1S5QDw7MIdbPKbcJHrqo7PEt5rqKL8THToCDChKA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 217.66.60.4) smtp.rcpttodomain=google.com smtp.mailfrom=opensynergy.com; dmarc=pass (p=reject sp=reject pct=100) action=none header.from=opensynergy.com; dkim=none (message not signed); arc=none (0) X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 217.66.60.4) smtp.mailfrom=opensynergy.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=opensynergy.com; Received-SPF: Pass (protection.outlook.com: domain of opensynergy.com designates 217.66.60.4 as permitted sender) receiver=protection.outlook.com; client-ip=217.66.60.4; helo=SR-MAIL-03.open-synergy.com; pr=C From: Peter Hilber To: linux-kernel@vger.kernel.org Cc: Peter Hilber , John Stultz , Thomas Gleixner , Stephen Boyd , "Christopher S. Hall" Subject: [RFC PATCH v3 1/7] timekeeping: Fix cross-timestamp interpolation on counter wrap Date: Mon, 18 Dec 2023 08:38:39 +0100 Message-Id: <20231218073849.35294-2-peter.hilber@opensynergy.com> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20231218073849.35294-1-peter.hilber@opensynergy.com> References: <20231218073849.35294-1-peter.hilber@opensynergy.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: AM6EUR05FT008:EE_|FR3P281MB1645:EE_ X-MS-Office365-Filtering-Correlation-Id: 087fe7dc-401e-4737-4e77-08dbff9ca3d4 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: 1GmSfGM7XOHIK2W85J11VPTWAqnRZAb0hCWkHp5eha010iH7kW9BcPmPZtQrmB6gD//z4omR7PQrDPWO3WHJwZ5RWe2x23fRBMzDOkqJMuSEp5/s9ZQHT4+ul469N7ak8aQWzkXRg81moem2anbDvKEr2yzOJD8HFs7zOOmuOn3wCxmTYqUD8A4NxVkZWMcg0UeVBMJ9FzaXAdUjL2GdQDXeTLyZqQQKAvzMrShoF1+x/ccvzyW1w/LdGawYBchDABYKOyU0zVFym+HK38FgFfd8o+5J8puoXECn8LCbRpToYbda7MZySDiEJmUasqRmUd9oB87AhCzsI2YPEp+U7RpYE8koWkHR45JN3dUtbOERqC1GWzwCc6jlBeZprVb3d5svy7gn5HXoeOkNSYsZy00kEsE5BjY6draB/Yk5yaS0gTWiS5/Lu0n/00fijZdrWDi2OA8BBGtzQcnp9vgjot3rKCW/A6o0MWnoq+SG1WN0tqF+EelehCdCakYHY0wJsJHLfB1M1snkmywpe1ZOe1AHXzLLe3IC/oZlQpLzmvSas/lvdYFOUC4fdcuxR+GWCFSTAGlZeze9kGIkgc2JiSV/0xAXCVAR7oXOB/hkq0/auTvcJ62fxUNZ9id1xTrDjzVwGiRjMjpeEnsYyWcipGxBE4ECgPz3KroudMm4QIeMB5FVdyx+O0VRguktWamwVBKHtGACID/2uvCKI1EVLnHBs8YS7S1Jz7g2Ig5IfU5UytjKOpvMXy6Vpvy0y4hB4dZol1nv57mSs3Vv04vD9Q== X-Forefront-Antispam-Report: CIP:217.66.60.4;CTRY:DE;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:SR-MAIL-03.open-synergy.com;PTR:InfoDomainNonexistent;CAT:NONE;SFS:(13230031)(136003)(346002)(39830400003)(396003)(376002)(230922051799003)(451199024)(82310400011)(64100799003)(186009)(1800799012)(46966006)(36840700001)(83380400001)(336012)(47076005)(1076003)(2616005)(36860700001)(316002)(26005)(4326008)(8936002)(5660300002)(44832011)(41300700001)(4744005)(2906002)(478600001)(70206006)(8676002)(42186006)(54906003)(6916009)(70586007)(36756003)(81166007)(86362001)(40480700001)(36900700001);DIR:OUT;SFP:1102; X-OriginatorOrg: opensynergy.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 18 Dec 2023 07:40:43.0856 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 087fe7dc-401e-4737-4e77-08dbff9ca3d4 X-MS-Exchange-CrossTenant-Id: 800fae25-9b1b-4edc-993d-c939c4e84a64 X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=800fae25-9b1b-4edc-993d-c939c4e84a64;Ip=[217.66.60.4];Helo=[SR-MAIL-03.open-synergy.com] X-MS-Exchange-CrossTenant-AuthSource: AM6EUR05FT008.eop-eur05.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: FR3P281MB1645 X-TM-AS-ERS: 104.47.7.168-0.0.0.0 X-TMASE-Version: StarCloud-1.3-9.1.1015-28064.005 X-TMASE-Result: 10--3.038700-4.000000 X-TMASE-MatchedRID: vveLpsopuKu6TyUO/xKZhTakEkBtr136rutCeVh17xk7dRmDCUrvToyD IPOAt5xjKy3tE1HfkQHDxsdOfchH340cVCEiK1Pf0pUa1RtpyoMqq8hD1DGRIIloy91GB/ZEZSL 4AKI4WH7m9Tc/GgfFJwFtWueZlMH03IFzQVLcaPdCPQBD3xA/3aODSWu0oxbK6gfKtA7Yhlrtmy EvxwC5ZFJxK/8gkcZzWa6vTkKxwrI7AFczfjr/7B2U/axB/TLSZg2qO/0BslMgcB+ImoL5a58mJ NfsSlkN5p04fCrux4g= X-TMASE-XGENCLOUD: 51bae1fc-2e60-4c2b-9b45-ff59488cf4c5-0-0-200-0 X-TM-Deliver-Signature: E16FEFEA6210024852D0EE0425D7112E X-TM-Addin-Auth: ZPVWLL62/fzzzd0bATplIpZhl03WZCSHU20WzbaPASPU5j/ThOZtcJHMfvd F4VlYOHPLYZqQi7TvzL4NrS7LCs3yv2sM8UE5rN5Ac92EROWYbOtUqHdu6kkCZQCCrNe5IOteXs 0TsiMpNtZq0Ss3rW8UGz0BCY0M8mQVeow4zvVEgzGpFsj/Omm2GuIViGy8LhHAdTYtDG5ynMNlm 8Z4GpL/MoZew3CtcFgKMzMwcy2L0gILrGfTSLeGx31MxKElm+4aUsZDG3tP8dpBQ57pj1DRdJ1W HoT+g2Hsyy5x+OY=.O9VHbA09UEFmyI6WFOXuvj8vpZtKIrPARbfEDNoK0mioq3+d3qAKIIzdWr NW5cs2rEj9gxl99HYSwSipOaGrN/WQmRV9VTW/2CDsF23C5VdZ9KlADDPRi/AsAVZAC0eeNBf2d qx3sTCpmJph2+X1Xnua0cYDCbuPwJ5qwEUhUgLu3kbprr6/m2p5LKA60B5j6uXUItDahSnmxi6Z OFsR7ASzRRN14Lj11FnwFDHmq7m1Bd0r7j6RkEp9eQARyqb0SajOIqYlUBGsoX1IptB56q8sOia saa7TnKjeTRRQMtgphhyUoLIq+rxJxDrndVSvm9WTSN7SIS7WTNXXNcP+Uw== X-TM-Addin-ProductCode: EMS DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=opensynergy.com; s=TM-DKIM-20210503141657; t=1702885244; bh=hUtsQVX0BvNcE4vhtfv+v3MQv6zXnNikIBucovKIXa4=; l=1035; h=From:To:Date; b=PbudoPQxf6xth7tuhoEt7XigszKLgVrXdPxemE63cX/xSEJ+DUzSTqfTyWztxASUe nInMvkdXEAK+Wa2uQHXrtCDM0SUW6bleh6FukQYNKTql73+GonlVJsf4AWfsTF+RTt DazzSURXix0/mNL+GQq+GsNwH6gHoMr7cHjcVylCp24GDoDjB6uA/hw5b4dY8SZBdN B1NgSp0LkPKSPQ9kTTC0cyIzaqEnNmED4SejKkSitZDYenad4hZtS84+MTrMa+akLW 4IXz1+dTpV+uFdCm3uQ4JW5GLI32DlAquwCsuCyebK2rCYiVyoPpJ7NrPE16k17+m4 L1Legpd4l7JJg== Content-Type: text/plain; charset="utf-8" cycle_between() decides whether get_device_system_crosststamp() will interpolate for older counter readings. cycle_between() yields wrong results for a counter wrap-around where after < before < test, and for the case after < test < before. Fix the comparison logic. Fixes: 2c756feb18d9 ("time: Add history to cross timestamp interface suppor= ting slower devices") Signed-off-by: Peter Hilber Acked-by: John Stultz --- kernel/time/timekeeping.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 0ff065c5d25b..08a3d0052baa 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -1186,7 +1186,7 @@ static bool cycle_between(u64 before, u64 test, u64 a= fter) { if (test > before && test < after) return true; - if (test < before && before > after) + if (before > after && (test > before || test < after)) return true; return false; } --=20 2.40.1 From nobody Sat Dec 27 17:01:13 2025 Received: from repost01.tmes.trendmicro.eu (repost01.tmes.trendmicro.eu [18.185.115.17]) (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 79991F9D9 for ; Mon, 18 Dec 2023 07:40:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=opensynergy.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=opensynergy.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=opensynergy.com header.i=@opensynergy.com header.b="z0hz/g8b" Received: from 104.47.7.168_.trendmicro.com (unknown [172.21.203.211]) by repost01.tmes.trendmicro.eu (Postfix) with SMTP id 4D85910000D8E; Mon, 18 Dec 2023 07:40:45 +0000 (UTC) X-TM-MAIL-RECEIVED-TIME: 1702885245.057000 X-TM-MAIL-UUID: c00a88ad-df20-4b22-8af2-20430592f62d Received: from DEU01-BE0-obe.outbound.protection.outlook.com (unknown [104.47.7.168]) by repre01.tmes.trendmicro.eu (Trend Micro Email Security) with ESMTPS id 0DFFF10020CE3; Mon, 18 Dec 2023 07:40:45 +0000 (UTC) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=ev7X/6EoJn2tjUeFIGF9zxmVeCJ1D/YSji/0RTt+vIyHoU3vrNL0EzLVBovEv4+PS6NWRoFvihjm9gQbYUFnGwbL4Er9/KpUzuNCXH+Xld7OOcP1OZw7pvUbm79+jCRkF78CuRXAMXyPAYyVxcRIGqDl1rCZ6cKFaLr24JIVQ3wbZcyvwcnpsr+onNzYlnVb3Hoa4KcYqhypH4/qLs4/ZaLKlxtUBjkWlM7u1Ih2/lq0bY+RVTkkKpwSpVF5aBY+s4wmvsQgdgGTW1La/13Ea9/wEmeCLPGMcMpRTNNdsXOcY5KYNXZ9/qq2zw2ihg1UoRb3XVbOzdndjGO8Jxlv0g== 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=s2IZ507OM6ksbzs3neAB9pnVNg/Lg+qzeVPyN5kTi14=; b=Qde7EyVUSTEAaLXo9B76k6dT9Mb1TLXJxrM/DMUfqxC8IeSt5iLYfLPt5VA8VYr1VvJTLeTB1LUFlHc/ll+xcrmHqX32cjNDy/SfEbkjx2jGpN4QlYTxRv68t8FU+ZlVx3wsREYSI1dNozfgqSz/46Ux3xwReeeHok2dSQGcZVk1fU/Vti6k8lzLhTspdy0GmqR9/ZNectdaQKfFxBOKvBUtHoNFawNrJgbcCA6H1/CASjftT+rwuYxjoyNvW1GvVHQUcZjo4iYMW2YwP/TCPUjGMXQPa5h1W4Ii6hY2p+FGgkyyWDDeC+UlSBnI//YDK/YqGpU6PP2Zk3oy+IkRIA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 217.66.60.4) smtp.rcpttodomain=google.com smtp.mailfrom=opensynergy.com; dmarc=pass (p=reject sp=reject pct=100) action=none header.from=opensynergy.com; dkim=none (message not signed); arc=none (0) X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 217.66.60.4) smtp.mailfrom=opensynergy.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=opensynergy.com; Received-SPF: Pass (protection.outlook.com: domain of opensynergy.com designates 217.66.60.4 as permitted sender) receiver=protection.outlook.com; client-ip=217.66.60.4; helo=SR-MAIL-03.open-synergy.com; pr=C From: Peter Hilber To: linux-kernel@vger.kernel.org Cc: Peter Hilber , John Stultz , Thomas Gleixner , Stephen Boyd , "Christopher S. Hall" Subject: [RFC PATCH v3 2/7] timekeeping: Fix cross-timestamp interpolation corner case decision Date: Mon, 18 Dec 2023 08:38:40 +0100 Message-Id: <20231218073849.35294-3-peter.hilber@opensynergy.com> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20231218073849.35294-1-peter.hilber@opensynergy.com> References: <20231218073849.35294-1-peter.hilber@opensynergy.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: AM6EUR05FT052:EE_|BE1P281MB2401:EE_ X-MS-Office365-Filtering-Correlation-Id: 26ad6a13-62c7-49c3-4a00-08dbff9ca3eb X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: 29rHFrDgD2/T5BFlSCYIQ/9QGsxI8G+VugFmhm0VLOdIODOeui4Q/sRQXjGM8vQPpmzhumR1Ho7q5jHO1vMyJ+JwOHhUxM0z2mYCi2TjjTXsE/z4aGKZnltkoJq/YQn/dfxqJsg0gYowm0nKrhAwgXy4j+/kNo/gtCAKTVL19wRxLSPs/QG7SDvyqZYHOrYgqGYz9hlXBmlS56rNnQDX4KpuMwFqgUjrhx8TAkXadw/BiAiGKYjcetFVA1xN7M2RjapwJODdsfMTlETIvQ2isX8kcFyVN5o5nJmQwuk3LIQU1/rE3Ym9bQV7BXQMHbeaFcuxIIfDmQqa4hWjS4W5KcZ4LIriMG3OQqrUcJi4pgXZNoSjgkbFAIJDBpbmrwxSo/yyNbmQcT3e2tUMh4TZtVh1nYFO94y1LfnjCGSAkacjLDUVf7HLaSEPBYQ2NkFi/M5U71BQk2OHEMUE6QGtWPa3IFw5NqJqQrjoMcZHNho7LzjU6fCS4lR27v0c2+a/sXLCPdF5XFUVwJi9Yq/OSfJYs3QJAtAIzrV610g4tSSGsKRKV4B+gLo1bzLgqIBbFlTMoO/HiGuVMnHtxKCOmizlLPgkahtuVcUJLho1rV3lmM9uAAFbNcDJOPHG2Vw3f3w3IaO04KxZ/LESLoRb3v4DXNjQyKjRF6ERREaY9/CAl7LW3cwGpvVXt69qs9K1d6fJwvYvCv9A8XQEtT/0y52faeoNIWkTmkz0RLXL0xpvywTgizj/0A8VQURhM+Gm8A7MN+p1cHESU709qBdCSBCBW+HKL8VCc3+KSUHBhC0= X-Forefront-Antispam-Report: CIP:217.66.60.4;CTRY:DE;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:SR-MAIL-03.open-synergy.com;PTR:InfoDomainNonexistent;CAT:NONE;SFS:(13230031)(346002)(396003)(136003)(376002)(39830400003)(230922051799003)(1800799012)(451199024)(186009)(82310400011)(64100799003)(46966006)(36840700001)(5660300002)(8676002)(8936002)(41300700001)(4326008)(36756003)(36860700001)(86362001)(47076005)(44832011)(40480700001)(6916009)(81166007)(70586007)(54906003)(42186006)(316002)(70206006)(2906002)(83380400001)(1076003)(26005)(336012)(2616005)(478600001)(36900700001);DIR:OUT;SFP:1102; X-OriginatorOrg: opensynergy.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 18 Dec 2023 07:40:43.2363 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 26ad6a13-62c7-49c3-4a00-08dbff9ca3eb X-MS-Exchange-CrossTenant-Id: 800fae25-9b1b-4edc-993d-c939c4e84a64 X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=800fae25-9b1b-4edc-993d-c939c4e84a64;Ip=[217.66.60.4];Helo=[SR-MAIL-03.open-synergy.com] X-MS-Exchange-CrossTenant-AuthSource: AM6EUR05FT052.eop-eur05.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: BE1P281MB2401 X-TM-AS-ERS: 104.47.7.168-0.0.0.0 X-TMASE-Version: StarCloud-1.3-9.1.1015-28064.005 X-TMASE-Result: 10--10.122800-4.000000 X-TMASE-MatchedRID: tTXG1YCXjlyHXEtxeZW06KF4nhfuztKa59KGlOljPvtYf8LrTKM9HLMr 1BCU9VEa9MR66Vl9gxh3ctDbGLJrCd7BQ4zNEspZnRTJpY7VAKebyUSNdkyqzgsPNAkPeS3Qjod z+U1nZVma3KYBmyydiEIlvMJDMU4GfNVPm/PTkb3dQKgLFATP1u5zvRYCQLoVvYvv3/bSxhtUfz 9bnWycdWILFRMBZjgurrSryEHqYI8CvRxvTnoekIruruLIWfnx3O2+pOfl+vcwLJ9PZUBQhZu1m GZ02rt+IcOU43RoyMaaqpJOgb8zX/axsint/cAcLrzngQuTvvQnfL6KqKSjbzB4jJltGVDbLN5w GPX3TPXYeXOEzfM22ez1ZBVjJwp/DeUZOJCXHMi/2tJ3foSBQiPzRlrdFGDwHCGr2Wk5lVXInHS iJPmGO8dDHZX32JRzuyRrXoaR96b7npjusD0LiA== X-TMASE-XGENCLOUD: 159f6a85-11cf-41f0-878a-66104a7187af-0-0-200-0 X-TM-Deliver-Signature: 545986F62613B371B835B9B918AD7416 X-TM-Addin-Auth: BUtqnBarHP0bgWzscdjgjGlWmOEumQ7NzaDkRCEFuqnjPtioewQeNlT068t h048NLoEZeQFXe90tc44TaDTw1skxkWpHtSexOZnrTT976aZWukwHq7s1oXwcPrVnmJqjjAGlZZ Itdzus4XVoBjT7jZ03LdN1pkb48VTetkEp0uRouDPNbJ614WYQhiunlCWSE/ThgJlq4dERSBfGu CcgsTm/9xpIFOWO+3ik5w9PCGJVTDVSEczjZkg9vGebucHYOxldUjoowCQxWfdh6QMzx55HO7QG EEPijYadLz5HukA=.hk5z7VrzTNKAoTn//xMnoW2yfZzSmi0JDBR14tXiI/rYAx2UC6ALNCmeTz EnL+5Wor+ywlBCRSXiRNVx9ciL402pgilSGv28bFfbWQMAnEYele26yF+1m2f1tq089b8Hca+re RBdbMJ5KMVbMPx1qd9iMhDJ9RlTLz46fokrzlh0t/7nfZqrnspwZgtQdIgbcR+m6BSszsJLdpQg x5LIFwGc0ejJ2Bd/pbk283VOD572H15MeUtSLM9j3QPTBtvQj2xf9OAlT6qqf/suhqh2IYIdoXJ cCv0A/tUez8Ogqm3Qwg8A4g83g0MIcInssiov7wEACOUDYJIFZhHdNEhxmA== X-TM-Addin-ProductCode: EMS DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=opensynergy.com; s=TM-DKIM-20210503141657; t=1702885245; bh=6hbFW5zT7dhfs2v0i1nOXGxD6lV3W89B3HUgfdPwo94=; l=4866; h=From:To:Date; b=z0hz/g8bZBvVxNXGsqoSU9fFaGUrtGUuo7NsyuFPJj+anixyAFR+end1wDCdJRfnP 40+JHqMS0AhT6G4s24S6pdqTzTGnyxP+9lYrh1q140/gYCEY5ZKrP702iwD+/ezSY6 /JcN730AuQhqbtb5JSWSAgWfzq6Mxsr3mcpH1Ib8COBVRQNJDd4NS7eJDBCKWFZ4vX dbkV/94dTuExSjo85in/yHIA+m+cgB8zHFhyGxDFtlqG6wimUZ5gGUIndI8vNdWEu3 B+rqxSWy6BJfYNipYOTL6yNvy0eBq/3w4PhUWkiDaECChroLNEgL59bYvfQE7rnhye hTeDiAqhMjzWA== Content-Type: text/plain; charset="utf-8" The cycle_between() helper checks if parameter test is in the open interval (before, after). Colloquially speaking, this also applies to the counter wrap-around special case before > after. get_device_system_crosststamp() currently uses cycle_between() at the first call site to decide whether to interpolate for older counter readings. get_device_system_crosststamp() has the following problem with cycle_between() testing against an open interval: Assume that, by chance, cycles =3D=3D tk->tkr_mono.cycle_last (in the following, "cycle_last" for brevity). Then, cycle_between() at the first call site, with effective argument values cycle_between(cycle_last, cycles, now), returns false, enabling interpolation. During interpolation, get_device_system_crosststamp() will then call cycle_between() at the second call site (if a history_begin was supplied). The effective argument values are cycle_between(history_begin->cycles, cycles, cycles), since system_counterval.cycles =3D=3D interval_start =3D=3D cycles, per the assum= ption. Due to the test against the open interval, cycle_between() returns false again. This causes get_device_system_crosststamp() to return -EINVAL. This failure should be avoided, since get_device_system_crosststamp() works both when cycles follows cycle_last (no interpolation), and when cycles precedes cycle_last (interpolation). For the case cycles =3D=3D cycle_last, interpolation is actually unneeded. Fix this by changing cycle_between() into timestamp_in_interval(), which now checks against the closed interval, rather than the open interval. This changes the get_device_system_crosststamp() behavior for three corner cases: 1. Bypass interpolation in the case cycles =3D=3D tk->tkr_mono.cycle_last, fixing the problem described above. 2. At the first timestamp_in_interval() call site, cycles =3D=3D now no lon= ger causes failure. 3. At the second timestamp_in_interval() call site, history_begin->cycles =3D=3D system_counterval.cycles no longer causes failure. adjust_historical_crosststamp() also works for this corner case, where partial_history_cycles =3D=3D total_history_cycles. These behavioral changes should not cause any problems. Fixes: 2c756feb18d9 ("time: Add history to cross timestamp interface suppor= ting slower devices") Signed-off-by: Peter Hilber --- Notes: v3: =20 - switch back to v1 style closed interval test (Thomas Gleixner) - document effect of closed interval test on corner cases - do not carry "Acked-by: John Stultz " due to above changes =20 v2: =20 - try to clarify problem description (John Stultz) - simplify fix kernel/time/timekeeping.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 08a3d0052baa..24ffd681aa23 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -1180,13 +1180,15 @@ static int adjust_historical_crosststamp(struct sys= tem_time_snapshot *history, } =20 /* - * cycle_between - true if test occurs chronologically between before and = after + * timestamp_in_interval - true if ts is chronologically in [start, end] + * + * True if ts occurs chronologically at or after start, and before or at e= nd. */ -static bool cycle_between(u64 before, u64 test, u64 after) +static bool timestamp_in_interval(u64 start, u64 end, u64 ts) { - if (test > before && test < after) + if (ts >=3D start && ts <=3D end) return true; - if (before > after && (test > before || test < after)) + if (start > end && (ts >=3D start || ts <=3D end)) return true; return false; } @@ -1247,7 +1249,7 @@ int get_device_system_crosststamp(int (*get_time_fn) */ now =3D tk_clock_read(&tk->tkr_mono); interval_start =3D tk->tkr_mono.cycle_last; - if (!cycle_between(interval_start, cycles, now)) { + if (!timestamp_in_interval(interval_start, now, cycles)) { clock_was_set_seq =3D tk->clock_was_set_seq; cs_was_changed_seq =3D tk->cs_was_changed_seq; cycles =3D interval_start; @@ -1278,13 +1280,13 @@ int get_device_system_crosststamp(int (*get_time_fn) bool discontinuity; =20 /* - * Check that the counter value occurs after the provided + * Check that the counter value is not before the provided * history reference and that the history doesn't cross a * clocksource change */ if (!history_begin || - !cycle_between(history_begin->cycles, - system_counterval.cycles, cycles) || + !timestamp_in_interval(history_begin->cycles, + cycles, system_counterval.cycles) || history_begin->cs_was_changed_seq !=3D cs_was_changed_seq) return -EINVAL; partial_history_cycles =3D cycles - system_counterval.cycles; --=20 2.40.1 From nobody Sat Dec 27 17:01:13 2025 Received: from refb02.tmes.trendmicro.eu (refb02.tmes.trendmicro.eu [18.185.115.58]) (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 37422F9D8 for ; Mon, 18 Dec 2023 07:41:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=opensynergy.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=opensynergy.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=opensynergy.com header.i=@opensynergy.com header.b="I5mFNRgU" Received: from 104.47.11.168_.trendmicro.com (unknown [172.21.19.56]) by refb02.tmes.trendmicro.eu (Postfix) with ESMTPS id 6556E109EA891 for ; Mon, 18 Dec 2023 07:40:52 +0000 (UTC) Received: from 104.47.11.168_.trendmicro.com (unknown [172.21.171.117]) by repost01.tmes.trendmicro.eu (Postfix) with SMTP id 814CD10000C35; Mon, 18 Dec 2023 07:40:45 +0000 (UTC) X-TM-MAIL-RECEIVED-TIME: 1702885245.214000 X-TM-MAIL-UUID: b216ee90-1167-4d77-b81b-6e29b7d01f2c Received: from DEU01-FR2-obe.outbound.protection.outlook.com (unknown [104.47.11.168]) by repre01.tmes.trendmicro.eu (Trend Micro Email Security) with ESMTPS id 3476D10020CE3; Mon, 18 Dec 2023 07:40:45 +0000 (UTC) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=O4nN89gvE3TMetq7g+vY5m5FnE2W4ozOoE6siZAkWLGcPiJSN1PkvutVwAYA2JMru8mrSL3T3ZxTod4edgnARTiVrnpt5NFBPAuLXqakKGDZJSl/Jmum3wJwo91WRLsUkI1rfljLBqGqtoFi3wROVXf1Iqi+UusNekNDAc2gwQYyLC4vs5f8FdQNRVIvL+Wx6IROpfp24c0dqNR+8TJIAmevEWDgKk1Njlq0dL8qKrT+H+/nv5FiHA9fm8QOSTkUl6i9mVrbbOvTE+ORKivLJd2R4oGKuCCjS2yb6fUsOWSGB0OMkEXJ4S7zJv2MNrrpunY8r+kQnnX+Zta+yezytg== 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=uJgaNBEzp9lR6H6IY7NbUAFUz6Y1OBwJFLiNK5ZnaYk=; b=g449OVrwDB8rw9JYqbtAPh//nyToH/kOHp/6up2l9vbnuWFHVHOA3RaU35VPFPW6CoHVHayGNWl8iFWGuMKRE4U+3xurcqwMRSkpvff/Z1OkJEgQuvwomxOUYh27J6QVlvvWvLtcorW8mST0PLACdAUHhmTQv6+h9qhvAdjwy0HILJ+L4Qmu4DmEd6TOb8pMBv9AVzN//QZwR7s9R4XkC5cXo+CMXU+mGrdqGV+qqYEtk8gRz54+Wpnqw1S69YbPaSATqRv4FeR1XYJYy5/k6CnWeVuddrQ2rVy+XhtvyY/XK+2hoOqR8wDxQDePvimD4GaU43FnydFmrbK4puqXgA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 217.66.60.4) smtp.rcpttodomain=google.com smtp.mailfrom=opensynergy.com; dmarc=pass (p=reject sp=reject pct=100) action=none header.from=opensynergy.com; dkim=none (message not signed); arc=none (0) X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 217.66.60.4) smtp.mailfrom=opensynergy.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=opensynergy.com; Received-SPF: Pass (protection.outlook.com: domain of opensynergy.com designates 217.66.60.4 as permitted sender) receiver=protection.outlook.com; client-ip=217.66.60.4; helo=SR-MAIL-03.open-synergy.com; pr=C From: Peter Hilber To: linux-kernel@vger.kernel.org Cc: Peter Hilber , John Stultz , Thomas Gleixner , Stephen Boyd , "Christopher S. Hall" Subject: [RFC PATCH v3 3/7] timekeeping: Fix cross-timestamp interpolation for non-x86 Date: Mon, 18 Dec 2023 08:38:41 +0100 Message-Id: <20231218073849.35294-4-peter.hilber@opensynergy.com> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20231218073849.35294-1-peter.hilber@opensynergy.com> References: <20231218073849.35294-1-peter.hilber@opensynergy.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: VI1EUR05FT064:EE_|FR3P281MB2203:EE_ X-MS-Office365-Filtering-Correlation-Id: 2447cebd-93e8-4ef9-8df7-08dbff9ca43a X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: hV/4Lpf/4GS1iU2eNA8WgohOhtG/czIihIksNJVOh0OV+KVQQrTt+o1wJUfMeWbbfbKJLbq0huNlTdKSCOTYrAdSv+9lOF6nE/vqtPKf7anvV5U6uQJgEYc9BX2Ns2/ScvOtALCRM4H9SBW0/bezCERBXCIIQVzKX0GXlAOv2BB8tHCFRHdXIb681kdDv9KeIysv/ftKooubWi7H4B+UMYS256XKHQ5URIaT+WiaPEIy7GC5HHSJOJzrS+YUSMO2HzpjFyAH+93C3KzPqO+cM12W2wec/Xmn1t6ZrI0vZ7EyAtxEqbDLFnN4VxjWOq6LyI57MBquqqQOe6JvjnftuPICu1/vd3JZThMp3LMFdC5zJLLy7Efh/h055kAeyashPVIbZcFibBcEztHyGyNHLPukMvibIj2xRVwzx+sDHA/5zcAsloeZyafp0ZUk+gQpNBQc73mdzb1sXZscOR3Tcq2hea4iZn2VDPlMCJIfw7YLicXSGuaeIDGZDA0a7/VcMn/7u75oryKGk4MjCYGYYhvCOi7p9vg1VB6NqYFxDttlEM0xd+XCrBZPZGmYHcROgntJ+nTVZcSkDQtSj8VayZk3hvLE81AR33MpoV/BfG52gFKgdT7MCsaJYTE4Ycd7rNee2/UUQ9EWRDwxsB22LNbcbwjUen05U7cDzJtO/QIIKVmaszGSkqVkFphNTvd4/We+gJWaLP7s7ANhFPOYtn/swnoO7V69oZENhAtpwF3OVxmROdiKKIJ/7vR9/D1ZJBMf7oR9AIslm2jGv9LUMWw8VQmfVvpcKf7jjNEorYY= X-Forefront-Antispam-Report: CIP:217.66.60.4;CTRY:DE;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:SR-MAIL-03.open-synergy.com;PTR:InfoDomainNonexistent;CAT:NONE;SFS:(13230031)(39830400003)(376002)(396003)(136003)(346002)(230922051799003)(82310400011)(64100799003)(451199024)(1800799012)(186009)(36840700001)(46966006)(26005)(336012)(2616005)(1076003)(83380400001)(478600001)(36860700001)(44832011)(40480700001)(8676002)(4326008)(41300700001)(8936002)(5660300002)(86362001)(47076005)(36756003)(2906002)(81166007)(6916009)(70206006)(54906003)(42186006)(70586007)(316002)(36900700001);DIR:OUT;SFP:1102; X-OriginatorOrg: opensynergy.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 18 Dec 2023 07:40:43.7557 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 2447cebd-93e8-4ef9-8df7-08dbff9ca43a X-MS-Exchange-CrossTenant-Id: 800fae25-9b1b-4edc-993d-c939c4e84a64 X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=800fae25-9b1b-4edc-993d-c939c4e84a64;Ip=[217.66.60.4];Helo=[SR-MAIL-03.open-synergy.com] X-MS-Exchange-CrossTenant-AuthSource: VI1EUR05FT064.eop-eur05.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: FR3P281MB2203 X-TM-AS-ERS: 104.47.11.168-0.0.0.0 X-TMASE-Version: StarCloud-1.3-9.1.1015-28064.005 X-TMASE-Result: 10--4.970100-4.000000 X-TMASE-MatchedRID: t1u9etd7zexeKR/wKUhyN50UyaWO1QCnDNB/jaV2d3ufOd3yw6VkrA9M 5f/N3N4Qthzaop7IM7sxRT5xs1+q/LIfFXYUihhJ9uL5hOvaG1KVmuhG06IIbTji23k3pyJLKLe iMOXj8x3VCWoGLJ7oTkLgBLH/nEyhKI9YY0txdTpSU7TOghylToHV87ajhAZw5LGd87xcOHdwLp z8B01lud9cNTZyIRQywqMZFCdDzWHPE8gn5ga5qlvIId8M26gTcEVHZ4vVAlhmrG+H0FSHunGDu y8y1qkuSOzJLIeTZAaj45JdBik2YvV6Jv37/R3WO5nVDm0S/sD25GFUd8k/Fw== X-TMASE-XGENCLOUD: 96cd9daa-7b3c-4ac2-801a-e6e48ee1ddd3-0-0-200-0 X-TM-Deliver-Signature: 928184199E900A744B7BBEB1C3B61368 X-TM-Addin-Auth: D+SUBOckl6OjIKaLJA0rQHc0X50yKi5HY80Iici+0iapvjj18OcDxWHQv8R IqRKegDLglAreiv1SAHJOupQtQuWZhPbmRqZx+y/Yl0ci7oXrhmcCbkvivbxXgzpZ3kGYIIf/OF LHsCCQCiFhthJQSlN41U9EIy8fIX5PTapcAxBByfBfYnvJfSwIOwY1xaix7rzRoi3Vue920ygwy 9kE8aE47mAaQQJ1fT/JEh1XdAjxKVe3qDmShFY/1K+FFLQaoqL3XYG/bkt7FvJDi++dRBZIz0CX /4Le3U7PHYvWtgM=.gnmt3d8QzuNc/gGm2gBBuJmGrq4UyAqlTuplSuT9ETxP9cYxRF9rDLPvKS l/MjrSnT+M6+5rCHEqTgqTorWOMRXpQmuwMAXkUKP2kjQ2RQKYVdSxFgwPi/EW1DfWpcdd305CD HaT51J47yR0hasdTHELwRtTmE+ksAdnqaZtfmJijOmj6/iO8a9EFUgaxIa1B3t7Z4rlOEeflTbL OeR+0Z9qOX1EAm9VgyNColBcZqQn3PbHRbMnIJb3FG228g5z9uydBHP/5mXILkm3oN3nQNSVWMd 9wAyvZKa7aIR0yC0MODzB++u69tsKZUFUUj7CIyEd/iYZKdNNZ4K8tDtnBg== X-TM-Addin-ProductCode: EMS DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=opensynergy.com; s=TM-DKIM-20210503141657; t=1702885245; bh=4Y3l9rtDRj9fZtWY1TyW5Z1YIMRN5Dq13DtOFcxl4/E=; l=2127; h=From:To:Date; b=I5mFNRgUgKybw+zW7adHWb3URb4DQrNLOfpi9NS75s9xOFBpA0vjvxocmAR7ubbiB y4tcRZL8zHyHirIv2C440HJtQ26Pt3ZnugoEvtMDiPVyj/IedB2sjiJs+pBufYQOXJ tFPza2l8xegk1vL8vPv4ff8PtFYkX1pddqhY1b4bUJISviNEiyNp7TfV0TZWvc8nm6 zSoPjLsyOIxNv3m4EZQSkr/A+85vBGKII+JGccCVSELgXHZfgUOD0ZXK6ppZjJXX9B +YGYtLR/zXZ114tyUmv8rd9aHYkGS98VB8DV/GPUIutQ9kqXFNTr093JU46UJB2YBO QU9tVVMkMjj0w== Content-Type: text/plain; charset="utf-8" So far, get_device_system_crosststamp() unconditionally passes system_counterval.cycles to timekeeping_cycles_to_ns(). But when interpolating system time (do_interp =3D=3D true), system_counterval.cycles= is before tkr_mono.cycle_last, contrary to the timekeeping_cycles_to_ns() expectations. On x86, CONFIG_CLOCKSOURCE_VALIDATE_LAST_CYCLE will mitigate on interpolating, setting delta to 0. With delta =3D=3D 0, xtstamp->sys_monoraw and xtstamp->sys_realtime are then set to the last update time, as implicitly expected by adjust_historical_crosststamp(). On other architectures, the resulting nonsense xtstamp->sys_monoraw and xtstamp->sys_realtime corrupt the xtstamp (ts) adjustment in adjust_historical_crosststamp(). Fix this by deriving xtstamp->sys_monoraw and xtstamp->sys_realtime from the last update time when interpolating, by using the local variable "cycles". The local variable already has the right value when interpolating, unlike system_counterval.cycles. Fixes: 2c756feb18d9 ("time: Add history to cross timestamp interface suppor= ting slower devices") Signed-off-by: Peter Hilber Acked-by: John Stultz --- Notes: v2: =20 - simplify fix (John Stultz) kernel/time/timekeeping.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 24ffd681aa23..b58dffc58a8f 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -1262,10 +1262,8 @@ int get_device_system_crosststamp(int (*get_time_fn) tk_core.timekeeper.offs_real); base_raw =3D tk->tkr_raw.base; =20 - nsec_real =3D timekeeping_cycles_to_ns(&tk->tkr_mono, - system_counterval.cycles); - nsec_raw =3D timekeeping_cycles_to_ns(&tk->tkr_raw, - system_counterval.cycles); + nsec_real =3D timekeeping_cycles_to_ns(&tk->tkr_mono, cycles); + nsec_raw =3D timekeeping_cycles_to_ns(&tk->tkr_raw, cycles); } while (read_seqcount_retry(&tk_core.seq, seq)); =20 xtstamp->sys_realtime =3D ktime_add_ns(base_real, nsec_real); --=20 2.40.1 From nobody Sat Dec 27 17:01:13 2025 Received: from refb02.tmes.trendmicro.eu (refb02.tmes.trendmicro.eu [18.185.115.60]) (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 1F3BD101DF for ; Mon, 18 Dec 2023 07:41:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=opensynergy.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=opensynergy.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=opensynergy.com header.i=@opensynergy.com header.b="pvj2fo1G" Received: from 104.47.11.168_.trendmicro.com (unknown [172.21.19.48]) by refb02.tmes.trendmicro.eu (Postfix) with ESMTPS id 74EDA109EA899; Mon, 18 Dec 2023 07:40:55 +0000 (UTC) Received: from 104.47.11.168_.trendmicro.com (unknown [172.21.171.117]) by repost01.tmes.trendmicro.eu (Postfix) with SMTP id A3F3A10000D09; Mon, 18 Dec 2023 07:40:48 +0000 (UTC) X-TM-MAIL-RECEIVED-TIME: 1702885247.890000 X-TM-MAIL-UUID: c9a2ed7b-3e21-45e1-873a-1a6bb68bdfaa Received: from DEU01-FR2-obe.outbound.protection.outlook.com (unknown [104.47.11.168]) by repre01.tmes.trendmicro.eu (Trend Micro Email Security) with ESMTPS id D977A10045513; Mon, 18 Dec 2023 07:40:47 +0000 (UTC) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=IgHjm8UYjlVJFyEHxnFZsbowPk1ygE+VwbBx1FWPVR4NVk+y2pqGEXdjOQSVZe6TdSwX3YbiGsEnOD9Cj+y25BMiuVxuI9XXvn/0Y2gHjp/W37/6m58o2hZikitjCZE2Zo81GdSBwDY1OP0/dTFJkVEms8PyGvq8YA6g06M497GYeNaSEmYh0iWWT5aeDL6zM7OvpraFMSNybiRQXvSCFrGTG8elOSvRfrDliK4W+9xgnKwlSqEcnaQv6K/oMcWNiYreAfhl4l9m+RMVZXRKDJ4r1haDUn4dnHdTeOvbaiRAjAGREk1KnaKU0M6mK6RWAnpuw95x0ZaGCamU2jXcbg== 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=OXUXTr5MnMoux6dJYiFK9OGc0xghjE5J6idg6nuU+As=; b=oHjvilhHFyCmkvw3ezjAOA0NetqtEBxaFP/e0cHGZX282ZPGlbmBV9yN0cKnm7HvkYM3ttc+iuduwxFKZkU6NKMVAe5FkN5NdNTh6L+OyP472ok80if0U7WCCAfF22uYomY8l+gwlhxCkEcR/jqNd560ksJ//6fkkAg3F8UGWLZ1KgflgbIUnRsPrnDYsHBSul/UoBgh1sCqH3FuisAjQth9r69hULGGEIAmX71UwP6ae2fpFNMVcwHlBO3oc3VtDA9+NzE8F0E4PsXqmCpO1cpRc4ZZzkIx2hX4PwHlqpg0UBpWijtHNNUtWsuAdvZc/BVN9N4QzRjfiATi8PnBeA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 217.66.60.4) smtp.rcpttodomain=arm.com smtp.mailfrom=opensynergy.com; dmarc=pass (p=reject sp=reject pct=100) action=none header.from=opensynergy.com; dkim=none (message not signed); arc=none (0) X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 217.66.60.4) smtp.mailfrom=opensynergy.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=opensynergy.com; Received-SPF: Pass (protection.outlook.com: domain of opensynergy.com designates 217.66.60.4 as permitted sender) receiver=protection.outlook.com; client-ip=217.66.60.4; helo=SR-MAIL-03.open-synergy.com; pr=C From: Peter Hilber To: linux-kernel@vger.kernel.org, virtualization@lists.linux.dev, virtio-dev@lists.oasis-open.org Cc: Peter Hilber , "Michael S. Tsirkin" , Jason Wang , Xuan Zhuo , Richard Cochran , netdev@vger.kernel.org, Marc Zyngier , Mark Rutland , Daniel Lezcano , Thomas Gleixner , linux-arm-kernel@lists.infradead.org, linux-rtc@vger.kernel.org, Alessandro Zummo , Alexandre Belloni Subject: [RFC PATCH v3 4/7] virtio_rtc: Add module and driver core Date: Mon, 18 Dec 2023 08:38:42 +0100 Message-Id: <20231218073849.35294-5-peter.hilber@opensynergy.com> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20231218073849.35294-1-peter.hilber@opensynergy.com> References: <20231218073849.35294-1-peter.hilber@opensynergy.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: VI1EUR05FT013:EE_|BEZP281MB2183:EE_ X-MS-Office365-Filtering-Correlation-Id: 424d96d3-c56b-45cc-f53b-08dbff9ca511 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: 7r94Q/KByjcOs4RLe9V4mrtm9UPAdBiT2ztklYaR+8sKI+bY/plEsj95C2S0QjXbYCjuw1A+DPJPxyUrrQa4n5ybNwvltliNh5XPA4autJ83DR4+u+JGRsF5fc0aw1VPnYeHouGaqRYEt66ALeWhYGmm7bt1ZlK87vUfKA5pK4HXVzS/05qC0g+DgD3kHAYuRphv1R22l/7vED8bJ+tfyIQAygDxx5JoI/K110FYdTxBOs5Kg2a6PYFFMpdL4vSXUwDAQV7lH6OqqZXjQSkYn99zHgA5XGEG0UlQesb1jp3/BumKuSOKVvZLRTMjihgEvfGNbfUuAr4WVgqa1WbIbC5MiPicUUsL0UX41DQA11FQ/UooB6R7zhJWxlq3X2Ct3dwM3VDuEX9ET8meK1ZiVLqa+WVa2LB1rN0YpYfL9fN+FgEJU4lm/1h/hCGQ5bwVdTC94LiOPNpwIOu9AS5SS6NwNpzMTxGj+qTwHftvAHRrOebvIFH5TY/GNa8h6uc6eib2tz4lMRFJWOeRj5WVCSpupI+OovWSJW+z6ejKfEl0I6yiBuJPslFLW9FFO2SqVa7Hoi3nvSNV+UExuT6v4AhmuUwL1cSfXXIXD8q2Dd5tLhfvfMJyBMpBKj187F3lka6KE/nGAlRSdVIe/2ytj0UvkcHpYDCwzcpsgCiQ0J+Z2EcrpJXPjae5B+TTU46bmQbDhBiYiaRDokERfFxvZqCd2qPmJbRUTwgGZhci+HDv215rlLm8IRijHc/V7sm/VQ/9vPbqKlWobeV00uk1mticBkCUeMyxKQR3J6DlzEY= X-Forefront-Antispam-Report: CIP:217.66.60.4;CTRY:DE;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:SR-MAIL-03.open-synergy.com;PTR:InfoDomainNonexistent;CAT:NONE;SFS:(13230031)(376002)(396003)(346002)(39840400004)(136003)(230922051799003)(82310400011)(1800799012)(64100799003)(451199024)(186009)(46966006)(36840700001)(1076003)(8936002)(8676002)(70586007)(70206006)(54906003)(42186006)(40480700001)(336012)(4326008)(316002)(47076005)(2616005)(83380400001)(26005)(36860700001)(478600001)(44832011)(5660300002)(30864003)(2906002)(66899024)(81166007)(41300700001)(7416002)(86362001)(36756003)(36900700001);DIR:OUT;SFP:1102; X-OriginatorOrg: opensynergy.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 18 Dec 2023 07:40:45.1518 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 424d96d3-c56b-45cc-f53b-08dbff9ca511 X-MS-Exchange-CrossTenant-Id: 800fae25-9b1b-4edc-993d-c939c4e84a64 X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=800fae25-9b1b-4edc-993d-c939c4e84a64;Ip=[217.66.60.4];Helo=[SR-MAIL-03.open-synergy.com] X-MS-Exchange-CrossTenant-AuthSource: VI1EUR05FT013.eop-eur05.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: BEZP281MB2183 X-TM-AS-ERS: 104.47.11.168-0.0.0.0 X-TMASE-Version: StarCloud-1.3-9.1.1015-28064.005 X-TMASE-Result: 10--11.013800-4.000000 X-TMASE-MatchedRID: CtIu++P39qfJ+P2VFrJmrGy53dw2JHQm5f2pKgY/c023UJJ8+n/4RSJS j0953fkRWpS5sR1Imtmbfc6n6VIFW7O1F/ODk5naCqJ0RbJ3bb3t08AkgFFynZASM5lkTKECyom U41gxOyP6Hdz3qeagEi77M0+ZVDsAefdn9/iBHHCIv5GuVax7CtUusl/JVaRNTWyDQcBBlE2uX7 jAFR99WZjz/Xnc2j+asen66SRX/zDT2djP7DKoDlJTtM6CHKVOgdXztqOEBnA3j/Mq9utADVBAV HJqFz648+eJ9G+ZDLXMglgMt0tendKRE65aapCPVj1dhrWbzEDOz+CaRbDFcNJAzldhFV5ZElJC CPFOoraxkjPUHfM63fWRBYx91SnJGzL7OqSPhBBch/PYekr/BIld6gdpSPED0g+dAcmSn6KEmEj VFBjobGwB+QHjMMuMBPsCWqKv2JA5D7FiRTCtpYruruLIWfnxAJ4bT6ig74eO46CtGFNzgMvlXM sLszNRZ5Hb8eCMiwmJwQLSKO0PQk+hKHoa1pxb4EfJdkIZseqWzpGKWacixMpF92GJdqYwypHo7 H4BiWhVK6IRFkYf/EVdqu6tIw9L7KpIQycMJiKSVDKCuaiEl57EkV3V/yv71KMHTXl0Cwc3qcpb SwktedJekV7oL2iI8CzPa2JJ3rfDrHDfg5pEBtwy9mwTudtiDyrqR96pNEIvMl4D6O45r0E/4tc JwKwA30NycNnao1Kqh33SVadweN+n/AcCed6xAZiMK6zpatWdVbkPpTjx9yLQjDgKVqdpOkf5WX S1f7rfXDU2ciEUMsKjGRQnQ81hzxPIJ+YGuapbyCHfDNuoE9umu0ICVejLoli4ZoiOHT/pP8tMO yYmaA== X-TMASE-XGENCLOUD: 72f14432-6e44-4bba-9967-37b6e77a700f-0-0-200-0 X-TM-Deliver-Signature: F0B89227EAA9D2F812BBF79DEDD49ECD X-TM-Addin-Auth: OqR3sAhrLrz7vzeCVIUwEli7+BZzybzlZG7d5JYRf8++sR1fLYlPQJsVJSo Zh8bxdnuXxUe2JYdnk2oZeEs5y4wKwLtvgg1bfSL/vugYAo3JJgYIRvO34yXwwL01V2WQNQl38X aOsETD//yPtbn6K90ijC+866cXLZHIWstB84G9tZGZbvWcCeVBg2xE7oVUNl4rjlXEwyYx9rBjn 2l6E+TtLvdR9VA4UiVbaxZVTLpD36hAruWKzd2METF0zKZy0712+XNxof9lMfpyYxjWFk+U514X y0lfPRTqQWyq9kM=.JAAt/ZQ3VvxzdO84Qbx1XGNSbUacqXf17GetPKSN81SNDj3TMKiFlHCEGX Z6E/mSEVWd/1MIFSXEiMJumhbLZYu+EvDzpi7l5rmeY0F8/OWj5MdNWH8gmL/rs3iLT6OReXRNM aK+diK+uGUFgIyWhyOHo2uWcgJJ21C7raj8uKsD0eX9OVVQikEPCtBwVeSWPY+CPg4N8PciKff7 HT6QKfLM9B9L7s1efmdaHUcWb38/RohyqeZzkpVOP7oe7Q2zlS1sXZBviHpy1Vr0j8aRTEcACpM nulY33Sk1a0yFAPu4FL6bJUE3P4O7t6iAhyVApoqLs8tyC25BOJj7+miVUw== X-TM-Addin-ProductCode: EMS DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=opensynergy.com; s=TM-DKIM-20210503141657; t=1702885248; bh=rYoV0FIQr5fBnmtQC1XPWa9nex5nC2CM2wGwkMqGNkY=; l=28851; h=From:To:Date; b=pvj2fo1G0/tmT52X1+Qioy88ulh3Qv3LtLDukYmf+U1NMpNpErAEGV6IZRbhceQwK wUl96ixFT56s/O6TMK6/v22cXHC+kZoPzr1PwuXCbw6Qd6XMTxZhQxeHh/jXhfL/Yu HGLVzyylbPfq1vLbgi+raJizP4vtsTfhHcPLEbQguJCDUhT+5OXafYHBROVHWb/O/W SKAFM5/tocAKsGxnW2m5m3To/zWjHXmCCj8q/yjWDwVbYzutiMHVIMLy5xXrjL5i4a iUcyOK5zxJ4/pqdby7EBl9jvx+zWMqzpFOf4u6u5WyUtvvwbMCluzHd/AB5on2XmqI o6d6A0fNAR7AQ== Content-Type: text/plain; charset="utf-8" Add the virtio_rtc module and driver core. The virtio_rtc module implements a driver compatible with the proposed Virtio RTC device specification. The Virtio RTC (Real Time Clock) device provides information about current time. The device can provide different clocks, e.g. for the UTC or TAI time standards, or for physical time elapsed since some past epoch. The driver can read the clocks with simple or more accurate methods. Implement the core, which interacts with the Virtio RTC device. Apart from this, the core does not expose functionality outside of the virtio_rtc module. A follow-up patch will expose PTP clocks. Provide synchronous messaging, which is enough for the expected time synchronization use cases through PTP clocks (similar to ptp_kvm) or RTC Class driver. Signed-off-by: Peter Hilber --- Notes: v3: =20 - merge readq and controlq into a single requestq (spec v3) =20 - don't guard cross-timestamping with feature bit (spec v3) =20 - pad message headers to 64 bits (spec v3) =20 - reduce clock id to 16 bits (spec v3) =20 - change Virtio status codes (spec v3) =20 - use 'VIRTIO_RTC_REQ_' prefix for request messages (spec v3) MAINTAINERS | 7 + drivers/virtio/Kconfig | 13 + drivers/virtio/Makefile | 2 + drivers/virtio/virtio_rtc_driver.c | 761 +++++++++++++++++++++++++++ drivers/virtio/virtio_rtc_internal.h | 23 + include/uapi/linux/virtio_rtc.h | 144 +++++ 6 files changed, 950 insertions(+) create mode 100644 drivers/virtio/virtio_rtc_driver.c create mode 100644 drivers/virtio/virtio_rtc_internal.h create mode 100644 include/uapi/linux/virtio_rtc.h diff --git a/MAINTAINERS b/MAINTAINERS index b589218605b4..0c157a19bbfd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -23200,6 +23200,13 @@ S: Maintained F: drivers/nvdimm/nd_virtio.c F: drivers/nvdimm/virtio_pmem.c =20 +VIRTIO RTC DRIVER +M: Peter Hilber +L: virtualization@lists.linux.dev +S: Maintained +F: drivers/virtio/virtio_rtc_* +F: include/uapi/linux/virtio_rtc.h + VIRTIO SOUND DRIVER M: Anton Yakovlev M: "Michael S. Tsirkin" diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig index 0a53a61231c2..834dd14bc070 100644 --- a/drivers/virtio/Kconfig +++ b/drivers/virtio/Kconfig @@ -173,4 +173,17 @@ config VIRTIO_DMA_SHARED_BUFFER This option adds a flavor of dma buffers that are backed by virtio resources. =20 +config VIRTIO_RTC + tristate "Virtio RTC driver" + depends on VIRTIO + depends on PTP_1588_CLOCK_OPTIONAL + help + This driver provides current time from a Virtio RTC device. The driver + provides the time through one or more clocks. + + To compile this code as a module, choose M here: the module will be + called virtio_rtc. + + If unsure, say M. + endif # VIRTIO_MENU diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile index 8e98d24917cc..f760414ed6ab 100644 --- a/drivers/virtio/Makefile +++ b/drivers/virtio/Makefile @@ -12,3 +12,5 @@ obj-$(CONFIG_VIRTIO_INPUT) +=3D virtio_input.o obj-$(CONFIG_VIRTIO_VDPA) +=3D virtio_vdpa.o obj-$(CONFIG_VIRTIO_MEM) +=3D virtio_mem.o obj-$(CONFIG_VIRTIO_DMA_SHARED_BUFFER) +=3D virtio_dma_buf.o +obj-$(CONFIG_VIRTIO_RTC) +=3D virtio_rtc.o +virtio_rtc-y :=3D virtio_rtc_driver.o diff --git a/drivers/virtio/virtio_rtc_driver.c b/drivers/virtio/virtio_rtc= _driver.c new file mode 100644 index 000000000000..ef1ea14b3bec --- /dev/null +++ b/drivers/virtio/virtio_rtc_driver.c @@ -0,0 +1,761 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * virtio_rtc driver core + * + * Copyright (C) 2022-2023 OpenSynergy GmbH + */ + +#include +#include +#include +#include +#include + +#include + +#include "virtio_rtc_internal.h" + +/* virtqueue order */ +enum { + VIORTC_REQUESTQ, + VIORTC_MAX_NR_QUEUES, +}; + +/** + * struct viortc_vq - virtqueue abstraction + * @vq: virtqueue + * @lock: protects access to vq + */ +struct viortc_vq { + struct virtqueue *vq; + spinlock_t lock; +}; + +/** + * struct viortc_dev - virtio_rtc device data + * @vdev: virtio device + * @vqs: virtqueues + * @num_clocks: # of virtio_rtc clocks + */ +struct viortc_dev { + struct virtio_device *vdev; + struct viortc_vq vqs[VIORTC_MAX_NR_QUEUES]; + u16 num_clocks; +}; + +/** + * struct viortc_msg - Message requested by driver, responded by device. + * @viortc: device data + * @req: request buffer + * @resp: response buffer + * @responded: vqueue callback signals response reception + * @refcnt: Message reference count, message and buffers will be deallocat= ed + * once 0. refcnt is decremented in the vqueue callback and in the + * thread waiting on the responded completion. + * If a message response wait function times out, the message wil= l be + * freed upon late reception (refcnt will reach 0 in the callback= ), or + * device removal. + * @req_size: size of request in bytes + * @resp_cap: maximum size of response in bytes + * @resp_actual_size: actual size of response + */ +struct viortc_msg { + struct viortc_dev *viortc; + void *req; + void *resp; + struct completion responded; + refcount_t refcnt; + unsigned int req_size; + unsigned int resp_cap; + unsigned int resp_actual_size; +}; + +/** + * viortc_msg_init() - Allocate and initialize requestq message. + * @viortc: device data + * @msg_type: virtio_rtc message type + * @req_size: size of request buffer to be allocated + * @resp_cap: size of response buffer to be allocated + * + * Initializes the message refcnt to 2. The refcnt will be decremented onc= e in + * the virtqueue callback, and once in the thread waiting on the message (= on + * completion or timeout). + * + * Context: Process context. + * Return: non-NULL on success. + */ +static struct viortc_msg *viortc_msg_init(struct viortc_dev *viortc, + u16 msg_type, unsigned int req_size, + unsigned int resp_cap) +{ + struct viortc_msg *msg; + struct device *dev =3D &viortc->vdev->dev; + struct virtio_rtc_req_head *req_head; + + msg =3D devm_kzalloc(dev, sizeof(*msg), GFP_KERNEL); + if (!msg) + return NULL; + + init_completion(&msg->responded); + + msg->req =3D devm_kzalloc(dev, req_size, GFP_KERNEL); + if (!msg->req) + goto err_free_msg; + + req_head =3D msg->req; + + msg->resp =3D devm_kzalloc(dev, resp_cap, GFP_KERNEL); + if (!msg->resp) + goto err_free_msg_req; + + msg->viortc =3D viortc; + msg->req_size =3D req_size; + msg->resp_cap =3D resp_cap; + + refcount_set(&msg->refcnt, 2); + + req_head->msg_type =3D virtio_cpu_to_le(msg_type, req_head->msg_type); + + return msg; + +err_free_msg_req: + devm_kfree(dev, msg->req); + +err_free_msg: + devm_kfree(dev, msg); + + return NULL; +} + +/** + * viortc_msg_release() - Decrement message refcnt, potentially free messa= ge. + * @msg: message requested by driver + * + * Context: Any context. + */ +static void viortc_msg_release(struct viortc_msg *msg) +{ + if (refcount_dec_and_test(&msg->refcnt)) { + struct device *dev =3D &msg->viortc->vdev->dev; + + devm_kfree(dev, msg->req); + devm_kfree(dev, msg->resp); + devm_kfree(dev, msg); + } +} + +/** + * viortc_do_cb() - generic virtqueue callback logic + * @vq: virtqueue + * @handle_buf: function to process a used buffer + * + * Context: virtqueue callback, typically interrupt. Takes and releases vq= lock. + */ +static void viortc_do_cb(struct virtqueue *vq, + void (*handle_buf)(void *token, unsigned int len, + struct virtqueue *vq, + struct viortc_vq *viortc_vq, + struct viortc_dev *viortc)) +{ + struct viortc_dev *viortc =3D vq->vdev->priv; + struct viortc_vq *viortc_vq; + bool cb_enabled =3D true; + unsigned long flags; + spinlock_t *lock; + unsigned int len; + void *token; + + viortc_vq =3D &viortc->vqs[vq->index]; + lock =3D &viortc_vq->lock; + + for (;;) { + spin_lock_irqsave(lock, flags); + + if (cb_enabled) { + virtqueue_disable_cb(vq); + cb_enabled =3D false; + } + + token =3D virtqueue_get_buf(vq, &len); + if (!token) { + if (virtqueue_enable_cb(vq)) { + spin_unlock_irqrestore(lock, flags); + return; + } + cb_enabled =3D true; + } + + spin_unlock_irqrestore(lock, flags); + + if (token) + handle_buf(token, len, vq, viortc_vq, viortc); + } +} + +/** + * viortc_requestq_hdlr() - process a requestq used buffer + * @token: token identifying the buffer + * @len: bytes written by device + * @vq: virtqueue + * @viortc_vq: device specific data for virtqueue + * @viortc: device data + * + * Signals completion for each received message. + * + * Context: virtqueue callback + */ +static void viortc_requestq_hdlr(void *token, unsigned int len, + struct virtqueue *vq, + struct viortc_vq *viortc_vq, + struct viortc_dev *viortc) +{ + struct viortc_msg *msg =3D token; + + msg->resp_actual_size =3D len; + + /* + * completion waiter must see our msg metadata, but complete() does not + * guarantee a memory barrier + */ + smp_wmb(); + + complete(&msg->responded); + viortc_msg_release(msg); +} + +/** + * viortc_cb_requestq() - callback for requestq + * @vq: virtqueue + * + * Context: virtqueue callback + */ +static void viortc_cb_requestq(struct virtqueue *vq) +{ + viortc_do_cb(vq, viortc_requestq_hdlr); +} + +/** + * viortc_get_resp_errno() - converts virtio_rtc errnos to system errnos + * @resp_head: message response header + * + * Return: negative system errno, or 0 + */ +static int viortc_get_resp_errno(struct virtio_rtc_resp_head *resp_head) +{ + switch (virtio_le_to_cpu(resp_head->status)) { + case VIRTIO_RTC_S_OK: + return 0; + case VIRTIO_RTC_S_EOPNOTSUPP: + return -EOPNOTSUPP; + case VIRTIO_RTC_S_EINVAL: + return -EINVAL; + case VIRTIO_RTC_S_ENODEV: + return -ENODEV; + case VIRTIO_RTC_S_EIO: + default: + return -EIO; + } +} + +/** + * viortc_msg_xfer() - send message request, wait until message response + * @vq: virtqueue + * @msg: message with driver request + * @timeout_jiffies: message response timeout, 0 for no timeout + * + * Context: Process context. Takes and releases vq.lock. May sleep. + */ +static int viortc_msg_xfer(struct viortc_vq *vq, struct viortc_msg *msg, + unsigned long timeout_jiffies) +{ + int ret; + unsigned long flags; + struct scatterlist out_sg[1]; + struct scatterlist in_sg[1]; + struct scatterlist *sgs[2] =3D { out_sg, in_sg }; + bool notify; + + sg_init_one(out_sg, msg->req, msg->req_size); + sg_init_one(in_sg, msg->resp, msg->resp_cap); + + spin_lock_irqsave(&vq->lock, flags); + + ret =3D virtqueue_add_sgs(vq->vq, sgs, 1, 1, msg, GFP_ATOMIC); + if (ret) { + spin_unlock_irqrestore(&vq->lock, flags); + /* + * Release in place of the response callback, which will never + * come. + */ + viortc_msg_release(msg); + return ret; + } + + notify =3D virtqueue_kick_prepare(vq->vq); + + spin_unlock_irqrestore(&vq->lock, flags); + + if (notify) + virtqueue_notify(vq->vq); + + if (timeout_jiffies) { + long timeout_ret; + + timeout_ret =3D wait_for_completion_interruptible_timeout( + &msg->responded, timeout_jiffies); + + if (!timeout_ret) + return -ETIMEDOUT; + else if (timeout_ret < 0) + return (int)timeout_ret; + } else { + ret =3D wait_for_completion_interruptible(&msg->responded); + if (ret) + return ret; + } + + /* + * Ensure we can read message metadata written in the virtqueue + * callback. + */ + smp_rmb(); + + /* + * There is not yet a case where returning a short message would make + * sense, so consider any deviation an error. + */ + if (msg->resp_actual_size !=3D msg->resp_cap) + return -EINVAL; + + return viortc_get_resp_errno(msg->resp); +} + +/* + * common message handle macros for messages of different types + */ + +/** + * VIORTC_DECLARE_MSG_HDL_ONSTACK() - declare message handle on stack + * @hdl: message handle name + * @msg_suf_lowerc: message type suffix in lowercase + * @msg_suf_upperc: message type suffix in uppercase + */ +#define VIORTC_DECLARE_MSG_HDL_ONSTACK(hdl, msg_suf_lowerc, msg_suf_upperc= ) \ + struct { \ + struct viortc_msg *msg; \ + struct virtio_rtc_req_##msg_suf_lowerc *req; \ + struct virtio_rtc_resp_##msg_suf_lowerc *resp; \ + unsigned int req_size; \ + unsigned int resp_cap; \ + u16 msg_type; \ + } hdl =3D { \ + NULL, \ + NULL, \ + NULL, \ + sizeof(struct virtio_rtc_req_##msg_suf_lowerc), \ + sizeof(struct virtio_rtc_resp_##msg_suf_lowerc), \ + VIRTIO_RTC_REQ_##msg_suf_upperc, \ + } + +/** + * VIORTC_MSG() - extract message from message handle + * + * Return: struct viortc_msg + */ +#define VIORTC_MSG(hdl) ((hdl).msg) + +/** + * VIORTC_MSG_INIT() - initialize message handle + * @hdl: message handle + * @viortc: device data (struct viortc_dev *) + * + * Context: Process context. + * Return: 0 on success, -ENOMEM otherwise. + */ +#define VIORTC_MSG_INIT(hdl, viortc) = \ + ({ \ + typeof(hdl) *_hdl =3D &(hdl); \ + \ + _hdl->msg =3D viortc_msg_init((viortc), _hdl->msg_type, \ + _hdl->req_size, _hdl->resp_cap); \ + if (_hdl->msg) { \ + _hdl->req =3D _hdl->msg->req; \ + _hdl->resp =3D _hdl->msg->resp; \ + } \ + _hdl->msg ? 0 : -ENOMEM; \ + }) + +/** + * VIORTC_MSG_WRITE() - write a request message field + * @hdl: message handle + * @dest_member: request message field name + * @src_ptr: pointer to data of compatible type + * + * Writes the field in little-endian format. + */ +#define VIORTC_MSG_WRITE(hdl, dest_member, src_ptr) = \ + do { \ + typeof(hdl) _hdl =3D (hdl); \ + typeof(src_ptr) _src_ptr =3D (src_ptr); \ + \ + /* Sanity check: must match the member's type */ \ + typecheck(typeof(_hdl.req->dest_member), *_src_ptr); \ + \ + _hdl.req->dest_member =3D \ + virtio_cpu_to_le(*_src_ptr, _hdl.req->dest_member); \ + } while (0) + +/** + * VIORTC_MSG_READ() - read from a response message field + * @hdl: message handle + * @src_member: response message field name + * @dest_ptr: pointer to data of compatible type + * + * Converts from little-endian format and writes to dest_ptr. + */ +#define VIORTC_MSG_READ(hdl, src_member, dest_ptr) \ + do { \ + typeof(dest_ptr) _dest_ptr =3D (dest_ptr); \ + \ + /* Sanity check: must match the member's type */ \ + typecheck(typeof((hdl).resp->src_member), *_dest_ptr); \ + \ + *_dest_ptr =3D virtio_le_to_cpu((hdl).resp->src_member); \ + } while (0) + +/* + * read requests + */ + +/** timeout for clock readings, where timeouts are considered non-fatal */ +#define VIORTC_MSG_READ_TIMEOUT (msecs_to_jiffies(60 * 1000)) + +/** + * viortc_read() - VIRTIO_RTC_REQ_READ wrapper + * @viortc: device data + * @vio_clk_id: virtio_rtc clock id + * @reading: clock reading [ns] + * + * Context: Process context. + * Return: Zero on success, negative error code otherwise. + */ +int viortc_read(struct viortc_dev *viortc, u16 vio_clk_id, u64 *reading) +{ + int ret; + VIORTC_DECLARE_MSG_HDL_ONSTACK(hdl, read, READ); + + ret =3D VIORTC_MSG_INIT(hdl, viortc); + if (ret) + return ret; + + VIORTC_MSG_WRITE(hdl, clock_id, &vio_clk_id); + + ret =3D viortc_msg_xfer(&viortc->vqs[VIORTC_REQUESTQ], VIORTC_MSG(hdl), + VIORTC_MSG_READ_TIMEOUT); + if (ret) { + dev_dbg(&viortc->vdev->dev, "%s: xfer returned %d\n", __func__, + ret); + goto out_release; + } + + VIORTC_MSG_READ(hdl, clock_reading, reading); + +out_release: + viortc_msg_release(VIORTC_MSG(hdl)); + + return ret; +} + +/** + * viortc_read_cross() - VIRTIO_RTC_REQ_READ_CROSS wrapper + * @viortc: device data + * @vio_clk_id: virtio_rtc clock id + * @hw_counter: virtio_rtc HW counter type + * @reading: clock reading [ns] + * @cycles: HW counter cycles during clock reading + * + * Context: Process context. + * Return: Zero on success, negative error code otherwise. + */ +int viortc_read_cross(struct viortc_dev *viortc, u16 vio_clk_id, u16 hw_co= unter, + u64 *reading, u64 *cycles) +{ + int ret; + VIORTC_DECLARE_MSG_HDL_ONSTACK(hdl, read_cross, READ_CROSS); + + ret =3D VIORTC_MSG_INIT(hdl, viortc); + if (ret) + return ret; + + VIORTC_MSG_WRITE(hdl, clock_id, &vio_clk_id); + VIORTC_MSG_WRITE(hdl, hw_counter, &hw_counter); + + ret =3D viortc_msg_xfer(&viortc->vqs[VIORTC_REQUESTQ], VIORTC_MSG(hdl), + VIORTC_MSG_READ_TIMEOUT); + if (ret) { + dev_dbg(&viortc->vdev->dev, "%s: xfer returned %d\n", __func__, + ret); + goto out_release; + } + + VIORTC_MSG_READ(hdl, clock_reading, reading); + VIORTC_MSG_READ(hdl, counter_cycles, cycles); + +out_release: + viortc_msg_release(VIORTC_MSG(hdl)); + + return ret; +} + +/* + * control requests + */ + +/** + * viortc_cfg() - VIRTIO_RTC_REQ_CFG wrapper + * @viortc: device data + * @num_clocks: # of virtio_rtc clocks + * + * Context: Process context. + * Return: Zero on success, negative error code otherwise. + */ +static int viortc_cfg(struct viortc_dev *viortc, u16 *num_clocks) +{ + int ret; + VIORTC_DECLARE_MSG_HDL_ONSTACK(hdl, cfg, CFG); + + ret =3D VIORTC_MSG_INIT(hdl, viortc); + if (ret) + return ret; + + ret =3D viortc_msg_xfer(&viortc->vqs[VIORTC_REQUESTQ], VIORTC_MSG(hdl), + 0); + if (ret) { + dev_dbg(&viortc->vdev->dev, "%s: xfer returned %d\n", __func__, + ret); + goto out_release; + } + + VIORTC_MSG_READ(hdl, num_clocks, num_clocks); + +out_release: + viortc_msg_release(VIORTC_MSG(hdl)); + + return ret; +} + +/** + * viortc_clock_cap() - VIRTIO_RTC_REQ_CLOCK_CAP wrapper + * @viortc: device data + * @vio_clk_id: virtio_rtc clock id + * @type: virtio_rtc clock type + * + * Context: Process context. + * Return: Zero on success, negative error code otherwise. + */ +static int viortc_clock_cap(struct viortc_dev *viortc, u16 vio_clk_id, + u16 *type) +{ + int ret; + VIORTC_DECLARE_MSG_HDL_ONSTACK(hdl, clock_cap, CLOCK_CAP); + + ret =3D VIORTC_MSG_INIT(hdl, viortc); + if (ret) + return ret; + + VIORTC_MSG_WRITE(hdl, clock_id, &vio_clk_id); + + ret =3D viortc_msg_xfer(&viortc->vqs[VIORTC_REQUESTQ], VIORTC_MSG(hdl), + 0); + if (ret) { + dev_dbg(&viortc->vdev->dev, "%s: xfer returned %d\n", __func__, + ret); + goto out_release; + } + + VIORTC_MSG_READ(hdl, type, type); + +out_release: + viortc_msg_release(VIORTC_MSG(hdl)); + + return ret; +} + +/** + * viortc_cross_cap() - VIRTIO_RTC_REQ_CROSS_CAP wrapper + * @viortc: device data + * @vio_clk_id: virtio_rtc clock id + * @hw_counter: virtio_rtc HW counter type + * @supported: xtstamping is supported for the vio_clk_id/hw_counter pair + * + * Context: Process context. + * Return: Zero on success, negative error code otherwise. + */ +int viortc_cross_cap(struct viortc_dev *viortc, u16 vio_clk_id, u16 hw_cou= nter, + bool *supported) +{ + int ret; + VIORTC_DECLARE_MSG_HDL_ONSTACK(hdl, cross_cap, CROSS_CAP); + u8 flags; + + ret =3D VIORTC_MSG_INIT(hdl, viortc); + if (ret) + return ret; + + VIORTC_MSG_WRITE(hdl, clock_id, &vio_clk_id); + VIORTC_MSG_WRITE(hdl, hw_counter, &hw_counter); + + ret =3D viortc_msg_xfer(&viortc->vqs[VIORTC_REQUESTQ], VIORTC_MSG(hdl), + 0); + if (ret) { + dev_dbg(&viortc->vdev->dev, "%s: xfer returned %d\n", __func__, + ret); + goto out_release; + } + + VIORTC_MSG_READ(hdl, flags, &flags); + *supported =3D !!(flags & VIRTIO_RTC_FLAG_CROSS_CAP); + +out_release: + viortc_msg_release(VIORTC_MSG(hdl)); + + return ret; +} + +/* + * init, deinit + */ + +/** + * viortc_clocks_init() - init local representations of virtio_rtc clocks + * @viortc: device data + * + * Context: Process context. + * Return: Zero on success, negative error code otherwise. + */ +static int viortc_clocks_init(struct viortc_dev *viortc) +{ + int ret; + u16 num_clocks; + + ret =3D viortc_cfg(viortc, &num_clocks); + if (ret) + return ret; + + if (num_clocks < 1) { + dev_err(&viortc->vdev->dev, "device reported 0 clocks\n"); + return -ENODEV; + } + + viortc->num_clocks =3D num_clocks; + + /* In the future, PTP clocks will be initialized here. */ + (void)viortc_clock_cap; + + return ret; +} + +/** + * viortc_init_vqs() - init virtqueues + * @viortc: device data + * + * Inits virtqueues and associated data. + * + * Context: Process context. + * Return: Zero on success, negative error code otherwise. + */ +static int viortc_init_vqs(struct viortc_dev *viortc) +{ + int ret; + struct virtio_device *vdev =3D viortc->vdev; + const char *names[VIORTC_MAX_NR_QUEUES]; + vq_callback_t *callbacks[VIORTC_MAX_NR_QUEUES]; + struct virtqueue *vqs[VIORTC_MAX_NR_QUEUES]; + int nr_queues; + + nr_queues =3D VIORTC_REQUESTQ + 1; + names[VIORTC_REQUESTQ] =3D "requestq"; + callbacks[VIORTC_REQUESTQ] =3D viortc_cb_requestq; + + ret =3D virtio_find_vqs(vdev, nr_queues, vqs, callbacks, names, NULL); + if (ret) + return ret; + + viortc->vqs[VIORTC_REQUESTQ].vq =3D vqs[VIORTC_REQUESTQ]; + spin_lock_init(&viortc->vqs[VIORTC_REQUESTQ].lock); + + return 0; +} + +/** + * viortc_probe() - probe a virtio_rtc virtio device + * @vdev: virtio device + * + * Context: Process context. + * Return: Zero on success, negative error code otherwise. + */ +static int viortc_probe(struct virtio_device *vdev) +{ + struct viortc_dev *viortc; + int ret; + + viortc =3D devm_kzalloc(&vdev->dev, sizeof(*viortc), GFP_KERNEL); + if (!viortc) + return -ENOMEM; + + vdev->priv =3D viortc; + viortc->vdev =3D vdev; + + ret =3D viortc_init_vqs(viortc); + if (ret) + return ret; + + virtio_device_ready(vdev); + + /* Ready vdev for use by frontend devices initialized next. */ + smp_wmb(); + + ret =3D viortc_clocks_init(viortc); + if (ret) + goto err_reset_vdev; + + return 0; + +err_reset_vdev: + virtio_reset_device(vdev); + vdev->config->del_vqs(vdev); + + return ret; +} + +/** + * viortc_remove() - remove a virtio_rtc virtio device + * @vdev: virtio device + */ +static void viortc_remove(struct virtio_device *vdev) +{ + /* In the future, PTP clocks will be deinitialized here. */ + + virtio_reset_device(vdev); + vdev->config->del_vqs(vdev); +} + +static struct virtio_device_id id_table[] =3D { + { VIRTIO_ID_CLOCK, VIRTIO_DEV_ANY_ID }, + { 0 }, +}; +MODULE_DEVICE_TABLE(virtio, id_table); + +static struct virtio_driver virtio_rtc_drv =3D { + .driver.name =3D KBUILD_MODNAME, + .driver.owner =3D THIS_MODULE, + .id_table =3D id_table, + .probe =3D viortc_probe, + .remove =3D viortc_remove, +}; + +module_virtio_driver(virtio_rtc_drv); + +MODULE_DESCRIPTION("Virtio RTC driver"); +MODULE_AUTHOR("OpenSynergy GmbH"); +MODULE_LICENSE("GPL"); diff --git a/drivers/virtio/virtio_rtc_internal.h b/drivers/virtio/virtio_r= tc_internal.h new file mode 100644 index 000000000000..9267661b8030 --- /dev/null +++ b/drivers/virtio/virtio_rtc_internal.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * virtio_rtc internal interfaces + * + * Copyright (C) 2022-2023 OpenSynergy GmbH + */ + +#ifndef _VIRTIO_RTC_INTERNAL_H_ +#define _VIRTIO_RTC_INTERNAL_H_ + +#include + +/* driver core IFs */ + +struct viortc_dev; + +int viortc_read(struct viortc_dev *viortc, u16 vio_clk_id, u64 *reading); +int viortc_read_cross(struct viortc_dev *viortc, u16 vio_clk_id, u16 hw_co= unter, + u64 *reading, u64 *cycles); +int viortc_cross_cap(struct viortc_dev *viortc, u16 vio_clk_id, u16 hw_cou= nter, + bool *supported); + +#endif /* _VIRTIO_RTC_INTERNAL_H_ */ diff --git a/include/uapi/linux/virtio_rtc.h b/include/uapi/linux/virtio_rt= c.h new file mode 100644 index 000000000000..f469276562d7 --- /dev/null +++ b/include/uapi/linux/virtio_rtc.h @@ -0,0 +1,144 @@ +/* SPDX-License-Identifier: ((GPL-2.0+ WITH Linux-syscall-note) OR BSD-3-C= lause) */ +/* + * Copyright (C) 2022-2023 OpenSynergy GmbH + */ + +#ifndef _LINUX_VIRTIO_RTC_H +#define _LINUX_VIRTIO_RTC_H + +#include + +/* read request message types */ + +#define VIRTIO_RTC_REQ_READ 0x0001 +#define VIRTIO_RTC_REQ_READ_CROSS 0x0002 + +/* control request message types */ + +#define VIRTIO_RTC_REQ_CFG 0x1000 +#define VIRTIO_RTC_REQ_CLOCK_CAP 0x1001 +#define VIRTIO_RTC_REQ_CROSS_CAP 0x1002 + +/* Message headers */ + +/** common request header */ +struct virtio_rtc_req_head { + __le16 msg_type; + __u8 reserved[6]; +}; + +/** common response header */ +struct virtio_rtc_resp_head { +#define VIRTIO_RTC_S_OK 0 +#define VIRTIO_RTC_S_EOPNOTSUPP 2 +#define VIRTIO_RTC_S_ENODEV 3 +#define VIRTIO_RTC_S_EINVAL 4 +#define VIRTIO_RTC_S_EIO 5 + __u8 status; + __u8 reserved[7]; +}; + +/* read requests */ + +/* VIRTIO_RTC_REQ_READ message */ + +struct virtio_rtc_req_read { + struct virtio_rtc_req_head head; + __le16 clock_id; + __u8 reserved[6]; +}; + +struct virtio_rtc_resp_read { + struct virtio_rtc_resp_head head; + __le64 clock_reading; +}; + +/* VIRTIO_RTC_REQ_READ_CROSS message */ + +struct virtio_rtc_req_read_cross { + struct virtio_rtc_req_head head; + __le16 clock_id; +/** Arm Generic Timer Virtual Count */ +#define VIRTIO_RTC_COUNTER_ARM_VIRT 0 +/** Arm Generic Timer Physical Count */ +#define VIRTIO_RTC_COUNTER_ARM_PHYS 1 +/** x86 Time Stamp Counter */ +#define VIRTIO_RTC_COUNTER_X86_TSC 2 + __le16 hw_counter; + __u8 reserved[4]; +}; + +struct virtio_rtc_resp_read_cross { + struct virtio_rtc_resp_head head; + __le64 clock_reading; + __le64 counter_cycles; +}; + +/* control requests */ + +/* VIRTIO_RTC_REQ_CFG message */ + +struct virtio_rtc_req_cfg { + struct virtio_rtc_req_head head; + /* no request params */ +}; + +struct virtio_rtc_resp_cfg { + struct virtio_rtc_resp_head head; + /** # of clocks -> clock ids < num_clocks are valid */ + __le16 num_clocks; + __u8 reserved[6]; +}; + +/* VIRTIO_RTC_REQ_CLOCK_CAP message */ + +struct virtio_rtc_req_clock_cap { + struct virtio_rtc_req_head head; + __le16 clock_id; + __u8 reserved[6]; +}; + +struct virtio_rtc_resp_clock_cap { + struct virtio_rtc_resp_head head; +#define VIRTIO_RTC_CLOCK_UTC 0 +#define VIRTIO_RTC_CLOCK_TAI 1 +#define VIRTIO_RTC_CLOCK_MONO 2 + __le16 type; + __u8 reserved[6]; +}; + +/* VIRTIO_RTC_REQ_CROSS_CAP message */ + +struct virtio_rtc_req_cross_cap { + struct virtio_rtc_req_head head; + __le16 clock_id; + __le16 hw_counter; + __u8 reserved[4]; +}; + +struct virtio_rtc_resp_cross_cap { + struct virtio_rtc_resp_head head; +#define VIRTIO_RTC_FLAG_CROSS_CAP (1 << 0) + __u8 flags; + __u8 reserved[7]; +}; + +/** Union of request types for requestq */ +union virtio_rtc_req_requestq { + struct virtio_rtc_req_read read; + struct virtio_rtc_req_read_cross read_cross; + struct virtio_rtc_req_cfg cfg; + struct virtio_rtc_req_clock_cap clock_cap; + struct virtio_rtc_req_cross_cap cross_cap; +}; + +/** Union of response types for requestq */ +union virtio_rtc_resp_requestq { + struct virtio_rtc_resp_read read; + struct virtio_rtc_resp_read_cross read_cross; + struct virtio_rtc_resp_cfg cfg; + struct virtio_rtc_resp_clock_cap clock_cap; + struct virtio_rtc_resp_cross_cap cross_cap; +}; + +#endif /* _LINUX_VIRTIO_RTC_H */ --=20 2.40.1 From nobody Sat Dec 27 17:01:13 2025 Received: from refb01.tmes.trendmicro.eu (refb01.tmes.trendmicro.eu [18.185.115.53]) (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 1754D1079A for ; Mon, 18 Dec 2023 07:41:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=opensynergy.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=opensynergy.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=opensynergy.com header.i=@opensynergy.com header.b="H0fLhR/H" Received: from 104.47.7.168_.trendmicro.com (unknown [172.21.19.198]) by refb01.tmes.trendmicro.eu (Postfix) with ESMTPS id 5640210B375C2 for ; Mon, 18 Dec 2023 07:40:56 +0000 (UTC) Received: from 104.47.7.168_.trendmicro.com (unknown [172.21.199.136]) by repost01.tmes.trendmicro.eu (Postfix) with SMTP id 3790310000C2F; Mon, 18 Dec 2023 07:40:49 +0000 (UTC) X-TM-MAIL-RECEIVED-TIME: 1702885248.524000 X-TM-MAIL-UUID: 25eae262-8632-49cc-ab01-ae3864541886 Received: from DEU01-BE0-obe.outbound.protection.outlook.com (unknown [104.47.7.168]) by repre01.tmes.trendmicro.eu (Trend Micro Email Security) with ESMTPS id 800C810000E27; Mon, 18 Dec 2023 07:40:48 +0000 (UTC) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=C6kbiQ6fnh5HHTU3odyBsR9pF3Q1FutO5fm2kpzUEoAwkmq7kGxWhxHbN70YhHtgPrfz2gVntvuMDLaEJ7S5RJM3D/eCm22J65q5cDgh2s2Vb+iB5BztlxfQtxPeuwiF3UDWSMFWHQamQFfs3fobbrCAbi/Vd9LEOLClF8ccPj+zknH/fzfepIDX0yv6nPxH7yjA+QXeoDXfxx4zrsE9h/HwfhZC6h0dN9HIwtTgkOXTftQAUQjiHIyipXdeTgNVuopp5lAlBqFZ7+UMMPyZS9O8bZMfmrYGwSRLhqB9fzOIEQ/Iko5BWovPKJEfnMXb7e/fTxyDUwo+fJ875RKsVg== 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=1StdKZOEhSHpd4g5bnliwSpc7ybHZgpRcNTDlpLxVW8=; b=IXlZpADEUzjBEVSNl/sMCKjiQunviy7eawOPKzoIJrnmXpw+R76j8Tb500jfpbLqItoixybg+YkW8LQnaqfg3CGqjaHIYB//9LSk7W9S8gBrfKNv0u4cTO3iwBnXB8I0mIaCEzCeAanT7yADYX17T+hHWtWkgUJon72R9Yx9RIzV8eQGD8LnmkSuzhFpCa5gquqD8KTUasFWMP5rVIYDbs4G0wAPdliyyYbRFJAsqMHMtG1X9Co/sw9qs+pQGnlwrNk/x2mAceVT1MMctINqe2IeSwQaTAMlPBa/lOqFypugvPvKYnZ2782e6TRtmwc1e2a1u9A9E/TMiLs8BwYAaQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 217.66.60.4) smtp.rcpttodomain=arm.com smtp.mailfrom=opensynergy.com; dmarc=pass (p=reject sp=reject pct=100) action=none header.from=opensynergy.com; dkim=none (message not signed); arc=none (0) X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 217.66.60.4) smtp.mailfrom=opensynergy.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=opensynergy.com; Received-SPF: Pass (protection.outlook.com: domain of opensynergy.com designates 217.66.60.4 as permitted sender) receiver=protection.outlook.com; client-ip=217.66.60.4; helo=SR-MAIL-03.open-synergy.com; pr=C From: Peter Hilber To: linux-kernel@vger.kernel.org, virtualization@lists.linux.dev, virtio-dev@lists.oasis-open.org Cc: Peter Hilber , "Michael S. Tsirkin" , Jason Wang , Xuan Zhuo , Richard Cochran , netdev@vger.kernel.org, Marc Zyngier , Mark Rutland , Daniel Lezcano , Thomas Gleixner , linux-arm-kernel@lists.infradead.org Subject: [RFC PATCH v3 5/7] virtio_rtc: Add PTP clocks Date: Mon, 18 Dec 2023 08:38:43 +0100 Message-Id: <20231218073849.35294-6-peter.hilber@opensynergy.com> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20231218073849.35294-1-peter.hilber@opensynergy.com> References: <20231218073849.35294-1-peter.hilber@opensynergy.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: VI1EUR05FT024:EE_|FRYP281MB2285:EE_ X-MS-Office365-Filtering-Correlation-Id: ab43eca4-4bf5-4a88-ca17-08dbff9ca5bf X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: Dqp20AZwGNI0CPtT+UB+vD7hiKb2iVHLHWQ3MNYevKceb2JaLfyTALh0SqFXjfDx1Y4KhjOllGgZ+hkTKmnl8wKB3LjqGgc3PUqrnYZULWgXHql9tDBol083FI4D4WDRnlSn5Gw4j2edbvyMBpKgDUjb1Mt+TnpNnF9fQLtpL9/YIddkAk7kG0NHXkafRzaw3v/FaQ4cvpd+xvg0Y/m/USi/tR65qltyCo8xpvMzj2M0EGg4icAWWXUGmH781cX+BsywHuWeTzeOl0RXwUHy8pFCbMrMMFrr2QOQNfaYCPXYewSBYXfxOqjw3QksL8Be48uFZ2wuwGlvBjGXbnuvtXIrSSfQxUW2NAx8nQoNen7zKyNRRxI1nkYOu7Wc4QHTg7pzq3Nggra174KB5AURG8mX+4RY6/czBxEoAHj5d/O5T5Z9uX4VpJ/u5mqNzNW6IoySV84zWPT1hFVYyOgMBWni/wfKLOo70GufpbzvP/TqnJU4FV+IZc0lvbkBCH5+lWTG3E4XwMtZMyzCn2C/PPwpAkqQhVHvCDCa0KAOtWLwmL9+o0e1VSEBIgEBP7yhua7/Ox/qikX+KM8lbSYaWalQVReX6setsLto3M0l/lDfVwHEvlpIGMknUtxuCsG1EheVKguvBnMSkKh5lojGUYNsgO21IKQrBv8DLDtG9rbpWW/uMvwdDA/gRfXBjUMbTh8NFrzTEFtunacLoo6VIkM8JQ2mjyWU4mOjSUx+1Z75qz3EqV3pvNMsq4uljm7UxjSJRObVWtaw9Xt1gDDojVhMWjioPmMJ4VAg3rON3/EDEXKBl2QX1SC0EHRKJWJ4glphS0EoJGTOV7ARDHuwrQ== X-Forefront-Antispam-Report: CIP:217.66.60.4;CTRY:DE;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:SR-MAIL-03.open-synergy.com;PTR:InfoDomainNonexistent;CAT:NONE;SFS:(13230031)(376002)(396003)(346002)(136003)(39840400004)(230922051799003)(230173577357003)(230273577357003)(82310400011)(64100799003)(1800799012)(186009)(451199024)(36840700001)(46966006)(40480700001)(70586007)(86362001)(81166007)(36756003)(316002)(36860700001)(26005)(2616005)(83380400001)(47076005)(1076003)(336012)(478600001)(2906002)(30864003)(54906003)(42186006)(70206006)(5660300002)(8676002)(4326008)(8936002)(7416002)(44832011)(41300700001)(36900700001);DIR:OUT;SFP:1102; X-OriginatorOrg: opensynergy.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 18 Dec 2023 07:40:46.2910 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: ab43eca4-4bf5-4a88-ca17-08dbff9ca5bf X-MS-Exchange-CrossTenant-Id: 800fae25-9b1b-4edc-993d-c939c4e84a64 X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=800fae25-9b1b-4edc-993d-c939c4e84a64;Ip=[217.66.60.4];Helo=[SR-MAIL-03.open-synergy.com] X-MS-Exchange-CrossTenant-AuthSource: VI1EUR05FT024.eop-eur05.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: FRYP281MB2285 X-TM-AS-ERS: 104.47.7.168-0.0.0.0 X-TMASE-Version: StarCloud-1.3-9.1.1015-28064.005 X-TMASE-Result: 10--21.325500-4.000000 X-TMASE-MatchedRID: 2kGot8vQMiMY9bhGrdH9F9wy9mwTudtiRyG5SSR7mMGmopAzNrNOJn+F psIKKIVlk8IAUKtJYbMmnuaVQc5qV4oSaqhQo1toHW+C8sNk3WDFZzmk4ajzuCe5CWghtIzPb1O 21F3h9PlzEFhMBQYFa/6kCjQkL+3Saroq2fxRivXHfwwbjh/dN1pMWq1GqY9ju/MvHv8cqImjxj +USeWICAX/qC69skJNMMrUUp1wb2VcV4l6mBSRB4gBJ2REjJVpgz5VmKZ8x87hCm8am+SP54vPi Bq/iW91MpPx8OFzfY0ZvOplNriRSZNrG/k+iz71sX4aFYAMIYMH/MsNCRnylfdjLuGFwc5lKq+K d6L61hF4tsh0iB6GbJB2/4Zk/kdWbc6z6hWXfyJ4ZqfDdG89Lhwr5LLKUXeOj8v426/NdLLWnmC QJIfHDBHANFoXrZpZGVpXbIDItBH3wLs+FSaf2UgfObGUdKnYnVW5D6U48feW56JO955kYFJNns bht/io0d8wVypPKQL96AoZAp2e8GgglWUFUjT3T+vZ3ApQRadQKm83vawLhOZb2thtW+nUrNM+r nFOGvZMwliXkYTsHQSQKEUpr4ba//lyRKkbk7rUT+gPVIJo9wzQf42ldnd7ijEMAGpMmld/kU2H 5OXFVazBcn//fMoK6xA0Ava73nAPm15xyht8lXx2eIlQG1sMfC4IwOLvyucC4DhlAS07elo7GmC OJYd1AqYBE3k9Mpw= X-TMASE-XGENCLOUD: 27111c8c-4602-4731-9fc0-fbea16473411-0-0-200-0 X-TM-Deliver-Signature: 169D64F23498B905EE744F478B3C02D0 X-TM-Addin-Auth: yto/9jN21XddCFvkohIG+Sbq3Q8zSTqnlQLf+PnGBnDN9YOoRakO2dJr/ZE 07L1x1hhYsdu9IwHjBF25p20sOa38buGH32UWKnKl02kmPb0L36x9FY6q3kJJ5agvwFVagEQy7o 0ujWpgIN2AcUtzNyy+9RfUl8W5+Ofrj3SyhzMYMyv+UUncLJYNxQt37AV1rqCV3lRus9fCEY3wc kPQVpkAX2hx0OO1rJOaKgMMtc9wwAIjbxCetFgGf4C2pVLWWsWvUOTnDorUyEALqN2CNuB6hUUs cAoWUY2wL+aQGro=.3ImFcXDkcCA2In7iZLEEPnxStOi4xjNCsrdKOEQ9PqFsUMclUJV18RrzZH +I3RsCZjBG7EaWNqdnPp8sNaxR6jU/+WEjyvToT/A6jU1JvOD7brHs8nvIhlvzBOmh39ojROwMN bAVtWA+9MIs0oBGIQjRWT5fWoXgLuKeQTUQphY8BBHSJVnT9E9frOjS2HG5sXDVZP2g33W2WaTb YR6C2WFEdjpTy5k/o2fxHZ9gYadl/4KwRVI9NIMAkHtI8HUxDt8Tq6KJmcrc+oul7iL2I/WY/G2 dPhtQfZj1mYifxK3NodRavOFIIqt+tT+/AnXBeJZMM5CKOERAhLLAaOdlZg== X-TM-Addin-ProductCode: EMS DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=opensynergy.com; s=TM-DKIM-20210503141657; t=1702885249; bh=aTm1DW57gLEsef7Sllsfu+XvPKCKzaeU5XR9q3DkYDQ=; l=20262; h=From:To:Date; b=H0fLhR/HRexVgeg/gmp0Ni91QA5B4f5R0/XGCDo/TfIvdCkt54W22YcLJqolPS0ah 8rFjYiG/pGXiNlHLfNTlbbNaTtSHeKkJbJahJfssA9gmhV5VGmffEwPCxPIpdjpZaW 0S2W6d2WWImZVvdupKJaElRzih1VXUrM2Cd1DUP0svpEm0H1Eq7woCPHCTvFnhAM4q cdnWA2KOotPtgaY0dZM1KhbRu/2VlimpnGumWionfsfHOCXySOPvNAi/omVCbhMj6x OxL7V7FF5p1vBIcwkDsnv3vwz39eeKMXR62ziVSpsvlW3YK8KujVQPTwxPPHbrGrTY XAQVYHa/47z2Q== Content-Type: text/plain; charset="utf-8" Expose the virtio_rtc clocks as PTP clocks to userspace, similar to ptp_kvm. virtio_rtc can expose multiple clocks, e.g. a UTC clock and a monotonic clock. Userspace should distinguish different clocks through the name assigned by the driver. A udev rule such as the following can be used to get a symlink /dev/ptp_virtio to the UTC clock: SUBSYSTEM=3D=3D"ptp", ATTR{clock_name}=3D=3D"Virtio PTP UTC", SYMLINK +=3D= "ptp_virtio" The preferred PTP clock reading method is ioctl PTP_SYS_OFFSET_PRECISE2, through the ptp_clock_info.getcrosststamp() op. For now, PTP_SYS_OFFSET_PRECISE2 will return -EOPNOTSUPP through a weak function. PTP_SYS_OFFSET_PRECISE2 requires cross-timestamping support for specific clocksources, which will be added in the following. If the clocksource specific code is enabled, check that the Virtio RTC device supports the respective HW counter before obtaining an actual cross-timestamp from the Virtio device. The Virtio RTC device response time may be higher than the timekeeper seqcount increment interval. Therefore, obtain the cross-timestamp before calling get_device_system_crosststamp(). As a fallback, support the ioctl PTP_SYS_OFFSET_EXTENDED2 for all platforms. Assume that concurrency issues during PTP clock removal are avoided by the posix_clock framework. Kconfig recursive dependencies prevent virtio_rtc from implicitly enabling PTP_1588_CLOCK, therefore just warn the user if PTP_1588_CLOCK is not available. Since virtio_rtc should in the future also expose clocks as RTC class devices, do not have VIRTIO_RTC depend on PTP_1588_CLOCK. Signed-off-by: Peter Hilber --- Notes: v3: =20 - don't guard cross-timestamping with feature bit (spec v3) =20 - reduce clock id to 16 bits (spec v3) =20 v2: =20 - Depend on prerequisite patch series "treewide: Use clocksource id for get_device_system_crosststamp()". =20 - Check clocksource id before sending crosststamp message to device. =20 - Do not support multiple hardware counters at runtime any more, since distinction of Arm physical and virtual counter appears unneeded after discussion with Marc Zyngier. drivers/virtio/Kconfig | 23 +- drivers/virtio/Makefile | 1 + drivers/virtio/virtio_rtc_driver.c | 131 +++++++++- drivers/virtio/virtio_rtc_internal.h | 46 ++++ drivers/virtio/virtio_rtc_ptp.c | 342 +++++++++++++++++++++++++++ 5 files changed, 539 insertions(+), 4 deletions(-) create mode 100644 drivers/virtio/virtio_rtc_ptp.c diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig index 834dd14bc070..8542b2f20201 100644 --- a/drivers/virtio/Kconfig +++ b/drivers/virtio/Kconfig @@ -179,11 +179,32 @@ config VIRTIO_RTC depends on PTP_1588_CLOCK_OPTIONAL help This driver provides current time from a Virtio RTC device. The driver - provides the time through one or more clocks. + provides the time through one or more clocks. The Virtio RTC PTP + clocks must be enabled to expose the clocks to userspace. =20 To compile this code as a module, choose M here: the module will be called virtio_rtc. =20 If unsure, say M. =20 +if VIRTIO_RTC + +comment "WARNING: Consider enabling VIRTIO_RTC_PTP." + depends on !VIRTIO_RTC_PTP + +comment "Enable PTP_1588_CLOCK in order to enable VIRTIO_RTC_PTP." + depends on PTP_1588_CLOCK=3Dn + +config VIRTIO_RTC_PTP + bool "Virtio RTC PTP clocks" + default y + depends on PTP_1588_CLOCK + help + This exposes any Virtio RTC clocks as PTP Hardware Clocks (PHCs) to + userspace. + + If unsure, say Y. + +endif # VIRTIO_RTC + endif # VIRTIO_MENU diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile index f760414ed6ab..4d48cbcae6bb 100644 --- a/drivers/virtio/Makefile +++ b/drivers/virtio/Makefile @@ -14,3 +14,4 @@ obj-$(CONFIG_VIRTIO_MEM) +=3D virtio_mem.o obj-$(CONFIG_VIRTIO_DMA_SHARED_BUFFER) +=3D virtio_dma_buf.o obj-$(CONFIG_VIRTIO_RTC) +=3D virtio_rtc.o virtio_rtc-y :=3D virtio_rtc_driver.o +virtio_rtc-$(CONFIG_VIRTIO_RTC_PTP) +=3D virtio_rtc_ptp.o diff --git a/drivers/virtio/virtio_rtc_driver.c b/drivers/virtio/virtio_rtc= _driver.c index ef1ea14b3bec..c331b7383285 100644 --- a/drivers/virtio/virtio_rtc_driver.c +++ b/drivers/virtio/virtio_rtc_driver.c @@ -35,11 +35,16 @@ struct viortc_vq { * struct viortc_dev - virtio_rtc device data * @vdev: virtio device * @vqs: virtqueues + * @clocks_to_unregister: Clock references, which are only used during dev= ice + * removal. + * For other uses, there would be a race between device + * creation and setting the pointers here. * @num_clocks: # of virtio_rtc clocks */ struct viortc_dev { struct virtio_device *vdev; struct viortc_vq vqs[VIORTC_MAX_NR_QUEUES]; + struct viortc_ptp_clock **clocks_to_unregister; u16 num_clocks; }; =20 @@ -626,6 +631,109 @@ int viortc_cross_cap(struct viortc_dev *viortc, u16 v= io_clk_id, u16 hw_counter, * init, deinit */ =20 +/** + * viortc_init_ptp_clock() - init and register PTP clock + * @viortc: device data + * @vio_clk_id: virtio_rtc clock id + * @clock_type: virtio_rtc clock type + * + * Context: Process context. + * Return: Zero on success, negative error code otherwise. + */ +static int viortc_init_ptp_clock(struct viortc_dev *viortc, u16 vio_clk_id, + u16 clock_type) +{ + struct device *dev =3D &viortc->vdev->dev; + char ptp_clock_name[PTP_CLOCK_NAME_LEN]; + const char *type_name; + /* fit prefix + u16 in decimal */ + char type_name_buf[5 + 5 + 1]; + struct viortc_ptp_clock *vio_ptp; + + switch (clock_type) { + case VIRTIO_RTC_CLOCK_UTC: + type_name =3D "UTC"; + break; + case VIRTIO_RTC_CLOCK_TAI: + type_name =3D "TAI"; + break; + case VIRTIO_RTC_CLOCK_MONO: + type_name =3D "monotonic"; + break; + default: + snprintf(type_name_buf, sizeof(type_name_buf), "type %hu", + clock_type); + type_name =3D type_name_buf; + } + + snprintf(ptp_clock_name, PTP_CLOCK_NAME_LEN, "Virtio PTP %s", + type_name); + + vio_ptp =3D viortc_ptp_register(viortc, dev, vio_clk_id, ptp_clock_name); + if (IS_ERR(vio_ptp)) { + dev_err(dev, "failed to register PTP clock '%s'\n", + ptp_clock_name); + return PTR_ERR(vio_ptp); + } + + viortc->clocks_to_unregister[vio_clk_id] =3D vio_ptp; + + if (!vio_ptp) + dev_warn(dev, "clock %d is not exposed to userspace\n", + vio_clk_id); + + return 0; +} + +/** + * viortc_init_clock() - init local representation of virtio_rtc clock + * @viortc: device data + * @vio_clk_id: virtio_rtc clock id + * + * Initializes PHC and/or RTC class device to represent virtio_rtc clock. + * + * Context: Process context. + * Return: Zero on success, negative error code otherwise. + */ +static int viortc_init_clock(struct viortc_dev *viortc, u16 vio_clk_id) +{ + u16 clock_type; + int ret; + + ret =3D viortc_clock_cap(viortc, vio_clk_id, &clock_type); + if (ret) + return ret; + + if (IS_ENABLED(CONFIG_VIRTIO_RTC_PTP)) { + ret =3D viortc_init_ptp_clock(viortc, vio_clk_id, clock_type); + if (ret) + return ret; + } + + return 0; +} + +/** + * viortc_clocks_exit() - unregister PHCs + * @viortc: device data + */ +static void viortc_clocks_exit(struct viortc_dev *viortc) +{ + unsigned int i; + struct viortc_ptp_clock *vio_ptp; + + for (i =3D 0; i < viortc->num_clocks; i++) { + vio_ptp =3D viortc->clocks_to_unregister[i]; + + if (!vio_ptp) + continue; + + viortc->clocks_to_unregister[i] =3D NULL; + + WARN_ON(viortc_ptp_unregister(vio_ptp, &viortc->vdev->dev)); + } +} + /** * viortc_clocks_init() - init local representations of virtio_rtc clocks * @viortc: device data @@ -637,6 +745,7 @@ static int viortc_clocks_init(struct viortc_dev *viortc) { int ret; u16 num_clocks; + unsigned int i; =20 ret =3D viortc_cfg(viortc, &num_clocks); if (ret) @@ -649,8 +758,22 @@ static int viortc_clocks_init(struct viortc_dev *viort= c) =20 viortc->num_clocks =3D num_clocks; =20 - /* In the future, PTP clocks will be initialized here. */ - (void)viortc_clock_cap; + viortc->clocks_to_unregister =3D + devm_kcalloc(&viortc->vdev->dev, num_clocks, + sizeof(*viortc->clocks_to_unregister), GFP_KERNEL); + if (!viortc->clocks_to_unregister) + return -ENOMEM; + + for (i =3D 0; i < num_clocks; i++) { + ret =3D viortc_init_clock(viortc, i); + if (ret) + goto err_free_clocks; + } + + return 0; + +err_free_clocks: + viortc_clocks_exit(viortc); =20 return ret; } @@ -734,7 +857,9 @@ static int viortc_probe(struct virtio_device *vdev) */ static void viortc_remove(struct virtio_device *vdev) { - /* In the future, PTP clocks will be deinitialized here. */ + struct viortc_dev *viortc =3D vdev->priv; + + viortc_clocks_exit(viortc); =20 virtio_reset_device(vdev); vdev->config->del_vqs(vdev); diff --git a/drivers/virtio/virtio_rtc_internal.h b/drivers/virtio/virtio_r= tc_internal.h index 9267661b8030..0dedced4aeae 100644 --- a/drivers/virtio/virtio_rtc_internal.h +++ b/drivers/virtio/virtio_rtc_internal.h @@ -9,6 +9,7 @@ #define _VIRTIO_RTC_INTERNAL_H_ =20 #include +#include =20 /* driver core IFs */ =20 @@ -20,4 +21,49 @@ int viortc_read_cross(struct viortc_dev *viortc, u16 vio= _clk_id, u16 hw_counter, int viortc_cross_cap(struct viortc_dev *viortc, u16 vio_clk_id, u16 hw_cou= nter, bool *supported); =20 +/* PTP IFs */ + +struct viortc_ptp_clock; + +#if IS_ENABLED(CONFIG_VIRTIO_RTC_PTP) + +struct viortc_ptp_clock *viortc_ptp_register(struct viortc_dev *viortc, + struct device *parent_dev, + u16 vio_clk_id, + const char *ptp_clock_name); +int viortc_ptp_unregister(struct viortc_ptp_clock *vio_ptp, + struct device *parent_dev); + +#else + +static inline struct viortc_ptp_clock * +viortc_ptp_register(struct viortc_dev *viortc, struct device *parent_dev, + u16 vio_clk_id, const char *ptp_clock_name) +{ + return NULL; +} + +static inline int viortc_ptp_unregister(struct viortc_ptp_clock *vio_ptp, + struct device *parent_dev) +{ + return -ENODEV; +} + +#endif + +/* HW counter IFs */ + +/** + * viortc_hw_xtstamp_params() - get HW-specific xtstamp params + * @hw_counter: virtio_rtc HW counter type + * @cs_id: clocksource id corresponding to hw_counter + * + * Gets the HW-specific xtstamp params. Returns an error if the driver can= not + * support xtstamp. + * + * Context: Process context. + * Return: Zero on success, negative error code otherwise. + */ +int viortc_hw_xtstamp_params(u16 *hw_counter, enum clocksource_ids *cs_id); + #endif /* _VIRTIO_RTC_INTERNAL_H_ */ diff --git a/drivers/virtio/virtio_rtc_ptp.c b/drivers/virtio/virtio_rtc_pt= p.c new file mode 100644 index 000000000000..4592cd070772 --- /dev/null +++ b/drivers/virtio/virtio_rtc_ptp.c @@ -0,0 +1,342 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Expose virtio_rtc clocks as PTP clocks. + * + * Copyright (C) 2022-2023 OpenSynergy GmbH + * + * Derived from ptp_kvm_common.c, virtual PTP 1588 clock for use with KVM + * guests. + * + * Copyright (C) 2017 Red Hat Inc. + */ + +#include +#include +#include + +#include + +#include "virtio_rtc_internal.h" + +/** + * struct viortc_ptp_clock - PTP clock abstraction + * @ptp_clock: PTP clock handle + * @viortc: virtio_rtc device data + * @ptp_info: PTP clock description + * @vio_clk_id: virtio_rtc clock id + * @have_cross: device supports crosststamp with available HW counter + */ +struct viortc_ptp_clock { + struct ptp_clock *ptp_clock; + struct viortc_dev *viortc; + struct ptp_clock_info ptp_info; + u16 vio_clk_id; + bool have_cross; +}; + +/** + * struct viortc_ptp_cross_ctx - context for get_device_system_crosststamp= () + * @device_time: device clock reading + * @system_counterval: HW counter value at device_time + * + * Provides the already obtained crosststamp to get_device_system_crosstst= amp(). + */ +struct viortc_ptp_cross_ctx { + ktime_t device_time; + struct system_counterval_t system_counterval; +}; + +/* Weak function in case get_device_system_crosststamp() is not supported = */ +int __weak viortc_hw_xtstamp_params(u16 *hw_counter, + enum clocksource_ids *cs_id) +{ + return -EOPNOTSUPP; +} + +/** + * viortc_ptp_get_time_fn() - callback for get_device_system_crosststamp() + * @device_time: device clock reading + * @system_counterval: HW counter value at device_time + * @ctx: context with already obtained crosststamp + * + * Return: zero (success). + */ +static int viortc_ptp_get_time_fn(ktime_t *device_time, + struct system_counterval_t *system_counterval, + void *ctx) +{ + struct viortc_ptp_cross_ctx *vio_ctx =3D ctx; + + *device_time =3D vio_ctx->device_time; + *system_counterval =3D vio_ctx->system_counterval; + + return 0; +} + +/** + * viortc_ptp_do_xtstamp() - get crosststamp from device + * @vio_ptp: virtio_rtc PTP clock + * @ctx: context for get_device_system_crosststamp() + * @hw_counter: virtio_rtc HW counter type + * @cs_id: clocksource id corresponding to hw_counter + * + * Reads HW-specific crosststamp from device. + * + * Context: Process context. + * Return: Zero on success, negative error code otherwise. + */ +static int viortc_ptp_do_xtstamp(struct viortc_ptp_clock *vio_ptp, + struct viortc_ptp_cross_ctx *ctx, + u16 hw_counter, enum clocksource_ids cs_id) +{ + u64 ns; + u64 max_ns; + int ret; + + ctx->system_counterval.cs_id =3D cs_id; + + ret =3D viortc_read_cross(vio_ptp->viortc, vio_ptp->vio_clk_id, + hw_counter, &ns, + &ctx->system_counterval.cycles); + if (ret) + return ret; + + max_ns =3D (u64)ktime_to_ns(KTIME_MAX); + if (ns > max_ns) + return -EINVAL; + + ctx->device_time =3D ns_to_ktime(ns); + + return 0; +} + +/* + * PTP clock operations + */ + +/** + * viortc_ptp_getcrosststamp() - PTP clock getcrosststamp op + * @vio_ptp: virtio_rtc PTP clock + * @xtstamp: crosststamp + * + * Context: Process context. + * Return: Zero on success, negative error code otherwise. + */ +static int viortc_ptp_getcrosststamp(struct ptp_clock_info *ptp, + struct system_device_crosststamp *xtstamp) +{ + struct viortc_ptp_clock *vio_ptp =3D + container_of(ptp, struct viortc_ptp_clock, ptp_info); + int ret; + struct system_time_snapshot history_begin; + struct viortc_ptp_cross_ctx ctx; + enum clocksource_ids cs_id; + u16 hw_counter; + + if (!vio_ptp->have_cross) + return -EOPNOTSUPP; + + ret =3D viortc_hw_xtstamp_params(&hw_counter, &cs_id); + if (ret) + return ret; + + ktime_get_snapshot(&history_begin); + if (history_begin.cs_id !=3D cs_id) + return -EOPNOTSUPP; + + /* + * Getting the timestamp can take many milliseconds with a slow Virtio + * device. This is too long for viortc_ptp_get_time_fn() passed to + * get_device_system_crosststamp(), which has to usually return before + * the timekeeper seqcount increases (every tick or so). + * + * So, get the actual cross-timestamp first. + */ + ret =3D viortc_ptp_do_xtstamp(vio_ptp, &ctx, hw_counter, cs_id); + if (ret) + return ret; + + ret =3D get_device_system_crosststamp(viortc_ptp_get_time_fn, &ctx, + &history_begin, xtstamp); + if (ret) + pr_debug("%s: get_device_system_crosststamp() returned %d\n", + __func__, ret); + + return ret; +} + +/** viortc_ptp_adjfine() - unsupported PTP clock adjfine op */ +static int viortc_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) +{ + return -EOPNOTSUPP; +} + +/** viortc_ptp_adjtime() - unsupported PTP clock adjtime op */ +static int viortc_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) +{ + return -EOPNOTSUPP; +} + +/** viortc_ptp_settime64() - unsupported PTP clock settime64 op */ +static int viortc_ptp_settime64(struct ptp_clock_info *ptp, + const struct timespec64 *ts) +{ + return -EOPNOTSUPP; +} + +/** + * viortc_ptp_gettimex64() - PTP clock gettimex64 op + * + * Context: Process context. + */ +static int viortc_ptp_gettimex64(struct ptp_clock_info *ptp, + struct timespec64 *ts, + struct ptp_system_timestamp *sts) +{ + struct viortc_ptp_clock *vio_ptp =3D + container_of(ptp, struct viortc_ptp_clock, ptp_info); + u64 ns; + int ret; + + ptp_read_system_prets(sts); + ret =3D viortc_read(vio_ptp->viortc, vio_ptp->vio_clk_id, &ns); + ptp_read_system_postts(sts); + + if (ret) + return ret; + + if (ns > (u64)S64_MAX) + return -EINVAL; + + *ts =3D ns_to_timespec64((s64)ns); + + return 0; +} + +/** viortc_ptp_enable() - unsupported PTP clock enable op */ +static int viortc_ptp_enable(struct ptp_clock_info *ptp, + struct ptp_clock_request *rq, int on) +{ + return -EOPNOTSUPP; +} + +/** + * viortc_ptp_info_template - ptp_clock_info template + * + * The .name member will be set for individual virtio_rtc PTP clocks. + */ +static const struct ptp_clock_info viortc_ptp_info_template =3D { + .owner =3D THIS_MODULE, + /* .name is set according to clock type */ + .adjfine =3D viortc_ptp_adjfine, + .adjtime =3D viortc_ptp_adjtime, + .gettimex64 =3D viortc_ptp_gettimex64, + .settime64 =3D viortc_ptp_settime64, + .enable =3D viortc_ptp_enable, + .getcrosststamp =3D viortc_ptp_getcrosststamp, +}; + +/** + * viortc_ptp_unregister() - PTP clock unregistering wrapper + * @vio_ptp: virtio_rtc PTP clock + * @parent_dev: parent device of PTP clock + * + * Return: Zero on success, negative error code otherwise. + */ +int viortc_ptp_unregister(struct viortc_ptp_clock *vio_ptp, + struct device *parent_dev) +{ + int ret =3D ptp_clock_unregister(vio_ptp->ptp_clock); + + if (!ret) + devm_kfree(parent_dev, vio_ptp); + + return ret; +} + +/** + * viortc_ptp_get_cross_cap() - get xtstamp support info from device + * @viortc: virtio_rtc device data + * @vio_ptp: virtio_rtc PTP clock abstraction + * + * Context: Process context. + * Return: Zero on success, negative error code otherwise. + */ +static int viortc_ptp_get_cross_cap(struct viortc_dev *viortc, + struct viortc_ptp_clock *vio_ptp) +{ + int ret; + enum clocksource_ids cs_id; + u16 hw_counter; + bool xtstamp_supported; + + ret =3D viortc_hw_xtstamp_params(&hw_counter, &cs_id); + if (ret) { + vio_ptp->have_cross =3D false; + return 0; + } + + ret =3D viortc_cross_cap(viortc, vio_ptp->vio_clk_id, hw_counter, + &xtstamp_supported); + if (ret) + return ret; + + vio_ptp->have_cross =3D xtstamp_supported; + + return 0; +} + +/** + * viortc_ptp_register() - prepare and register PTP clock + * @viortc: virtio_rtc device data + * @parent_dev: parent device for PTP clock + * @vio_clk_id: id of virtio_rtc clock which backs PTP clock + * @ptp_clock_name: PTP clock name + * + * Context: Process context. + * Return: Pointer on success, ERR_PTR() otherwise; NULL if PTP clock supp= ort + * not available. + */ +struct viortc_ptp_clock *viortc_ptp_register(struct viortc_dev *viortc, + struct device *parent_dev, + u16 vio_clk_id, + const char *ptp_clock_name) +{ + struct viortc_ptp_clock *vio_ptp; + struct ptp_clock *ptp_clock; + ssize_t len; + int ret; + + vio_ptp =3D devm_kzalloc(parent_dev, sizeof(*vio_ptp), GFP_KERNEL); + if (!vio_ptp) + return ERR_PTR(-ENOMEM); + + vio_ptp->viortc =3D viortc; + vio_ptp->vio_clk_id =3D vio_clk_id; + vio_ptp->ptp_info =3D viortc_ptp_info_template; + len =3D strscpy(vio_ptp->ptp_info.name, ptp_clock_name, + sizeof(vio_ptp->ptp_info.name)); + if (len < 0) { + ret =3D len; + goto err_free_dev; + } + + ret =3D viortc_ptp_get_cross_cap(viortc, vio_ptp); + if (ret) + goto err_free_dev; + + ptp_clock =3D ptp_clock_register(&vio_ptp->ptp_info, parent_dev); + if (IS_ERR(ptp_clock)) + goto err_on_register; + + vio_ptp->ptp_clock =3D ptp_clock; + + return vio_ptp; + +err_on_register: + ret =3D PTR_ERR(ptp_clock); + +err_free_dev: + devm_kfree(parent_dev, vio_ptp); + return ERR_PTR(ret); +} --=20 2.40.1 From nobody Sat Dec 27 17:01:13 2025 Received: from refb01.tmes.trendmicro.eu (refb01.tmes.trendmicro.eu [18.185.115.53]) (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 1752A10799 for ; Mon, 18 Dec 2023 07:41:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=opensynergy.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=opensynergy.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=opensynergy.com header.i=@opensynergy.com header.b="t+DZhYPB" Received: from 104.47.11.168_.trendmicro.com (unknown [172.21.9.50]) by refb01.tmes.trendmicro.eu (Postfix) with ESMTPS id 4F7C810B282D8 for ; Mon, 18 Dec 2023 07:40:56 +0000 (UTC) Received: from 104.47.11.168_.trendmicro.com (unknown [172.21.199.136]) by repost01.tmes.trendmicro.eu (Postfix) with SMTP id E564710000E34; Mon, 18 Dec 2023 07:40:48 +0000 (UTC) X-TM-MAIL-RECEIVED-TIME: 1702885248.450000 X-TM-MAIL-UUID: 31e06f38-11a2-421c-b5ae-d5339e368442 Received: from DEU01-FR2-obe.outbound.protection.outlook.com (unknown [104.47.11.168]) by repre01.tmes.trendmicro.eu (Trend Micro Email Security) with ESMTPS id 6E14E10000E3E; Mon, 18 Dec 2023 07:40:48 +0000 (UTC) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=NK/hQE8iKWcwRYsj7tUbw68UHPjokjjCkJCEK29D3NwbtRaJLWedWDU9kT+G7bEEg5F5vAwwGKVbgqgoA9BcuzxrkBI6Sh8XW80ouuXH+D53I21BK29aHsQfWjNp8qLCW/6dBsnoXqmCYXjda6xb3T5qHYnlyUHol5ZCkXw2iekhJdMxFHbI3Tt3fpI/cblKtGkLBlK9u86ENXX5YQ3ccGrCtvFMMmY7euu/jIuhJjeKmVr385z1nrZdhALdEkdku3eOUdEYqFIiAov8WDpfxuxtKs89coUN5PiEiRHy2L9yImcMxae+8pqh5j0fY9x+jgNWq6z6e9MUyXoR2yxENg== 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=YBJEa+VSM5FoMWndM2MPL8alyUCPzdErHELlZP8FuFk=; b=eP3PgGHawxvTvXYkns37PAUk4i2jb6Mbshz8Nykl2MnztAqGGt53VWCNarCjMUtGQufXP9dNP8rJlfzdnmvq0ghubpjxjVekhjhRborgLBkv9KRss8czzpnaf+thoRNSeIoaLeavWz5hEk8CItrbiCimVc+u4H+MDPvq21Dwf7IYMxdQDLwwrLVbKtszcjPBcDOu+7vpyv3IJAhkDCXtAnAPsDHbZlI2Fp+/1+B04IPALop4zD7caVBS9Z2ZJ0TB5D9XknoXV7vHHPDtHEcdU6GLUQeRHltQDwb8iQGwQhRqi/EhGAQwx4AR7+Q6gfvQh/B4yaNp6SWmMsCmLq4Lqw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 217.66.60.4) smtp.rcpttodomain=arm.com smtp.mailfrom=opensynergy.com; dmarc=pass (p=reject sp=reject pct=100) action=none header.from=opensynergy.com; dkim=none (message not signed); arc=none (0) X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 217.66.60.4) smtp.mailfrom=opensynergy.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=opensynergy.com; Received-SPF: Pass (protection.outlook.com: domain of opensynergy.com designates 217.66.60.4 as permitted sender) receiver=protection.outlook.com; client-ip=217.66.60.4; helo=SR-MAIL-03.open-synergy.com; pr=C From: Peter Hilber To: linux-kernel@vger.kernel.org, virtualization@lists.linux.dev, virtio-dev@lists.oasis-open.org, linux-arm-kernel@lists.infradead.org Cc: Peter Hilber , "Michael S. Tsirkin" , Jason Wang , Xuan Zhuo , Marc Zyngier , Mark Rutland , Daniel Lezcano , Thomas Gleixner Subject: [RFC PATCH v3 6/7] virtio_rtc: Add Arm Generic Timer cross-timestamping Date: Mon, 18 Dec 2023 08:38:44 +0100 Message-Id: <20231218073849.35294-7-peter.hilber@opensynergy.com> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20231218073849.35294-1-peter.hilber@opensynergy.com> References: <20231218073849.35294-1-peter.hilber@opensynergy.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: VI1EUR05FT004:EE_|BEZP281MB2456:EE_ X-MS-Office365-Filtering-Correlation-Id: b749595c-4cbf-4540-6660-08dbff9ca634 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: RusVH3la176wxDg+L7Xq0fuHHTOvkxf+VNdAefakPvc+G60YmWlz7ShLVc1VaGEDPk9mGnpBQg/prQcrLDZd1nscDLOyNzo1qAdgUIEPGfqK/yEu9Ajp8X8hl/IJS80niwXxtIx9BbcIt5YeinMD4PrZ9lNbP0a/9blcxA7P1S2k0460V0TsV/rKQScQCwKpCKz0s9a45zGcFXIYc+GVsnaTY7ayefkwhnfzpWxL3xQQRNAXOuZ/+ZuBktSEh8nJRp0agFBRTeRrQEXApk1AvnyAiHs/minIwyiYJr2zWSexvj2eHTjyss7MqE/kPmOlqOFkD6JGAEJHxvXi0zlAgR2RnN7MlVbcHI8eumgdOIYGQXTgv7tYSl/zjflyG0uremUrcJWieDX8t6lsNcdr66QcCiVy7vKCNuo4M/yGwuyFVfuq+MHryBZ9rbSrsqcBr+mmFi31OEy9B9nnqFVwRL57GY+iV6Bp2cz/nCqeHzuMq7JGkKdz7I60ysFs+Uir3LUSTVQWMA3d1pvZ2SQ4hIYSmecnOSRpckf/Xo61KKvPzGbxhY/7c/LnA2B2molIsFn4Qn8YKbfLwfM0Hh1/R+87wwZ3kK/zyR1X9FfPF6Bq234NLoRSkWVLxPO6u3ueqZgiPo5UsSNj7D0mGdILRRd8a3RLmEPCrsp12bKShkV4FakUUpBKxE+CdqdBGv1XIuwvnsEdQTFrrw8BlwtunPv3/VU9ljCxcaAclbV3dXe15Ea2Fc/PY2Zp8Yy1iMvPRoPkWt/bF886Ex74iY93BwBX32yT0yvoa6gZVOf3u2A+uheG5Md/QtpwrUdzM2zV X-Forefront-Antispam-Report: CIP:217.66.60.4;CTRY:DE;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:SR-MAIL-03.open-synergy.com;PTR:InfoDomainNonexistent;CAT:NONE;SFS:(13230031)(39840400004)(136003)(376002)(346002)(396003)(230922051799003)(186009)(64100799003)(82310400011)(451199024)(1800799012)(36840700001)(46966006)(40480700001)(70586007)(86362001)(81166007)(36756003)(8936002)(36860700001)(47076005)(83380400001)(336012)(26005)(2616005)(1076003)(478600001)(2906002)(42186006)(54906003)(70206006)(4326008)(316002)(8676002)(5660300002)(44832011)(7416002)(41300700001)(41533002)(36900700001);DIR:OUT;SFP:1102; X-OriginatorOrg: opensynergy.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 18 Dec 2023 07:40:47.0708 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: b749595c-4cbf-4540-6660-08dbff9ca634 X-MS-Exchange-CrossTenant-Id: 800fae25-9b1b-4edc-993d-c939c4e84a64 X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=800fae25-9b1b-4edc-993d-c939c4e84a64;Ip=[217.66.60.4];Helo=[SR-MAIL-03.open-synergy.com] X-MS-Exchange-CrossTenant-AuthSource: VI1EUR05FT004.eop-eur05.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: BEZP281MB2456 X-TM-AS-ERS: 104.47.11.168-0.0.0.0 X-TMASE-Version: StarCloud-1.3-9.1.1015-28064.005 X-TMASE-Result: 10--18.516800-4.000000 X-TMASE-MatchedRID: ZAkTtSyZ7B7c1YtpVABxhScOunEIf0eXRyG5SSR7mMFHwPpoS7xiTQ3u hqemVNab4tr/y+kNIhx+41laLbgwdzURLmZdK2fK9K6xgLnDQNjrlkvw0pZ13MhGESF2QtYSsgk fnaHAFPzm9Tc/GgfFJwFtWueZlMH0Hw0ziwm/5yd81fikUYgyLUMxQVRV15qN9zxz+98nLbrqqp KNT13hEpMgmvUQU/w2ftTV5S2xLn0yxlgWcGNdNffKbx7F+zg4FkXEytHxBjkweIyZbRlQ2yzec Bj190z12HlzhM3zNtns9WQVYycKfw3lGTiQlxzIv9rSd36EgUI+Mqg+CyrtwA== X-TMASE-XGENCLOUD: 5d705e4f-6d2a-4add-99e1-f085abd63cdc-0-0-200-0 X-TM-Deliver-Signature: 814341606C3CE357FAA4FD95D4083D3D X-TM-Addin-Auth: oQqVyGfEqq1tPlA0MO11HPq0hwnejF6i8E6IARDqyDafuHtMRehVBO4//ml go3/nrkqd4jsFcyczmBclIjpUY1+OsQpPGXNlH9WPVWIwU03DEFJBPKXQL2a7g1n8R7wolHQ9M7 dxcrNAbUSyM3pcsqP64QEbZQ/Rsf05X19gqNFaCBBe6xXIpQzIkBtt30VUDjPoGja47r7PB8Ji3 AhMhGyxWokLkMQ/oQEpzJQYFfCHP3dDuAWmNC1AW6krRYU0Cjn8SiCH31mR1F0LRGos9Rw3H6AF ToiBDYSODFPs9nk=.ijNlbM3fQ75twsMA63aue4qsotouRPH3Vq5/TRxJPcMTK/2O748XJiS+g5 +8tI58pi8B9lOrxLqKzmqB8yQpzlpjCCceLHNib11OfBfTKEjExpMpBYqsxadk887rSWZkyoltD BwVGSDExQPZec6Ixx9CY1kgKDklyEA7YTvG4i/KhxcVQb6B9Aj1GbMVMRKVqqMKa0sgHwtYyQMw q9VdmyNiplJHPy4tgl5rmJ+oUCQVqb76/A7/gjTXx99Gx91+QAJreVq6MSQmKJ4jepH3GEkHAa8 Qq1ClqkAerIIPA5c/D74f/s3aLhEIVfZ8jEaIMGc45YcJGywvPogZPHs+eg== X-TM-Addin-ProductCode: EMS DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=opensynergy.com; s=TM-DKIM-20210503141657; t=1702885248; bh=6hVVzTyrWz2NxW0Xbbqmz0lggsHQStQh+Y3VVthviWo=; l=2933; h=From:To:Date; b=t+DZhYPBVm/MoOVvER/iFnMKZrtBALEzj6jKR5gvbClh98KljLP36O/+v1RnujmY4 jEex3Pz2VTQU/dXTUguXLv6Tr1AsJb/8xN6RIdVliiPVDM/gZ/Y8rWTmFzWgeeQ0Uo VgHz3BTi7dBgmSO/T0ST0twn0ErJm0v3AhLbhHiNrCxLr/u1nSNpQHo4bbiKX9lMVq acCPr+VyXSUU05/jD8PYmGuNKOjCQcRIKmCQq/IoLJ53sBvOip18+9/LG0XXuNHSem 9vMlnVk/Ce6u/16jO/lXm7JRP5wj/+HzQW0QrZAUXIhN8hklvhwI3vPcvE0Rfy6bM/ 3mv2CKx4GGMOw== Content-Type: text/plain; charset="utf-8" Add PTP_SYS_OFFSET_PRECISE2 support on platforms using the Arm Generic Timer. Always report the CP15 virtual counter as the HW counter in use by arm_arch_timer, since the Linux kernel's usage of the Arm Generic Timer should always be compatible with this. Signed-off-by: Peter Hilber --- Notes: v2: =20 - Depend on prerequisite patch series "treewide: Use clocksource id for get_device_system_crosststamp()". =20 - Return clocksource id instead of calling dropped arm_arch_timer helpe= rs. =20 - Always report the CP15 virtual counter to be in use by arm_arch_timer, since distinction of Arm physical and virtual counter appears unneeded after discussion with Marc Zyngier. drivers/virtio/Kconfig | 13 +++++++++++++ drivers/virtio/Makefile | 1 + drivers/virtio/virtio_rtc_arm.c | 22 ++++++++++++++++++++++ 3 files changed, 36 insertions(+) create mode 100644 drivers/virtio/virtio_rtc_arm.c diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig index 8542b2f20201..d35c728778d2 100644 --- a/drivers/virtio/Kconfig +++ b/drivers/virtio/Kconfig @@ -205,6 +205,19 @@ config VIRTIO_RTC_PTP =20 If unsure, say Y. =20 +config VIRTIO_RTC_ARM + bool "Virtio RTC cross-timestamping using Arm Generic Timer" + default y + depends on VIRTIO_RTC_PTP && ARM_ARCH_TIMER + help + This enables Virtio RTC cross-timestamping using the Arm Generic Timer. + It only has an effect if the Virtio RTC device also supports this. The + cross-timestamp is available through the PTP clock driver precise + cross-timestamp ioctl (PTP_SYS_OFFSET_PRECISE2 or + PTP_SYS_OFFSET_PRECISE). + + If unsure, say Y. + endif # VIRTIO_RTC =20 endif # VIRTIO_MENU diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile index 4d48cbcae6bb..781dff9f8822 100644 --- a/drivers/virtio/Makefile +++ b/drivers/virtio/Makefile @@ -15,3 +15,4 @@ obj-$(CONFIG_VIRTIO_DMA_SHARED_BUFFER) +=3D virtio_dma_bu= f.o obj-$(CONFIG_VIRTIO_RTC) +=3D virtio_rtc.o virtio_rtc-y :=3D virtio_rtc_driver.o virtio_rtc-$(CONFIG_VIRTIO_RTC_PTP) +=3D virtio_rtc_ptp.o +virtio_rtc-$(CONFIG_VIRTIO_RTC_ARM) +=3D virtio_rtc_arm.o diff --git a/drivers/virtio/virtio_rtc_arm.c b/drivers/virtio/virtio_rtc_ar= m.c new file mode 100644 index 000000000000..5185b130b3f1 --- /dev/null +++ b/drivers/virtio/virtio_rtc_arm.c @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Provides cross-timestamp params for Arm. + * + * Copyright (C) 2022-2023 OpenSynergy GmbH + */ + +#include + +#include + +#include "virtio_rtc_internal.h" + +/* see header for doc */ + +int viortc_hw_xtstamp_params(u16 *hw_counter, enum clocksource_ids *cs_id) +{ + *hw_counter =3D VIRTIO_RTC_COUNTER_ARM_VIRT; + *cs_id =3D CSID_ARM_ARCH_COUNTER; + + return 0; +} --=20 2.40.1 From nobody Sat Dec 27 17:01:13 2025 Received: from repost01.tmes.trendmicro.eu (repost01.tmes.trendmicro.eu [18.185.115.110]) (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 4FF19E578 for ; Mon, 18 Dec 2023 07:40:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=opensynergy.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=opensynergy.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=opensynergy.com header.i=@opensynergy.com header.b="0I4AoBdA" Received: from 104.47.11.169_.trendmicro.com (unknown [172.21.165.80]) by repost01.tmes.trendmicro.eu (Postfix) with SMTP id 9B89410001333; Mon, 18 Dec 2023 07:40:51 +0000 (UTC) X-TM-MAIL-RECEIVED-TIME: 1702885251.036000 X-TM-MAIL-UUID: d7ec7c30-d5a0-478c-970d-ed207558c072 Received: from DEU01-FR2-obe.outbound.protection.outlook.com (unknown [104.47.11.169]) by repre01.tmes.trendmicro.eu (Trend Micro Email Security) with ESMTPS id 08E9710000407; Mon, 18 Dec 2023 07:40:51 +0000 (UTC) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=jpcpK80/qbWNIZdYRSpt+2uSDb0xzQ8LaSHVfXTpWpdHDYS/VVyqJdK29oFx9VNpJNXFk+DrM5BHssAheUZrMwoZW2SCCe6KfGKF2jP0Pnfx0d/DhwveYJskdo6wTFJ0utHOBndCh6KWSSIfioEIyqKziSVj7D11Mhrp7r9w5nvT1BQFoFHCAAB3M3dcl0t/ZRkrli4zu1wx2EepB+ss/0Z3/+IYEMszMMhZPba90NTcLHdDfUdzw16mpbpCeuUtwKNjNCPuKwtLkTTrlc/jvdU2W5A2tV48C7BiZ4Op4Dh61urXaksCaviUwRpZi+tF40WsyK90nagycsbZIGDDLw== 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=2prUkZRVNY0FTA+o+kDgRaNf+5zCWU9dRgxNuO+ktug=; b=knY+AvmSUTe29Nq+ttTTbZUbl0Y8VouukYVQuMuFVdHchPGUmVvC4uhyu4ttOY9DKx/9TTDBEYWMGuJidQU74DI6VC3F3x5w+OXTMhxlrjVcNo/zjKORx0jGQqoaGwcptucPKPElAP//5q7Ox+jVOy/yuL34x0TWt+dIlEx0CPduFcfPytn5H82cOXS/Rm2v3lt9BFIcD7TD/p7PlB6LK3aUWHrx/+viLjyZQNvakvVY00uLVWGtMci2Bdsbg0Rs5q/tk2tIwEOL/JQcFw/3JMt4Akh9TBAUnKgl1Veajal/CKQKqgI66cBpLXazdXpOwXnZko9FlOs+wUXnrath7g== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 217.66.60.4) smtp.rcpttodomain=bootlin.com smtp.mailfrom=opensynergy.com; dmarc=pass (p=reject sp=reject pct=100) action=none header.from=opensynergy.com; dkim=none (message not signed); arc=none (0) X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 217.66.60.4) smtp.mailfrom=opensynergy.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=opensynergy.com; Received-SPF: Pass (protection.outlook.com: domain of opensynergy.com designates 217.66.60.4 as permitted sender) receiver=protection.outlook.com; client-ip=217.66.60.4; helo=SR-MAIL-03.open-synergy.com; pr=C From: Peter Hilber To: linux-kernel@vger.kernel.org, virtualization@lists.linux.dev, virtio-dev@lists.oasis-open.org, linux-rtc@vger.kernel.org Cc: Peter Hilber , "Michael S. Tsirkin" , Jason Wang , Xuan Zhuo , Alessandro Zummo , Alexandre Belloni Subject: [RFC PATCH v3 7/7] virtio_rtc: Add RTC class driver Date: Mon, 18 Dec 2023 08:38:45 +0100 Message-Id: <20231218073849.35294-8-peter.hilber@opensynergy.com> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20231218073849.35294-1-peter.hilber@opensynergy.com> References: <20231218073849.35294-1-peter.hilber@opensynergy.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: AM6EUR05FT059:EE_|FRYP281MB2287:EE_ X-MS-Office365-Filtering-Correlation-Id: dcd0f863-b3d1-4816-267d-08dbff9ca73a X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: ApKFjTmyLhQISZsCDlGxMa9kfbV29IooHEULoQvOt7+K+ok1HEgot4+b/nKQ0BtYb08xo40g276UDdqCzk5jCjzOE9SLI2pNFBxGG2/ANtjbWyiI+jIBkQCr+R/fWnp/N082UF4FYUBsBd5RMc7UISE8NK0OhNX/4jLXGvixJDZdaQ3mS4DMcEh/VyY2VpW0BfSs1TkK3m8rVR8BETkoIylfmBuWTammltXfhfE9Y10UOAAX8MLd++guQMb4lM+nUKdeb0pa3L3MdKgv+0F/yXalJAh4o0i2S5EUwJKv4m6uEcx8ml4ciqJlOfD/q4NKuMhesY9i3AXH/9ZXzzK0QcL9vpcnznWWvMEkJ7ackTVhCuQCB76gvuJSDdhhOya9ZNASM4vURaVXSInb8sjC153+qOuUVa14CNMAqsMwE3ulKLpYPg+AbCj56HkI5gtOU1h8CMnEA9nQRLZjco1dPiuiIb/sRe6UGbc3wlOfLLu0nH9rjTfaZeMx85HMf0GZ4hE4OSAMK9V2BccCJZKDlafDpazCimPfHcp1gCmFRso4SXjO/NGjrK/O2i2z6gOwl/A+YEaCOdWeFHUFRgw6kmk0bft/l11ezDAH2fvcL/05B4TYgzFuuH/Fmj3ZtMKP/Fgrj3Ut79yqExDvL2P8V9O66SHN5V+o/XPxd8XH/Fy12h12eeu36U0hwK1TKSujXO8O6r0cpQ6IBcEE5ABWhOxiNF2R5h1OOc62N/mskAWDJp6Fz8uFNqOnC2qhWU5nUR3xmUmPPFl9V0Pr8QElcdCX4aLjhG771Ug7Jb1C0qqDgQct8SHzoRW7swtJMEG4S0OlyG8RPoUJtv+WEs9oYA== X-Forefront-Antispam-Report: CIP:217.66.60.4;CTRY:DE;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:SR-MAIL-03.open-synergy.com;PTR:InfoDomainNonexistent;CAT:NONE;SFS:(13230031)(136003)(396003)(346002)(39840400004)(376002)(230922051799003)(230273577357003)(230173577357003)(186009)(64100799003)(82310400011)(451199024)(1800799012)(36840700001)(46966006)(40480700001)(70586007)(86362001)(81166007)(36756003)(36860700001)(47076005)(83380400001)(5660300002)(336012)(26005)(2616005)(1076003)(2906002)(30864003)(54906003)(42186006)(70206006)(8936002)(8676002)(4326008)(478600001)(316002)(44832011)(41300700001)(36900700001);DIR:OUT;SFP:1102; X-OriginatorOrg: opensynergy.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 18 Dec 2023 07:40:48.7862 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: dcd0f863-b3d1-4816-267d-08dbff9ca73a X-MS-Exchange-CrossTenant-Id: 800fae25-9b1b-4edc-993d-c939c4e84a64 X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=800fae25-9b1b-4edc-993d-c939c4e84a64;Ip=[217.66.60.4];Helo=[SR-MAIL-03.open-synergy.com] X-MS-Exchange-CrossTenant-AuthSource: AM6EUR05FT059.eop-eur05.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: FRYP281MB2287 X-TM-AS-ERS: 104.47.11.169-0.0.0.0 X-TMASE-Version: StarCloud-1.3-9.1.1015-28064.005 X-TMASE-Result: 10--20.975100-4.000000 X-TMASE-MatchedRID: HE8hON2ynzcZcVp47R3UL4i/ka5VrHsK59KGlOljPvudWHshdQbtCmj7 YB3H2ACVroemFU6CMMt2c8QLYDsid7HIqhLyDZStx35zxu/gQ2a6wG+1uTW14JdigZi17dHqiiD 5/mqQEv3XmD2V2hHPPhm86mU2uJFJvhggj6xTCeGheJ4X7s7SmoM+VZimfMfO4QpvGpvkj+eLz4 gav4lvdTKT8fDhc32NGbzqZTa4kUmTaxv5Pos+9bF+GhWADCGDB/zLDQkZ8pX3Yy7hhcHOZUkDm TLjTIiV9XuNqVIcQim2/m2VjREHcXV2KXA5dledk5TUws0flAjmA0wyh8gcn0hGs13Bi4vq2R0Y BCalbtLOrvLZg63S7caHD1snQ4DU5acuDxctLyzJtoyGVE0N8J/3FGZTHRdAzlzdPgwPz4TPNHj 34vvM/ZFTEeUAtxHGvmV+TYH45pwnFbk2KPuAbAm9LIMJ3oyCz2luKw/BlozQ20YfCq2u8jmy/Q TJSx1wsjjTgfiEfufvTl2mStwk1xPSDOhTpONb5EX3mCzYKG4n/i0u8thcpKiqsiuuQaXiu5O+W bkQuS1BcU6CpTnhbMSnIV45MVcNITqikU7uj0tIHzmxlHSp2PiqvKqCLVt1ojKyNVmXOrv17wdl 9yt6Y3fAXoF8xEcLtISJoH+KyQ0v49UPRUOtXcVNAYApHGPk2j7jyCKpnCcSCDdzAMeX/RLdYzv 1bejiZrfFxrTdHoz+61oPYZ99anht3q2IwW5dftwZ3X11IV0= X-TMASE-XGENCLOUD: eee4f4ab-e6a9-4f0b-93f5-89333376bf31-0-0-200-0 X-TM-Deliver-Signature: 963450F06DA24750A172672A8241A86A X-TM-Addin-Auth: AhrXST7ML2QfYEoiYNg+7olDP5RMIrQ304udOvkQM0EEIbVHv2GJHiHAjml 16qClXjcdMRyDVkIktj6+ir9xt5034wSpWSY+8208G1HP88Cphl4PodXpx0MD2YDWlhobJkoKiD EdxvwEkwjPAfxxvby9x9Ybc1UhmKf7emDnjBbUCrvNVDwhSq6wOT4vkkk0UUWoKFmOmZ92ZVXsi Bt+F+vSxLU2fTsv6M3Aups6oG1J1hvhbOIYGSlXz5IJlBtXdbQrhtBtwcEQxOUtFVEReO9+o6OH N91D6HkrLEDAY64=.hrM+jxJgRDcxCRHlTjhzwdEfH21SaupkfjOBKXgMoYLa33O6c+OXIQRQlD yoxbpWYecLbPwUsb/cYCXEZzlT+IusajD7UX+sQGXzjrrxLX9xsmQqMQZNuAvUAoRu6IpYjWQt2 0aq42h/WcXJMs2BR9U5NWoul59N56CtuZoi9glbQ2NH/AitI/AnaBHz7h4grMwAVTNMtay+SV+3 HOHFqGbkPEQayg0w9BFTiplH5JTFLl49x5JX0syfcitIPJ5iLfyC27In9MtzRxYYylBetQJzDGe 5lflie0KcXEgLI6W5QU7onhiK7gmiVuZd6o5bfowkgb/DX+e+sOXxE6cYdg== X-TM-Addin-ProductCode: EMS DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=opensynergy.com; s=TM-DKIM-20210503141657; t=1702885251; bh=o/K5jOWoeGu336KD1xhaOpjJKfGQa031n6XzJYQZOK0=; l=34717; h=From:To:Date; b=0I4AoBdAlRj1NynfwuFonhTm9CgGgiqffaGrXCaDNxRtDOYkUtYYsrrrvGCnWy6oc WmcQn0fdFu1zHHYboDpnuoIY4lQtMcD1GP4f3vJxfgTO1L9f/ShOpBhys3t7PFhZbs YRt67Ozzt0t4J3aRblSHFqcjJXO2nODsm5RbtkljoDb18RhZdncvZFw0Sve6/2IJpq heQiSi/o3Iq0bOrU0BPm1Hz+hPiCSwfCAq96o2Ef/PNqrid3FX32mQB59Sbw8I9mB3 AkzQmhpQ9NAseHIBSv0mQwJYaTZGGoQ+G0/X3kMHgN3/nam5jFDX5Luaos+0XugquI mOHbS40QJ6h9g== Content-Type: text/plain; charset="utf-8" Expose the virtio-rtc UTC clock as an RTC clock to userspace, if it is present. Support RTC alarm if the virtio-rtc alarm feature is present. The virtio-rtc device signals an alarm by marking an alarmq buffer as used. Peculiarities ------------- A virtio-rtc clock is a bit special for an RTC clock in that - the clock may step (also backwards) autonomously at any time and - the device, and its notification mechanism, will be reset during boot or resume from sleep. The virtio-rtc device avoids that the driver might miss an alarm. The device signals an alarm whenever the clock has reached or passed the alarm time, and also when the device is reset (on boot or resume from sleep), if the alarm time is in the past. Open Issue ---------- The CLOCK_BOOTTIME_ALARM will use the RTC clock to wake up from sleep, and implicitly assumes that no RTC clock steps will occur during sleep. The RTC class driver does not know whether the current alarm is a real-time alarm or a boot-time alarm. Perhaps this might be handled by the driver also setting a virtio-rtc monotonic alarm (which uses a clock similar to CLOCK_BOOTTIME_ALARM). The virtio-rtc monotonic alarm would just be used to wake up in case it was a CLOCK_BOOTTIME_ALARM alarm. Otherwise, the behavior should not differ from other RTC class drivers. Signed-off-by: Peter Hilber --- Notes: Added in v3. drivers/virtio/Kconfig | 21 +- drivers/virtio/Makefile | 1 + drivers/virtio/virtio_rtc_class.c | 269 +++++++++++++++ drivers/virtio/virtio_rtc_driver.c | 477 ++++++++++++++++++++++++++- drivers/virtio/virtio_rtc_internal.h | 53 +++ include/uapi/linux/virtio_rtc.h | 88 ++++- 6 files changed, 902 insertions(+), 7 deletions(-) create mode 100644 drivers/virtio/virtio_rtc_class.c diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig index d35c728778d2..e97bb2e9eca1 100644 --- a/drivers/virtio/Kconfig +++ b/drivers/virtio/Kconfig @@ -180,7 +180,8 @@ config VIRTIO_RTC help This driver provides current time from a Virtio RTC device. The driver provides the time through one or more clocks. The Virtio RTC PTP - clocks must be enabled to expose the clocks to userspace. + clocks and/or the Real Time Clock driver for Virtio RTC must be + enabled to expose the clocks to userspace. =20 To compile this code as a module, choose M here: the module will be called virtio_rtc. @@ -189,8 +190,8 @@ config VIRTIO_RTC =20 if VIRTIO_RTC =20 -comment "WARNING: Consider enabling VIRTIO_RTC_PTP." - depends on !VIRTIO_RTC_PTP +comment "WARNING: Consider enabling VIRTIO_RTC_PTP and/or VIRTIO_RTC_CLASS= ." + depends on !VIRTIO_RTC_PTP && !VIRTIO_RTC_CLASS =20 comment "Enable PTP_1588_CLOCK in order to enable VIRTIO_RTC_PTP." depends on PTP_1588_CLOCK=3Dn @@ -218,6 +219,20 @@ config VIRTIO_RTC_ARM =20 If unsure, say Y. =20 +comment "Enable RTC_CLASS in order to enable VIRTIO_RTC_CLASS." + depends on RTC_CLASS=3Dn + +config VIRTIO_RTC_CLASS + bool "Real Time Clock driver for Virtio RTC" + default y + depends on RTC_CLASS + help + This exposes the Virtio RTC UTC clock as a Linux Real Time Clock. It + only has an effect if the Virtio RTC device has a UTC clock. The Real + Time Clock is read-only, and may support setting an alarm. + + If unsure, say Y. + endif # VIRTIO_RTC =20 endif # VIRTIO_MENU diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile index 781dff9f8822..6c26bad777db 100644 --- a/drivers/virtio/Makefile +++ b/drivers/virtio/Makefile @@ -16,3 +16,4 @@ obj-$(CONFIG_VIRTIO_RTC) +=3D virtio_rtc.o virtio_rtc-y :=3D virtio_rtc_driver.o virtio_rtc-$(CONFIG_VIRTIO_RTC_PTP) +=3D virtio_rtc_ptp.o virtio_rtc-$(CONFIG_VIRTIO_RTC_ARM) +=3D virtio_rtc_arm.o +virtio_rtc-$(CONFIG_VIRTIO_RTC_CLASS) +=3D virtio_rtc_class.o diff --git a/drivers/virtio/virtio_rtc_class.c b/drivers/virtio/virtio_rtc_= class.c new file mode 100644 index 000000000000..fcb694f0f9a0 --- /dev/null +++ b/drivers/virtio/virtio_rtc_class.c @@ -0,0 +1,269 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * virtio_rtc RTC class driver + * + * Copyright (C) 2023 OpenSynergy GmbH + */ + +#include +#include +#include + +#include + +#include "virtio_rtc_internal.h" + +/** + * struct viortc_class - RTC class wrapper + * @viortc: virtio_rtc device data + * @rtc: RTC device + * @vio_clk_id: virtio_rtc clock id + * @stopped: Whether RTC ops are disallowed. Access protected by rtc_lock(= ). + */ +struct viortc_class { + struct viortc_dev *viortc; + struct rtc_device *rtc; + u16 vio_clk_id; + bool stopped; +}; + +/** + * viortc_class_get_locked() - get RTC class wrapper, if ops allowed + * @dev: virtio device + * + * Gets the RTC class wrapper from the virtio device, if it is available a= nd + * ops are allowed. + * + * Context: Caller must hold rtc_lock(). + * Return: RTC class wrapper if available and ops allowed, ERR_PTR otherwi= se. + */ +static struct viortc_class *viortc_class_get_locked(struct device *dev) +{ + struct viortc_class *viortc_class; + + viortc_class =3D viortc_class_from_dev(dev); + if (IS_ERR(viortc_class)) + return viortc_class; + + if (viortc_class->stopped) + return ERR_PTR(-EBUSY); + + return viortc_class; +} + +/** + * viortc_class_read_time() - RTC class op read_time + * @dev: virtio device + * @tm: read time + * + * Context: Process context. + * Return: Zero on success, negative error code otherwise. + */ +static int viortc_class_read_time(struct device *dev, struct rtc_time *tm) +{ + struct viortc_class *viortc_class; + time64_t sec; + int ret; + u64 ns; + + viortc_class =3D viortc_class_get_locked(dev); + if (IS_ERR(viortc_class)) + return PTR_ERR(viortc_class); + + ret =3D viortc_read(viortc_class->viortc, viortc_class->vio_clk_id, &ns); + if (ret) + return ret; + + sec =3D ns / NSEC_PER_SEC; + + rtc_time64_to_tm(sec, tm); + + return 0; +} + +/** + * viortc_class_read_alarm() - RTC class op read_alarm + * @dev: virtio device + * @alrm: alarm read out + * + * Context: Process context. + * Return: Zero on success, negative error code otherwise. + */ +static int viortc_class_read_alarm(struct device *dev, struct rtc_wkalrm *= alrm) +{ + struct viortc_class *viortc_class; + time64_t alarm_time_sec; + u64 alarm_time_ns; + bool enabled; + int ret; + + viortc_class =3D viortc_class_get_locked(dev); + if (IS_ERR(viortc_class)) + return PTR_ERR(viortc_class); + + ret =3D viortc_read_alarm(viortc_class->viortc, viortc_class->vio_clk_id, + &alarm_time_ns, &enabled); + if (ret) + return ret; + + alarm_time_sec =3D alarm_time_ns / NSEC_PER_SEC; + rtc_time64_to_tm(alarm_time_sec, &alrm->time); + + alrm->enabled =3D enabled; + + return 0; +} + +/** + * viortc_class_set_alarm() - RTC class op set_alarm + * @dev: virtio device + * @alrm: alarm to set + * + * Context: Process context. + * Return: Zero on success, negative error code otherwise. + */ +static int viortc_class_set_alarm(struct device *dev, struct rtc_wkalrm *a= lrm) +{ + struct viortc_class *viortc_class; + time64_t alarm_time_sec; + u64 alarm_time_ns; + + viortc_class =3D viortc_class_get_locked(dev); + if (IS_ERR(viortc_class)) + return PTR_ERR(viortc_class); + + alarm_time_sec =3D rtc_tm_to_time64(&alrm->time); + + if (alarm_time_sec < 0) + return -EINVAL; + + if (check_mul_overflow((u64)alarm_time_sec, (u64)NSEC_PER_SEC, + &alarm_time_ns)) + return -EINVAL; + + return viortc_set_alarm(viortc_class->viortc, viortc_class->vio_clk_id, + alarm_time_ns, alrm->enabled); +} + +/** + * viortc_class_alarm_irq_enable() - RTC class op alarm_irq_enable + * @dev: virtio device + * @enabled: enable or disable alarm IRQ + * + * Context: Process context. + * Return: Zero on success, negative error code otherwise. + */ +static int viortc_class_alarm_irq_enable(struct device *dev, + unsigned int enabled) +{ + struct viortc_class *viortc_class; + + viortc_class =3D viortc_class_get_locked(dev); + if (IS_ERR(viortc_class)) + return PTR_ERR(viortc_class); + + return viortc_set_alarm_enabled(viortc_class->viortc, + viortc_class->vio_clk_id, enabled); +} + +static const struct rtc_class_ops viortc_class_with_alarm_ops =3D { + .read_time =3D viortc_class_read_time, + .read_alarm =3D viortc_class_read_alarm, + .set_alarm =3D viortc_class_set_alarm, + .alarm_irq_enable =3D viortc_class_alarm_irq_enable, +}; + +static const struct rtc_class_ops viortc_class_no_alarm_ops =3D { + .read_time =3D viortc_class_read_time, +}; + +/** + * viortc_class_alarm() - propagate alarm notification as alarm interrupt + * @viortc_class: RTC class wrapper + * @vio_clk_id: virtio_rtc clock id + * + * Context: Any context. + */ +void viortc_class_alarm(struct viortc_class *viortc_class, u16 vio_clk_id) +{ + if (WARN_ONCE( + !viortc_class, + "virtio_rtc: unexpected alarm, no RTC class device available\n")) + return; + + if (vio_clk_id !=3D viortc_class->vio_clk_id) { + dev_err_ratelimited(&viortc_class->rtc->dev, + "%s: unexpected clock id %d !=3D %d\n", + __func__, vio_clk_id, + viortc_class->vio_clk_id); + return; + } + + rtc_update_irq(viortc_class->rtc, 1, RTC_AF | RTC_IRQF); +} + +/** + * viortc_class_stop() - disallow RTC class ops + * @viortc_class: RTC class wrapper + * + * Context: Process context. Caller must NOT hold rtc_lock(). + */ +void viortc_class_stop(struct viortc_class *viortc_class) +{ + rtc_lock(viortc_class->rtc); + + viortc_class->stopped =3D true; + + rtc_unlock(viortc_class->rtc); +} + +/** + * viortc_class_register() - register RTC class device + * @viortc_class: RTC class wrapper + * + * Context: Process context. + * Return: Zero on success, negative error code otherwise. + */ +int viortc_class_register(struct viortc_class *viortc_class) +{ + return devm_rtc_register_device(viortc_class->rtc); +} + +/** + * viortc_class_init() - init RTC class wrapper and device + * @viortc: device data + * @vio_clk_id: virtio_rtc clock id + * @have_alarm: expose alarm ops + * @parent_dev: virtio device + * + * Context: Process context. + * Return: RTC class wrapper on success, ERR_PTR otherwise. + */ +struct viortc_class *viortc_class_init(struct viortc_dev *viortc, + u16 vio_clk_id, bool have_alarm, + struct device *parent_dev) +{ + struct viortc_class *viortc_class; + struct rtc_device *rtc; + + viortc_class =3D + devm_kzalloc(parent_dev, sizeof(*viortc_class), GFP_KERNEL); + if (!viortc_class) + return ERR_PTR(-ENOMEM); + + viortc_class->viortc =3D viortc; + + rtc =3D devm_rtc_allocate_device(parent_dev); + if (IS_ERR(rtc)) + return ERR_PTR(PTR_ERR(rtc)); + + viortc_class->rtc =3D rtc; + + clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->features); + + rtc->ops =3D have_alarm ? &viortc_class_with_alarm_ops : + &viortc_class_no_alarm_ops; + rtc->range_max =3D U64_MAX / NSEC_PER_SEC; + + return viortc_class; +} diff --git a/drivers/virtio/virtio_rtc_driver.c b/drivers/virtio/virtio_rtc= _driver.c index c331b7383285..a4b5c3634de9 100644 --- a/drivers/virtio/virtio_rtc_driver.c +++ b/drivers/virtio/virtio_rtc_driver.c @@ -9,15 +9,19 @@ #include #include #include +#include #include =20 #include =20 #include "virtio_rtc_internal.h" =20 +#define VIORTC_ALARMQ_BUF_CAP sizeof(union virtio_rtc_notif_alarmq) + /* virtqueue order */ enum { VIORTC_REQUESTQ, + VIORTC_ALARMQ, VIORTC_MAX_NR_QUEUES, }; =20 @@ -34,17 +38,23 @@ struct viortc_vq { /** * struct viortc_dev - virtio_rtc device data * @vdev: virtio device + * @viortc_class: RTC class wrapper for UTC clock, NULL if not available * @vqs: virtqueues * @clocks_to_unregister: Clock references, which are only used during dev= ice * removal. * For other uses, there would be a race between device * creation and setting the pointers here. + * @alarmq_bufs: alarmq buffers list + * @num_alarmq_bufs: # of alarmq buffers * @num_clocks: # of virtio_rtc clocks */ struct viortc_dev { struct virtio_device *vdev; + struct viortc_class *viortc_class; struct viortc_vq vqs[VIORTC_MAX_NR_QUEUES]; struct viortc_ptp_clock **clocks_to_unregister; + void **alarmq_bufs; + unsigned int num_alarmq_bufs; u16 num_clocks; }; =20 @@ -75,6 +85,60 @@ struct viortc_msg { unsigned int resp_actual_size; }; =20 +/** + * viortc_class_from_dev() - Get RTC class object from virtio device. + * @dev: virtio device + * + * Context: Any context. + * Return: RTC class object if available, ERR_PTR otherwise. + */ +struct viortc_class *viortc_class_from_dev(struct device *dev) +{ + struct virtio_device *vdev; + struct viortc_dev *viortc; + + vdev =3D container_of(dev, typeof(*vdev), dev); + viortc =3D vdev->priv; + + return viortc->viortc_class ?: ERR_PTR(-ENODEV); +} + +/** + * viortc_alarms_supported() - Whether device and driver support alarms. + * @vdev: virtio device + * + * NB: Device and driver may not support alarms for the same clocks. + * + * Context: Any context. + * Return: True if both device and driver can support alarms. + */ +static bool viortc_alarms_supported(struct virtio_device *vdev) +{ + return IS_ENABLED(CONFIG_VIRTIO_RTC_CLASS) && + virtio_has_feature(vdev, VIRTIO_RTC_F_ALARM); +} + +/** + * viortc_feed_vq() - Make a device write-only buffer available. + * @viortc: device data + * @vq: notification virtqueue + * @buf: buffer + * @buf_len: buffer capacity in bytes + * @data: token, identifying buffer + * + * Context: Caller must prevent concurrent access to vq. + * Return: Zero on success, negative error code otherwise. + */ +static int viortc_feed_vq(struct viortc_dev *viortc, struct virtqueue *vq, + void *buf, unsigned int buf_len, void *data) +{ + struct scatterlist sg; + + sg_init_one(&sg, buf, buf_len); + + return virtqueue_add_inbuf(vq, &sg, 1, data, GFP_ATOMIC); +} + /** * viortc_msg_init() - Allocate and initialize requestq message. * @viortc: device data @@ -239,6 +303,81 @@ static void viortc_cb_requestq(struct virtqueue *vq) viortc_do_cb(vq, viortc_requestq_hdlr); } =20 +/** + * viortc_alarmq_hdlr() - process an alarmq used buffer + * @token: token identifying the buffer + * @len: bytes written by device + * @vq: virtqueue + * @viortc_vq: device specific data for virtqueue + * @viortc: device data + * + * Processes a VIRTIO_RTC_NOTIF_ALARM notification by calling the RTC class + * driver. Makes the buffer available again. + * + * Context: virtqueue callback + */ +static void viortc_alarmq_hdlr(void *token, unsigned int len, + struct virtqueue *vq, + struct viortc_vq *viortc_vq, + struct viortc_dev *viortc) +{ + struct virtio_rtc_notif_alarm *notif =3D token; + struct virtio_rtc_notif_head *head =3D token; + unsigned long flags; + u16 clock_id; + bool notify; + + if (len < sizeof(*head)) { + dev_err_ratelimited( + &viortc->vdev->dev, + "%s: ignoring notification with short header\n", + __func__); + goto feed_vq; + } + + if (virtio_le_to_cpu(head->msg_type) !=3D VIRTIO_RTC_NOTIF_ALARM) { + dev_err_ratelimited(&viortc->vdev->dev, + "%s: unknown notification type\n", + __func__); + goto feed_vq; + } + + if (len < sizeof(*notif)) { + dev_err_ratelimited(&viortc->vdev->dev, + "%s: alarm notification too small\n", + __func__); + goto feed_vq; + } + + clock_id =3D virtio_le_to_cpu(notif->clock_id); + + viortc_class_alarm(viortc->viortc_class, clock_id); + +feed_vq: + spin_lock_irqsave(&viortc_vq->lock, flags); + + WARN_ON(viortc_feed_vq(viortc, vq, notif, VIORTC_ALARMQ_BUF_CAP, + token)); + + notify =3D virtqueue_kick_prepare(vq); + + spin_unlock_irqrestore(&viortc_vq->lock, flags); + + if (notify) + virtqueue_notify(vq); +} + +/** + * viortc_cb_alarmq() - callback for alarmq + * @vq: virtqueue + * + * Context: virtqueue callback + */ +static void viortc_cb_alarmq(struct virtqueue *vq) +{ + viortc_do_cb(vq, viortc_alarmq_hdlr); +} + /** * viortc_get_resp_errno() - converts virtio_rtc errnos to system errnos * @resp_head: message response header @@ -554,12 +693,13 @@ static int viortc_cfg(struct viortc_dev *viortc, u16 = *num_clocks) * @viortc: device data * @vio_clk_id: virtio_rtc clock id * @type: virtio_rtc clock type + * @flags: struct virtio_rtc_resp_clock_cap.flags * * Context: Process context. * Return: Zero on success, negative error code otherwise. */ static int viortc_clock_cap(struct viortc_dev *viortc, u16 vio_clk_id, - u16 *type) + u16 *type, u8 *flags) { int ret; VIORTC_DECLARE_MSG_HDL_ONSTACK(hdl, clock_cap, CLOCK_CAP); @@ -579,6 +719,7 @@ static int viortc_clock_cap(struct viortc_dev *viortc, = u16 vio_clk_id, } =20 VIORTC_MSG_READ(hdl, type, type); + VIORTC_MSG_READ(hdl, flags, flags); =20 out_release: viortc_msg_release(VIORTC_MSG(hdl)); @@ -627,10 +768,176 @@ int viortc_cross_cap(struct viortc_dev *viortc, u16 = vio_clk_id, u16 hw_counter, return ret; } =20 +/** + * viortc_read_alarm() - VIRTIO_RTC_REQ_READ_ALARM wrapper + * @viortc: device data + * @vio_clk_id: virtio_rtc clock id + * @alarm_time: alarm time in ns + * @enabled: whether alarm is enabled + * + * Context: Process context. + * Return: Zero on success, negative error code otherwise. + */ +int viortc_read_alarm(struct viortc_dev *viortc, u16 vio_clk_id, + u64 *alarm_time, bool *enabled) +{ + VIORTC_DECLARE_MSG_HDL_ONSTACK(hdl, read_alarm, READ_ALARM); + u8 flags; + int ret; + + ret =3D VIORTC_MSG_INIT(hdl, viortc); + if (ret) + return ret; + + VIORTC_MSG_WRITE(hdl, clock_id, &vio_clk_id); + + ret =3D viortc_msg_xfer(&viortc->vqs[VIORTC_REQUESTQ], VIORTC_MSG(hdl), + 0); + if (ret) { + dev_dbg(&viortc->vdev->dev, "%s: xfer returned %d\n", __func__, + ret); + goto out_release; + } + + VIORTC_MSG_READ(hdl, alarm_time, alarm_time); + VIORTC_MSG_READ(hdl, flags, &flags); + + *enabled =3D !!(flags & VIRTIO_RTC_FLAG_ALARM_ENABLED); + +out_release: + viortc_msg_release(VIORTC_MSG(hdl)); + + return ret; +} + +/** + * viortc_set_alarm() - VIRTIO_RTC_REQ_SET_ALARM wrapper + * @viortc: device data + * @vio_clk_id: virtio_rtc clock id + * @alarm_time: alarm time in ns + * @alarm_enable: enable or disable alarm + * + * Context: Process context. + * Return: Zero on success, negative error code otherwise. + */ +int viortc_set_alarm(struct viortc_dev *viortc, u16 vio_clk_id, u64 alarm_= time, + bool alarm_enable) +{ + VIORTC_DECLARE_MSG_HDL_ONSTACK(hdl, set_alarm, SET_ALARM); + u8 flags =3D 0; + int ret; + + ret =3D VIORTC_MSG_INIT(hdl, viortc); + if (ret) + return ret; + + if (alarm_enable) + flags |=3D VIRTIO_RTC_FLAG_ALARM_ENABLED; + + VIORTC_MSG_WRITE(hdl, clock_id, &vio_clk_id); + VIORTC_MSG_WRITE(hdl, alarm_time, &alarm_time); + VIORTC_MSG_WRITE(hdl, flags, &flags); + + ret =3D viortc_msg_xfer(&viortc->vqs[VIORTC_REQUESTQ], VIORTC_MSG(hdl), + 0); + if (ret) { + dev_dbg(&viortc->vdev->dev, "%s: xfer returned %d\n", __func__, + ret); + goto out_release; + } + +out_release: + viortc_msg_release(VIORTC_MSG(hdl)); + + return ret; +} + +/** + * viortc_set_alarm_enabled() - VIRTIO_RTC_REQ_SET_ALARM_ENABLED wrapper + * @viortc: device data + * @vio_clk_id: virtio_rtc clock id + * @alarm_enable: enable or disable alarm + * + * Context: Process context. + * Return: Zero on success, negative error code otherwise. + */ +int viortc_set_alarm_enabled(struct viortc_dev *viortc, u16 vio_clk_id, + bool alarm_enable) +{ + VIORTC_DECLARE_MSG_HDL_ONSTACK(hdl, set_alarm_enabled, + SET_ALARM_ENABLED); + u8 flags =3D 0; + int ret; + + ret =3D VIORTC_MSG_INIT(hdl, viortc); + if (ret) + return ret; + + if (alarm_enable) + flags |=3D VIRTIO_RTC_FLAG_ALARM_ENABLED; + + VIORTC_MSG_WRITE(hdl, clock_id, &vio_clk_id); + VIORTC_MSG_WRITE(hdl, flags, &flags); + + ret =3D viortc_msg_xfer(&viortc->vqs[VIORTC_REQUESTQ], VIORTC_MSG(hdl), + 0); + if (ret) { + dev_dbg(&viortc->vdev->dev, "%s: xfer returned %d\n", __func__, + ret); + goto out_release; + } + +out_release: + viortc_msg_release(VIORTC_MSG(hdl)); + + return ret; +} + /* * init, deinit */ =20 +/** + * viortc_init_clock_rtc_class() - init and register a RTC class device + * @viortc: device data + * @vio_clk_id: virtio_rtc clock id + * @flags: struct virtio_rtc_resp_clock_cap.flags + * + * The clock must be a UTC clock. + * + * Context: Process context. + * Return: Zero on success, negative error code otherwise. + */ +static int viortc_init_clock_rtc_class(struct viortc_dev *viortc, + u16 vio_clk_id, u8 flags) +{ + struct virtio_device *vdev =3D viortc->vdev; + struct viortc_class *viortc_class; + struct device *dev =3D &vdev->dev; + bool have_alarm; + + if (viortc->viortc_class) { + dev_warn_once( + dev, + "multiple UTC clocks are present, but creating only one RTC class devic= e\n"); + return 0; + } + + have_alarm =3D viortc_alarms_supported(vdev) && + !!(flags & VIRTIO_RTC_FLAG_ALARM_CAP); + + viortc_class =3D viortc_class_init(viortc, vio_clk_id, have_alarm, dev); + if (IS_ERR(viortc_class)) + return PTR_ERR(viortc_class); + + viortc->viortc_class =3D viortc_class; + + if (have_alarm) + device_init_wakeup(dev, true); + + return viortc_class_register(viortc_class); +} + /** * viortc_init_ptp_clock() - init and register PTP clock * @viortc: device data @@ -698,12 +1005,20 @@ static int viortc_init_ptp_clock(struct viortc_dev *= viortc, u16 vio_clk_id, static int viortc_init_clock(struct viortc_dev *viortc, u16 vio_clk_id) { u16 clock_type; + u8 flags; int ret; =20 - ret =3D viortc_clock_cap(viortc, vio_clk_id, &clock_type); + ret =3D viortc_clock_cap(viortc, vio_clk_id, &clock_type, &flags); if (ret) return ret; =20 + if (clock_type =3D=3D VIRTIO_RTC_CLOCK_UTC && + IS_ENABLED(CONFIG_VIRTIO_RTC_CLASS)) { + ret =3D viortc_init_clock_rtc_class(viortc, vio_clk_id, flags); + if (ret) + return ret; + } + if (IS_ENABLED(CONFIG_VIRTIO_RTC_PTP)) { ret =3D viortc_init_ptp_clock(viortc, vio_clk_id, clock_type); if (ret) @@ -714,7 +1029,7 @@ static int viortc_init_clock(struct viortc_dev *viortc= , u16 vio_clk_id) } =20 /** - * viortc_clocks_exit() - unregister PHCs + * viortc_clocks_exit() - unregister PHCs, stop RTC ops * @viortc: device data */ static void viortc_clocks_exit(struct viortc_dev *viortc) @@ -732,6 +1047,9 @@ static void viortc_clocks_exit(struct viortc_dev *vior= tc) =20 WARN_ON(viortc_ptp_unregister(vio_ptp, &viortc->vdev->dev)); } + + if (viortc->viortc_class) + viortc_class_stop(viortc->viortc_class); } =20 /** @@ -778,6 +1096,74 @@ static int viortc_clocks_init(struct viortc_dev *vior= tc) return ret; } =20 +/** + * viortc_alloc_vq_bufs() - allocate alarmq buffers + * @viortc: device data + * @num_elems: # of buffers + * @buf_cap: per-buffer device-writable capacity in bytes + * + * Context: Process context. + * Return: Zero on success, negative error code otherwise. + */ +static int viortc_alloc_vq_bufs(struct viortc_dev *viortc, + unsigned int num_elems, u32 buf_cap) +{ + struct device *dev =3D &viortc->vdev->dev; + void **buf_list; + unsigned int i; + void *buf; + + buf_list =3D devm_kcalloc(dev, num_elems, sizeof(*buf_list), GFP_KERNEL); + if (!buf_list) + return -ENOMEM; + + viortc->alarmq_bufs =3D buf_list; + viortc->num_alarmq_bufs =3D num_elems; + + for (i =3D 0; i < num_elems; i++) { + buf =3D devm_kzalloc(dev, buf_cap, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + buf_list[i] =3D buf; + } + + return 0; +} + +/** + * viortc_populate_vq() - populate alarmq with device-writable buffers + * @viortc: device data + * @vq: virtqueue + * @buf_cap: device-writable buffer size in bytes + * + * Populates the alarmq with pre-allocated buffers. + * + * The caller is responsible for kicking the device. + * + * Context: Process context. + * Return: Zero on success, negative error code otherwise. + */ +static int viortc_populate_vq(struct viortc_dev *viortc, struct virtqueue = *vq, + u32 buf_cap) +{ + unsigned int num_elems, i; + void *buf; + int ret; + + num_elems =3D viortc->num_alarmq_bufs; + + for (i =3D 0; i < num_elems; i++) { + buf =3D viortc->alarmq_bufs[i]; + + ret =3D viortc_feed_vq(viortc, vq, buf, buf_cap, buf); + if (ret) + return ret; + } + + return 0; +} + /** * viortc_init_vqs() - init virtqueues * @viortc: device data @@ -794,12 +1180,22 @@ static int viortc_init_vqs(struct viortc_dev *viortc) const char *names[VIORTC_MAX_NR_QUEUES]; vq_callback_t *callbacks[VIORTC_MAX_NR_QUEUES]; struct virtqueue *vqs[VIORTC_MAX_NR_QUEUES]; + unsigned int num_elems; + bool have_alarms; int nr_queues; =20 + have_alarms =3D viortc_alarms_supported(vdev); + nr_queues =3D VIORTC_REQUESTQ + 1; names[VIORTC_REQUESTQ] =3D "requestq"; callbacks[VIORTC_REQUESTQ] =3D viortc_cb_requestq; =20 + if (have_alarms) { + nr_queues =3D VIORTC_ALARMQ + 1; + names[VIORTC_ALARMQ] =3D "alarmq"; + callbacks[VIORTC_ALARMQ] =3D viortc_cb_alarmq; + } + ret =3D virtio_find_vqs(vdev, nr_queues, vqs, callbacks, names, NULL); if (ret) return ret; @@ -807,6 +1203,25 @@ static int viortc_init_vqs(struct viortc_dev *viortc) viortc->vqs[VIORTC_REQUESTQ].vq =3D vqs[VIORTC_REQUESTQ]; spin_lock_init(&viortc->vqs[VIORTC_REQUESTQ].lock); =20 + if (have_alarms) { + viortc->vqs[VIORTC_ALARMQ].vq =3D vqs[VIORTC_ALARMQ]; + spin_lock_init(&viortc->vqs[VIORTC_ALARMQ].lock); + + num_elems =3D virtqueue_get_vring_size(vqs[VIORTC_ALARMQ]); + if (num_elems =3D=3D 0) + return -ENOSPC; + + if (!viortc->alarmq_bufs) { + ret =3D viortc_alloc_vq_bufs(viortc, num_elems, + VIORTC_ALARMQ_BUF_CAP); + if (ret) + return ret; + } else { + viortc->num_alarmq_bufs =3D + min(num_elems, viortc->num_alarmq_bufs); + } + } + return 0; } =20 @@ -819,6 +1234,7 @@ static int viortc_init_vqs(struct viortc_dev *viortc) */ static int viortc_probe(struct virtio_device *vdev) { + struct virtqueue *alarm_vq; struct viortc_dev *viortc; int ret; =20 @@ -842,6 +1258,26 @@ static int viortc_probe(struct virtio_device *vdev) if (ret) goto err_reset_vdev; =20 + if (viortc_alarms_supported(vdev)) { + /* + * Now that the RTC device was registered, ready viortc to + * receive alarms. + */ + smp_wmb(); + + alarm_vq =3D viortc->vqs[VIORTC_ALARMQ].vq; + + ret =3D viortc_populate_vq(viortc, alarm_vq, + VIORTC_ALARMQ_BUF_CAP); + if (ret) + goto err_reset_vdev; + + if (!virtqueue_kick(alarm_vq)) { + ret =3D -EIO; + goto err_reset_vdev; + } + } + return 0; =20 err_reset_vdev: @@ -865,6 +1301,35 @@ static void viortc_remove(struct virtio_device *vdev) vdev->config->del_vqs(vdev); } =20 +#ifdef CONFIG_PM_SLEEP +static int viortc_freeze(struct virtio_device *dev) +{ + return 0; +} + +static int viortc_restore(struct virtio_device *dev) +{ + struct viortc_dev *viortc =3D dev->priv; + int ret; + + ret =3D viortc_init_vqs(viortc); + if (ret) + return ret; + + if (viortc_alarms_supported(dev)) + ret =3D viortc_populate_vq(viortc, viortc->vqs[VIORTC_ALARMQ].vq, + VIORTC_ALARMQ_BUF_CAP); + + return ret; +} +#endif + +static unsigned int features[] =3D { +#if IS_ENABLED(CONFIG_VIRTIO_RTC_CLASS) + VIRTIO_RTC_F_ALARM, +#endif +}; + static struct virtio_device_id id_table[] =3D { { VIRTIO_ID_CLOCK, VIRTIO_DEV_ANY_ID }, { 0 }, @@ -874,9 +1339,15 @@ MODULE_DEVICE_TABLE(virtio, id_table); static struct virtio_driver virtio_rtc_drv =3D { .driver.name =3D KBUILD_MODNAME, .driver.owner =3D THIS_MODULE, + .feature_table =3D features, + .feature_table_size =3D ARRAY_SIZE(features), .id_table =3D id_table, .probe =3D viortc_probe, .remove =3D viortc_remove, +#ifdef CONFIG_PM_SLEEP + .freeze =3D viortc_freeze, + .restore =3D viortc_restore, +#endif }; =20 module_virtio_driver(virtio_rtc_drv); diff --git a/drivers/virtio/virtio_rtc_internal.h b/drivers/virtio/virtio_r= tc_internal.h index 0dedced4aeae..ebd5dbf5bbc5 100644 --- a/drivers/virtio/virtio_rtc_internal.h +++ b/drivers/virtio/virtio_rtc_internal.h @@ -8,8 +8,11 @@ #ifndef _VIRTIO_RTC_INTERNAL_H_ #define _VIRTIO_RTC_INTERNAL_H_ =20 +#include +#include #include #include +#include =20 /* driver core IFs */ =20 @@ -20,6 +23,16 @@ int viortc_read_cross(struct viortc_dev *viortc, u16 vio= _clk_id, u16 hw_counter, u64 *reading, u64 *cycles); int viortc_cross_cap(struct viortc_dev *viortc, u16 vio_clk_id, u16 hw_cou= nter, bool *supported); +int viortc_read_alarm(struct viortc_dev *viortc, u16 vio_clk_id, + u64 *alarm_time, bool *enabled); +int viortc_set_alarm(struct viortc_dev *viortc, u16 vio_clk_id, u64 alarm_= time, + bool alarm_enable); +int viortc_set_alarm_enabled(struct viortc_dev *viortc, u16 vio_clk_id, + bool alarm_enable); + +struct viortc_class; + +struct viortc_class *viortc_class_from_dev(struct device *dev); =20 /* PTP IFs */ =20 @@ -66,4 +79,44 @@ static inline int viortc_ptp_unregister(struct viortc_pt= p_clock *vio_ptp, */ int viortc_hw_xtstamp_params(u16 *hw_counter, enum clocksource_ids *cs_id); =20 +/* RTC class IFs */ + +#if IS_ENABLED(CONFIG_VIRTIO_RTC_CLASS) + +void viortc_class_alarm(struct viortc_class *viortc_class, u16 vio_clk_id); + +void viortc_class_stop(struct viortc_class *viortc_class); + +int viortc_class_register(struct viortc_class *viortc_class); + +struct viortc_class *viortc_class_init(struct viortc_dev *viortc, + u16 vio_clk_id, bool have_alarm, + struct device *parent_dev); + +#else /* CONFIG_VIRTIO_RTC_CLASS */ + +static inline void viortc_class_alarm(struct viortc_class *viortc_class, + u16 vio_clk_id) +{ +} + +static inline void viortc_class_stop(struct viortc_class *viortc_class) +{ +} + +static inline int viortc_class_register(struct viortc_class *viortc_class) +{ + return -ENODEV; +} + +static inline struct viortc_class *viortc_class_init(struct viortc_dev *vi= ortc, + u16 vio_clk_id, + bool have_alarm, + struct device *parent_dev) +{ + return ERR_PTR(-ENODEV); +} + +#endif /* CONFIG_VIRTIO_RTC_CLASS */ + #endif /* _VIRTIO_RTC_INTERNAL_H_ */ diff --git a/include/uapi/linux/virtio_rtc.h b/include/uapi/linux/virtio_rt= c.h index f469276562d7..26be3574fabe 100644 --- a/include/uapi/linux/virtio_rtc.h +++ b/include/uapi/linux/virtio_rtc.h @@ -8,6 +8,9 @@ =20 #include =20 +/* alarm feature */ +#define VIRTIO_RTC_F_ALARM 0 + /* read request message types */ =20 #define VIRTIO_RTC_REQ_READ 0x0001 @@ -18,6 +21,13 @@ #define VIRTIO_RTC_REQ_CFG 0x1000 #define VIRTIO_RTC_REQ_CLOCK_CAP 0x1001 #define VIRTIO_RTC_REQ_CROSS_CAP 0x1002 +#define VIRTIO_RTC_REQ_READ_ALARM 0x1003 +#define VIRTIO_RTC_REQ_SET_ALARM 0x1004 +#define VIRTIO_RTC_REQ_SET_ALARM_ENABLED 0x1005 + +/* alarmq message types */ + +#define VIRTIO_RTC_NOTIF_ALARM 0x2000 =20 /* Message headers */ =20 @@ -38,6 +48,12 @@ struct virtio_rtc_resp_head { __u8 reserved[7]; }; =20 +/** common notification header */ +struct virtio_rtc_notif_head { + __le16 msg_type; + __u8 reserved[6]; +}; + /* read requests */ =20 /* VIRTIO_RTC_REQ_READ message */ @@ -104,7 +120,9 @@ struct virtio_rtc_resp_clock_cap { #define VIRTIO_RTC_CLOCK_TAI 1 #define VIRTIO_RTC_CLOCK_MONO 2 __le16 type; - __u8 reserved[6]; +#define VIRTIO_RTC_FLAG_ALARM_CAP (1 << 0) + __u8 flags; + __u8 reserved[5]; }; =20 /* VIRTIO_RTC_REQ_CROSS_CAP message */ @@ -123,6 +141,53 @@ struct virtio_rtc_resp_cross_cap { __u8 reserved[7]; }; =20 +/* VIRTIO_RTC_REQ_READ_ALARM message */ + +struct virtio_rtc_req_read_alarm { + struct virtio_rtc_req_head head; + __le16 clock_id; + __u8 reserved[6]; +}; + +struct virtio_rtc_resp_read_alarm { + struct virtio_rtc_resp_head head; + __le64 alarm_time; +#define VIRTIO_RTC_FLAG_ALARM_ENABLED (1 << 0) + __u8 flags; + __u8 reserved[7]; +}; + +/* VIRTIO_RTC_REQ_SET_ALARM message */ + +struct virtio_rtc_req_set_alarm { + struct virtio_rtc_req_head head; + __le64 alarm_time; + __le16 clock_id; + /* flag VIRTIO_RTC_ALARM_ENABLED */ + __u8 flags; + __u8 reserved[5]; +}; + +struct virtio_rtc_resp_set_alarm { + struct virtio_rtc_resp_head head; + /* no response params */ +}; + +/* VIRTIO_RTC_REQ_SET_ALARM_ENABLED message */ + +struct virtio_rtc_req_set_alarm_enabled { + struct virtio_rtc_req_head head; + __le16 clock_id; + /* flag VIRTIO_RTC_ALARM_ENABLED */ + __u8 flags; + __u8 reserved[5]; +}; + +struct virtio_rtc_resp_set_alarm_enabled { + struct virtio_rtc_resp_head head; + /* no response params */ +}; + /** Union of request types for requestq */ union virtio_rtc_req_requestq { struct virtio_rtc_req_read read; @@ -130,6 +195,9 @@ union virtio_rtc_req_requestq { struct virtio_rtc_req_cfg cfg; struct virtio_rtc_req_clock_cap clock_cap; struct virtio_rtc_req_cross_cap cross_cap; + struct virtio_rtc_req_read_alarm read_alarm; + struct virtio_rtc_req_set_alarm set_alarm; + struct virtio_rtc_req_set_alarm_enabled set_alarm_enabled; }; =20 /** Union of response types for requestq */ @@ -139,6 +207,24 @@ union virtio_rtc_resp_requestq { struct virtio_rtc_resp_cfg cfg; struct virtio_rtc_resp_clock_cap clock_cap; struct virtio_rtc_resp_cross_cap cross_cap; + struct virtio_rtc_resp_read_alarm read_alarm; + struct virtio_rtc_resp_set_alarm set_alarm; + struct virtio_rtc_resp_set_alarm_enabled set_alarm_enabled; +}; + +/* alarmq notifications */ + +/* VIRTIO_RTC_NOTIF_ALARM notification */ + +struct virtio_rtc_notif_alarm { + struct virtio_rtc_notif_head head; + __le16 clock_id; + __u8 reserved[6]; +}; + +/** Union of notification types for alarmq */ +union virtio_rtc_notif_alarmq { + struct virtio_rtc_notif_alarm alarm; }; =20 #endif /* _LINUX_VIRTIO_RTC_H */ --=20 2.40.1