In the process of writing Linux drivers, DMA programming is a very important technology. It can achieve high-speed data transmission and improve system performance and response speed. In this article, we will delve into the implementation principles and related technologies of Linux driver technology (3) _DMA programming.
DMA, Direct Memory Access, is a technology that allows peripherals to directly access memory data without CPU involvement. When the peripherals complete reading and writing the memory, DMAC notifies the CPU through interrupts. This technology is multi-purpose It is suitable for peripheral control that has high requirements on data volume and data transmission speed, such as display devices, etc.
We know that in order to improve system operating efficiency, modern CPUs adopt a multi-level cache structure, which includes the use of multi-level Cache technology to cache data in memory to alleviate the problem of CPU and memory speed differences. Under this premise, it is obvious that if the data in the DMA memory has been cached by the Cache, and the peripheral modifies the data, this will cause a mismatch between the Cache data and the memory data, that is, DMA and Cache Consistency issue. In order to solve this problem, the simplest way is to disable the Cache function of DMA memory. Obviously, this will lead to a decrease in performance
In a computer with an MMU, the CPU sees the virtual address, which is converted into a physical address after being sent to the MMU. The virtual address is then converted into ## through the corresponding circuit. #Bus address is the address seen by the peripheral. Therefore, the address seen by the DMA peripheral is actually the bus address. The Linux kernel provides corresponding APIs to achieve conversion between three types of addresses:
//虚拟->物理 virt_to_phys() //物理->虚拟 ioremap() //虚拟->总线 virt_to_bus() //总线->虚拟 bus_to_virt()
int dma_set_mask(struct device *dev,u64 mask);
dma_set_mask(dev,0xffffff)
/** * request_dma - 申请DMA通道 * On certain platforms, we have to allocate an interrupt as well... */ int request_dma(unsigned int chan, const char *device_id); /** * dma_alloc_coherent - allocate consistent memory for DMA * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices * @size: required memory size * @handle: bus-specific DMA address * * Allocate some memory for a device for performing DMA. This function * allocates pages, and will return the CPU-viewed address, and sets @handle * to be the device-viewed address. */ void * dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag) //申请PCI设备的DMA缓冲区 void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) //释放DMA缓冲区 void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr_t dma_handle ) //释放PCI设备的DMA缓冲区 void pci_free_consistent() /** * free_dma - 释放DMA通道 * On certain platforms, we have to free interrupt as well... */ void free_dma(unsigned int chan);
/** * request_dma - 申请DMA通道 * On certain platforms, we have to allocate an interrupt as well... */ int request_dma(unsigned int chan, const char *device_id); //映射流式DMA dma_addr_t dma_map_single(struct device *dev,void *buf, size_t size, enum dma_datadirection direction); //驱动获得DMA拥有权,通常驱动不该这么做 void dma_sync_single_for_cpu(struct device *dev,dma_addr_t dma_handle_t bus_addr,size_t size, enum dma_data_direction direction); //将DMA拥有权还给设备 void dma_sync_single_for_device(struct device *dev,dma_addr_t dma_handle_t bus_addr,size_t size, enum dma_data_direction direction); //去映射流式DMA dma_addr_t dma_unmap_single(struct device *dev,void *buf, size_t size, enum dma_datadirection direction); /** * free_dma - 释放DMA通道 * On certain platforms, we have to free interrupt as well... */ void free_dma(unsigned int chan);
The above is the detailed content of In-depth discussion of Linux driver technology (3) _The implementation principles and related technologies of DMA programming. For more information, please follow other related articles on the PHP Chinese website!