ֱ���ڴ��ȡ, ���� DMA, �ǽ������ǵ��ڴ���������ĸ߼�����. DMA ��Ӳ�������������������ֱ�Ӵ������ǵ� I/O ���ݵ��ʹ����ڴ�, ������Ҫ����ϵͳ������. ���ֻ��Ƶ�ʹ���ܹ��ܴ�������������ʹ�һ���豸, ��Ϊ�����ļ��㿪����������.

15.4.1. һ�� DMA ���ݴ���ĸſ�

�ڽ��ܳ���ϸ��֮ǰ, �����ǻع�һ�� 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 �Ļ���. ע�����������������ǵĻ����ڳ�ʼ��ʱ����ʹ������ֱ���ر� -- ��֮ǰ�б��еķ���һ��, ��˼��"���һ��֮ǰ����Ļ���".

15.4.2. ���� 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 ��( ��������������� )�����仺���Խ������豸������.

15.4.2.1. �Լ�������

�����Ѽ��� 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 ���û��ռ�ʱ, ����������õؽ����������Ҫһ�������󻺳�ʱ.

15.4.3. ���ߵ�ַ

һ��ʹ�� 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 ��, �����������ת�Ƶ��������.

15.4.4. ͨ�� DMA ��

DMA ����, ���, �µ�����һ�����岢�Ҵ������ߵ�ַ������豸. ����, ��д��������ϵ�ϰ�ȫ����ȷ���� DMA �Ŀ���ֲ����������������Ҫ��. ��ͬ��ϵͳ�в�ͬ�ĸ���, ���ڻ���һ����Ӧ����ι����ĸ���; ����㲻��ȷ�����������, ������������ƻ��ڴ�. һЩϵͳ�и��ӵ�����Ӳ��, ��ʹ DMA ��������� - ���߸���. ���Ҳ������е�ϵͳ�������ڴ����в��ֽ��� DMA. ���˵���, �ں��ṩ��һ�����ߺ���ϵ������ DMA �����������������ش󲿷���Щ����. ���Ƿdz���������ʹ��������� DMA ����, ���κ����д��������.

��������ຯ����Ҫһ��ָ�� struct device ��ָ��. ����ṹ�� Linux �豸ģ�����豸�ĵͼ���ʾ. ������������������ֱ��ʹ�õĶ���, ������ȷʵ��Ҫ����ʹ��ͨ�� DMA ��ʱ. ������, ��ɷ�������ṹ, ��������������豸������. ����, ������ struct pci_device ���� struct usb_device �з�������Ϊ dev ��Ա. �豸�ṹ�� 14 ������ϸ����.

ʹ�����溯��������Ӧ������ <linux/dma-mapping.h>.

15.4.4.1. ��������Ӳ��

�ڳ��� 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.

15.4.4.2. DMA ӳ��

һ�� 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 ��ӳ�����ͱ����Բ�ͬ�ķ�ʽ����; ��ʱ�򿴿�ϸ����.

15.4.4.3. ����һ�� DMA ӳ��

һ���������Խ���һ��һ��ӳ��, ʹ�ö� 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 ��ַ, �� ���ߵ�ַ����.

15.4.4.4. DMA ��

һ�� 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); 

15.4.4.5. ������ DMA ӳ��

��ӳ���һ��ӳ���и����ӵĽӿ�, �м���ԭ��. ��Щӳ����Ϊʹ��һ���������Ѿ�����Ļ���, ���, ���봦������û��ѡ��ĵ�ַ. ��һЩ��ϵ��, ��ӳ��Ҳ�����ж����������ҳ�Ͷಿ�ֵ�"��ɢ/���"����. ������Щԭ��, ��ӳ���������Լ���һ��ӳ�亯��.

������һ����ӳ��ʱ, ������֪�ں����������ĸ�����. һЩ����(enum dam_data_direction ����)��Ϊ�˶���:

DMA_TO_DEVICE
DMA_FROM_DEVICE

�� 2 ������Ӧ�����Խ��͵�. ������ݱ���������豸(��Ӧ��, Ҳ��, ��һ�� write ϵͳ����), DMA_IO_DEVICE Ӧ����ʹ��; ȥ�� CPU ������, �෴, �� DMA_FROM_DEVICE ��־.

DMA_BIDIRECTIONAL

������ݱ�����һ�����ƶ�, ʹ�� DMA_BIDIRECTIONAL.

DMA_NONE

�������ֻ��Ϊһ�����Ը������ṩ. ��ͼʹ�ô��������Ļ��嵼���ں˱���.

����������ʱ������ͼֻʹ�� 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 ����.

15.4.4.6. ��ҳ��ӳ��

żȻ��, ������뽨��һ�������ӳ��, �����������һ�� 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��ֿ��ܵ��»���һ��������, ����������ֻ����һ�������ߵ�һ����; ��, ��֮, �ᵼ���ڴ��ƻ������ص����Ե��ԵĴ���.

15.4.4.7. ��ɢ/���ӳ��

��ɢ/���ӳ����һ���������͵��� DMA ӳ��. �������м�������, ����Ҫ�������ݵ����ߴ��豸. �����������Լ�����ʽ, ������һ�� readv ���� writev ϵͳ����, һ���ɴصĴ��� I/O ����, ����һ��ҳ������һ����ӳ����ں� I/O ����. ��ɼ򵥵�ӳ��ÿ������, ������, ���ҽ���Ҫ��IJ���, �����м����ŵ���һ��ӳ����������.

�����豸���Խ���һ��ɢ��������ָ��ͳ���, ���Ҵ�������ȫ����һ�� DMA ������; ����, "�㿽��"�����Ǹ�������������ڶ��Ƭ�н���. ��һ��ӳ�䷢ɢ�б�Ϊһ�����������������������Ӳ������ӳ��Ĵ�����ϵͳ. ��������ϵͳ��, �����ϲ�������ҳ���豸�Ĺ۵㿴�ɱ��㼯Ϊһ��������, ����������. �������ֻ��ɢ�����е����ڳ����ϵ���ҳ��С(���˵�һ�������һ��), ���ǵ������������ʱ, ����ת�����������һ�������� DMA, ��������Եļ�������.

���, ���һ������������뱻ʹ��, Ӧ�����������б�Ϊһ����������(��Ϊ���ڱ����κη�ʽ����).

���������ȷ��ɢ������ӳ����ijЩ�������ֵ�õ�. ӳ��һ��ɢ�����ĵ�һ���Ǵ��������һ�� struct scatterlist ����, ������������Ļ���. ����ṹ����ϵ������, ������ <asm/scatterlist.h> ������. ����, ���������� 3 ����Ա:

struct page *page;

struct page ָ��, ��Ӧ�ڷ�ɢ/��۲�����ʹ�õĻ���.

unsigned int length;
unsigned int offset;

����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); 

15.4.4.8. PCI ˫��ַ����ӳ��

������, 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);

15.4.4.9. һ���򵥵� PCI DMA ����

��Ϊһ�� 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 ����.

15.4.5. ISA �豸�� DMA

ISA �������� 2 �� DMA ����: ���� DMA �� ISA ������ DMA. ���� DMA ʹ���������ϵı�׼ DMA-��������·������ ISA �����ϵ��ź���. ISA ������ DMA, ��һ����, ��ȫ�����账��, ���ٴ������Ĺ۵㿴. һ�� ISA �������������� 1542 SCSI ������, ���ں�Դ�������� drivers/scsi/aha1542.c.

���ڱ��� DMA, �� 3 ��ʵ������� ISA �����ϵ� DMA ���ݴ���.

The 8237 DMA controller (DMAC)

���������й��� DMA ���͵���Ϣ, ���緽��, �ڴ��ַ, �Լ����͵Ĵ�С. ��������һ�������������ٽ����еĴ��͵�״̬. ������������յ�һ�� DMA �����ź�, ��������ߵĿ���Ȩ���������ź����Ա��豸�ɶ���Щ��������.

The peripheral device

����豸���뼤�� DMA �����ߵ���׼����������ʱ. ʵ�ʵĴ����� DMAC ����; Ӳ���豸˳�����д���ݵ����ߵ�������̽���豸ʱ. �豸���������жϵ����ͽ���ʱ.

The device driver

�������ʲô����; ���ṩ�� 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 ������������ͨ����Ϣ.

15.4.5.1. ע�� 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 ������������, ��ͬǰ����͵�.

15.4.5.2. �� DMA ������ͨѶ

��ע���, ������������Ҫ���ְ������� DMA ��������ȷ����. ������񲢷�΢�������, �������˵���, �ں�����˵���������Ҫ�����еĺ���.

������Ҫ���� DMA ���������߶���д������ʱ, ���ߵ�׼���첽����ʱ. ���������������ڴ�ʱ���л�����Ӧһ�� ioctl ����, ������������ʵ�ֵIJ���. ����չʾ�Ĵ����ǵ��͵ر�����д�豸�������õ�.

��һС���ṩһ������ DMA �������ڲ��Ŀ��ٸ���, �����������������ܵĴ���. �������֪������, ����Ȱ��� <asm/dma.h> ��һЩ���� PC ��ϵ��Ӳ���ֲ�. �ر��, ���Dz����� 8-λ �� 16-λ ���͵�����. ������ڱ�д�豸������ ISA �豸��, ��Ӧ�����豸��Ӳ���ֲ����ҵ���ص���Ϣ.

DMA ��������һ����������Դ, ������������������ͼͬʱ������̻��������. Ϊ��, ��������һ������������, ��Ϊ dma_spin_lock. ������Ӧ��ֱ�Ӳ��������; ����, 2 ���������ṩ�����������:

unsigned long claim_dma_lock( );

��ȡ DMA ������. ����������ڱ��ش������������ж�; ���, ����ֵ��һЩ����֮ǰ�ж�״̬�ı�־; �����뱻���ݸ����ĺ������ָ��ж�״̬, �������������.

void release_dma_lock(unsigned long flags);

���� DMA ���������һָ�ǰ����ж�״̬.

������Ӧ��������, ��ʹ�����������ĺ���ʱ. ����, ����Ӧ��������, ��ʵ�ʵ� I/O ����. һ������Ӧ���Ӳ�˯�ߵ�����һ��������ʱ.

���뱻���ص��������е���Ϣ���� 3 ��: RAM ��ַ, ���뱻���͵�ԭ�������Ŀ(���ֽڻ��ּ�), �Լ����͵ķ���. Ϊ��, ���к����� <asm/dma.h> ���:

void set_dma_mode(unsigned int channel, char mode);

ָʾ�Ƿ����ͨ��������豸��( DMA_MODE_READ)����д���豸(DMA_MODE_WRITE). ���ڵ� 3 ��ģʽ, DMA_MODE_CASCADE, ���������ͷŶ����ߵĿ���. ����ǵ� 1 �����������ӵ��� 2 �������������ķ�ʽ, ������Ҳ���Ա������� ISA �������豸ʹ��. �������ﲻ�������߿���.

void set_dma_addr(unsigned int channel, unsigned int addr);

���� DMA ����ĵ�ַ. ��������洢 addr �ĵ� 24 ��Чλ�ڿ�������. addr ����������һ�����ߵ�ַ(��"���ߵ�ַ"һ��, �ڱ���ǰ��).

void set_dma_count(unsigned int channel, unsigned int count);

���䴫�͵��ֽ���. count ����Ҳ��ʾ�� 16-λ ͨ�����ֽ�; ����������, �����������ż��.

������Щ����, ��һЩά�����߱�����, ������ DMA �豸ʱ:

void disable_dma(unsigned int channel);

һ�� DMA ͨ�����ڿ������ڲ����ر�. ���ͨ��Ӧ���ڿ�����������Ϊ��ֹ��һ������ȷ�IJ���ǰ���ر�. (����, ����Ϊ��������ͨ�� 8-λ���ݴ��ͱ���̶������ƻ�, ����, ���, ֮ǰ�Ĺ��ܶ����Զ�ִ��.

void enable_dma(unsigned int channel);

���������֪������ DMA ͨ��������Ч����.

int get_dma_residue(unsigned int channel);

���������ʱ��Ҫ֪���Ƿ�һ�� DMA �����Ѿ����. �������������Ҫ�����͵��ֽ���. ��һ�γɹ��Ĵ��ͺ�ķ���ֵ�� 0 �����ڿ������ڹ���ʱ�Dz���Ԥ��� (������ 0). ���ֲ���Ԥ����������Ҫͨ�� 2 ��8-λ������������ 16-λ ������.

void clear_dma_ff(unsigned int channel) ;

����������� 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 �����ж��, ������ʱ�������ò���һ����Ӳ�����豸�е�ֵ. Ϊ���ð�, Ӳ���ֲ�����Ψһ������.



[49] ��Ȼ, ʲô���鶼������; ��"�����жϻ���"һ���� 17 ��, ��ʾ�˸���������������α�ʹ����ѯ��õ�ʵ��.

[50] ��Ƭһ�ʳ������ڴ����������ļ�û�������洢�ڴŽ�����. ��ͬ�ĸ����������ڴ�, ����ÿ�������ַ�ռ����������� RAM ɢ��, �������ڻ�ȡ�����Ŀ���ҳ������һ�� DMA ����.

[51] ��Щ��·����������оƬ���һ����, ���Ǽ���ǰ������ 2 �������� 8237 оƬ.