Linux device-driven I/O ports and I/O memory __linux

Source: Internet
Author: User

http://www.cnblogs.com/geneil/archive/2011/12/08/2281367.html


I. Unified address and independent addressing

This part comes from: http://blog.chinaunix.net/space.php?uid=21347954&do=blog&id=443670, thanks to Mason_hu's sharing.
From the CPU to a line: Data bus, address bus, control bus, this line hangs n interfaces, there are the same, there are different, the name is called Memory interface, interrupt control interface, DMA interface, parallel interface, serial interface, AD interface ... A device to access, with its own interface and a matching interface on the bus docking ... Then a variety of devices appear on the bus: memory, hard disk, mouse, keyboard, monitor ...
For the CPU, if it is to send data to a device, is actually sent to the corresponding interface, the interface circuit has multiple registers (also known as the port), the access device is actually access to the relevant port, all the information will be transferred to its device interface. Then the CPU will prepare data to the bus, but many interfaces, which should be sent to. Then you need to assign an address to each interface, then put the address on the address bus select、read, the required control information on the control bus, you can communicate with the device.
For a system, there are usually multiple peripherals, each peripheral interface circuit, there will be more than one port, each port needs an address, for them to identify a specific address value, is the system must be resolved, at the same time, you also have a memory bar, may be 512M or 1G or greater Kingston, Modern DDR2 and the like, each of their addresses also need to allocate an identity value, in addition, many peripherals have their own memory, buffer, like your memory, you also need to allocate memory for them ... Your CPU may need to deal with every byte of it, so: don't expect to be lazy, every inch of their land must be planned. This sounds annoying, and can be done directly to cause all the brain cells to be killed. But things always have to be done, arm may do this: he designed the CPU is 32 bits, can address 2^32=4g space at most, so put this 4GB space to memory and port, let them partition. But Intel may have a better way of allocating ...

1, the concept of the address
1) Physical Address : The address transmitted by the CPU address bus select、read, the hardware circuit controls its specific meaning. A large part of the physical address is reserved for memory in the memory bar, but it is often mapped to other memory (such as memory, BIOS, etc.). After the virtual address in the program instruction passes the segment mapping and the page map, the physical address is generated, and the physical address is placed on the CPU's address line.
Physical address space, part of the physical RAM (memory) used, part of the bus, which is determined by the hardware design, so in the bits address line of the x86 processor, the physical address space is 2 32 times, that is 4GB, but the physical RAM is not generally up to 4GB, Because there is still a part to be used for the bus (there are many other devices hanging on the bus). In the PC, is generally the low-end physical address to RAM, high-end physical address to the bus.
2 Bus address : The address line of the bus or the signal generated on the address cycle. The peripheral uses a bus address, and the CPU uses a physical address. The relationship between the
Physical address and the bus address is determined by the system design. On the x86 platform, the physical address is the bus address, because they share the same address space-this is a bit difficult to understand, as described in the following "independent address." On other platforms, you may need to convert/map. For example: The CPU needs to access the physical address is 0xfa000 unit, then on the x86 platform, will produce a PCI bus on the 0xfa000 address access. Because the physical address is the same as the bus address, it is not possible to determine where the address is used, either in memory, or as a storage unit on a card, or even on this address, with no corresponding memory.

3 virtual Address : Modern operating systems generally use virtual memory management (Memory Management) mechanism, which requires the support of MMU (Memory Management unit). MMU is usually part of the CPU, if the processor is not MMU, or if there is MMU but not enabled, the memory address issued by the CPU execution unit will go directly to the chip pin and be received by the memory chip (physical memory), which is called the Physical Address (physical addresses), If the processor has enabled the memory address issued by the MMU,CPU execution unit to be intercepted by MMU, the address from CPU to MMU is called the virtual address, and MMU translates the address into another address on the external address pin of the CPU chip, That is, the virtual address is mapped to a physical address.

In Linux, the process of 4GB (virtual) memory is divided into user space, kernel space. The user space is distributed as 0~3GB (that is, Page_offset, which equals 0xc0000000 in 0x86), and the remaining 1G is kernel space. Programmers can only use virtual addresses. Each process in the system has its own private user space (0~3G), which is not visible to other processes in the system.
The address of the CPU when requesting the instruction is the virtual address of the current context, MMU the physical address of the virtual address from the page table, and completes the reference. Also read the data is a virtual address, such as Mov ax, var. at compile time Var is a virtual address, it is also through the MMU from the table to find the physical address, and then generate the bus time series, complete data retrieval.

2, the way of addressing
1 peripherals are read and write devices on the register to do, peripheral registers are also known as "I/O port", and IO Port has two ways to address: Independent address and unified programming.
  Unified Address : The IO registers in the peripheral interface (that is, IO port) are treated as the main deposit, each end population with the address of a storage unit, and a part of main memory is used as IO address space, for example, in PDP-11, the highest 4K main memory is used as the IO device register address. The port occupies the memory address space and reduces the storage capacity.
Unified address also known as "I/O Memory" mode, peripheral registers are located in "Memory Space" (many peripherals have their own memory, buffer, peripheral registers and memory collectively referred to as "I/O space").
For example, Samsung's s3c2440 is a 32-bit ARM processor, and its 4GB address space is partitioned by peripherals, RAM, and so on:
0x8000 1000 LED 8*8 dot matrix address
0x4800 0000 ~ 0x6000 0000 SFR (Special Register) address space
0x3800 1002 Keyboard Address
0x3000 0000 ~ 0x3400 0000 SDRAM Space
0x2000 0020 ~ 0x2000 002e IDE
0x1900 0300 CS8900

  Independent address (separate address): The IO address is separately addressed from the storage address, the I/O port address does not occupy the address range of the storage space, so that there is another IO address independent of the storage address in the system, and the CPU must have the IO instruction (in, out etc.) and control logic dedicated to the input and output operation. At a separate address, the address bus select、read comes up with a location where the device does not know whether to give IO ports or to memory, so the processor implements different addressing to I/O ports and storage via MEMR/MEMW and IOR/IOW control signals. For example, Intel 80x86 is a separate address, and CPU memory and I/O are addressed together, that is, the addresses and I/O addresses of parts of memory overlap.
Independent addresses are also known as "I/O ports", and peripheral registers are located in the I/O (address) space.
For x86 architectures, access through in/out directives. PC architecture A total of 65,536 8bit I/O ports, composed of 64K I/O address space, numbered from 0~0XFFFF, 16 bits, 80x86 with a low 16-bit address line a0-a15 addressing. A two consecutive 8bit port can comprise a 16bit port with 4 consecutive ports forming a 32bit. The I/O address space and the CPU's physical address space are two different concepts, such as the I/O address space is 64K, and a 32bit CPU physical address space is 4G. For example, use "More/proc/ioports" under Intel 8086+redhat9.0 to see:
0000-001f:dma1
0020-003f:pic1
0040-005f:timer
0060-006f:keyboard
0070-007f:rtc
0080-008F:DMA Page Reg
00a0-00bf:pic2
00c0-00df:dma2
00f0-00ff:fpu
0170-0177:ide1
......
However, the Intel x86 platform generally uses a technology called Memory Mapping (MMIO), which is part of the PCI specification, and the IO device port is mapped to memory space, and the CPU accesses the IO port as if it were accessing memory. Look at the typical memory address allocation table for the x86/x64 system given by the Intel TA 719 Document:
System Resource Usage
------------------------------------------------------------------------
BIOS 1M
Local APIC 4K
Chipset reserved for 2M
IO APIC 4K
PCI Device 256M
PCI Express Equipment 256M
PCI device (optional) 256M
Display Frame Cache 16M
Tseg 1M

For an established system, it is either a stand-alone address or a unified address, depending on the CPU architecture. For example, PowerPC, m68k and so on adopt the unified address, but X86 and so on uses the independent address, exists the IO space concept. At present, most embedded microcontrollers such as ARM, PowerPC and so on do not provide I/O space, there is only memory space, can directly use the address, pointer access. But for the Linux kernel, it may be used for different CPUs, so it has to be considered in both ways, so it takes a new approach, using the I/O mapping method or memory-mapped I/O port as "I/O region" (I/O region), regardless of the way you use it, You must first apply for IO area: Request_resource (), and release it at the end: Release_resource ().

Second, Linux I/O port and memory

IO port : When a register or memory is in IO space;
IO memory : When a memory or register is in the memory space;

While some CPU manufacturers have implemented a single address space (uniform addressing) on their chips, other CPU manufacturers consider peripherals to be different from memory and should have a separate address space for peripherals (individually addressed), and their production processors (especially the x86 family) i/ The O port has its own read-write signal line and special CPU instructions to access the port. Because peripherals are designed to match peripheral buses, and most popular I/O buses are modeled on personal computers (primarily the x86 family), even processors that do not have a separate address space for I/O ports must be emulated as read-write ports when accessing peripherals. This is usually done via an external chipset (the north-south bridge in the PC) or by attaching additional circuitry to the CPU core (based on the embedded application processor).
For the same reason, Linux has implemented I/O ports on all computer platforms, even on the CPU platforms of those single address spaces (analog I/O ports). However, not all devices will map their registers to the I/O port. Although the I/O ports are commonly used by ISA devices, most PCI devices map registers to a memory address area. This I/O memory method is usually preferred because it eliminates the need for special processor instructions, the CPU access memory is more efficient, and the compiler has more freedom in the choice of register allocation and addressing mode when accessing memory.

The primary difference between

1.IO registers and general memory
I/O registers and RAM is that I/O operations have marginal effects (side effect), while memory operations do not: Access memory only stores values in a single location in memory. Because memory access speeds severely affect CPU performance, the compiler may optimize the source code, primarily by using caching and the order in which read/write instructions are to be reset. These optimizations are transparent and useful for traditional memory (at least in a single-processor system), but for I/O registers, this can be a fatal error because they interfere with those "marginal effects" (the driver accesses the I/O registers to gain marginal effects). Therefore, the driver must ensure that the cache is not used and the order of read and write instructions cannot be rearranged when the registers are accessed.
Side effect refers to: when accessing an I/O register, not only affects the value of the storage cell like normal memory, but more importantly, it may change the CPU's I/O port level, output timing or CPU response to I/O port level, and so on, so as to achieve CPU control function. The meaning of CPU in the circuit is to realize its side effect. For example, the interrupt status registers for some devices are automatically zeroed out as soon as they are read. The problem with

hardware buffering is the easiest: any hardware buffering (I/O memory or I/O ports) is prohibited as long as the underlying hardware configuration (or automatically or through Linux initialization code) is used to access the I/O zone. The solution to the

compiler optimizations and hardware rescheduling of read and write instructions is to place a memory barrier (memory barrier) between the operations that the hardware or the processor must perform in a particular order.

2. Operation IO port (request, access, release) :
I/O port is the way to drive communication with many devices.
(1) applies the I/O port :
should not operate on the port until the device is not fully exclusive. The kernel provides a registration interface to allow drivers to declare the ports they need:

/* Request_region tells the kernel: N ports to use first. The parameter name is the device name. If the assigned successful return value is Non-null, you cannot use the port you need (/proc/ioports contains the allocation information for all current ports on the system, and if the Request_region allocation fails, you can view the file to see who first used the port you want)
. struct Resource *request_region (unsigned long, unsigned long n, const char *name);

(2) access to IO ports:

After the driver successfully requests to the I/O port, you can read and write these ports. Most hardware separates the 8-bit, 16-bit, and 32-bit ports, and cannot be used as confusing as accessing memory. The driver must call different functions to access ports of different sizes.
The Linux kernel header file (System dependent header file <asm/io.h>) defines the following inline functions to access the I/O port:

/* INB/OUTB: Read/write section port (8-bit wide). Some systems define the port parameter as unsigned long, while some platforms define it as unsigned short. The return type of INB is also a
/unsigned inb (unsigned port) of the dependent system;
void Outb (unsigned char byte, unsigned port);

/* INW/OUTW: Read/write port (16-bit wide)/
unsigned inw (unsigned port);
void outw (unsigned short word, unsigned port);

/* Inl/outl: Read/write 32-bit port. Longword is also dependent on the system, and some systems are unsigned long, while some are unsigned int
/unsigned inl (unsigned port);
void Outl (unsigned longword, unsigned port);

(3) Free IO port:

/* After the I/O port is exhausted (possibly when the module is unloaded), you should call Release_region to return the I/O port to the system. The parameter start and N should be passed to the request_region consistent
/void release_region (unsigned long start, unsigned long n);

3. Operation IO Memory (application, mapping, access, release ):
Although I/O ports are very popular in the x86 world, the primary mechanism for communicating with devices is memory-mapped registers and device memory, both of which are called I/O memory, because the difference between registers and memory is transparent to the software.
I/O memory is just a ram-like area where the processor accesses the zone through the bus to enable access to the device. Similarly, reading and writing is a marginal effect of the region.
Depending on the computer system and the bus, I/O memory can be divided into can or can not be accessed through the page table. If accessed through the page table, the kernel must first rearrange the physical address to make it visible to the driver, which means that you must invoke Ioremap before any I/O operation is done, and if you do not need a page table, I/O memory zones are similar to I/O ports and you can read and write them directly using the appropriate I/O functions
Because of the marginal effect, it is discouraged to use the I/O memory pointers directly, regardless of whether the ioremap is needed, instead of using specialized I/O memory operation functions. These I/O memory operation functions are not only secure on all platforms, but are optimized for directly manipulating I/O memory using pointers.

(1) Application for I/O Memory:
The I/O memory area must be allocated before use. function interface for allocating memory area in <linux/ioport.h> definition:

/* Request_mem_region allocates an I/O memory area that starts with Start,len bytes. The assignment succeeds, returns a non-null pointer, or returns NULL. All current I/O memory allocation information is listed in the/proc/iomem file, you can check the file when you assign a failure, see who occupies the memory area first/
struct resource *request_mem_region (unsigned Long start, unsigned long len, char *name);

(2) Mapping:
Allocating I/O memory is not the only required step prior to accessing I/O memory, and you must also ensure that the kernel has access to the I/O memory. Access to I/O memory is not just a simple dereference pointer, in many systems, I/O memory cannot be accessed directly in this way. Therefore, you must also set up a mapping through the IOREMAP function.

/* Ioremap is used to map the I/O memory area to a virtual address. Parameter phys_addr is the starting address of the I/O memory to map, the parameter size is the size of the I/O memory to map, the return value is the virtual address that is mapped to/
void *ioremap (unsigned long phys_addr, unsigned Long size);

(3) Accessing IO Memory:
After Ioremap, the device driver can access any I/O memory address. Note that the address returned by Ioremap is not directly solvable; instead, you should use the access functions provided by the kernel. The correct way to access I/O memory is through a series of functions specifically designed to accomplish this:

#include <asm/io.h> * I/O memory read function. The parameter addr should be the address obtained from the Ioremap (possibly containing an integer offset);
The return value is the value read from the given I/O memory/unsigned int ioread8 (void *addr);
unsigned int ioread16 (void *addr);

unsigned int ioread32 (void *addr); /* I/O memory write function.
Parameter addr with I/O memory read function, parameter value is the value to write/void Iowrite8 (U8 value, void *addr);
void Iowrite16 (U16 value, void *addr);

void Iowrite32 (u32 value, void *addr); /* The following functions read and write a series of values to a given I/O memory address, reading or writing count values from a given buf to a given addr.
The parameter count represents the number of data to read, not the byte size/void Ioread8_rep (void *addr, void *buf, unsigned long count);
void Ioread16_rep (void *addr, void *buf, unsigned long count);
void Ioread32_rep (void *addr, void *buf, unsigned long count);
void Iowrite8_rep (void *addr, const void *buf, unsigned long count);
void Iowrite16_rep (void *addr, const void *buf, unsigned long count);

void Iowrite32_rep (void *addr,,onst void *buf,,nsigned long Count);
/* When you need to manipulate an I/O address, use the following functions (these functions behave like their C-Library-like functions): */void Memset_io (void *addr, U8 value, unsigned int count); void Memcpy_fromio (void *dest, void *source, UnsigNed int count);

void Memcpy_toio (void *dest, void *source, unsigned int count);
/* old I/O memory read-write function, do not recommend the use of * * unsigned readb (address);
unsigned readw (address); 
unsigned readl (address);
void Writeb (unsigned value, address);
void Writew (unsigned value, address); void Writel (unsigned value, address);

(4) Free IO memory steps:

void Iounmap (void * addr); /* Iounmap for releasing mappings that are no longer needed
/void release_mem_region (unsigned long start, unsigned long len);/* Iounmap for releasing mappings that are no longer needed * *

4. Use ports like IO memory

Some of the hardware has an interesting feature: Some versions use I/O ports, while others use I/O memory. Regardless of the I/O or I/O memory, the processor sees the same device registers, except that the access methods are different. To make the driver easy to write for a unified programming interface, the 2.6 kernel provides a ioport_map function:

/* Ioport_map to Remap count I/O ports so that they look I/O memory. Thereafter, the driver can use IOREAD8 and similar functions on the address returned by Ioport_map. This allows you to eliminate the difference between I/O and memory in programming,/
void *ioport_map (unsigned long port, unsigned int count);

void Ioport_unmap (void *addr);/* Ioport_unmap for releasing mappings that are no longer needed * *

Note that the I/O ports must allocate the required I/O ports using request_region before remapping.

5, the IO operation interface of the arm system
S3c24x0 processor uses I/O memory , which means that the S3c24x0 processor uses a unified address approach, i/ o Registers and memory use a single address space, and the instructions for reading and writing I/O registers and read and write memory are the same. Therefore, I recommend the use of I/O memory related instructions and functions. However, this does not indicate that the I/O port directives are not available in s3c24x0. If you have noticed s3c24x0 about I/O kernel source code, you will find: actually I/O port instruction is only a shell, internal or use the same as I/O memory. Note the following:
1) All of the Read and write instructions (I/O operation functions) are assigned addresses must be virtual address, you have two options: the use of the kernel has been defined as a good address, such as in the include/asm-arm/arch-s3c2410/ Regs-xxx.h defines the address of the S3C2410 processor's peripheral registers (other processor chips can also find the virtual address of the kernel-defined peripheral registers in a similar path; another way is to use the virtual address that you have mapped with Ioremap. The actual physical address can never be used, otherwise the oops will appear because the kernel cannot handle the address.
2) When using I/O directives, you can use request_region and request_mem_region without using the instructions Outb, Ioread, and so on. Because the function of request only tells the kernel port to be occupied by WHO, if request again, the kernel will stop (resource busy). However, this is not recommended, such code is not standardized, may cause concurrency problems (many times we need to monopolize the device).
3) When using I/O directives, the assigned address data must sometimes be cast to unsigned long by coercion, or there will be a warning.
4) In the include\asm-arm\arch-s3c2410\hardware.h defines a lot of IO port operation functions, there is a need to be used directly in the drive, very convenient.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.