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
37 regs, //37 regs, //
38};38};
39 39
40pub(crate) type IoMem = kernel::io::mem::IoMem<SZ_2M>;40pub(crate) type IoMem = kernel::io::mem::IoMem<'static, SZ_2M>;
41 41
42pub(crate) struct TyrDrmDriver;42pub(crate) struct TyrDrmDriver;
43 43
@@ -110,7 +110,7 @@ impl platform::Driver for TyrPlatformDriverData { · 66 unmodified lines
110 let sram_regulator = Regulator::<regulator::Enabled>::get(pdev.as_ref(), c"sram")?;110 let sram_regulator = Regulator::<regulator::Enabled>::get(pdev.as_ref(), c"sram")?;
111 111
112 let request = pdev.io_request_by_index(0).ok_or(ENODEV)?;112 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)?;
114 114
115 issue_soft_reset(pdev.as_ref(), &iomem)?;115 issue_soft_reset(pdev.as_ref(), &iomem)?;
116 gpu::l2_power_on(pdev.as_ref(), &iomem)?;116 gpu::l2_power_on(pdev.as_ref(), &iomem)?;
drivers/pwm/pwm_th1520.rs+2−2
@@ -92,7 +92,7 @@ struct Th1520WfHw { · 91 unmodified lines
92#[pin_data(PinnedDrop)]92#[pin_data(PinnedDrop)]
93struct Th1520PwmDriverData {93struct Th1520PwmDriverData {
94 #[pin]94 #[pin]
95 iomem: devres::Devres<IoMem<TH1520_PWM_REG_SIZE>>,95 iomem: devres::Devres<IoMem<'static, TH1520_PWM_REG_SIZE>>,
96 clk: Clk,96 clk: Clk,
97}97}
98 98
@@ -352,7 +352,7 @@ impl platform::Driver for Th1520PwmPlatformDriver { · 253 unmodified lines
352 dev,352 dev,
353 TH1520_MAX_PWM_NUM,353 TH1520_MAX_PWM_NUM,
354 try_pin_init!(Th1520PwmDriverData {354 try_pin_init!(Th1520PwmDriverData {
355 iomem <- request.iomap_sized::<TH1520_PWM_REG_SIZE>(),355 iomem <- request.iomap_sized::<TH1520_PWM_REG_SIZE>()?.into_devres(),
356 clk <- clk,356 clk <- clk,
357 }),357 }),
358 )?;358 )?;
rust/kernel/io/mem.rs+52−51
@@ -74,22 +74,19 @@ impl<'a> IoRequest<'a> { · 73 unmodified lines
74 /// //74 /// //
75 /// // No runtime checks will apply when reading and writing.75 /// // No runtime checks will apply when reading and writing.
76 /// let request = pdev.io_request_by_index(0).ok_or(ENODEV)?;76 /// let request = pdev.io_request_by_index(0).ok_or(ENODEV)?;
77 /// let iomem = request.iomap_sized::<42>();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())?;
81 ///78 ///
82 /// // Read and write a 32-bit value at `offset`.79 /// // Read and write a 32-bit value at `offset`.
83 /// let data = io.read32(offset);80 /// let data = iomem.read32(offset);
84 ///81 ///
85 /// io.write32(data, offset);82 /// iomem.write32(data, offset);
86 ///83 ///
87 /// # Ok(SampleDriver)84 /// # Ok(SampleDriver)
88 /// }85 /// }
89 /// }86 /// }
90 /// ```87 /// ```
91 pub fn iomap_sized<const SIZE: usize>(self) -> impl PinInit<Devres<IoMem<SIZE>>, Error> + 'a {88 pub fn iomap_sized<const SIZE: usize>(self) -> Result<IoMem<'a, SIZE>> {
92 IoMem::new(self)89 IoMem::ioremap(self.device, self.resource)
93 }90 }
94 91
95 /// Same as [`Self::iomap_sized`] but with exclusive access to the92 /// Same as [`Self::iomap_sized`] but with exclusive access to the
@@ -98,10 +95,8 @@ impl<'a> IoRequest<'a> { · 2 unmodified lines
98 /// This uses the [`ioremap()`] C API.95 /// This uses the [`ioremap()`] C API.
99 ///96 ///
100 /// [`ioremap()`]: https://docs.kernel.org/driver-api/device-io.html#getting-access-to-the-device97 /// [`ioremap()`]: https://docs.kernel.org/driver-api/device-io.html#getting-access-to-the-device
101 pub fn iomap_exclusive_sized<const SIZE: usize>(98 pub fn iomap_exclusive_sized<const SIZE: usize>(self) -> Result<ExclusiveIoMem<'a, SIZE>> {
102 self,99 ExclusiveIoMem::ioremap(self.device, self.resource)
103 ) -> impl PinInit<Devres<ExclusiveIoMem<SIZE>>, Error> + 'a {
104 ExclusiveIoMem::new(self)
105 }100 }
106 101
107 /// Maps an [`IoRequest`] where the size is not known at compile time,102 /// Maps an [`IoRequest`] where the size is not known at compile time,
@@ -140,27 +135,24 @@ impl<'a> IoRequest<'a> { · 32 unmodified lines
140 /// // family of functions should be used, leading to runtime checks on every135 /// // family of functions should be used, leading to runtime checks on every
141 /// // access.136 /// // access.
142 /// let request = pdev.io_request_by_index(0).ok_or(ENODEV)?;137 /// let request = pdev.io_request_by_index(0).ok_or(ENODEV)?;
143 /// let iomem = request.iomap();138 /// let iomem = request.iomap()?;
144 /// let iomem = KBox::pin_init(iomem, GFP_KERNEL)?;
145 ///
146 /// let io = iomem.access(pdev.as_ref())?;
147 ///139 ///
148 /// let data = io.try_read32(offset)?;140 /// let data = iomem.try_read32(offset)?;
149 ///141 ///
150 /// io.try_write32(data, offset)?;142 /// iomem.try_write32(data, offset)?;
151 ///143 ///
152 /// # Ok(SampleDriver)144 /// # Ok(SampleDriver)
153 /// }145 /// }
154 /// }146 /// }
155 /// ```147 /// ```
156 pub fn iomap(self) -> impl PinInit<Devres<IoMem<0>>, Error> + 'a {148 pub fn iomap(self) -> Result<IoMem<'a>> {
157 Self::iomap_sized::<0>(self)149 self.iomap_sized::<0>()
158 }150 }
159 151
160 /// Same as [`Self::iomap`] but with exclusive access to the underlying152 /// Same as [`Self::iomap`] but with exclusive access to the underlying
161 /// region.153 /// region.
162 pub fn iomap_exclusive(self) -> impl PinInit<Devres<ExclusiveIoMem<0>>, Error> + 'a {154 pub fn iomap_exclusive(self) -> Result<ExclusiveIoMem<'a, 0>> {
163 Self::iomap_exclusive_sized::<0>(self)155 self.iomap_exclusive_sized::<0>()
164 }156 }
165}157}
166 158
@@ -169,9 +161,9 @@ impl<'a> IoRequest<'a> { · 2 unmodified lines
169/// # Invariants161/// # Invariants
170///162///
171/// - [`ExclusiveIoMem`] has exclusive access to the underlying [`IoMem`].163/// - [`ExclusiveIoMem`] has exclusive access to the underlying [`IoMem`].
172pub struct ExclusiveIoMem<const SIZE: usize> {164pub struct ExclusiveIoMem<'a, const SIZE: usize> {
173 /// The underlying `IoMem` instance.165 /// The underlying `IoMem` instance.
174 iomem: IoMem<SIZE>,166 iomem: IoMem<'a, SIZE>,
175 167
176 /// The region abstraction. This represents exclusive access to the168 /// The region abstraction. This represents exclusive access to the
177 /// range represented by the underlying `iomem`.169 /// range represented by the underlying `iomem`.
@@ -180,9 +172,9 @@ pub struct ExclusiveIoMem<const SIZE: usize> { · 2 unmodified lines
180 _region: Region,172 _region: Region,
181}173}
182 174
183impl<const SIZE: usize> ExclusiveIoMem<SIZE> {175impl<'a, const SIZE: usize> ExclusiveIoMem<'a, SIZE> {
184 /// Creates a new `ExclusiveIoMem` instance.176 /// Creates a new `ExclusiveIoMem` instance.
185 fn ioremap(resource: &Resource) -> Result<Self> {177 fn ioremap(dev: &'a Device<Bound>, resource: &Resource) -> Result<Self> {
186 let start = resource.start();178 let start = resource.start();
187 let size = resource.size();179 let size = resource.size();
188 let name = resource.name().unwrap_or_default();180 let name = resource.name().unwrap_or_default();
@@ -196,26 +188,29 @@ impl<const SIZE: usize> ExclusiveIoMem<SIZE> { · 7 unmodified lines
196 )188 )
197 .ok_or(EBUSY)?;189 .ok_or(EBUSY)?;
198 190
199 let iomem = IoMem::ioremap(resource)?;191 let iomem = IoMem::ioremap(dev, resource)?;
200 192
201 let iomem = ExclusiveIoMem {193 Ok(ExclusiveIoMem {
202 iomem,194 iomem,
203 _region: region,195 _region: region,
204 };196 })
205
206 Ok(iomem)
207 }197 }
208 198
209 /// Creates a new `ExclusiveIoMem` instance from a previously acquired [`IoRequest`].199 /// Consume the `ExclusiveIoMem` and register it as a device-managed resource.
210 pub fn new<'a>(io_request: IoRequest<'a>) -> impl PinInit<Devres<Self>, Error> + 'a {200 ///
211 let dev = io_request.device;201 /// The returned `Devres<ExclusiveIoMem<'static, SIZE>>` can outlive the original lifetime
212 let res = io_request.resource;202 /// `'a`. Access to the I/O memory is revoked when the device is unbound.
213 203 pub fn into_devres(self) -> Result<Devres<ExclusiveIoMem<'static, SIZE>>> {
214 Devres::new(dev, Self::ioremap(res))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)
215 }210 }
216}211}
217 212
218impl<const SIZE: usize> Deref for ExclusiveIoMem<SIZE> {213impl<const SIZE: usize> Deref for ExclusiveIoMem<'_, SIZE> {
219 type Target = Mmio<SIZE>;214 type Target = Mmio<SIZE>;
220 215
221 fn deref(&self) -> &Self::Target {216 fn deref(&self) -> &Self::Target {
@@ -232,12 +227,13 @@ impl<const SIZE: usize> Deref for ExclusiveIoMem<SIZE> { · 10 unmodified lines
232///227///
233/// [`IoMem`] always holds an [`MmioRaw`] instance that holds a valid pointer to the228/// [`IoMem`] always holds an [`MmioRaw`] instance that holds a valid pointer to the
234/// start of the I/O memory mapped region.229/// start of the I/O memory mapped region.
235pub struct IoMem<const SIZE: usize = 0> {230pub struct IoMem<'a, const SIZE: usize = 0> {
231 dev: &'a Device<Bound>,
236 io: MmioRaw<SIZE>,232 io: MmioRaw<SIZE>,
237}233}
238 234
239impl<const SIZE: usize> IoMem<SIZE> {235impl<'a, const SIZE: usize> IoMem<'a, SIZE> {
240 fn ioremap(resource: &Resource) -> Result<Self> {236 fn ioremap(dev: &'a Device<Bound>, resource: &Resource) -> Result<Self> {
241 // Note: Some ioremap() implementations use types that depend on the CPU237 // Note: Some ioremap() implementations use types that depend on the CPU
242 // word width rather than the bus address width.238 // word width rather than the bus address width.
243 //239 //
@@ -269,28 +265,33 @@ impl<const SIZE: usize> IoMem<SIZE> { · 25 unmodified lines
269 }265 }
270 266
271 let io = MmioRaw::new(addr as usize, size)?;267 let io = MmioRaw::new(addr as usize, size)?;
272 let io = IoMem { io };
273 268
274 Ok(io)269 Ok(IoMem { dev, io })
275 }270 }
276 271
277 /// Creates a new `IoMem` instance from a previously acquired [`IoRequest`].272 /// Consume the `IoMem` and register it as a device-managed resource.
278 pub fn new<'a>(io_request: IoRequest<'a>) -> impl PinInit<Devres<Self>, Error> + 'a {273 ///
279 let dev = io_request.device;274 /// The returned `Devres<IoMem<'static, SIZE>>` can outlive the original
280 let res = io_request.resource;275 /// lifetime `'a`. Access to the I/O memory is revoked when the device
281 276 /// is unbound.
282 Devres::new(dev, Self::ioremap(res))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)
283 }284 }
284}285}
285 286
286impl<const SIZE: usize> Drop for IoMem<SIZE> {287impl<const SIZE: usize> Drop for IoMem<'_, SIZE> {
287 fn drop(&mut self) {288 fn drop(&mut self) {
288 // SAFETY: Safe as by the invariant of `Io`.289 // SAFETY: Safe as by the invariant of `Io`.
289 unsafe { bindings::iounmap(self.io.addr() as *mut c_void) }290 unsafe { bindings::iounmap(self.io.addr() as *mut c_void) }
290 }291 }
291}292}
292 293
293impl<const SIZE: usize> Deref for IoMem<SIZE> {294impl<const SIZE: usize> Deref for IoMem<'_, SIZE> {
294 type Target = Mmio<SIZE>;295 type Target = Mmio<SIZE>;
295 296
296 fn deref(&self) -> &Self::Target {297 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