// SPDX-License-Identifier: GPL-2.012//! Generic memory-mapped IO.34use core::ops::Deref;56use crate::c_str;7use crate::device::Bound;8use crate::device::Device;9use crate::devres::Devres;10use crate::io;11use crate::io::resource::Region;12use crate::io::resource::Resource;13use crate::io::Io;14use crate::io::IoRaw;15use crate::prelude::*;1617/// An IO request for a specific device and resource.18pub struct IoRequest<'a> {19device: &'a Device<Bound>,20resource: &'a Resource,21}2223impl<'a> IoRequest<'a> {24/// Creates a new [`IoRequest`] instance.25///26/// # Safety27///28/// Callers must ensure that `resource` is valid for `device` during the29/// lifetime `'a`.30pub(crate) unsafe fn new(device: &'a Device<Bound>, resource: &'a Resource) -> Self {31IoRequest { device, resource }32}3334/// Maps an [`IoRequest`] where the size is known at compile time.35///36/// This uses the [`ioremap()`] C API.37///38/// [`ioremap()`]: https://docs.kernel.org/driver-api/device-io.html#getting-access-to-the-device39///40/// # Examples41///42/// The following example uses a [`kernel::platform::Device`] for43/// illustration purposes.44///45/// ```no_run46/// use kernel::{bindings, c_str, platform, of, device::Core};47/// struct SampleDriver;48///49/// impl platform::Driver for SampleDriver {50/// # type IdInfo = ();51///52/// fn probe(53/// pdev: &platform::Device<Core>,54/// info: Option<&Self::IdInfo>,55/// ) -> Result<Pin<KBox<Self>>> {56/// let offset = 0; // Some offset.57///58/// // If the size is known at compile time, use [`Self::iomap_sized`].59/// //60/// // No runtime checks will apply when reading and writing.61/// let request = pdev.io_request_by_index(0).ok_or(ENODEV)?;62/// let iomem = request.iomap_sized::<42>();63/// let iomem = KBox::pin_init(iomem, GFP_KERNEL)?;64///65/// let io = iomem.access(pdev.as_ref())?;66///67/// // Read and write a 32-bit value at `offset`.68/// let data = io.read32_relaxed(offset);69///70/// io.write32_relaxed(data, offset);71///72/// # Ok(KBox::new(SampleDriver, GFP_KERNEL)?.into())73/// }74/// }75/// ```76pub fn iomap_sized<const SIZE: usize>(self) -> impl PinInit<Devres<IoMem<SIZE>>, Error> + 'a {77IoMem::new(self)78}7980/// Same as [`Self::iomap_sized`] but with exclusive access to the81/// underlying region.82///83/// This uses the [`ioremap()`] C API.84///85/// [`ioremap()`]: https://docs.kernel.org/driver-api/device-io.html#getting-access-to-the-device86pub fn iomap_exclusive_sized<const SIZE: usize>(87self,88) -> impl PinInit<Devres<ExclusiveIoMem<SIZE>>, Error> + 'a {89ExclusiveIoMem::new(self)90}9192/// Maps an [`IoRequest`] where the size is not known at compile time,93///94/// This uses the [`ioremap()`] C API.95///96/// [`ioremap()`]: https://docs.kernel.org/driver-api/device-io.html#getting-access-to-the-device97///98/// # Examples99///100/// The following example uses a [`kernel::platform::Device`] for101/// illustration purposes.102///103/// ```no_run104/// use kernel::{bindings, c_str, platform, of, device::Core};105/// struct SampleDriver;106///107/// impl platform::Driver for SampleDriver {108/// # type IdInfo = ();109///110/// fn probe(111/// pdev: &platform::Device<Core>,112/// info: Option<&Self::IdInfo>,113/// ) -> Result<Pin<KBox<Self>>> {114/// let offset = 0; // Some offset.115///116/// // Unlike [`Self::iomap_sized`], here the size of the memory region117/// // is not known at compile time, so only the `try_read*` and `try_write*`118/// // family of functions should be used, leading to runtime checks on every119/// // access.120/// let request = pdev.io_request_by_index(0).ok_or(ENODEV)?;121/// let iomem = request.iomap();122/// let iomem = KBox::pin_init(iomem, GFP_KERNEL)?;123///124/// let io = iomem.access(pdev.as_ref())?;125///126/// let data = io.try_read32_relaxed(offset)?;127///128/// io.try_write32_relaxed(data, offset)?;129///130/// # Ok(KBox::new(SampleDriver, GFP_KERNEL)?.into())131/// }132/// }133/// ```134pub fn iomap(self) -> impl PinInit<Devres<IoMem<0>>, Error> + 'a {135Self::iomap_sized::<0>(self)136}137138/// Same as [`Self::iomap`] but with exclusive access to the underlying139/// region.140pub fn iomap_exclusive(self) -> impl PinInit<Devres<ExclusiveIoMem<0>>, Error> + 'a {141Self::iomap_exclusive_sized::<0>(self)142}143}144145/// An exclusive memory-mapped IO region.146///147/// # Invariants148///149/// - [`ExclusiveIoMem`] has exclusive access to the underlying [`IoMem`].150pub struct ExclusiveIoMem<const SIZE: usize> {151/// The underlying `IoMem` instance.152iomem: IoMem<SIZE>,153154/// The region abstraction. This represents exclusive access to the155/// range represented by the underlying `iomem`.156///157/// This field is needed for ownership of the region.158_region: Region,159}160161impl<const SIZE: usize> ExclusiveIoMem<SIZE> {162/// Creates a new `ExclusiveIoMem` instance.163fn ioremap(resource: &Resource) -> Result<Self> {164let start = resource.start();165let size = resource.size();166let name = resource.name().unwrap_or(c_str!(""));167168let region = resource169.request_region(170start,171size,172name.to_cstring()?,173io::resource::Flags::IORESOURCE_MEM,174)175.ok_or(EBUSY)?;176177let iomem = IoMem::ioremap(resource)?;178179let iomem = ExclusiveIoMem {180iomem,181_region: region,182};183184Ok(iomem)185}186187/// Creates a new `ExclusiveIoMem` instance from a previously acquired [`IoRequest`].188pub fn new<'a>(io_request: IoRequest<'a>) -> impl PinInit<Devres<Self>, Error> + 'a {189let dev = io_request.device;190let res = io_request.resource;191192Devres::new(dev, Self::ioremap(res))193}194}195196impl<const SIZE: usize> Deref for ExclusiveIoMem<SIZE> {197type Target = Io<SIZE>;198199fn deref(&self) -> &Self::Target {200&self.iomem201}202}203204/// A generic memory-mapped IO region.205///206/// Accesses to the underlying region is checked either at compile time, if the207/// region's size is known at that point, or at runtime otherwise.208///209/// # Invariants210///211/// [`IoMem`] always holds an [`IoRaw`] instance that holds a valid pointer to the212/// start of the I/O memory mapped region.213pub struct IoMem<const SIZE: usize = 0> {214io: IoRaw<SIZE>,215}216217impl<const SIZE: usize> IoMem<SIZE> {218fn ioremap(resource: &Resource) -> Result<Self> {219// Note: Some ioremap() implementations use types that depend on the CPU220// word width rather than the bus address width.221//222// TODO: Properly address this in the C code to avoid this `try_into`.223let size = resource.size().try_into()?;224if size == 0 {225return Err(EINVAL);226}227228let res_start = resource.start();229230let addr = if resource231.flags()232.contains(io::resource::Flags::IORESOURCE_MEM_NONPOSTED)233{234// SAFETY:235// - `res_start` and `size` are read from a presumably valid `struct resource`.236// - `size` is known not to be zero at this point.237unsafe { bindings::ioremap_np(res_start, size) }238} else {239// SAFETY:240// - `res_start` and `size` are read from a presumably valid `struct resource`.241// - `size` is known not to be zero at this point.242unsafe { bindings::ioremap(res_start, size) }243};244245if addr.is_null() {246return Err(ENOMEM);247}248249let io = IoRaw::new(addr as usize, size)?;250let io = IoMem { io };251252Ok(io)253}254255/// Creates a new `IoMem` instance from a previously acquired [`IoRequest`].256pub fn new<'a>(io_request: IoRequest<'a>) -> impl PinInit<Devres<Self>, Error> + 'a {257let dev = io_request.device;258let res = io_request.resource;259260Devres::new(dev, Self::ioremap(res))261}262}263264impl<const SIZE: usize> Drop for IoMem<SIZE> {265fn drop(&mut self) {266// SAFETY: Safe as by the invariant of `Io`.267unsafe { bindings::iounmap(self.io.addr() as *mut c_void) }268}269}270271impl<const SIZE: usize> Deref for IoMem<SIZE> {272type Target = Io<SIZE>;273274fn deref(&self) -> &Self::Target {275// SAFETY: Safe as by the invariant of `IoMem`.276unsafe { Io::from_raw(&self.io) }277}278}279280281