ֱ���ڴ��ȡ, ���� DMA, �ǽ������ǵ��ڴ���������ĸ�����. DMA ��Ӳ�������������������ֱ�Ӵ������ǵ� I/O ���ݵ��ʹ����ڴ�, ������Ҫ����ϵͳ������. ���ֻ��Ƶ�ʹ���ܹ��ܴ�������������ʹ�һ���豸, ��Ϊ�����ļ��㿪����������.
�ڽ��ܳ���ϸ��֮ǰ, �����ǻع�һ�� DMA ������η�����, ֻ�������봫����������.
���ݴ������ 2 �ַ�������:����������������(ͨ��һ���������� read)����Ӳ���첽�����ݵ�ϵͳ.
�ڵ�һ�����, �����IJ����ܽ�����:
1. ��һ�����̵��� read, ������������һ�� DMA ���岢����Ӳ���������������ݵ��Ǹ�����. ������̱���Ϊ˯��.
2. Ӳ��д���ݵ���� DMA ���岢���������ʱ����һ���ж�.
3. �жϴ��������������, ȷ���ж�, ���һ��ѽ���, �����ڿ��Զ�������.
�� 2 ����������ǵ� DMA ���첽ʹ��. ����, �ⷢ�������ݻ�ȡ�豸, ����û���˶����ǵ�ʱ��Ҳ������������. ����������, ����Ӧ��ά��һ�����������ں����Ķ������ܷ������е��ۻ������ݸ��û��ռ�. ���ഫ������IJ����е㲻ͬ:
1. Ӳ������һ���ж��������������Ѿ�����.
2. �жϴ�������һ�����岢�Ҹ�֪Ӳ�������ﴫ������.
3. ����д���ݵ����岢��������һ���жϵ����ʱ.
�����߷���������, �����κ���صĽ���, ���Ҹ�������.
�첽�����ı��峣���������м���. ��Щ��������������һ�����ڴ��кʹ����������Ļ��λ���(��������Ϊһ�� DMA �Ļ���); ÿ�������ı��ı������ڻ�����һ�����õĻ���, ���ҷ���һ���ж�. �������Ŵ������籾�ĵ��ں��������ֲ����ڻ��з���һ���� DMA ����.
��������Щ����еĴ����IJ��趼ǿ��, ��Ч�� DMA ���������жϱ���. ��Ȼ����ʵ�� DMA ʹ��һ����ѯ����, ��������������, ��Ϊһ����ѯ���������˷� DMA �ṩ�������洦���������Ĵ�����������I/O.[49]
��������ܵ���һ��������� DMA ����. DMA Ҫ���豸����������һ������������ʺ� DMA �Ļ���. ע�����������������ǵĻ����ڳ�ʼ��ʱ����ʹ������ֱ���ر� -- ��֮ǰ�б��еķ���һ��, ��˼��"���һ��֮ǰ����Ļ���".
���ں��� DMA �����ڵײ�ķ���; �����Ժ����һ�����ӿ�, ��������������չʾ����������һ��������.
�� DMA �����������Ҫ������, �����Ǵ���һҳ, ���DZ���ռ�������ڴ������ҳ��Ϊ�豸ʹ�� ISA ���� PCI ϵͳ���ߴ�������, ���Ƕ�ʹ��������ַ. ע����Ȥ����������Ʋ����� SBus ( �� 12 �µ�"SBus"һ�� ), ��������������ʹ�������ַ. һЩ��ϵ�ṹ�������� PCI ������ʹ�������ַ, ����һ������ֲ���������������������.
���� DMA ����ɱ����������ϵͳ����ʱ����������ʱ, ģ��ֻ��������ʱ�������ǵĻ���. (�� 8 �½�����Щ����; "��ȡ��"һ�ں�����ϵͳ����ʱ����, ��"kmalloc ����ʵ"��"get_free_page ������"����������ʱ����). ������д�߱�����ķ�����ȷ���ڴ�,���������� DMA ����ʱ; ���������ڴ����Ǻ��ʵ�. �ر��, ��һЩϵͳ�е�һЩ�豸�ϸ߶��ڴ���ܲ�Ϊ DMA ���� - ������ȫ��ʹ�ø߶˵�ַ.
���ִ������ϵĴ��豸���Դ��� 32-λ ��ַ, ��˼���������ڴ����������Ǹոպõ�. һЩ PCI �豸, ����, ����ʵ�������� PCI �����Ҳ���ʹ�� 32-λ ��ַ. ���� ISA �豸, ��Ȼ, ����ֻ�� 24-λ ��ַ.
�������������Ƶ��豸, �ڴ�Ӧ���� DMA �����з���, ͨ������ GFP_DMA ��־�� kmalloc ���� get_free_pages ����. �������־����, ֻ�п��� 24-λ Ѱַ���ڴ汻����. ��һ��ѡ��, �����ʹ��ͨ�õ� DMA ��( ��������������� )�����仺���Խ������豸������.
�����Ѽ��� get_free_pages ��η���ֱ������ MByte (���� order ����ֱ�� MAX_ORDER, ��ǰ�� 11), ���Ǹ�������������ʧ�ܵ�����Ļ���ԶԶС�� 128 KB, ��Ϊϵͳ�ڴ�ʱ�䳤�˱������.[50]
���ں������������������ڴ���ߵ�����Ҫ���� 128 KB(����, һ��ͨ���� PCI ֡ץȡ������), һ��������� -ENOMEM ��������������ʱ�����ڴ���߱������� RAM �Ķ�������Ļ���. �����ڵ� 8 �µ� "��ô�������" һ������������ʱ�����, ��������ģ���Dz����õ�. ���� RAM �Ķ�����ͨ��������ʱ����һ�� mem= �������ں�ʵ�ֵ�. ����, ������� 256 MB, ���� mem=255M ʹ�ں˲�ʹ�ö����� MByte. ���ģ����ܺ���ʹ�����д�������ö�����ڴ�Ĵ�ȡ:
dmabuf = ioremap (0xFF00000 /* 255M */, 0x100000 /* 1M */);
������, ��ϱ�������Ӵ����һ����, �ṩ��һ���� API ��̽����������ı��� RAM �������ڼ�����ϵ�ϱ��ɹ�ʹ��. ����, ������ɵ�����һ�����ڴ�ϵͳʱ��Ч(��, һ���б��ʺ� CPU ��ַ�ռ����������ڴ��ϵͳ ).
��Ȼ, ��һ��ѡ��, ��ʹ�� GFP_NOFAIL ��������Ļ���. �������, ����, ȷʵ���صض��ڴ������ϵͳ��ѹ��, ������ð��סϵͳ�ķ���; ����DZ������ȷʵû����������.
��������һ���� DMA ���嵽�����ij���, ����, ֵ����һ������ķ���. �������豸��������ɢ/��� I/O, ����Է�����Ļ����Ը�С��Ƭ�β������豸��������. ��ɢ/��� I/O Ҳ�����õ�����ֱ�� I/O ���û��ռ�ʱ, ����������õؽ����������Ҫһ��������ʱ.
һ��ʹ�� DMA ���豸������������ӵ��ӿ����ߵ�Ӳ��ͨѶ, ����ʹ��������ַ, ���������ʹ�������ַ.
��ʵ��, ������������Щ����. ����DMA ��Ӳ��ʹ�����ߵ�ַ, ������������ַ. ���� ISA �� PCI ���ߵ�ַ�� PC ����ȫ��������ַ, ���ÿ��ƽ̨ȴ���������. ��ʱ�ӿ����߱�ͨ���Žӵ�·����, ��ӳ�� I/O ��ַ����ͬ��������ַ. һЩϵͳ������һ��ҳӳ�����, ʹ�����ҳ������������������.
����ͼ���(�ٴ�, ���ǽ����ϲ鿴һ�����������), Linux �ں��ṩһ������ֲ�ķ���, ͨ��������к���, �� <asm/io.h> ����. ��Щ������ʹ�ò����Ƽ�, ��Ϊ����ֻ���зdz��� I/O ��ϵ��ϵͳ����������; ����, ������������ǵ�ʹ���ں˴���ʱ.
unsigned long virt_to_bus(volatile void *address); void *bus_to_virt(unsigned long address);
��Щ��������һ����ת�����ں�����ַ�����ߵ�ַ֮��. ��������������²�����, һ�� I/O �ڴ������Ԫ���뱻��̵ĵط����߱���ʹ�÷�������ĵط�. �����ת������ȷ������ʹ��ͨ�õ� DMA ��, �����������ת�Ƶ��������.
DMA ����, ���, �µ�����һ�����岢�Ҵ������ߵ�ַ������豸. ����, ��д��������ϵ�ϰ�ȫ����ȷ���� DMA �Ŀ���ֲ����������������Ҫ��. ��ͬ��ϵͳ�в�ͬ�ĸ���, ���ڻ���һ����Ӧ����ι����ĸ���; ����㲻��ȷ�����������, ������������ƻ��ڴ�. һЩϵͳ�и��ӵ�����Ӳ��, ��ʹ DMA ��������� - ���߸���. ���Ҳ������е�ϵͳ�������ڴ����в��ֽ��� DMA. ���˵���, �ں��ṩ��һ�����ߺ���ϵ������ DMA �����������������ش���Щ����. ���Ƿdz���������ʹ��������� DMA ����, ���κ����д��������.
��������ຯ����Ҫһ��ָ�� struct device ��ָ��. ����ṹ�� Linux �豸ģ�����豸�ĵͼ���ʾ. ������������������ֱ��ʹ�õĶ���, ������ȷʵ��Ҫ����ʹ��ͨ�� DMA ��ʱ. ������, ��ɷ�������ṹ, ��������������豸������. ����, ������ struct pci_device ���� struct usb_device �з�������Ϊ dev ��Ա. �豸�ṹ�� 14 ������ϸ����.
ʹ�����溯��������Ӧ������ <linux/dma-mapping.h>.
�ڳ��� DMA ֮ǰ����ش�ĵ�һ�������Ǹ����豸�Ƿ��ܹ��ڵ�ǰ�������������IJ���. �����豸�����������ܹ�Ѱַ���ڴ淶Χ, ��Ϊ��������. ȱʡ��, �ں˼ٶ�����豸�ܹ����κ� 32-λ ��ַ���� DMA. �����������, ��Ӧ��֪ͨ�ں������ʵ, ʹ��һ������:
int dma_set_mask(struct device *dev, u64 mask);
mask Ӧ����ʾ����豸�ܹ�Ѱַ��λ; ����������Ƶ� 24 λ, ����, ��Ҫ���� mask ��Ϊ 0x0FFFFFF. ����ֵ�Ƿ������ʹ�ø����� mask ���� DMA; ��� dma_set_mask ���� 0, �㲻�ܶ�����豸ʹ�� DMA ����. ���, �豸�������еij�ʼ���������Ƶ� 24-λ DMA �������ܿ�����:
if (dma_set_mask (dev, 0xffffff)) card->use_dma = 1; else { card->use_dma = 0; /* We'll have to live without DMA */ printk (KERN_WARN, "mydev: DMA not supported\n"); }
�ٴ�, �������豸֧��������, 32-λ DMA ����, û�б�Ҫ���� dma_set_mask.
һ�� DMA ӳ���Ƿ���һ�� DMA ����Ͳ���һ���豸���Դ�ȡ�ĵ�ַ�Ľ��. ����ͼʹ��һ���Ķ� virt_to_bus �ĵ�������������ַ, �����г�ֵ������������Ǹ�����. �����еĵ�һ���Ǻ�����Ӳ������һ�� IOMMU ��Ϊ�����ṩһ��ӳ��Ĵ���. IOMMU ��Ϊ�κ������ڴ氲�����������豸�ɴ�ȡ�ĵ�ַ��Χ��, ��������ʹ������ɢ���Ļ�����豸������������. ʹ�� IOMMU ��Ҫʹ��ͨ�õ� DMA ��; virt_to_bus �������������.
ע�ⲻ�����е���ϵ����һ�� IOMMU; �ر��, ���е� x86 ƽ̨û�� IOMMU ֧��. һ����ȷ��д����������Ҫ֪������֮�����е� I/O ֧��Ӳ��, ����.
Ϊ�豸����һ�����õĵ�ַ����Ҳ, ��ijЩ�����, Ҫ��һ����������Ľ���. ���������ǵ�һ��������ͼ��һ�����費�ܴﵽ�ĵ�ַ�Ͻ��� DMA ʱ������, ����һ�����ڴ��ַ. ���ݽ��Ÿ�����Ҫ���������ʹӷ�������. ����˵, ���������ʹ������������, ������ʱû������ѡ��.
DMA ӳ��Ҳ����������һ��������. ��ס�ִ����������������ȡ���ڴ����Ŀ�����һ�����ٵı��ػ�����; ���û���������, �����������Dz����ܵ�. �������豸�ı�����һ����, ��ǿ��ʹ�κΰ����Ǹ����Ĵ��������汻ʧЧ; ������������ʹ�ò���ȷ������ӳ��, ���ҵ��������ƻ�. ���Ƶ�, ������豸ʹ�� DMA ���������ж�ȡ����, �κζ��Ǹ�פ���ڴ�����������ڴ�ĸı�������ȱ�ˢ��. ��Щ����һ����������Բ�����ͷ��ģ������Ѱ�Ĵ���, �������߲�С��. һ����ϵ��Ӳ���й�������һ����, ����������Ҫ������֧��. ͨ�õ� DMA ������ܶ�����֤��������ϵ�����鶼��ȷ����, ����, ��ͬ���ǽ�������, ��ȷ����ΪҪ�����һЩ����.
DMA ӳ������һ��������, dma_addr_t, ���������ߵ�ַ. ���� dma_addr_t �ı���Ӧ������������������; Ψһ�������IJ����Ǵ������ǵ� DMA ֧�ֹ��̺��豸����. ��Ϊһ�����ߵ�ַ, dma_addr_t �ɵ��²���������������� CPU ֱ��ʹ��.
PCI ������ 2 �� DMA ӳ�������Բ�ͬ, ���� DMA ���屻����ͣ���ʱ��:
Coherent DMA mappings����� DMA ӳ��. ��Щӳ�䳣�����������������ڴ���. һ������Ļ��������ͬʱ�� CPU ���������(������ӳ������, ��ͬ����֮������, ���κθ���ʱ��ֻ��һ������һ������). ���, һ�µ�ӳ������ڻ���һ�µ��ڴ�. һ�µ�ӳ�佨����ʹ�ÿ����ǰ����.
Streaming DMA mappings�� DMA ӳ��. ��ӳ�䳣��Ϊһ��������������. һЩ��ϵ��ʹ����ӳ��ʱ��������Ż�, ����������, ������Щӳ��Ҳ����һ�����ϸ�Ĺ�����δ�ȡ���ǵĹ���. �ں˿����߽���ʹ��һ��ӳ���������ӳ�����κο��ܵ�ʱ��. ��������� 2 ��ԭ��. ��һ��, ��֧��ӳ��Ĵ�����ϵͳ��, ÿ�� DMA ӳ����������ʹ������һ������. һ��ӳ��, �г�����������, ���Գ�ʱ���ռ��Щ�Ĵ���, ���������Dz���ʹ��ʱ. ����һ��ԭ����, ��ijЩӲ����, ��ӳ�����������һ��ӳ����ʹ�õķ������Ż�.
�� 2 ��ӳ�����ͱ����Բ�ͬ�ķ�ʽ����; ��ʱ��ϸ����.
һ���������Խ���һ��һ��ӳ��, ʹ�ö� dma_alloc_coherent �ĵ���:
void *dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, int flag);
���������������ķ����ӳ��. ǰ 2 ���������豸�������Ҫ�Ļ����С. ����������� DMA ӳ��Ľ���� 2 ���ط�. ������������ķ���ֵ�ǻ����һ���ں������ַ, ���ɱ�����ʹ��; �����ص����ߵ�ַ�� dma_handle �з���. ��������������б������������屻������һ������ʹ�� DMA ��λ��; �������ڴ�ֻ��ʹ�� get_free_pages ������(����ע���С�����ֽڼƵ�, ������һ�� order ֵ). flag ������ͨ���� GFP_ ֵ�������ڴ���α�����; ����Ӧ���� GFP_KERNEL (����) ���� GFP_ATOMIC (����ԭ��������������ʱ).
��������Ҫ����(������ģ��ж��ʱ), ��Ӧ�������ظ�ϵͳ, ʹ�� dma_free_coherent:
void dma_free_coherent(struct device *dev, size_t size, void *vaddr, dma_addr_t dma_handle);
ע��, �������������ͨ���� DMA ����, ��Ҫ�ṩ���еĴ�С, CPU ��ַ, �� ���ߵ�ַ����.
һ�� DMA�� �Ƿ���С��, һ��DMAӳ��ķ������. �� dma_alloc_coherent ��õ�ӳ�������һҳ����С��С. ������������Ҫ���Ǹ���С�� DMA ����, ��Ӧ������ʹ��һ�� DMA ��. DMA ��Ҳ���������������, ���������ͼ��Ƕ��һ����ṹ�е�С������� DMA ����. һЩ�dz�ģ�������������ѱ��ٵ�����һ��������, �ڿ���С DMA ����Ľṹ��Ա. Ϊ�����������, ��Ӧ��һֱ��ȷ������� DMA ����������, �������ķ� DMA ���ݽṹ�ֿ�.
DMA �غ��������� <linux/dmapool.h>.
һ�� DMA �ر�����ʹ��ǰ����, ʹ��һ������:
struct dma_pool *dma_pool_create(const char *name, struct device *dev, size_t size, size_t align, size_t allocation);
����, name �dzص�����, dev ������豸�ṹ, size ��Ҫ������ط���Ļ�������С, align �����Գصķ���Ҫ���Ӳ������(���ֽڱ����), �Լ� allocation��, �������, һ�����䲻Ӧ��Խ�����ڴ�߽�. ��� allocation �� 4096 ����, ����, �ӳط���Ļ��岻Խ�� 4-KB �߽�.
��������һ����, �ɱ��ͷ�, ��:
void dma_pool_destroy(struct dma_pool *pool);
��Ӧ���������еķ������, ��������֮ǰ. ���䱻�� dma_pool_alloc ����:
void *dma_pool_alloc(struct dma_pool *pool, int mem_flags, dma_addr_t *handle);
���������, mem_flags �dz��õ� GFP_ �����־������. ������ж�����˳��, һ���ڴ���(��С�ǵ��ش���ʱָ����)������ͷ���. ���� dam_alloc_coherent, ��� DMA �����ַ��������Ϊһ���ں������ַ, ����Ϊһ�����ߵ�ַ������ handle.
����Ҫ�Ļ���Ӧ�����س�, ʹ��:
void dma_pool_free(struct dma_pool *pool, void *vaddr, dma_addr_t addr);
��ӳ���һ��ӳ���и����ӵĽӿ�, �м���ԭ��. ��Щӳ����Ϊʹ��һ���������Ѿ�����Ļ���, ���, ���봦������û��ѡ��ĵ�ַ. ��һЩ��ϵ��, ��ӳ��Ҳ�����ж����������ҳ�Ͷಿ�ֵ�"��ɢ/���"����. ������Щԭ��, ��ӳ���������Լ���һ��ӳ�亯��.
������һ����ӳ��ʱ, ������֪�ں����������ĸ�����. һЩ����(enum dam_data_direction ����)��Ϊ�˶���:
�� 2 ������Ӧ�����Խ��͵�. ������ݱ���������豸(��Ӧ��, Ҳ��, ��һ�� write ϵͳ����), DMA_IO_DEVICE Ӧ����ʹ��; ȥ�� CPU ������, �෴, �� DMA_FROM_DEVICE ��־.
������ݱ�����һ�����ƶ�, ʹ�� DMA_BIDIRECTIONAL.
�������ֻ��Ϊһ�����Ը������ṩ. ��ͼʹ�ô��������Ļ��嵼���ں˱���.
����������ʱ������ͼֻʹ�� DMA_BIDIRECTIONAL, ������������Ӧ���ֵ�ס����ջ�. ��һЩ��ϵ��, ���ѡ�����������ʧ.
�����е�������Ҫ����, ʹ�� dma_map_single ��ӳ����:
dma_addr_t dma_map_single(struct device *dev, void *buffer, size_t size, enum dma_data_direction direction);
����ֵ�����ߵ�ַ, ����Դ��ݵ��豸, ������ NULL ����д���.
һ���������, ӳ��Ӧ���� dma_unmap_single ��ɾ��:
void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, enum dma_data_direction direction);
����, size �� direction ��������ƥ����Щ����ӳ�仺���.
һЩ��Ҫ�Ĺ����������� DMA ӳ��:
�����������ֻƥ������ӳ��ʱ�����ķ���Ĵ���.
һ��һ�������ѱ�ӳ��, ����������豸, ���Ǵ�����. ֱ����������ѱ�ȥӳ��, ������Ӧ�����κη�ʽ������������. ֻ�ڵ��� dma_unmap_single �������ſɰ�ȫ��ȡ���������(��һ������, �������ϼ���). ����������, �����������һ���ڱ�д���豸�Ļ��岻�ܱ�ӳ��, ֱ�����������е�Ҫд������.
���������벻��ӳ��, �� DMA ��Ȼ����, ����϶��������ص�ϵͳ���ȶ�.
��������Ϊʲôһ��һ�������ѱ�ӳ�������Ͳ�����ʹ����. Ϊʲô�������������ʵ������ 2 ��ԭ��. ��һ, ��һ������Ϊ DMA ����ӳ��, �ں˱���ȷ�������е����е�����ʵ�����ѱ�д���ڴ�. �п���һЩ�����ڴ������Ļ��浱 dma_unmap_single ������ʱ, ���ұ��뱻��ȷˢ��. ����������ˢ�º�д�뻺������ݿ��ܶ��豸���ɼ�.
�ڶ�, ����һ�»ᷢ��ʲô, ����ӳ��Ļ�����һ�����豸���ɴ�ȡ���ڴ���. һЩ��ϵ�������������ȫʧ��, ���������Ĵ���һ����������. ��������ֻ��һ���ֿ����ڴ���, �����豸�ɴ�ȡ. ���һ�����屻ӳ��ʹ�� DMA_TO_DEVICE ����, ����Ҫ��һ����������, ԭʼ�����������Ϊӳ�������һ���ֱ�����. ���Ե�, �ڿ�����Ķ�ԭʼ����ĸı��豸������. ���Ƶ�, DMA_FROM_DEVICE �������屻 dma_unmap_single ���ص�ԭʼ����; �����豸������ֱ��������ɲų���.
żȻ��, Ϊʲô�����ȷ��������Ҫ��, ����������һ��ԭ��. DMA_BIDIRECTIONAL ���������ڲ���ǰ����, �ⳣ����һ�� CPU ���ڵIJ���Ҫ�˷�.
ż��һ��������Ҫ��ȡһ���� DMA ��������ݶ���ӳ����. ���ṩ��һ�������������:
void dma_sync_single_for_cpu(struct device *dev, dma_handle_t bus_addr, size_t size, enum dma_data_direction direction);
�������Ӧ���ڴ�������ȡһ���� DMA ����ǰ����. һ���������������, CPU "ӵ��" DMA ���岢�ҿ�����ʹ����. ���豸��ȡ�������ǰ, ����, ӵ��ȨӦ�����ݻظ���, ʹ��:
void dma_sync_single_for_device(struct device *dev, dma_handle_t bus_addr, size_t size, enum dma_data_direction direction);
������, ��һ��, �ڵ������֮��Ӧ����ȡ DMA ����.
żȻ��, ������뽨��һ�������ӳ��, �����������һ�� struct page ָ��; ����, ����ܷ�����ʹ�� get_user_pages ӳ���û�����. Ϊ������ȡ����ӳ��ʹ�� struct page ָ��, ʹ������:
dma_addr_t dma_map_page(struct device *dev, struct page *page, unsigned long offset, size_t size, enum dma_data_direction direction); void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, enum dma_data_direction direction);
offset �� size �����ɱ�����ӳ��ҳ�IJ���. ����, ���鲿��ҳӳ��Ӧ������, ����������ȷ��������ʲô. ӳ��һҳ�IJ��ֿ��ܵ��»���һ��������, ����������ֻ����һ�������ߵ�һ����; ��, ��֮, �ᵼ���ڴ��ƻ������ص����Ե��ԵĴ���.
��ɢ/���ӳ����һ���������͵��� DMA ӳ��. �������м�������, ����Ҫ�������ݵ����ߴ��豸. �����������Լ�����ʽ, ������һ�� readv ���� writev ϵͳ����, һ���ɴصĴ��� I/O ����, ����һ��ҳ������һ����ӳ����ں� I/O ����. ��ɼ�ӳ��ÿ������, ������, ���ҽ���Ҫ��IJ���, �����м����ŵ���һ��ӳ����������.
�����豸���Խ���һ��ɢ��������ָ��ͳ���, ���Ҵ�������ȫ����һ�� DMA ������; ����, "�㿽��"�����Ǹ�������������ڶ��Ƭ�н���. ��һ��ӳ�䷢ɢ�б�Ϊһ�����������������������Ӳ������ӳ��Ĵ�����ϵͳ. ��������ϵͳ��, �����ϲ�������ҳ���豸�Ĺ۵㿴�ɱ��㼯Ϊһ��������, ����������. �������ֻ��ɢ�����е����ڳ����ϵ���ҳ��С(���˵�һ�������һ��), ���ǵ������������ʱ, ����ת�����������һ�������� DMA, ��������Եļ�������.
���, ���һ������������뱻ʹ��, Ӧ�����������б�Ϊһ����������(��Ϊ���ڱ����κη�ʽ����).
���������ȷ��ɢ������ӳ����ijЩ�������ֵ�õ�. ӳ��һ��ɢ�����ĵ�һ���Ǵ��������һ�� struct scatterlist ����, ������������Ļ���. ����ṹ����ϵ������, ������ <asm/scatterlist.h> ������. ����, ���������� 3 ����Ա:
struct page ָ��, ��Ӧ�ڷ�ɢ/��۲�����ʹ�õĻ���.
����ij��Ⱥ�����ҳ��ƫ��.
Ϊӳ��һ����ɢ/��� DMA ����, �������Ӧ������ page, offset, �� length ��Ա��һ�� struct scatterlist ���ÿ��Ҫ�����͵Ļ���. ���ŵ���:
int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction direction)
���� nents �Ǵ����ɢ���������Ŀ. ����ֵ��Ҫ���͵� DMA �������Ŀ. ������С�� nents.
��������ɢ�����е�ÿ������, dma_map_sg ��������ȷ�ĸ��豸�����ߵ�ַ. ��Ϊ�����һ����, ��Ҳ�������ڴ�������Ļ���. �������������е�ϵͳ��һ�� I/O �ڴ������Ԫ, dma_map_sg Ҳ��������Ԫ��ӳ��Ĵ���, ���ܵĽ����, ����������Ĺ۵�, ���ܹ�����һ��������, �����Ļ���. �㽫����֪�����͵Ľ�����������, ����, ֱ���ڵ���֮��.
�������Ӧ�������� pci_map_sg ���ص�ÿ������. ���ߵ�ַ��ÿ������ij��ȴ洢�� struct scatterlist ��, ���������ڽṹ�е�λ��ÿ����ϵ��ͬ. 2 ���궨���ѱ�������ʹ�ÿ��ܱ�д����ֲ�Ĵ���:
dma_addr_t sg_dma_address(struct scatterlist *sg);
�����ɢ������ڷ�������( DMA )��ַ.
unsigned int sg_dma_len(struct scatterlist *sg);
�����������ij���.
�ٴ�, ��סҪ���͵Ļ���ĵ�ַ�ͳ��ȿ��ܺʹ��ݸ� dma_map_sg �IJ�ͬ.
һ���������, һ�� ��ɢ/��� ӳ�䱻ʹ�� dma_unmap_sg ȥӳ��:
void dma_unmap_sg(struct device *dev, struct scatterlist *list, int nents, enum dma_data_direction direction);
ע�� nents ��������������ݸ� dma_map_sg ����������Ŀ, ���Ҳ�������������ظ���� DMA �������Ŀ.
��ɢ/���ӳ������ DMA ӳ��, ����ͬ���Ĵ�ȡ������ͬ��һӳ��һ������. ���������ȡһ����ӳ��ķ�ɢ/����б�, ���������ͬ����:
void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction direction); void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction direction);
������, DMA ֧�ֲ�ʹ�� 32-λ ���ߵ�ַ, ����������һ���ض��豸�� DMA ����. PCI ����, ����, Ҳ֧��һ�� 64-λ��ַģʽ, ˫��ַ����(DAC). ͨ���� DMA �㲻֧�����ģʽ, ��Ϊ��������, ��һ��������һ�� PCI-�ض� ������. ����, ���� DAC ��ʵ�����Ǵ���, ����, ��Ϊ DAC ����һ�������, 32-λ DMA, ������һ�����ܿ���. �������, �е�Ӧ�ó���ʹ�� DAC ����ȷ������; �������һ���豸����ʹ�÷dz����λ�ڸ��ڴ�Ļ���, �����Ҫ����ʵ�� DAC ֧��. ���֧��ֻ�� PCI ��������, ��� PCI-�ض��ĺ������뱻ʹ��.
Ϊʹ�� DAC, �������������� <linux/pci.h>. ���������һ�������� DMA ����:
int pci_dac_set_dma_mask(struct pci_dev *pdev, u64 mask);
���ʹ�� DAC Ѱַֻ��������÷��� 0 ʱ. һ����������� (dma64_addr_t) ������ DAC ӳ��. Ϊ����һ����Щӳ��, ���� pci_dac_page_to_dma:
dma64_addr_t pci_dac_page_to_dma(struct pci_dev *pdev, struct page *page, unsigned long offset, int direction);
DAC ӳ��, �㽫ע�, ���ܱ����ֻ�� struct page ָ��(����Ӧ��λ�ڸ��ڴ�, �Ͼ�, ����ʹ������û��������); ���DZ���һ��һҳ�ر�����. direction ��������ͨ�� DMA ����ʹ�õ� enum dma_data_direction �� PCI �Ե���; ��Ӧ���� PCI_DMA_TODEVICE, PCI_DMA_FROMDEVICE, ���� PCI_DMA_BIRDIRECTIONAL.
DAC ӳ�䲻Ҫ���ⲿ��Դ, �����ʹ�ú�û�б�Ҫ��ȷ�ͷ�����. ����, �б�Ҫ��Դ�������ӳ��һ���Դ� DAC ӳ��, �������ع��ڻ�������Ȩ�Ĺ���. ��һ������ͬ�� DMA ����, ��ͨ���ı�������:
void pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction); void pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction);
��Ϊһ�� DMA ӳ����α�ʹ�õ�����, ����չʾ��һ���ĸ�һ�� PCI �豸�� DMA ���������. �� PCI �����ϵ����ݵ� DMA ��������ʽ�dz��������������豸. ���, ������Ӳ��������κ���ʵ���豸; �෴, ����һ����Ϊ dad ( DMA Acquisiton Device) �ļ���������һ����. һ��������豸���������ܶ���һ�����ͺ���������:
int dad_transfer(struct dad_dev *dev, int write, void *buffer, size_t count) { dma_addr_t bus_addr; /* Map the buffer for DMA */ dev->dma_dir = (write ? DMA_TO_DEVICE : DMA_FROM_DEVICE); dev->dma_size = count; bus_addr = dma_map_single(&dev->pci_dev->dev, buffer, count, dev->dma_dir); dev->dma_addr = bus_addr; /* Set up the device */ writeb(dev->registers.command, DAD_CMD_DISABLEDMA); writeb(dev->registers.command, write ? DAD_CMD_WR : DAD_CMD_RD); writel(dev->registers.addr, cpu_to_le32(bus_addr)); writel(dev->registers.len, cpu_to_le32(count)); /* Start the operation */ writeb(dev->registers.command, DAD_CMD_ENABLEDMA); return 0; }
�������ӳ��Ҫ�����͵Ļ��岢�������豸����. �����������һ��������жϷ�����������, ����������:
void dad_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct dad_dev *dev = (struct dad_dev *) dev_id; /* Make sure it's really our device interrupting */ /* Unmap the DMA buffer */ dma_unmap_single(dev->pci_dev->dev, dev->dma_addr, dev->dma_size, dev->dma_dir); /* Only now is it safe to access the buffer, copy to user, etc. */ ... }
��Ȼ, �������ȱ��������ϸ��, ����������Ҫ���κβ�������ֹ�������ͬʱ�� DMA ����.
ISA �������� 2 �� DMA ����: ���� DMA �� ISA ������ DMA. ���� DMA ʹ���������ϵı� DMA-��������·������ ISA �����ϵ��ź���. ISA ������ DMA, ��һ����, ��ȫ�����账��, ���ٴ������Ĺ۵㿴. һ�� ISA �������������� 1542 SCSI ������, ���ں�Դ�������� drivers/scsi/aha1542.c.
���ڱ��� DMA, �� 3 ��ʵ������� ISA �����ϵ� DMA ���ݴ���.
���������й��� DMA ���͵���Ϣ, ���緽��, �ڴ��ַ, �Լ����͵Ĵ�С. ��������һ�������������ٽ����еĴ��͵�״̬. ������������յ�һ�� DMA �����ź�, ��������ߵĿ���Ȩ���������ź����Ա��豸�ɶ���Щ��������.
����豸���뼤�� DMA �����ߵ�������������ʱ. ʵ�ʵĴ����� DMAC ����; Ӳ���豸˳�����д���ݵ����ߵ�������̽���豸ʱ. �豸���������жϵ����ͽ���ʱ.
�������ʲô����; ���ṩ�� DMA ����������, ���ߵ�ַ,�ʹ��͵Ĵ�С. ��������������ͨѶ�����������ݺ���Ӧ�жϵ� DMA ����ʱ.
��ʼ���� PC ��ʹ�õ� DMA ���������� 4 ��"ͨ��", ÿ����һ�� DMA �Ĵ���. 4 ���豸��ͬʱ�洢���ǵ� DMA ��Ϣ�ڿ�������. ���µ� PC ������ͬ�� 2 �� DMAC �豸[51]: �� 2 ��������(��)�����ӵ�ϵͳ�Ĵ�����, ���ҵ� 1 ��(��)�����ӵ��� 2 ����������ͨ�� 0.
����� PC ֻ��һ��������; �� 2 �����ڻ��� 286 ��ƽ̨�����ӵ�. ����, �� 2 ����������ͬ��������һ��������, ��Ϊ������ 16-λ�Ĵ���; �� 1 ��ֻ���� 8 λÿ�β�����Ϊ�����ݶ�����.
ͨ���ı�Ŵ� 0 �� 7: ͨ�� 4 �� ISA ���費����, ��Ϊ�����ڲ���������ӿ���������������. ���, ���õ�ͨ���� 0 �� 3 �ڴӿ�������( 8-λ ͨ��) �� 5 �� 7 ������������( 16-λͨ��). �κ� DMA ���͵Ĵ�С, �����洢�ڿ�������, ��һ�������������ڵ���Ŀ�� 16-λ��. ���Ĵ��ʹ�С��, ���, 64KB ���ڴӿ�����(��Ϊ������ 8 λ��һ������)�� 128KB ������������( ������ 16-λ ����).
��Ϊ DMA ��������һ��ϵͳ��Χ����Դ, �ں˰����������. ��ʹ��һ�� DMA ע�����ṩһ�������ͷŻ��Ƹ� DMA ͨ��, ��һ�������� DMA ������������ͨ����Ϣ.
��Ӧ����Ϥ�ں�ע�� -- �����Ѿ����������� I/O �˿ں��ж���. DMA ͨ��ע�������������. �� <asm/dma.h> ���Ѿ�����, ����ĺ�����������ú��ͷ�һ�� DMA ͨ����ӵ��Ȩ:
int request_dma(unsigned int channel, const char *name); void free_dma(unsigned int channel);
ͨ��������һ���� 0 �� 7 ֮�����, ����ȷЩ, һ��С�� MAX_DMA_CHANNELS ����ֵ. �� PC ��, MAX_DMA_CHANNELS ����Ϊ 8 ��ƥ��Ӳ��. name ������һ���ַ�������ʶ�豸. �ض��� name �������ļ� /proc/dma, ���ɱ��û������.
�� request_dma �ķ���ֵ�� 0 ���ڳɹ�, �� -EINVAL ���� -EBUSY ����д���. ǰ����˼�������ͨ������Χ, ������˼����һ���豸�������ͨ��.
�����Ƽ�����Դ� I/O �˿ں��ж���һ��С�ĶԴ� DMA ͨ��; �ڴ�ʱ����ͨ�����ڴ�ģ���ʼ��������������. �Ӻ���������������֮���һЩ����; ����, ���������ģ�� I/O �ӿڿ��Թ��� DMA ͨ��ֻҪ���Dz�ͬʱʹ��.
���ǻ����������� DMA ͨ�������������ж���֮���������ж�ǰ�ͷ���. ���ǹ��õ�˳���������� 2 ����Դ; ��ѭ������������������Ŀ���. ע��ÿ��ʹ�� DMA ���豸��Ҫһ�� IRQ ��; ����, ������ָʾ���ݴ��͵����.
��һ�����͵����, open ���뿴������, ���������ǵļ���� dad ģ��. dad �豸ʹ����һ�������жϴ���, �������� IRQ ��֧��.
int dad_open (struct inode *inode, struct file *filp) { struct dad_device *my_device; /* ... */ if ( (error = request_irq(my_device.irq, dad_interrupt, SA_INTERRUPT, "dad", NULL)) ) return error; /* or implement blocking open */ if ( (error = request_dma(my_device.dma, "dad")) ) { free_irq(my_device.irq, NULL); return error; /* or implement blocking open */ } /* ... */ return 0; }
�� open ƥ��� close ʵ�ֿ������:
void dad_close (struct inode *inode, struct file *filp) { struct dad_device *my_device; /* ... */ free_dma(my_device.dma); free_irq(my_device.irq, NULL); /* ... */ }
���� /proc/dma �ļ� ��һ����װ��������ϵͳ�е�����:
merlino% cat /proc/dma 1: Sound Blaster8 4: cascade
ע��, ȱʡ������������� DMA ͨ����ϵͳ����ʱ���ҴӲ��ͷ���. ����������һ��ռλ��, ָ��ͨ�� 4 ������������, ��ͬǰ����͵�.
��ע���, ������������Ҫ���ְ������� DMA ��������ȷ����. ��������������, �������˵���, �ں�����˵���������Ҫ�����еĺ���.
������Ҫ���� DMA ���������߶���д������ʱ, ���ߵ����첽����ʱ. ���������������ڴ�ʱ���л�����Ӧһ�� ioctl ����, ������������ʵ�ֵIJ���. ����չʾ�Ĵ����ǵ��͵ر�����д�豸�������õ�.
��һС���ṩһ������ DMA �������ڲ��Ŀ��ٸ���, �����������������ܵĴ���. �������֪������, ����Ȱ��� <asm/dma.h> ��һЩ���� PC ��ϵ��Ӳ���ֲ�. �ر��, ���Dz����� 8-λ �� 16-λ ���͵�����. ������ڱ�д�豸������ ISA �豸��, ��Ӧ�����豸��Ӳ���ֲ����ҵ���ص���Ϣ.
DMA ��������һ����������Դ, ������������������ͼͬʱ������̻��������. Ϊ��, ��������һ������������, ��Ϊ dma_spin_lock. ������Ӧ��ֱ�Ӳ��������; ����, 2 ���������ṩ�����������:
��ȡ DMA ������. ����������ڱ��ش������������ж�; ���, ����ֵ��һЩ����֮ǰ�ж�״̬�ı�־; �����뱻���ݸ����ĺ������ָ��ж�״̬, �������������.
���� DMA ���������һָ�ǰ����ж�״̬.
������Ӧ��������, ��ʹ�����������ĺ���ʱ. ����, ����Ӧ��������, ��ʵ�ʵ� I/O ����. һ������Ӧ���Ӳ�˯�ߵ�����һ��������ʱ.
���뱻���ص��������е���Ϣ���� 3 ��: RAM ��ַ, ���뱻���͵�ԭ�������Ŀ(���ֽڻ��ּ�), �Լ����͵ķ���. Ϊ��, ���к����� <asm/dma.h> ���:
ָʾ�Ƿ����ͨ��������豸��( DMA_MODE_READ)����д���豸(DMA_MODE_WRITE). ���ڵ� 3 ��ģʽ, DMA_MODE_CASCADE, ���������ͷŶ����ߵĿ���. ����ǵ� 1 �����������ӵ��� 2 �������������ķ�ʽ, ������Ҳ���Ա������� ISA �������豸ʹ��. �������ﲻ�������߿���.
���� DMA ����ĵ�ַ. ��������洢 addr �ĵ� 24 ��Чλ�ڿ�������. addr ����������һ�����ߵ�ַ(��"���ߵ�ַ"һ��, �ڱ���ǰ��).
���䴫�͵��ֽ���. count ����Ҳ��ʾ�� 16-λ ͨ�����ֽ�; ����������, �����������ż��.
������Щ����, ��һЩά�����߱�����, ������ DMA �豸ʱ:
һ�� DMA ͨ�����ڿ������ڲ����ر�. ���ͨ��Ӧ���ڿ�����������Ϊ��ֹ��һ������ȷ�IJ���ǰ���ر�. (����, ����Ϊ��������ͨ�� 8-λ���ݴ��ͱ���̶������ƻ�, ����, ���, ֮ǰ�Ĺ��ܶ����Զ�ִ��.
���������֪������ DMA ͨ��������Ч����.
���������ʱ��Ҫ֪���Ƿ�һ�� DMA �����Ѿ����. �������������Ҫ�����͵��ֽ���. ��һ�γɹ��Ĵ��ͺ�ķ���ֵ�� 0 �����ڿ������ڹ���ʱ�Dz���Ԥ��� (������ 0). ���ֲ���Ԥ����������Ҫͨ�� 2 ��8-λ������������ 16-λ ������.
����������� DMA flip-flop. ��� flip-flop �������ƶ� 16-λ �Ĵ����Ĵ�ȡ. ��Щ�Ĵ����� 2 �������� 8-λ��������ȡ, ������� flip-flop ������ѡ�����Ч�ֽ�(����������)�����������Ч�ֽ�(��������λ). flip-flop �Զ���ת���Ѿ������� 8 λ; ����Ա������� flip-flop( ��������Ϊ��֪��״̬ )�ڴ�ȡ DMA �Ĵ���֮ǰ.
ʹ����Щ, һ������������ʵ��һ����������һ�� DMA ����:
int dad_dma_prepare(int channel, int mode, unsigned int buf, unsigned int count) { unsigned long flags; flags = claim_dma_lock(); disable_dma(channel); clear_dma_ff(channel); set_dma_mode(channel, mode); set_dma_addr(channel, virt_to_bus(buf)); set_dma_count(channel, count); enable_dma(channel); release_dma_lock(flags); return 0; }
����, һ������һ���ĺ������������ DMA �ijɹ����:
int dad_dma_isdone(int channel) { int residue; unsigned long flags = claim_dma_lock (); residue = get_dma_residue(channel); release_dma_lock(flags); return (residue == 0); }
δ��ɵ�Ψһһ�������������豸��. ����豸�ض���������������д���� I/O �˿�. �豸�ڼ�����ķ��治ͬ. ����, һЩ�豸��������Ա����Ӳ�� DMA �����ж��, ������ʱ�������ò���һ����Ӳ�����豸�е�ֵ. Ϊ���ð�, Ӳ���ֲ�����Ψһ������.