Ion past and future

| categories: kernel, fedora

I've mentioned Ion a few times in past posts now, so this post is explaining some of past, present, and maybe future for Ion from my perspective.

Ion arose mostly out of necessity for Android. When Google first released Android, most hardware blocks required large chunks of contiguous memory. Most vendors also had their own custom driver for allocating and managing this memory because features like CMA did not exist yet. Google eventually got tired of this and decided to write a unified manager for vendors to use for their HALs. Android doesn't use the standard DRM framework for graphics so having a unified way of allocating memory was beneficial to Google. Ion was out of tree for a couple of years until 2013 or so when it was placed into staging. Today, even though features like CMA are now standard and fewer devices need large memory Ion still serves an important purpose for being an API to userspace.

Ion was written to have three main purposes: allocation of memory, mapping of memory, and sharing of memory.

  • Most applications call malloc or kmalloc to allocate heap memory and will never think twice about that. Drivers have to be a bit more thoughtful about where their memory is coming from. Most modern CPUs have an MMU to make memory appear contiguous even if isn't in reality. Some hardware blocks may have their own MMU (sometimes called an IOMMU or a System MMU) to do something simlar to the CPU MMU. Certain memory may be optimized for hardware blocks so it's beneficial to be able to get memory from a particular area. Ion attempts to manage this through an abstraction called 'heaps'. A heap represents a particular type of memory. Common heap types are system memory, carveout and DMA. Users of Ion can pass in the ID of a particular heap to allocate corresponding memory. There are APIs to do this both in the kernel and userspace via an ioctl interface.

  • Once the memory has been allocted, it needs to be mapped into some address space to be accessed by the CPU. Ion provides APIs to map into the kernel's address space and a method to get a file descriptor associated with a memory allocation. A user can then call mmap to map the fd into the process address space.

  • One of the goals of most frameworks is to be 'zero copy'. This phrase does not mean 'copy zeros'. When one part of the system allocates memory for some data, this data should be passed around so it can be accessible to others without copying the data to another part of memory. The mechanism that Ion uses for sharing is the same as mapping to userspace: fds. File descriptors provide a natural namespace already (file descriptor 12 means completely different things in different processes) and there are mechanisms to allow file descriptors to be shared between proceses. (It's important to us something like binder or sockets to share the file descriptors. These mechanisms take care of properly opening a new file descriptor in the receiving process)

If a lot of this sounds similar to the dma_buf framework, that's because the two came around at about the same time. dma_buf provided more generic methods for use across all subsystems. These days, Ion is a dma_buf exporter. This means that, in theory, any driver which uses dma_buf APIs should be able to import and use Ion buffers transparently. Realistically though, Ion is still fairly self-contained and there would probably be integration issues for non-Ion-tweaked drivers. Among other work:

  • The cache maintainance is a mess. Ion was originally written for ARM devices. The first drop of Ion was calling cache APIs that existed only for ARM devices. When Ion was dropped into staging, the ARM only APIs were changed to use the dma_sync_sg APIs. These work and provide the expected cache work but their use is not quite correct. Technically, dma_sync_sg should only be called a) with a device pointer to the device that is using it and b) after calling dma_map. Ion does neither. I gave a talk about this at LPC 2014 and talked more at LPC 2015. The conclusion is that Ion should just be calling cache APIs directly, properly abstracted. I expect this to be controversial when an RFC drops.

  • Devicetree bindings. Every vendor is currently using their own method for specifying. I put up a first draft of common bindings. The feedback was basically "Why is this in devicetree devicetree describes the hardware" which is a common refrain when propsing bindings. The next version will hopefully address those concerns.

  • A better ABI for userspace. The ion_alloc API takes a bit mask of heaps to allocate from. The bit mask is currently set up via #defines in a header file. #defines and bitmasks work okay if the ABI that's being established is fixed and unlikely to change. That doesn't match up well with the actual use cases of Ion though. Each device ends up needing to establish its own ABI of heap IDs. If userspace and kernel space end up out of sync when changes happen, allocations from the wrong heap can happen. This setup just doesn't scale. Ideally, there would be some discoverable way to find out what heaps are available and then allocate from them.

  • Integration with the rest of the system. As mentioned above, Ion is mostly being used self contained; all uses are from drivers worked to handle Ion buffers to other drivers that can handle Ion buffers. Ion makes a lot of assumptions about how the sg_lists are set up and what APIs can actually be called and when. Ion buffers need to be able to be allocated and used trasnparently. This should also mean Ion as a framework should be able to import other dma_buf buffers besides those from Ion.

  • Constraint solving. One of the things Ion does a reasonable job of is abstracting away hardware requirements. A heap on one system can be contiguous memory and discontiguous memory on another. Ultimately though, the users may still have to make an informed choice about which heap to allocate from to ensure the right type of memory is allocated. Sumit Semwal has been doing some work on cenalloc to develop a constraint based allocator. This would determine what type of memory to allocate based on what devices are present in the system. His presentation at LPC 2015 does a great job of hilighting more of the problems and pitfalls. This has a bit of overlap with some of the problems also mentioned above.

Ideally what I'd see in the future is for Ion to disappear. Not be deleted but parts of Ion be absorbed into different parts of the kernel. I'd love to have some of this become an outreachy project but I need to do a lot more background work before that would be appropriate.