From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 EBBF43D4110; Wed, 25 Feb 2026 16:26:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772036811; cv=none; b=bU1xEMPLAOdmIiFSN5+BwhefhlXuUll0oaJGRnJsNl6c8mN/CpSJEgokvYNR0CkYzaLmUDcyhuNztDeU6Izq9f2iLNNew6gMdHpc/9NHXiWQ67bmZnHVzrPXEFtAkduYaB12ywp8ZC5ypry+LYIxpnfdB5KHT10q+V/BUFo1oIY= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772036811; c=relaxed/simple; bh=YUN9M0AR4tx7LcUF/R+6u5VZbMi7IE1VKfYANVdBxkI=; h=Mime-Version:Content-Type:Date:Message-Id:Subject:Cc:To:From: References:In-Reply-To; b=fbS0x6L6SV3gv7uirZi/Drxx6MNbvSUGpgyqpOZQHwNGYp/cSynR38dP2nkxh2XHdydQwPbrddPuSCsh4aWz82kTEOUNzu34whVcgRthOz7RryidJgCiWqrcGVw/RAOZDYe60XXSen5YhdUl0ukzLjcxiKnETIOr+Y53ze7asbc= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=GGexLGMP; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="GGexLGMP" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 1CB2EC116D0; Wed, 25 Feb 2026 16:26:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1772036810; bh=YUN9M0AR4tx7LcUF/R+6u5VZbMi7IE1VKfYANVdBxkI=; h=Date:Subject:Cc:To:From:References:In-Reply-To:From; b=GGexLGMPjLpx0LmPFOJBELVinx2geWAs5rZ8WmuSl4lCq/BfvAHDQ/AQr3OSko5BL +auam0L7mAlBPzgKtNJnDZo4gAb1l5OhnhK8H0l+5D3fHNne9EmsyUbUL7S0kWVE30 clrXPdUlXaceDAfY80CHRwuku0iGO0foydZJVSonas1xbM6unQZPBxwFoyHSje+oxV oSXoW3JKB8KJYXPao82ei8zZAjGeyPNTndN4cGpTUvo44F0ckr5Hf11MdRuW190ZBX HxgO7i03bgVuF0IY9hsGuPetTadNQVC8FqFNewrq1+6olwWoACgzx942rFUMaSww9R Tde+TjXStwiUg== Precedence: bulk X-Mailing-List: linux-rtc@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=UTF-8 Date: Wed, 25 Feb 2026 17:26:46 +0100 Message-Id: Subject: Re: [RFC PATCH v3 1/5] rtc: add device selector for rtc_class_ops callbacks Cc: "Alexandre Belloni" , "Alvin Sun" , "Miguel Ojeda" , "Boqun Feng" , "Gary Guo" , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , "Benno Lossin" , "Andreas Hindborg" , "Alice Ryhl" , "Trevor Gross" , , , "Greg Kroah-Hartman" To: "Rafael J. Wysocki" From: "Danilo Krummrich" References: <20260221111619162a41a1@mail.local> <20260222000556ea1938c0@mail.local> <2026022415010804e28202@mail.local> <20260224172822de7f4569@mail.local> In-Reply-To: On Wed Feb 25, 2026 at 2:33 PM CET, Rafael J. Wysocki wrote: > On Tue, Feb 24, 2026 at 11:23=E2=80=AFPM Danilo Krummrich wrote: >> Here's also some sketched up code for what I wrote above: >> >> fn probe(pdev: &pci::Device, info: &Self::IdInfo) -> impl = PinInit { >> let dev =3D pdev.as_ref(); >> >> let rtc_data =3D impl_pin_init!(SampleRtcData { >> io: pdev.iomap_region_sized::(0, c"my_rtc/bar= 0")?, >> hw_variant: VendorVariant::StV1, >> irq <- irq::Registration::new(...), >> }); >> >> let rtc =3D rtc::Device::new(dev, rtc_data)?; >> >> rtc::Registration::register(rtc)?; >> >> Ok(Self { rtc }) >> } >> >> Note that if any of the RTC callbacks would ever need to call irq.synchr= onize(), >> irq.disable(), etc. the compiler would enforce correct ordering, as ther= e would >> not be any other possibility to put the irq::Registration other than int= o the >> rtc_data that goes into rtc::Device::new(). > > IIUC, the interrupt handler can only access the rtc_data because the > parent's driver_data may not exist yet when it runs. Or am I missing > something? In the code above the IRQ handler can also not access rtc_data, as struct SampleRtcData might not be fully initialized when it runs, i.e. let rtc_data =3D impl_pin_init!(SampleRtcData { io: pdev.iomap_region_sized::(0, c"my_rtc/bar0")?, hw_variant: VendorVariant::StV1, irq <- irq::Registration::new(..., rtc_data), }); would not compile in the first place. irq::Registration, for this purpose, has its own private data on the handle= r itself, see also [1]. In fact, the C code has the same concept with the dev= _id argument in request_threaded_irq() [2]. The difference is that the C compiler does not ensure that the IRQ handler actually owns the data behind the dev_id pointer. I.e. the driver has to so= mehow ensure that whatever is behind the dev_id pointer remains valid for the dur= ation the IRQ handler is registered. In the Rust implementation the compiler does ensure that what is behind the dev_id pointer remains valid for the duration of the lifetime of the irq::Registration. Having that said, I assume you wonder what we would pass into the irq::Registration instead, if it is not rtc_data. The answer is it depends; it depends on what's actually needed, what other entities interact with the IRQ (e.g. some scheduled work, etc.) and maybe e= ven preference to some extend. Here is one example: let irq_data =3D impl_pin_init!(SampleIrqData { io <- pdev.iomap_region_sized::(0, c"my_rtc/bar0")?, hw_variant: VendorVariant::StV1, }); let rtc_data =3D impl_pin_init!(SampleRtcData { irq <- irq::Registration::new(..., irq_data), ..., }); let rtc =3D rtc::Device::new(dev, rtc_data)?; This would compile as it ensures that irq_data (struct SampleIrqData) is fu= lly initialized before irq::Registration::new() is called. At a first glance this might look like we need an additional allocation, on= e for irq_data and one for rtc_data, but that is not the case. irq_data is an initializer that is passed to another initializer, i.e. rtc_data is still a= n initializer. The actual (single) allocation happens in rtc::Device::new(). In terms of accessing it through the the rtc::Device in an RTC device callb= ack, we would likely use accessor methods to make it a bit more convinient, i.e. fn read_time( rtc: &rtc::Device parent: &platform::Device, time: &mut rtc::Time, ) -> Result { let io =3D rtc.io().access(parent)?; match rtc.hw_variant() { VendorVariant::Arm | VendorVariant::StV1 =3D> { let my_time =3D io.read(...); my_time.write_into(time); }, VendorVariant::StV2 =3D> { ... }, } } As mentioned above there are a few other options to implement this, dependi= ng on what's required, etc. For instance, if the I/O bar is actually shared between multiple entities w= e might want to initialize it within an Arc [3] (reference count it) for shar= ed ownership. For the future we will also be able to support references within initialize= rs to other pinned fields, which make things a bit more convinient, so you could = do things like this: let irq_data =3D impl_pin_init!(SampleIrqData { io <- pdev.iomap_region_sized::(0, c"my_rtc/bar0")?, hw_variant: VendorVariant::StV1, }); let rtc_data =3D impl_pin_init!(SampleRtcData { irq <- irq::Registration::new(..., irq_data), io: &irq.io, ..., }); let rtc =3D rtc::Device::new(dev, rtc_data)?; Note the additional `io: &irq.io,` in the rtc_data initializer. This would = be legal as we know that `irq` is pinned within `rtc_data`, hence it is valid = to hold a reference to one of its pinned fields. I am not sure how far we are from having this supported, I assume Benno and= Gary can say more about this. I hope this helps, and thanks for asking those questions! [1] https://rust.docs.kernel.org/kernel/irq/struct.Registration.html [2] https://elixir.bootlin.com/linux/v6.19.3/source/kernel/irq/manage.c#L20= 90 [3] https://rust.docs.kernel.org/kernel/sync/struct.Arc.html