标 题: [合集] 请问如何实现这个问题?
发信站: 水木社区 (Sun Dec 24 14:00:17 2006), 站内
☆—————————————————————————————————————☆
terrac (xiaoyt) 于 (Sat Mar 6 14:26:12 2004) 提到:
在win2000 DDK 中有个接口函数:
PVOID ScsiPortGetPhysicalAddress( IN PIDE_Channel IdeChannelIdeChannel, IN PSC
SI_REQUEST_BLOCK Srb,IN PVOID dataPointer, OUT ULONG *length) ;
它的作用是将 用户空间的一个首地址为dataPointer (假设长度为count)的连续数据块
,映射为一个内核空间不连续的离散数据块集合,该离散数据块的第一个数据块的块基地
址为该函数的返回值(设为pysAddress1),第一个数据块的长度由length 返回。
(这样,当第二次再次调用 pysAddress2=ScsiPortGetPhysicalAddress(IdeChannel, S
rb, dataPointer+length,&length2)时,得到第二块内核空间数据块,块首地址和块长
度分别为pysAddress2和length2,以次类推 。
问题时,在linux下,如何实现这个映射?有这样的系统调用吗?如果没有,如何实现?
linux下在 drivers/ide/ide_dma.c中有个建立scatterlist的函数如下:
/**
* ide_build_sglist - map IDE scatter gather for DMA I/O
* @hwif: the interface to build the DMA table for
* @rq: the request holding the sg list
* @ddir: data direction
*
* Perform the PCI mapping magic neccessary to access the source or
* target buffers of a request via PCI DMA. The lower layers of the
* kernel provide the neccessary cache management so that we can
* operate in a portable fashion
*/
static int ide_build_sglist (ide_hwif_t *hwif, struct request *rq, int ddir)
{
struct buffer_head *bh;
struct scatterlist *sg = hwif->sg_table;
unsigned long lastdataend = ~0UL;
int nents = 0;
if (hwif->sg_dma_active)
BUG();
bh = rq->bh;
do {
int contig = 0;
if (bh->b_page) {
if (bh_phys(bh) == lastdataend)
contig = 1;
} else {
if ((unsigned long) bh->b_data == lastdataend)
contig = 1;
}
if (contig) {
sg[nents - 1].length += bh->b_size;
lastdataend += bh->b_size;
continue;
}
if (nents >= PRD_ENTRIES)
return 0;
memset(&sg[nents], 0, sizeof(*sg));
if (bh->b_page) {
sg[nents].page = bh->b_page;
sg[nents].offset = bh_offset(bh);
lastdataend = bh_phys(bh) + bh->b_size;
} else {
if ((unsigned long) bh->b_data < PAGE_SIZE)
BUG();
sg[nents].address = bh->b_data;
lastdataend = (unsigned long) bh->b_data + bh->b_size;
}
sg[nents].length = bh->b_size;
nents++;
} while ((bh = bh->b_reqnext) != NULL);
if(nents == 0)
BUG();
hwif->sg_dma_direction = ddir;
return pci_map_sg(hwif->pci_dev, sg, nents, ddir);
}
该函数也基本上是在构建散离表,但是我的那个设备根本不设计到扇区、块等块设备参
数和变量。只是需要将用户空间的地址映射为物理地址。因此也无法构造struct request
和struct buffer_head 结构。但想避开这些结构,如何操作?
恳请大侠救命!
☆—————————————————————————————————————☆
terrac (xiaoyt) 于 (Mon Mar 8 12:29:08 2004) 提到:
这几天很痛苦的查了大量资料,只有一点想法,但还是不敢确定,还恳请高手指点!
(在driver中)
先用remap_page_range建立从用户空间地址到物理地址的映射,得到一个物理地址
void * buffer.然后进行强制转换:
struct scatterlist * sgList = (struct scatterlist *)buffer;
然后再将sgList的每一项copy到一个要建的散离表各项中。
我没有读过linux内核,这些只是猜测。不知各位高手有何看法?
附scatterlist结构如下:
struct scatterlist {
char * address; /* Location data is to be transferred to, NULL for
* highmem page */
struct page * page; /* Location for highmem page, if any */
unsigned int offset;/* for highmem, page offset */
dma_addr_t dma_address;
unsigned int length;
};
【 在 terrac (xiaoyt) 的大作中提到: 】
: 在win2000 DDK 中有个接口函数:
: PVOID ScsiPortGetPhysicalAddress( IN PIDE_Channel IdeChannelIdeChannel, IN..
: SI_REQUEST_BLOCK Srb,IN PVOID dataPointer, OUT ULONG *length) ;
: 它的作用是将 用户空间的一个首地址为dataPointer (假设长度为count)的连续数..
: ,映射为一个内核空间不连续的离散数据块集合,该离散数据块的第一个数据块的块..
: 址为该函数的返回值(设为pysAddress1),第一个数据块的长度由length 返回。
: (这样,当第二次再次调用 pysAddress2=ScsiPortGetPhysicalAddress(IdeChanne..
: rb, dataPointer+length,&length2)时,得到第二块内核空间数据块,块首地址和..
: 度分别为pysAddress2和length2,以次类推 。
: 问题时,在linux下,如何实现这个映射?有这样的系统调用吗?如果没有,如何实�..
: ...................
☆—————————————————————————————————————☆
terrac (xiaoyt) 于 (Tue Mar 9 11:32:04 2004) 提到:
我目前在写一个driver。driver做的工作就是:
用户程序写时(即发送数据),实现xxx_write(struct file *filp,char *buff,size_t
cont,loff_t * offset) 时,不想先把用户数据拷贝到kernel空间,而是直接将用户空间
连续的数据映射成内核离散的数据,并锁定这些用户数据,这样将得到一个散离表(scat
terlist)。driver 将这个散离表基地址写进设备的SCAT_GATHER_TX_BASE_ADDRESS 寄存
器,并启动DMA传输,即可(然后等到中断服务程序唤醒)。读时(即接受数据时,同样,
只需将内核接受数局的散离表基地址写入 SCAT_GATHER_RX_BASE_ADDRESS 寄存器中,然后
再启动DMA传输。
linux下提供了一种用scatter/gather的DMA方式,pci_map_sg(), 实现虚地址映射。
scatter/gather就是为支持它的硬件实现 zero copy的一种途径。scatter/gather 可以一
次DMA传多个buffer块. 这样就在setup dma的时候指定一系列的buffer( offset, len).
(一般来说DMA到一个连续的内存上.也有能够DMA到不连续上面的.)也就是直接让硬件DM
A传到用户空间的buffer里面.
我现在遇到的问题时,我不知道如何实现直接从I/O内存读/写数据到用户空间,如何将用户空间映射成DMA离散的内核空间,不知道如何构建散离表。(即不知道怎样才能得到散离表基地址)。
在win2000 DDK 中有个接口函数:
PVOID ScsiPortGetPhysicalAddress( IN PIDE_Channel IdeChannelIdeChannel, IN PSC
SI_REQUEST_BLOCK Srb,IN PVOID dataPointer, OUT ULONG *length) ;
它的作用是将 用户空间的一个首地址为dataPointer (假设长度为count)的连续数据块
,映射为一个内核空间不连续的离散数据块集合,该离散数据块的第一个数据块的块基地
址为该函数的返回值(设为pysAddress1),第一个数据块的长度由length 返回。
(这样,当第二次再次调用 pysAddress2=ScsiPortGetPhysicalAddress(IdeChannel, S
rb, dataPointer+length,&length2)时,得到第二块内核空间数据块,块首地址和块长
度分别为pysAddress2和length2,以次类推 。
问题时,在linux下,如何实现这个映射?有这样的系统调用吗?如果没有,如何实现?
我的那个设备根本不设计到扇区、块等块设备参
数和变量。只是需要将用户空间的地址映射为物理地址。因此也无法构造struct request
和struct buffer_head 结构。但想避开这些结构,如何操作?
我觉得这个问题对于高手应当很普通的,可是对于我就很困难了。我又重新看了mmap,
不知用kiobuf能否实现?我对mmap这章总是难以理解,对kiobuf也是。希望理解kiobuf很深刻的高手帮忙解答一下。
【 在 terrac (xiaoyt) 的大作中提到: 】
: 这几天很痛苦的查了大量资料,只有一点想法,但还是不敢确定,还恳请高手指点!
: (在driver中)
: 先用remap_page_range建立从用户空间地址到物理地址的映射,得到一个物理地址
: void * buffer.然后进行强制转换:
: struct scatterlist * sgList = (struct scatterlist *)buffer;
: 然后再将sgList的每一项copy到一个要建的散离表各项中。
: 我没有读过linux内核,这些只是猜测。不知各位高手有何看法?
: 附scatterlist结构如下:
: struct scatterlist {
: char * address; /* Location data is to be transferred to, NULL for
: * highmem page */
: ...................
☆—————————————————————————————————————☆
voidkey (探索者) 于 (Thu Mar 11 17:35:12 2004) 提到:
要实现外设直接dma到用户空间既zero copy,我的想法是:
1.先保证用户空间缓冲区全部进行了映射,这可以参考map_user_kiobuf的实现,该函数
在mm/memory.c中,如果直接使用这个函数,就会得到一个struct kiobuf结构变量
2.进行dma映射
这可以使用多次pci_map_single
也可以构造scatterlist然后使用pci_map_sg
3.把一系列dma地址写到外设相应的寄存器中
【 在 terrac (xiaoyt) 的大作中提到: 】
: 我目前在写一个driver。driver做的工作就是:
: 用户程序写时(即发送数据),实现xxx_write(struct file *filp,char *buff,size_t
: cont,loff_t * offset) 时,不想先把用户数据拷贝到kernel空间,而是直接将用户空间
: 连续的数据映射成内核离散的数据,并锁定这些用户数据,这样将得到一个散离表(scat
: terlist)。driver 将这个散离表基地址写进设备的SCAT_GATHER_TX_BASE_ADDRESS 寄存
: 器,并启动DMA传输,即可(然后等到中断服务程序唤醒)。读时(即接受数据时,同样,
: 只需将内核接受数局的散离表基地址写入 SCAT_GATHER_RX_BASE_ADDRESS 寄存器中,然后
: 再启动DMA传输。
: linux下提供了一种用scatter/gather的DMA方式,pci_map_sg(), 实现虚地址映射。
: scatter/gather就是为支持它的硬件实现 zero copy的一种途径。scatter/gather 可以一
: 次DMA传多个buffer块. 这样就在setup dma的时候指定一系列的buffer( offset, len).
: (一般来说DMA到一个连续的内存上.也有能够DMA到不连续上面的.)也就是直接让硬件DM
: A传到用户空间的buffer里面.
: 我现在遇到的问题时,我不知道如何实现直接从I/O内存读/写数据到用户空间,如何将用户空间映射成DMA离散的内核空间,不知道如何构建散离表。(即不知道怎样才能得到散离表基地址)。
: 在win2000 DDK 中有个接口函数:
: PVOID ScsiPortGetPhysicalAddress( IN PIDE_Channel IdeChannelIdeChannel, IN PSC
: SI_REQUEST_BLOCK Srb,IN PVOID dataPointer, OUT ULONG *length) ;
: 它的作用是将 用户空间的一个首地址为dataPointer (假设长度为count)的连续数据块
: ,映射为一个内核空间不连续的离散数据块集合,该离散数据块的第一个数据块的块基地
: 址为该函数的返回值(设为pysAddress1),第一个数据块的长度由length 返回。
: (这样,当第二次再次调用 pysAddress2=ScsiPortGetPhysicalAddress(IdeChannel, S
: rb, dataPointer+length,&length2)时,得到第二块内核空间数据块,块首地址和块长
: 度分别为pysAddress2和length2,以次类推 。
: 问题时,在linux下,如何实现这个映射?有这样的系统调用吗?如果没有,如何实现?
: 我的那个设备根本不设计到扇区、块等块设备参
: 数和变量。只是需要将用户空间的地址映射为物理地址。因此也无法构造struct request
: 和struct buffer_head 结构。但想避开这些结构,如何操作?
: 我觉得这个问题对于高手应当很普通的,可是对于我就很困难了。我又重新看了mmap,
: 不知用kiobuf能否实现?我对mmap这章总是难以理解,对kiobuf也是。希望理解kiobuf很深刻的高手帮忙解答一下。
发信站: 水木社区 (Sun Dec 24 14:00:17 2006), 站内
☆—————————————————————————————————————☆
terrac (xiaoyt) 于 (Sat Mar 6 14:26:12 2004) 提到:
在win2000 DDK 中有个接口函数:
PVOID ScsiPortGetPhysicalAddress( IN PIDE_Channel IdeChannelIdeChannel, IN PSC
SI_REQUEST_BLOCK Srb,IN PVOID dataPointer, OUT ULONG *length) ;
它的作用是将 用户空间的一个首地址为dataPointer (假设长度为count)的连续数据块
,映射为一个内核空间不连续的离散数据块集合,该离散数据块的第一个数据块的块基地
址为该函数的返回值(设为pysAddress1),第一个数据块的长度由length 返回。
(这样,当第二次再次调用 pysAddress2=ScsiPortGetPhysicalAddress(IdeChannel, S
rb, dataPointer+length,&length2)时,得到第二块内核空间数据块,块首地址和块长
度分别为pysAddress2和length2,以次类推 。
问题时,在linux下,如何实现这个映射?有这样的系统调用吗?如果没有,如何实现?
linux下在 drivers/ide/ide_dma.c中有个建立scatterlist的函数如下:
/**
* ide_build_sglist - map IDE scatter gather for DMA I/O
* @hwif: the interface to build the DMA table for
* @rq: the request holding the sg list
* @ddir: data direction
*
* Perform the PCI mapping magic neccessary to access the source or
* target buffers of a request via PCI DMA. The lower layers of the
* kernel provide the neccessary cache management so that we can
* operate in a portable fashion
*/
static int ide_build_sglist (ide_hwif_t *hwif, struct request *rq, int ddir)
{
struct buffer_head *bh;
struct scatterlist *sg = hwif->sg_table;
unsigned long lastdataend = ~0UL;
int nents = 0;
if (hwif->sg_dma_active)
BUG();
bh = rq->bh;
do {
int contig = 0;
if (bh->b_page) {
if (bh_phys(bh) == lastdataend)
contig = 1;
} else {
if ((unsigned long) bh->b_data == lastdataend)
contig = 1;
}
if (contig) {
sg[nents - 1].length += bh->b_size;
lastdataend += bh->b_size;
continue;
}
if (nents >= PRD_ENTRIES)
return 0;
memset(&sg[nents], 0, sizeof(*sg));
if (bh->b_page) {
sg[nents].page = bh->b_page;
sg[nents].offset = bh_offset(bh);
lastdataend = bh_phys(bh) + bh->b_size;
} else {
if ((unsigned long) bh->b_data < PAGE_SIZE)
BUG();
sg[nents].address = bh->b_data;
lastdataend = (unsigned long) bh->b_data + bh->b_size;
}
sg[nents].length = bh->b_size;
nents++;
} while ((bh = bh->b_reqnext) != NULL);
if(nents == 0)
BUG();
hwif->sg_dma_direction = ddir;
return pci_map_sg(hwif->pci_dev, sg, nents, ddir);
}
该函数也基本上是在构建散离表,但是我的那个设备根本不设计到扇区、块等块设备参
数和变量。只是需要将用户空间的地址映射为物理地址。因此也无法构造struct request
和struct buffer_head 结构。但想避开这些结构,如何操作?
恳请大侠救命!
☆—————————————————————————————————————☆
terrac (xiaoyt) 于 (Mon Mar 8 12:29:08 2004) 提到:
这几天很痛苦的查了大量资料,只有一点想法,但还是不敢确定,还恳请高手指点!
(在driver中)
先用remap_page_range建立从用户空间地址到物理地址的映射,得到一个物理地址
void * buffer.然后进行强制转换:
struct scatterlist * sgList = (struct scatterlist *)buffer;
然后再将sgList的每一项copy到一个要建的散离表各项中。
我没有读过linux内核,这些只是猜测。不知各位高手有何看法?
附scatterlist结构如下:
struct scatterlist {
char * address; /* Location data is to be transferred to, NULL for
* highmem page */
struct page * page; /* Location for highmem page, if any */
unsigned int offset;/* for highmem, page offset */
dma_addr_t dma_address;
unsigned int length;
};
【 在 terrac (xiaoyt) 的大作中提到: 】
: 在win2000 DDK 中有个接口函数:
: PVOID ScsiPortGetPhysicalAddress( IN PIDE_Channel IdeChannelIdeChannel, IN..
: SI_REQUEST_BLOCK Srb,IN PVOID dataPointer, OUT ULONG *length) ;
: 它的作用是将 用户空间的一个首地址为dataPointer (假设长度为count)的连续数..
: ,映射为一个内核空间不连续的离散数据块集合,该离散数据块的第一个数据块的块..
: 址为该函数的返回值(设为pysAddress1),第一个数据块的长度由length 返回。
: (这样,当第二次再次调用 pysAddress2=ScsiPortGetPhysicalAddress(IdeChanne..
: rb, dataPointer+length,&length2)时,得到第二块内核空间数据块,块首地址和..
: 度分别为pysAddress2和length2,以次类推 。
: 问题时,在linux下,如何实现这个映射?有这样的系统调用吗?如果没有,如何实�..
: ...................
☆—————————————————————————————————————☆
terrac (xiaoyt) 于 (Tue Mar 9 11:32:04 2004) 提到:
我目前在写一个driver。driver做的工作就是:
用户程序写时(即发送数据),实现xxx_write(struct file *filp,char *buff,size_t
cont,loff_t * offset) 时,不想先把用户数据拷贝到kernel空间,而是直接将用户空间
连续的数据映射成内核离散的数据,并锁定这些用户数据,这样将得到一个散离表(scat
terlist)。driver 将这个散离表基地址写进设备的SCAT_GATHER_TX_BASE_ADDRESS 寄存
器,并启动DMA传输,即可(然后等到中断服务程序唤醒)。读时(即接受数据时,同样,
只需将内核接受数局的散离表基地址写入 SCAT_GATHER_RX_BASE_ADDRESS 寄存器中,然后
再启动DMA传输。
linux下提供了一种用scatter/gather的DMA方式,pci_map_sg(), 实现虚地址映射。
scatter/gather就是为支持它的硬件实现 zero copy的一种途径。scatter/gather 可以一
次DMA传多个buffer块. 这样就在setup dma的时候指定一系列的buffer( offset, len).
(一般来说DMA到一个连续的内存上.也有能够DMA到不连续上面的.)也就是直接让硬件DM
A传到用户空间的buffer里面.
我现在遇到的问题时,我不知道如何实现直接从I/O内存读/写数据到用户空间,如何将用户空间映射成DMA离散的内核空间,不知道如何构建散离表。(即不知道怎样才能得到散离表基地址)。
在win2000 DDK 中有个接口函数:
PVOID ScsiPortGetPhysicalAddress( IN PIDE_Channel IdeChannelIdeChannel, IN PSC
SI_REQUEST_BLOCK Srb,IN PVOID dataPointer, OUT ULONG *length) ;
它的作用是将 用户空间的一个首地址为dataPointer (假设长度为count)的连续数据块
,映射为一个内核空间不连续的离散数据块集合,该离散数据块的第一个数据块的块基地
址为该函数的返回值(设为pysAddress1),第一个数据块的长度由length 返回。
(这样,当第二次再次调用 pysAddress2=ScsiPortGetPhysicalAddress(IdeChannel, S
rb, dataPointer+length,&length2)时,得到第二块内核空间数据块,块首地址和块长
度分别为pysAddress2和length2,以次类推 。
问题时,在linux下,如何实现这个映射?有这样的系统调用吗?如果没有,如何实现?
我的那个设备根本不设计到扇区、块等块设备参
数和变量。只是需要将用户空间的地址映射为物理地址。因此也无法构造struct request
和struct buffer_head 结构。但想避开这些结构,如何操作?
我觉得这个问题对于高手应当很普通的,可是对于我就很困难了。我又重新看了mmap,
不知用kiobuf能否实现?我对mmap这章总是难以理解,对kiobuf也是。希望理解kiobuf很深刻的高手帮忙解答一下。
【 在 terrac (xiaoyt) 的大作中提到: 】
: 这几天很痛苦的查了大量资料,只有一点想法,但还是不敢确定,还恳请高手指点!
: (在driver中)
: 先用remap_page_range建立从用户空间地址到物理地址的映射,得到一个物理地址
: void * buffer.然后进行强制转换:
: struct scatterlist * sgList = (struct scatterlist *)buffer;
: 然后再将sgList的每一项copy到一个要建的散离表各项中。
: 我没有读过linux内核,这些只是猜测。不知各位高手有何看法?
: 附scatterlist结构如下:
: struct scatterlist {
: char * address; /* Location data is to be transferred to, NULL for
: * highmem page */
: ...................
☆—————————————————————————————————————☆
voidkey (探索者) 于 (Thu Mar 11 17:35:12 2004) 提到:
要实现外设直接dma到用户空间既zero copy,我的想法是:
1.先保证用户空间缓冲区全部进行了映射,这可以参考map_user_kiobuf的实现,该函数
在mm/memory.c中,如果直接使用这个函数,就会得到一个struct kiobuf结构变量
2.进行dma映射
这可以使用多次pci_map_single
也可以构造scatterlist然后使用pci_map_sg
3.把一系列dma地址写到外设相应的寄存器中
【 在 terrac (xiaoyt) 的大作中提到: 】
: 我目前在写一个driver。driver做的工作就是:
: 用户程序写时(即发送数据),实现xxx_write(struct file *filp,char *buff,size_t
: cont,loff_t * offset) 时,不想先把用户数据拷贝到kernel空间,而是直接将用户空间
: 连续的数据映射成内核离散的数据,并锁定这些用户数据,这样将得到一个散离表(scat
: terlist)。driver 将这个散离表基地址写进设备的SCAT_GATHER_TX_BASE_ADDRESS 寄存
: 器,并启动DMA传输,即可(然后等到中断服务程序唤醒)。读时(即接受数据时,同样,
: 只需将内核接受数局的散离表基地址写入 SCAT_GATHER_RX_BASE_ADDRESS 寄存器中,然后
: 再启动DMA传输。
: linux下提供了一种用scatter/gather的DMA方式,pci_map_sg(), 实现虚地址映射。
: scatter/gather就是为支持它的硬件实现 zero copy的一种途径。scatter/gather 可以一
: 次DMA传多个buffer块. 这样就在setup dma的时候指定一系列的buffer( offset, len).
: (一般来说DMA到一个连续的内存上.也有能够DMA到不连续上面的.)也就是直接让硬件DM
: A传到用户空间的buffer里面.
: 我现在遇到的问题时,我不知道如何实现直接从I/O内存读/写数据到用户空间,如何将用户空间映射成DMA离散的内核空间,不知道如何构建散离表。(即不知道怎样才能得到散离表基地址)。
: 在win2000 DDK 中有个接口函数:
: PVOID ScsiPortGetPhysicalAddress( IN PIDE_Channel IdeChannelIdeChannel, IN PSC
: SI_REQUEST_BLOCK Srb,IN PVOID dataPointer, OUT ULONG *length) ;
: 它的作用是将 用户空间的一个首地址为dataPointer (假设长度为count)的连续数据块
: ,映射为一个内核空间不连续的离散数据块集合,该离散数据块的第一个数据块的块基地
: 址为该函数的返回值(设为pysAddress1),第一个数据块的长度由length 返回。
: (这样,当第二次再次调用 pysAddress2=ScsiPortGetPhysicalAddress(IdeChannel, S
: rb, dataPointer+length,&length2)时,得到第二块内核空间数据块,块首地址和块长
: 度分别为pysAddress2和length2,以次类推 。
: 问题时,在linux下,如何实现这个映射?有这样的系统调用吗?如果没有,如何实现?
: 我的那个设备根本不设计到扇区、块等块设备参
: 数和变量。只是需要将用户空间的地址映射为物理地址。因此也无法构造struct request
: 和struct buffer_head 结构。但想避开这些结构,如何操作?
: 我觉得这个问题对于高手应当很普通的,可是对于我就很困难了。我又重新看了mmap,
: 不知用kiobuf能否实现?我对mmap这章总是难以理解,对kiobuf也是。希望理解kiobuf很深刻的高手帮忙解答一下。