Linux Device Drivers 2nd Edition (779877), страница 55
Текст из файла (страница 55)
Code that must be portable back to Linux 2.0should stick with kmalloc and kfr ee. Moreover, kmem_destr oy_cache was introduced during 2.3 development and has only been backported to 2.2 as of 2.2.18.For this reason scullc refuses to compile with a 2.2 kernel older than that._ _get_fr ee_pages in Linux 2.0 had a third, integer argument called dma; it servedthe same function that the _ _GFP_DMA flag serves in modern kernels but it wasnot merged in the flags argument. To address the problem, sysdep.h passes 0 asthe third argument to the 2.0 function. If you want to request DMA pages and bebackward compatible with 2.0, you need to call get_dma_ pages instead of using_ _GFP_DMA.22322 June 2001 16:38http://openlib.org.uaChapter 7: Getting Hold of Memoryvmalloc and vfr ee are unchanged across all 2.x kernels.
However, the ior emapfunction was called vr emap in the 2.0 days, and there was no iounmap. Instead,an I/O mapping obtained with vr emap would be freed with vfr ee. Also, the header<linux/vmalloc.h> didn’t exist in 2.0; the functions were declared by<linux/mm.h> instead. As usual, sysdep.h makes 2.4 code work with earlier kernels; it also includes <linux/vmalloc.h> if <linux/mm.h> is included, thushiding this difference as well.Quick ReferenceThe functions and symbols related to memory allocation follow.#include <linux/malloc.h>void *kmalloc(size_t size, int flags);void kfree(void *obj);The most frequently used interface to memory allocation.#include <linux/mm.h>GFP_KERNELGFP_ATOMIC_ _GFP_DMA_ _GFP_HIGHMEMkmalloc flags.
_ _GFP_DMA and _ _GFP_HIGHMEM are flags that can be OR’dto either GFP_KERNEL or GFP_ATOMIC.#include <linux/malloc.h>kmem_cache_t *kmem_cache_create(char *name, size_t size,size_t offset, unsigned long flags, constructor(),destructor());int kmem_cache_destroy(kmem_cache_t *cache);Create and destroy a slab cache.
The cache can be used to allocate severalobjects of the same size.SLAB_NO_REAPSLAB_HWCACHE_ALIGNSLAB_CACHE_DMAFlags that can be specified while creating a cache.SLAB_CTOR_ATOMICSLAB_CTOR_CONSTRUCTORFlags that the allocator can pass to the constructor and the destructor functions.22422 June 2001 16:38http://openlib.org.uaQuick Referencevoid *kmem_cache_alloc(kmem_cache_t *cache, int flags);void kmem_cache_free(kmem_cache_t *cache, const void *obj);Allocate and release a single object from the cache.unsigned long get_zeroed_page(int flags);unsigned long _ _get_free_page(int flags);unsigned long _ _get_free_pages(int flags, unsigned longorder);unsigned long _ _get_dma_pages(int flags, unsigned longorder);The page-oriented allocation functions.
get_zer oed_page returns a single,zero-filled page. All the other versions of the call do not initialize the contentsof the returned page(s). _ _get_dma_ pages is only a compatibility macro inLinux 2.2 and later (you can use _ _GFP_DMA instead).void free_page(unsigned long addr);void free_pages(unsigned long addr, unsigned long order);These functions release page-oriented allocations.#include <linux/vmalloc.h>void * vmalloc(unsigned long size);void vfree(void * addr);#include <asm/io.h>void * ioremap(unsigned long offset, unsigned long size);void iounmap(void *addr);These functions allocate or free a contiguous virtual address space.
ior emapaccesses physical memory through virtual addresses, while vmalloc allocatesfree pages. Regions mapped with ior emap are freed with iounmap, whilepages obtained from vmalloc are released with vfr ee.#include <linux/bootmem.h>void *alloc_bootmem(unsigned long size);void *alloc_bootmem_low(unsigned long size);void *alloc_bootmem_pages(unsigned long size);void *alloc_bootmem_low_pages(unsigned long size);Only with version 2.4 of the kernel, memory can be allocated at boot timeusing these functions.
The facility can only be used by drivers directly linkedin the kernel image.22522 June 2001 16:38http://openlib.org.uaCHAPTER EIGHTHARDWAREMANAGEMENTAlthough playing with scull and similar toys is a good introduction to the softwareinterface of a Linux device driver, implementing a real device requires hardware.The driver is the abstraction layer between software concepts and hardware circuitry; as such, it needs to talk with both of them. Up to now, we have examinedthe internals of software concepts; this chapter completes the picture by showingyou how a driver can access I/O ports and I/O memory while being portableacross Linux platforms.This chapter continues in the tradition of staying as independent of specific hardware as possible.
However, where specific examples are needed, we use simpledigital I/O ports (like the standard PC parallel port) to show how the I/O instructions work, and normal frame-buffer video memory to show memory-mapped I/O.We chose simple digital I/O because it is the easiest form of input/output port.Also, the Centronics parallel port implements raw I/O and is available in mostcomputers: data bits written to the device appear on the output pins, and voltagelevels on the input pins are directly accessible by the processor. In practice, youhave to connect LEDs to the port to actually see the results of a digital I/O operation, but the underlying hardware is extremely easy to use.I/O Ports and I/O MemoryEvery peripheral device is controlled by writing and reading its registers.
Most ofthe time a device has several registers, and they are accessed at consecutiveaddresses, either in the memory address space or in the I/O address space.At the hardware level, there is no conceptual difference between memory regionsand I/O regions: both of them are accessed by asserting electrical signals on the22622 June 2001 16:39http://openlib.org.uaI/O Ports and I/O Memoryaddress bus and control bus (i.e., the read and write signals)* and by reading fromor writing to the data bus.While some CPU manufacturers implement a single address space in their chips,some others decided that peripheral devices are different from memory and therefore deserve a separate address space. Some processors (most notably the x86family) have separate read and write electrical lines for I/O ports, and special CPUinstructions to access ports.Because peripheral devices are built to fit a peripheral bus, and the most popularI/O buses are modeled on the personal computer, even processors that do nothave a separate address space for I/O ports must fake reading and writing I/Oports when accessing some peripheral devices, usually by means of externalchipsets or extra circuitry in the CPU core.
The latter solution is only commonwithin tiny processors meant for embedded use.For the same reason, Linux implements the concept of I/O ports on all computerplatforms it runs on, even on platforms where the CPU implements a singleaddress space. The implementation of port access sometimes depends on the specific make and model of the host computer (because different models use differentchipsets to map bus transactions into memory address space).Even if the peripheral bus has a separate address space for I/O ports, not alldevices map their registers to I/O ports.
While use of I/O ports is common for ISAperipheral boards, most PCI devices map registers into a memory address region.This I/O memory approach is generally preferred because it doesn’t require use ofspecial-purpose processor instructions; CPU cores access memory much more efficiently, and the compiler has much more freedom in register allocation andaddressing-mode selection when accessing memory.I/O Registers and Conventional MemoryDespite the strong similarity between hardware registers and memory, a programmer accessing I/O registers must be careful to avoid being tricked by CPU (orcompiler) optimizations that can modify the expected I/O behavior.The main difference between I/O registers and RAM is that I/O operations haveside effects, while memory operations have none: the only effect of a memorywrite is storing a value to a location, and a memory read returns the last valuewritten there.
Because memory access speed is so critical to CPU performance, theno-side-effects case has been optimized in several ways: values are cached andread/write instructions are reordered.* Not all computer platform use a read and a write signal; some have different means toaddress external circuits. The difference is irrelevant at software level, however, and we’llassume all have read and write to simplify the discussion.22722 June 2001 16:39http://openlib.org.uaChapter 8: Hardware ManagementThe compiler can cache data values into CPU registers without writing them tomemory, and even if it stores them, both write and read operations can operate oncache memory without ever reaching physical RAM. Reordering can also happenboth at compiler level and at hardware level: often a sequence of instructions canbe executed more quickly if it is run in an order different from that which appearsin the program text, for example, to prevent interlocks in the RISC pipeline.