History

rust: io: make IoMem and ExclusiveIoMem lifetime-parameterized

Add a lifetime parameter to IoMem<'a, SIZE> and ExclusiveIoMem<'a, SIZE>, storing a &'a Device<Bound> reference to tie the mapping to the device's lifetime. This mirrors the pci::Bar<'a, SIZE> design and enables drivers to hold I/O memory mappings directly in their HRT private data, tied to the device lifetime. IoRequest::iomap_* methods now return the mapping directly instead of wrapping it in Devres. Callers that need device-managed revocation can call the new into_devres() method.

Danilo Krummrich committed 5 months ago

Commit 89f55d01 parent 8ea0b6d3 files · +56 −55Browse files

Unified · Split

3 files
  1. drivers/gpu/drm/tyr/driver.rs +2 −2
  2. drivers/pwm/pwm_th1520.rs +2 −2
  3. rust/kernel/io/mem.rs +52 −51
drivers/gpu/drm/tyr/driver.rs+2−2
@@ -37,7 +37,7 @@ use crate::{ · 36 unmodified lines
3737 regs, //
3838 };
3939
40−pub(crate) type IoMem = kernel::io::mem::IoMem<SZ_2M>;
40+pub(crate) type IoMem = kernel::io::mem::IoMem<'static, SZ_2M>;
4141
4242 pub(crate) struct TyrDrmDriver;
4343
@@ -110,7 +110,7 @@ impl platform::Driver for TyrPlatformDriverData { · 66 unmodified lines
110110 let sram_regulator = Regulator::<regulator::Enabled>::get(pdev.as_ref(), c"sram")?;
111111
112112 let request = pdev.io_request_by_index(0).ok_or(ENODEV)?;
113− let iomem = Arc::pin_init(request.iomap_sized::<SZ_2M>(), GFP_KERNEL)?;
113+ let iomem = Arc::new(request.iomap_sized::<SZ_2M>()?.into_devres()?, GFP_KERNEL)?;
114114
115115 issue_soft_reset(pdev.as_ref(), &iomem)?;
116116 gpu::l2_power_on(pdev.as_ref(), &iomem)?;
drivers/pwm/pwm_th1520.rs+2−2
@@ -92,7 +92,7 @@ struct Th1520WfHw { · 91 unmodified lines
9292 #[pin_data(PinnedDrop)]
9393 struct Th1520PwmDriverData {
9494 #[pin]
95− iomem: devres::Devres<IoMem<TH1520_PWM_REG_SIZE>>,
95+ iomem: devres::Devres<IoMem<'static, TH1520_PWM_REG_SIZE>>,
9696 clk: Clk,
9797 }
9898
@@ -352,7 +352,7 @@ impl platform::Driver for Th1520PwmPlatformDriver { · 253 unmodified lines
352352 dev,
353353 TH1520_MAX_PWM_NUM,
354354 try_pin_init!(Th1520PwmDriverData {
355− iomem <- request.iomap_sized::<TH1520_PWM_REG_SIZE>(),
355+ iomem <- request.iomap_sized::<TH1520_PWM_REG_SIZE>()?.into_devres(),
356356 clk <- clk,
357357 }),
358358 )?;
rust/kernel/io/mem.rs+52−51
@@ -74,22 +74,19 @@ impl<'a> IoRequest<'a> { · 73 unmodified lines
7474 /// //
7575 /// // No runtime checks will apply when reading and writing.
7676 /// let request = pdev.io_request_by_index(0).ok_or(ENODEV)?;
77− /// let iomem = request.iomap_sized::<42>();
78− /// let iomem = KBox::pin_init(iomem, GFP_KERNEL)?;
79− ///
80− /// let io = iomem.access(pdev.as_ref())?;
77+ /// let iomem = request.iomap_sized::<42>()?;
8178 ///
8279 /// // Read and write a 32-bit value at `offset`.
83− /// let data = io.read32(offset);
80+ /// let data = iomem.read32(offset);
8481 ///
85− /// io.write32(data, offset);
82+ /// iomem.write32(data, offset);
8683 ///
8784 /// # Ok(SampleDriver)
8885 /// }
8986 /// }
9087 /// ```
91− pub fn iomap_sized<const SIZE: usize>(self) -> impl PinInit<Devres<IoMem<SIZE>>, Error> + 'a {
92− IoMem::new(self)
88+ pub fn iomap_sized<const SIZE: usize>(self) -> Result<IoMem<'a, SIZE>> {
89+ IoMem::ioremap(self.device, self.resource)
9390 }
9491
9592 /// Same as [`Self::iomap_sized`] but with exclusive access to the
@@ -98,10 +95,8 @@ impl<'a> IoRequest<'a> { · 2 unmodified lines
9895 /// This uses the [`ioremap()`] C API.
9996 ///
10097 /// [`ioremap()`]: https://docs.kernel.org/driver-api/device-io.html#getting-access-to-the-device
101− pub fn iomap_exclusive_sized<const SIZE: usize>(
102− self,
103− ) -> impl PinInit<Devres<ExclusiveIoMem<SIZE>>, Error> + 'a {
104− ExclusiveIoMem::new(self)
98+ pub fn iomap_exclusive_sized<const SIZE: usize>(self) -> Result<ExclusiveIoMem<'a, SIZE>> {
99+ ExclusiveIoMem::ioremap(self.device, self.resource)
105100 }
106101
107102 /// Maps an [`IoRequest`] where the size is not known at compile time,
@@ -140,27 +135,24 @@ impl<'a> IoRequest<'a> { · 32 unmodified lines
140135 /// // family of functions should be used, leading to runtime checks on every
141136 /// // access.
142137 /// let request = pdev.io_request_by_index(0).ok_or(ENODEV)?;
143− /// let iomem = request.iomap();
144− /// let iomem = KBox::pin_init(iomem, GFP_KERNEL)?;
145− ///
146− /// let io = iomem.access(pdev.as_ref())?;
138+ /// let iomem = request.iomap()?;
147139 ///
148− /// let data = io.try_read32(offset)?;
140+ /// let data = iomem.try_read32(offset)?;
149141 ///
150− /// io.try_write32(data, offset)?;
142+ /// iomem.try_write32(data, offset)?;
151143 ///
152144 /// # Ok(SampleDriver)
153145 /// }
154146 /// }
155147 /// ```
156− pub fn iomap(self) -> impl PinInit<Devres<IoMem<0>>, Error> + 'a {
157− Self::iomap_sized::<0>(self)
148+ pub fn iomap(self) -> Result<IoMem<'a>> {
149+ self.iomap_sized::<0>()
158150 }
159151
160152 /// Same as [`Self::iomap`] but with exclusive access to the underlying
161153 /// region.
162− pub fn iomap_exclusive(self) -> impl PinInit<Devres<ExclusiveIoMem<0>>, Error> + 'a {
163− Self::iomap_exclusive_sized::<0>(self)
154+ pub fn iomap_exclusive(self) -> Result<ExclusiveIoMem<'a, 0>> {
155+ self.iomap_exclusive_sized::<0>()
164156 }
165157 }
166158
@@ -169,9 +161,9 @@ impl<'a> IoRequest<'a> { · 2 unmodified lines
169161 /// # Invariants
170162 ///
171163 /// - [`ExclusiveIoMem`] has exclusive access to the underlying [`IoMem`].
172−pub struct ExclusiveIoMem<const SIZE: usize> {
164+pub struct ExclusiveIoMem<'a, const SIZE: usize> {
173165 /// The underlying `IoMem` instance.
174− iomem: IoMem<SIZE>,
166+ iomem: IoMem<'a, SIZE>,
175167
176168 /// The region abstraction. This represents exclusive access to the
177169 /// range represented by the underlying `iomem`.
@@ -180,9 +172,9 @@ pub struct ExclusiveIoMem<const SIZE: usize> { · 2 unmodified lines
180172 _region: Region,
181173 }
182174
183−impl<const SIZE: usize> ExclusiveIoMem<SIZE> {
175+impl<'a, const SIZE: usize> ExclusiveIoMem<'a, SIZE> {
184176 /// Creates a new `ExclusiveIoMem` instance.
185− fn ioremap(resource: &Resource) -> Result<Self> {
177+ fn ioremap(dev: &'a Device<Bound>, resource: &Resource) -> Result<Self> {
186178 let start = resource.start();
187179 let size = resource.size();
188180 let name = resource.name().unwrap_or_default();
@@ -196,26 +188,29 @@ impl<const SIZE: usize> ExclusiveIoMem<SIZE> { · 7 unmodified lines
196188 )
197189 .ok_or(EBUSY)?;
198190
199− let iomem = IoMem::ioremap(resource)?;
191+ let iomem = IoMem::ioremap(dev, resource)?;
200192
201− let iomem = ExclusiveIoMem {
193+ Ok(ExclusiveIoMem {
202194 iomem,
203195 _region: region,
204− };
205−
206− Ok(iomem)
196+ })
207197 }
208198
209− /// Creates a new `ExclusiveIoMem` instance from a previously acquired [`IoRequest`].
210− pub fn new<'a>(io_request: IoRequest<'a>) -> impl PinInit<Devres<Self>, Error> + 'a {
211− let dev = io_request.device;
212− let res = io_request.resource;
213−
214− Devres::new(dev, Self::ioremap(res))
199+ /// Consume the `ExclusiveIoMem` and register it as a device-managed resource.
200+ ///
201+ /// The returned `Devres<ExclusiveIoMem<'static, SIZE>>` can outlive the original lifetime
202+ /// `'a`. Access to the I/O memory is revoked when the device is unbound.
203+ pub fn into_devres(self) -> Result<Devres<ExclusiveIoMem<'static, SIZE>>> {
204+ // SAFETY: Casting to `'static` is sound because `Devres` guarantees the
205+ // `ExclusiveIoMem` does not actually outlive the device -- access is revoked and the
206+ // resource is released when the device is unbound.
207+ let iomem: ExclusiveIoMem<'static, SIZE> = unsafe { core::mem::transmute(self) };
208+ let dev = iomem.iomem.dev;
209+ Devres::new(dev, iomem)
215210 }
216211 }
217212
218−impl<const SIZE: usize> Deref for ExclusiveIoMem<SIZE> {
213+impl<const SIZE: usize> Deref for ExclusiveIoMem<'_, SIZE> {
219214 type Target = Mmio<SIZE>;
220215
221216 fn deref(&self) -> &Self::Target {
@@ -232,12 +227,13 @@ impl<const SIZE: usize> Deref for ExclusiveIoMem<SIZE> { · 10 unmodified lines
232227 ///
233228 /// [`IoMem`] always holds an [`MmioRaw`] instance that holds a valid pointer to the
234229 /// start of the I/O memory mapped region.
235−pub struct IoMem<const SIZE: usize = 0> {
230+pub struct IoMem<'a, const SIZE: usize = 0> {
231+ dev: &'a Device<Bound>,
236232 io: MmioRaw<SIZE>,
237233 }
238234
239−impl<const SIZE: usize> IoMem<SIZE> {
240− fn ioremap(resource: &Resource) -> Result<Self> {
235+impl<'a, const SIZE: usize> IoMem<'a, SIZE> {
236+ fn ioremap(dev: &'a Device<Bound>, resource: &Resource) -> Result<Self> {
241237 // Note: Some ioremap() implementations use types that depend on the CPU
242238 // word width rather than the bus address width.
243239 //
@@ -269,28 +265,33 @@ impl<const SIZE: usize> IoMem<SIZE> { · 25 unmodified lines
269265 }
270266
271267 let io = MmioRaw::new(addr as usize, size)?;
272− let io = IoMem { io };
273268
274− Ok(io)
269+ Ok(IoMem { dev, io })
275270 }
276271
277− /// Creates a new `IoMem` instance from a previously acquired [`IoRequest`].
278− pub fn new<'a>(io_request: IoRequest<'a>) -> impl PinInit<Devres<Self>, Error> + 'a {
279− let dev = io_request.device;
280− let res = io_request.resource;
281−
282− Devres::new(dev, Self::ioremap(res))
272+ /// Consume the `IoMem` and register it as a device-managed resource.
273+ ///
274+ /// The returned `Devres<IoMem<'static, SIZE>>` can outlive the original
275+ /// lifetime `'a`. Access to the I/O memory is revoked when the device
276+ /// is unbound.
277+ pub fn into_devres(self) -> Result<Devres<IoMem<'static, SIZE>>> {
278+ // SAFETY: Casting to `'static` is sound because `Devres` guarantees the `IoMem` does not
279+ // actually outlive the device -- access is revoked and the resource is released when the
280+ // device is unbound.
281+ let iomem: IoMem<'static, SIZE> = unsafe { core::mem::transmute(self) };
282+ let dev = iomem.dev;
283+ Devres::new(dev, iomem)
283284 }
284285 }
285286
286−impl<const SIZE: usize> Drop for IoMem<SIZE> {
287+impl<const SIZE: usize> Drop for IoMem<'_, SIZE> {
287288 fn drop(&mut self) {
288289 // SAFETY: Safe as by the invariant of `Io`.
289290 unsafe { bindings::iounmap(self.io.addr() as *mut c_void) }
290291 }
291292 }
292293
293−impl<const SIZE: usize> Deref for IoMem<SIZE> {
294+impl<const SIZE: usize> Deref for IoMem<'_, SIZE> {
294295 type Target = Mmio<SIZE>;
295296
296297 fn deref(&self) -> &Self::Target {

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t