| 1 | |
| 2 | The allocator shown here exploits high memory. This document explains |
| 3 | how a user can deal with drivers uses this allocator and how a |
| 4 | programmer can link in the module. |
| 5 | |
| 6 | The module is being used by my pxc and pxdrv device drivers (as well as |
| 7 | other ones), available from ftp.systemy.it/pub/develop and |
| 8 | ftp.linux.it/pub/People/Rubini |
| 9 | |
| 10 | User's manual |
| 11 | ============= |
| 12 | |
| 13 | |
| 14 | One of the most compelling problems with any DMA-capable device is the |
| 15 | allocation of a suitable memory buffer. The "allocator" module tries |
| 16 | to deal with the problem in a clean way. The module is able to use |
| 17 | high memory (above the one used in normal operation) for DMA |
| 18 | allocation. |
| 19 | |
| 20 | To prevent the kernel for using high memory, so that it remains |
| 21 | available for DMA, you should pass a command line argument to the |
| 22 | kernel. Command line arguments can be passed to Lilo, to Loadlin or |
| 23 | to whichever loader you are using (unless it's very poor in design). |
| 24 | For Lilo, either use "append=" in /etc/lilo.conf or add commandline |
| 25 | arguments to the interactive prompt. For example, I have a 32MB box |
| 26 | and reserve two megs for DMA: |
| 27 | |
| 28 | In lilo.conf: |
| 29 | image = /zImage |
| 30 | label = linux |
| 31 | append = "mem=30M" |
| 32 | |
| 33 | Or, interactively: |
| 34 | LILO: linux mem=30M |
| 35 | |
| 36 | Once the kernel is booted with the right command-line argument, any |
| 37 | driver linked with the allocator module will be able to get |
| 38 | DMA-capable memory without much trouble (unless the various drivers |
| 39 | need more memory than available). |
| 40 | |
| 41 | The module implements an alloc/free mechanism, so that it can serve |
| 42 | multiple drivers at the same time. Note however that the allocator |
| 43 | uses all of high memory and assumes to be the only piece of software |
| 44 | using such memory. |
| 45 | |
| 46 | |
| 47 | Programmer's manual |
| 48 | =================== |
| 49 | |
| 50 | The allocator, as released, is designed to be linked to a device |
| 51 | driver. In this case, the driver must call allocator_init() before |
| 52 | using the allocator and must call allocator_cleanup() before |
| 53 | unloading. This is usually done from within init_module() and |
| 54 | cleanup_module(). If the allocator is linked to a driver, it won't be |
| 55 | possible for several drivers to allocate high DMA memory, as explained |
| 56 | above. |
| 57 | |
| 58 | It is possible, on the other hand, to compile the module as a standalone |
| 59 | module, so that several modules can rely on the allocator for they DMA |
| 60 | buffers. To compile the allocator as a standalone module, do the |
| 61 | following in this directory (or provide a suitable Makefile, or edit |
| 62 | the source code): |
| 63 | |
| 64 | make allocator.o CC="gcc -Dallocator_init=init_module -Dallocator_cleanup=cleanup_module -include /usr/include/linux/module.h" |
| 65 | |
| 66 | The previous commandline tells to include <linux/module.h> in the |
| 67 | first place, and to rename the init and cleanup function to the ones |
| 68 | needed for module loading and unloading. Drivers using a standalone |
| 69 | allocator won't need to call allocator_init() nor allocator_cleanup(). |
| 70 | |
| 71 | The allocator exports the following functions (declared in allocator.h): |
| 72 | |
| 73 | unsigned long allocator_allocate_dma (unsigned long kilobytes, |
| 74 | int priority); |
| 75 | |
| 76 | This function returns a physical address, over high_memory, |
| 77 | which corresponds to an area of at least "kilobytes" kilobytes. |
| 78 | The area will be owned by the module calling the function. |
| 79 | The returned address can be passed to device boards, to instruct |
| 80 | their DMA controllers, via phys_to_bus(). The address can be used |
| 81 | by C code after vremap()/ioremap(). The "priority" argument should |
| 82 | be GFP_KERNEL or GFP_ATOMIC, according to the context of the |
| 83 | caller; it is used to call kmalloc(), as the allocator must keep |
| 84 | track of any region it gives away. In case of error the function |
| 85 | returns 0, and the caller is expected to issue a -ENOMEM error. |
| 86 | |
| 87 | |
| 88 | void allocator_free_dma (unsigned long address); |
| 89 | |
| 90 | This function is the reverse of the previous one. If a driver |
| 91 | doesn't free the DMA memory it allocated, the allocator will |
| 92 | consider such memory as busy. Note, however, that |
| 93 | allocator_cleanup() calls kfree() on every region it reclaimed, |
| 94 | so that a driver with the allocator linked in can avoid calling |
| 95 | allocator_free_dma() at unload time. |
| 96 | |
| 97 | |
| 98 | |