zero-bounce highmem I/O
Subsystems (12)
PATCH 1/1 zero-bounce highmem I/O
Hi,
I updated the patches to 2.4.9-pre4 along with a few other changes:
- Fix bh_kmap_irq nested irq bug (Andrea, me)
- Remove __scsi_end_request changes and add hard_cur_sectors locally. Done to minimize changes on core code, the new code was not buggy but it's probably more of a 2.5 thing. (me)
- Remove 'enabling highmem I/O' messages (me)
- Up queue_nr_requests a bit (me)
- Drop page_to_bus and page_to_phys from my tree, identical version are in the main line now. (me)
- Sync pci-dma changes with my bio patch set -- use of sg_list and pci_map_sgl makes support of highmem easy. See ide-dma changes. The single page mappings of pci_map_page/unmap_page are good too, of course. SCSI uses the horrible pci_map_sg hack... (me)
There are just two patches now:
- block-highmem-all-7 has everything
- pci-dma-high-1 has PCI DMA changes to support mapping of highmem pages
- block-highmem-7 has core and driver updates
The two latter patches equals the former. Currently it will only compile on x86 due to the scatterlist changes, I'd appreciate info from arch maintainers on whether the pci-dma-high-1 patch does something which can't be readily supported on non-x86 platforms. Dave, comments on that? To me it looks fine, but I could be missing something. And Dave, should I add the 64-bit stuff I started again? :-)
Testers are more than welcome. Oracle had some very abysmal profiling numbers for the stock kernel and bouncing, I won't even show those here in fear of inducing vomit attacks in the readers. The patch is considered stable.
Can't get in to kernel.org currently, so I'm attaching the two patches. They aren't that big anyway...
Signature · 1 line
Jens Axboe
include/asm-i386/pci.h renamed from opt/kernel/linux-2.4.9-pre4/include/asm-i386/pci.h +68 -3
@@ -28,6 +28,7 @@#include <linux/types.h> #include <linux/slab.h> +#include <linux/highmem.h> #include <asm/scatterlist.h> #include <linux/string.h> #include <asm/io.h>
@@ -84,6 +85,27 @@/* Nothing to do */ } +/* +* pci_{map,unmap}_single_page maps a kernel page to a dma_addr_t. identical +* to pci_map_single, but takes a struct page instead of a virtual address +*/ +extern inline dma_addr_t pci_map_page (struct pci_dev *hwdev,struct page *page, +size_t size,int offset,int direction) +{ +if (direction ==PCI_DMA_NONE ) +BUG (); + +return (page - mem_map) *PAGE_SIZE + offset; +} + +extern inline void pci_unmap_page (struct pci_dev *hwdev,dma_addr_t dma_address, +size_t size,int direction) +{ +if (direction ==PCI_DMA_NONE ) +BUG (); +/* Nothing to do */ +} +/* Map a set of buffers described by scatterlist in streaming * mode for DMA. This is the scather-gather version of the * above pci_map_single interface. Here the scatter gather list
@@ -102,8 +124,26 @@static inline int pci_map_sg (struct pci_dev *hwdev,struct scatterlist *sg,int nents,int direction) { +int i; +if (direction ==PCI_DMA_NONE )BUG (); + +/* +* temporary 2.4 hack +*/ +for (i =0 ; i < nents; i++ ) { +if (sg[i].address && sg[i].page) +BUG (); +else if (!sg[i].address && !sg[i].page) +BUG (); + +if (sg[i].page) + sg[i].dma_address =page_to_bus (sg[i].page) + sg[i].offset; +else + sg[i].dma_address =virt_to_bus (sg[i].address); + } +return nents; }
@@ -119,6 +159,32 @@/* Nothing to do */ } +/* +* meant to replace the pci_map_sg api, new drivers should use this +* interface +*/ +extern inline int pci_map_sgl (struct pci_dev *hwdev,struct sg_list *sg, +int nents,int direction) +{ +int i; + +if (direction ==PCI_DMA_NONE ) +BUG (); + +for (i =0 ; i < nents; i++) + sg[i].dma_address =page_to_bus (sg[i].page) + sg[i].offset; + +return nents; +} + +extern inline void pci_unmap_sgl (struct pci_dev *hwdev,struct sg_list *sg, +int nents,int direction) +{ +if (direction ==PCI_DMA_NONE ) +BUG (); +/* Nothing to do */ +} +/* Make physical memory consistent for a single * streaming mode DMA translation after a transfer. *
@@ -173,10 +239,9 @@/* These macros should be used after a pci_map_sg call has been done * to get bus addresses of each of the SG entries and their lengths. * You should only work with the number of sg entries pci_map_sg -* returns, or alternatively stop on the first sg_dma_len(sg) which -* is 0. +* returns. */ -#define sg_dma_address (sg) (virt_to_bus((sg)->address)) +#define sg_dma_address (sg) ((sg)->dma_address)#define sg_dma_len (sg) ((sg)->length)/* Return the index of the PCI controller for device. */
include/asm-i386/scatterlist.h renamed from opt/kernel/linux-2.4.9-pre4/include/asm-i386/scatterlist.h +45 -1
57 lines not on this page · raw message
include/linux/pci.h renamed from opt/kernel/linux-2.4.9-pre4/include/linux/pci.h +2 -0
@@ -314,6 +314,8 @@#define PCI_DMA_FROMDEVICE 2#define PCI_DMA_NONE 3 +#define PCI_MAX_DMA32 (0xffffffff) +#define DEVICE_COUNT_COMPATIBLE 4#define DEVICE_COUNT_IRQ 2#define DEVICE_COUNT_DMA 2
drivers/block/cciss.c renamed from opt/kernel/linux-2.4.9-pre4/drivers/block/cciss.c +19 -14
@@ -1129,7 +1129,7 @@ { temp64.val32.lower = cmd->SG[i].Addr.lower; temp64.val32.upper = cmd->SG[i].Addr.upper; -pci_unmap_single (hba[cmd->ctlr]->pdev, +pci_unmap_page (hba[cmd->ctlr]->pdev, temp64.val, cmd->SG[i].Len, (cmd->Request.Type.Direction ==XFER_READ ) ?PCI_DMA_FROMDEVICE :PCI_DMA_TODEVICE );
@@ -1225,7 +1225,7 @@static int cpq_back_merge_fn (request_queue_t *q,struct request *rq,struct buffer_head *bh,int max_segments) { -if (rq->bhtail->b_data + rq->bhtail->b_size == bh->b_data) +if (bh_bus (rq->bhtail) + rq->bhtail->b_size ==bh_bus (bh))return 1 ;return cpq_new_segment (q, rq, max_segments); }
@@ -1233,7 +1233,7 @@static int cpq_front_merge_fn (request_queue_t *q,struct request *rq,struct buffer_head *bh,int max_segments) { -if (bh->b_data + bh->b_size == rq->bh->b_data) +if (bh_bus (bh) + bh->b_size ==bh_bus (rq->bh))return 1 ;return cpq_new_segment (q, rq, max_segments); }
@@ -1243,7 +1243,7 @@ {int total_segments = rq->nr_segments + nxt->nr_segments; -if (rq->bhtail->b_data + rq->bhtail->b_size == nxt->bh->b_data) +if (bh_bus (rq->bhtail) + rq->bhtail->b_size ==bh_bus (nxt->bh)) total_segments--;if (total_segments >MAXSGENTRIES )
@@ -1264,7 +1264,7 @@ctlr_info_t *h= q->queuedata;CommandList_struct *c;int log_unit, start_blk, seg, sect; -char *lastdataend; +unsigned long lastdataend;struct buffer_head *bh;struct list_head *queue_head = &q->queue_head;struct request *creq;
@@ -1272,10 +1272,15 @@struct my_sg tmp_sg[MAXSGENTRIES ];int i; -// Loop till the queue is empty if or it is plugged +if (q->plugged) { +start_io (h); +return ; + } + +// Loop till the queue is empty while (1 ) { -if (q->plugged ||list_empty (queue_head)) { +if (list_empty (queue_head)) {start_io (h);return ; }
@@ -1323,12 +1328,12 @@ (int) creq->nr_sectors);#endif /* CCISS_DEBUG */ seg =0 ; - lastdataend =NULL ; + lastdataend =0 ; sect =0 ;while (bh) { sect += bh->b_size/512 ; -if (bh->b_data == lastdataend) +if (bh_bus (bh) == lastdataend) {// tack it on to the last segment tmp_sg[seg-1 ].len +=bh->b_size; lastdataend += bh->b_size;
@@ -1336,9 +1341,10 @@ {if (seg ==MAXSGENTRIES )BUG (); + tmp_sg[seg].page = bh->b_page; tmp_sg[seg].len = bh->b_size; - tmp_sg[seg].start_addr = bh->b_data; - lastdataend = bh->b_data + bh->b_size; + tmp_sg[seg].offset =bh_offset (bh); + lastdataend =bh_bus (bh) + bh->b_size; seg++; } bh = bh->b_reqnext;
@@ -1347,9 +1353,8 @@for (i=0 ; i<seg; i++) { c->SG[i].Len = tmp_sg[i].len; - temp64.val = (__u64 )pci_map_single ( h->pdev, - tmp_sg[i].start_addr, - tmp_sg[i].len, + temp64.val = (__u64 )pci_map_page ( h->pdev, + tmp_sg[i].page, tmp_sg[i].len, tmp_sg[i].offset, (c->Request.Type.Direction ==XFER_READ ) ?PCI_DMA_FROMDEVICE :PCI_DMA_TODEVICE ); c->SG[i].Addr.lower = temp64.val32.lower;
drivers/block/cciss.h renamed from opt/kernel/linux-2.4.9-pre4/drivers/block/cciss.h +3 -2
@@ -16,8 +16,9 @@#define MAJOR_NR COMPAQ_CISS_MAJORstruct my_sg { -int len; -char *start_addr; +struct page *page; +unsigned short len; +unsigned short offset; };struct ctlr_info ;
drivers/block/cpqarray.c renamed from opt/kernel/linux-2.4.9-pre4/drivers/block/cpqarray.c +21 -14
@@ -367,7 +367,7 @@static int cpq_back_merge_fn (request_queue_t *q,struct request *rq,struct buffer_head *bh,int max_segments) { -if (rq->bhtail->b_data + rq->bhtail->b_size == bh->b_data) +if (bh_bus (rq->bhtail) + rq->bhtail->b_size ==bh_bus (bh))return 1 ;return cpq_new_segment (q, rq, max_segments); }
@@ -375,7 +375,7 @@static int cpq_front_merge_fn (request_queue_t *q,struct request *rq,struct buffer_head *bh,int max_segments) { -if (bh->b_data + bh->b_size == rq->bh->b_data) +if (bh_bus (bh) + bh->b_size ==bh_bus (rq->bh))return 1 ;return cpq_new_segment (q, rq, max_segments); }
@@ -385,7 +385,7 @@ {int total_segments = rq->nr_segments + nxt->nr_segments; -if (rq->bhtail->b_data + rq->bhtail->b_size == nxt->bh->b_data) +if (bh_bus (rq->bhtail) + rq->bhtail->b_size ==bh_bus (nxt->bh)) total_segments--;if (total_segments >SG_MAX )
@@ -532,6 +532,7 @@ q =BLK_DEFAULT_QUEUE (MAJOR_NR + i); q->queuedata = hba[i];blk_init_queue (q, do_ida_request); +blk_queue_bounce_limit (q,BLK_BOUNCE_4G );blk_queue_headactive (q,0 ); blksize_size[MAJOR_NR +i] = ida_blocksizes + (i*256 ); hardsect_size[MAJOR_NR +i] = ida_hardsizes + (i*256 );
@@ -923,17 +924,22 @@ctlr_info_t *h = q->queuedata;cmdlist_t *c;int seg, sect; -char *lastdataend; +unsigned long lastdataend;struct list_head * queue_head = &q->queue_head;struct buffer_head *bh;struct request *creq;struct my_sg tmp_sg[SG_MAX ];int i; -// Loop till the queue is empty if or it is plugged +if (q->plugged) { +start_io (h); +return ; + } + +// Loop till the queue is empty while (1 ) { -if (q->plugged ||list_empty (queue_head)) { +if (list_empty (queue_head)) {start_io (h);return ; }
@@ -973,19 +979,20 @@printk ("sector=%d, nr_sectors=%d\n" , creq->sector, creq->nr_sectors); ); - seg =0 ; lastdataend =NULL ; + seg = lastdataend =0 ; sect =0 ;while (bh) { sect += bh->b_size/512 ; -if (bh->b_data == lastdataend) { +if (bh_bus (bh) == lastdataend) { tmp_sg[seg-1 ].size += bh->b_size; lastdataend += bh->b_size; }else {if (seg ==SG_MAX )BUG (); + tmp_sg[seg].page = bh->b_page; tmp_sg[seg].size = bh->b_size; - tmp_sg[seg].start_addr = bh->b_data; - lastdataend = bh->b_data + bh->b_size; + tmp_sg[seg].offset =bh_offset (bh); + lastdataend =bh_bus (bh) + bh->b_size; seg++; } bh = bh->b_reqnext;
@@ -994,9 +1001,9 @@for ( i=0 ; i < seg; i++) { c->req.sg[i].size = tmp_sg[i].size; - c->req.sg[i].addr = (__u32 )pci_map_single ( - h->pci_dev, tmp_sg[i].start_addr, - tmp_sg[i].size, + c->req.sg[i].addr = (__u32 )pci_map_page ( + h->pci_dev, tmp_sg[i].page, tmp_sg[i].size, + tmp_sg[i].offset, (creq->cmd ==READ ) ?PCI_DMA_FROMDEVICE :PCI_DMA_TODEVICE ); }
@@ -1103,7 +1110,7 @@/* unmap the DMA mapping for all the scatter gather elements */ for (i=0 ; i<cmd->req.hdr.sg_cnt; i++) { -pci_unmap_single (hba[cmd->ctlr]->pci_dev, +pci_unmap_page (hba[cmd->ctlr]->pci_dev, cmd->req.sg[i].addr, cmd->req.sg[i].size, (cmd->req.hdr.cmd ==IDA_READ ) ?PCI_DMA_FROMDEVICE :PCI_DMA_TODEVICE ); }
drivers/block/cpqarray.h renamed from opt/kernel/linux-2.4.9-pre4/drivers/block/cpqarray.h +3 -2
@@ -57,8 +57,9 @@#ifdef __KERNEL__struct my_sg { -int size; -char *start_addr; +struct page *page; +unsigned short size; +unsigned short offset; };struct ctlr_info ;
drivers/block/elevator.c renamed from opt/kernel/linux-2.4.9-pre4/drivers/block/elevator.c +0 -1
@@ -110,7 +110,6 @@break ; }else if (__rq->sector - count == bh->b_rsector) { ret =ELEVATOR_FRONT_MERGE ; - __rq->elevator_sequence -= count; *req = __rq;break ; }
drivers/block/ll_rw_blk.c renamed from opt/kernel/linux-2.4.9-pre4/drivers/block/ll_rw_blk.c +41 -27
168 lines not on this page · raw message
drivers/block/loop.c renamed from opt/kernel/linux-2.4.9-pre4/drivers/block/loop.c +1 -3
@@ -453,9 +453,7 @@ goto err; } -#if CONFIG_HIGHMEM - rbh =create_bounce (rw, rbh); -#endif + rbh =blk_queue_bounce (q, rw, rbh);/* * file backed, queue for loop_thread to handle
drivers/ide/hpt34x.c renamed from opt/kernel/linux-2.4.9-pre4/drivers/ide/hpt34x.c +1 -0
@@ -425,6 +425,7 @@ hwif->autodma =0 ; hwif->dmaproc = &hpt34x_dmaproc; + hwif->highmem =1 ; }else { hwif->drives[0 ].autotune =1 ; hwif->drives[1 ].autotune =1 ;
drivers/ide/hpt366.c renamed from opt/kernel/linux-2.4.9-pre4/drivers/ide/hpt366.c +1 -0
@@ -720,6 +720,7 @@ hwif->autodma =1 ; else hwif->autodma = 0; + hwif->highmem =1 ; }else { hwif->autodma =0 ; hwif->drives[0 ].autotune =1 ;
drivers/ide/ide-disk.c renamed from opt/kernel/linux-2.4.9-pre4/drivers/ide/ide-disk.c +21 -11
@@ -27,9 +27,10 @@* Version 1.09 added increment of rq->sector in ide_multwrite * added UDMA 3/4 reporting * Version 1.10 request queue changes, Ultra DMA 100 +* Version 1.11 Highmem I/O support, Jens Axboe <[email protected]> */ -#define IDEDISK_VERSION "1.10" +#define IDEDISK_VERSION "1.11"#undef REALLY_SLOW_IO/* most systems can safely undef this */
@@ -139,7 +140,9 @@byte stat;int i;unsigned int msect, nsect; +unsigned long flags;struct request *rq; +char *to;/* new way for dealing with premature shared PCI interrupts */ if (!OK_STAT (stat=GET_STAT (),DATA_READY ,BAD_R_STAT )) {
@@ -150,8 +153,8 @@ide_set_handler (drive, &read_intr,WAIT_CMD ,NULL );return ide_started; } + msect = drive->mult_count; - read_next: rq =HWGROUP (drive)->rq;if (msect) {
@@ -160,14 +163,15 @@ msect -= nsect; }else nsect =1 ; -idedisk_input_data (drive, rq->buffer, nsect *SECTOR_WORDS ); + to =ide_map_buffer (rq, &flags); +idedisk_input_data (drive, to, nsect *SECTOR_WORDS );#ifdef DEBUG printk ("%s: read: sectors(%ld-%ld), buffer=0x%08lx, remaining=%ld\n" , drive->name, rq->sector, rq->sector+nsect-1 , (unsigned long ) rq->buffer+(nsect<<9 ), rq->nr_sectors-nsect);#endif +ide_unmap_buffer (to, &flags); rq->sector += nsect; - rq->buffer += nsect<<9 ; rq->errors =0 ; i = (rq->nr_sectors -= nsect);if (((long )(rq->current_nr_sectors -= nsect)) <=0 )
@@ -201,14 +205,16 @@#endif if ((rq->nr_sectors ==1 ) ^ ((stat &DRQ_STAT ) !=0 )) { rq->sector++; - rq->buffer +=512 ; rq->errors =0 ; i = --rq->nr_sectors; --rq->current_nr_sectors;if (((long )rq->current_nr_sectors) <=0 )ide_end_request (1 , hwgroup);if (i >0 ) { -idedisk_output_data (drive, rq->buffer,SECTOR_WORDS ); +unsigned long flags; +char *to =ide_map_buffer (rq, &flags); +idedisk_output_data (drive, to,SECTOR_WORDS ); +ide_unmap_buffer (to, &flags);ide_set_handler (drive, &write_intr,WAIT_CMD ,NULL );return ide_started; }
@@ -238,14 +244,14 @@ do { char *buffer; int nsect = rq->current_nr_sectors; - + unsigned long flags; + if (nsect > mcount) nsect = mcount; mcount -= nsect; - buffer = rq->buffer; + buffer = ide_map_buffer(rq, &flags); rq->sector += nsect; - rq->buffer += nsect << 9; rq->nr_sectors -= nsect; rq->current_nr_sectors -= nsect;
@@ -259,7 +265,7 @@ }else { rq->bh = bh; rq->current_nr_sectors = bh->b_size >>9 ; - rq->buffer = bh->b_data; + rq->hard_cur_sectors = rq->current_nr_sectors; } }
@@ -268,6 +274,7 @@* re-entering us on the last transfer. */ idedisk_output_data (drive, buffer, nsect<<7 ); +ide_unmap_buffer (buffer, &flags); }while (mcount);return 0 ;
@@ -452,8 +459,11 @@return ide_stopped; } }else { +unsigned long flags; +char *buffer =ide_map_buffer (rq, &flags);ide_set_handler (drive, &write_intr,WAIT_CMD ,NULL ); -idedisk_output_data (drive, rq->buffer,SECTOR_WORDS ); +idedisk_output_data (drive, buffer,SECTOR_WORDS ); +ide_unmap_buffer (buffer, &flags); }return ide_started; }
drivers/ide/ide-dma.c renamed from opt/kernel/linux-2.4.9-pre4/drivers/ide/ide-dma.c +77 -53
211 lines not on this page · raw message
drivers/ide/pdc202xx.c renamed from opt/kernel/linux-2.4.9-pre4/drivers/ide/pdc202xx.c +1 -0
@@ -891,6 +891,7 @@#ifdef CONFIG_BLK_DEV_IDEDMA if (hwif->dma_base) { hwif->dmaproc = &pdc202xx_dmaproc; + hwif->highmem =1 ;if (!noautodma) hwif->autodma =1 ; }else {
drivers/ide/piix.c renamed from opt/kernel/linux-2.4.9-pre4/drivers/ide/piix.c +1 -0
@@ -521,6 +521,7 @@if (!hwif->dma_base)return ; + hwif->highmem =1 ;#ifndef CONFIG_BLK_DEV_IDEDMA hwif->autodma =0 ;#else /* CONFIG_BLK_DEV_IDEDMA */
drivers/scsi/aic7xxx/aic7xxx_linux_host.h renamed from opt/kernel/linux-2.4.9-pre4/drivers/scsi/aic7xxx/aic7xxx_linux_host.h +2 -1
@@ -81,7 +81,8 @@ present: 0, /* number of 7xxx's present */\ unchecked_isa_dma: 0, /* no memory DMA restrictions */\ use_clustering: ENABLE_CLUSTERING, \ - use_new_eh_code: 1 \ + use_new_eh_code: 1, \ + can_dma_32: 1 \ } #endif /* _AIC7XXX_LINUX_HOST_H_ */
drivers/scsi/hosts.c renamed from opt/kernel/linux-2.4.9-pre4/drivers/scsi/hosts.c +1 -0
@@ -235,6 +235,7 @@ retval->cmd_per_lun = tpnt->cmd_per_lun; retval->unchecked_isa_dma = tpnt->unchecked_isa_dma; retval->use_clustering = tpnt->use_clustering; + retval->can_dma_32 = tpnt->can_dma_32; retval->select_queue_depths = tpnt->select_queue_depths; retval->max_sectors = tpnt->max_sectors;
drivers/scsi/hosts.h renamed from opt/kernel/linux-2.4.9-pre4/drivers/scsi/hosts.h +3 -0
@@ -291,6 +291,8 @@*/ unsigned emulated:1; + unsigned can_dma_32:1; +/* * Name of proc directory */
@@ -390,6 +392,7 @@ unsigned in_recovery:1; unsigned unchecked_isa_dma:1; unsigned use_clustering:1; + unsigned can_dma_32:1;/* * True if this host was loaded as a loadable module */
drivers/scsi/qlogicfc.h renamed from opt/kernel/linux-2.4.9-pre4/drivers/scsi/qlogicfc.h +2 -1
@@ -100,7 +100,8 @@ cmd_per_lun: QLOGICFC_CMD_PER_LUN, \ present: 0, \ unchecked_isa_dma: 0, \ - use_clustering: ENABLE_CLUSTERING \ + use_clustering: ENABLE_CLUSTERING, \ + can_dma_32: 1 \ } #endif /* _QLOGICFC_H */
drivers/scsi/scsi.c renamed from opt/kernel/linux-2.4.9-pre4/drivers/scsi/scsi.c +7 -4
@@ -178,10 +178,13 @@* handler in the list - ultimately they call scsi_request_fn * to do the dirty deed. */ -void scsi_initialize_queue (Scsi_Device * SDpnt,struct Scsi_Host * SHpnt) { -blk_init_queue (&SDpnt->request_queue, scsi_request_fn); -blk_queue_headactive (&SDpnt->request_queue,0 ); - SDpnt->request_queue.queuedata = (void *) SDpnt; +void scsi_initialize_queue (Scsi_Device * SDpnt,struct Scsi_Host * SHpnt) +{ +request_queue_t *q = &SDpnt->request_queue; + +blk_init_queue (q, scsi_request_fn); +blk_queue_headactive (q,0 ); + q->queuedata = (void *) SDpnt; }#ifdef MODULE
drivers/scsi/scsi.h renamed from opt/kernel/linux-2.4.9-pre4/drivers/scsi/scsi.h +1 -1
@@ -391,7 +391,7 @@#define CONTIGUOUS_BUFFERS (X ,Y ) \ (virt_to_phys((X)->b_data+(X)->b_size-1)+1==virt_to_phys((Y)->b_data))#else -#define CONTIGUOUS_BUFFERS (X ,Y ) ((X->b_data+X->b_size) == Y->b_data) +#define CONTIGUOUS_BUFFERS (X ,Y ) (bh_bus((X)) + (X)->b_size == bh_bus((Y)))#endif
drivers/scsi/scsi_lib.c renamed from opt/kernel/linux-2.4.9-pre4/drivers/scsi/scsi_lib.c +13 -9
@@ -388,6 +388,7 @@ req->nr_sectors -= nsect; req->current_nr_sectors = bh->b_size >>9 ; + req->hard_cur_sectors = req->current_nr_sectors;if (req->nr_sectors < req->current_nr_sectors) { req->nr_sectors = req->current_nr_sectors;printk ("scsi_end_request: buffer-list destroyed\n" );
@@ -410,7 +411,6 @@ q = &SCpnt->device->request_queue; - req->buffer = bh->b_data;/* * Bleah. Leftovers again. Stick the leftovers in * the front of the queue, and goose the queue again.
@@ -489,6 +489,8 @@*/ static void scsi_release_buffers (Scsi_Cmnd * SCpnt) { +struct request *req = &SCpnt->request; +ASSERT_LOCK (&io_request_lock,0 );/*
@@ -507,9 +509,8 @@ }scsi_free (SCpnt->request_buffer, SCpnt->sglist_len); }else { -if (SCpnt->request_buffer != SCpnt->request.buffer) { -scsi_free (SCpnt->request_buffer, SCpnt->request_bufflen); - } +if (SCpnt->request_buffer != req->buffer) +scsi_free (SCpnt->request_buffer,SCpnt->request_bufflen); }/*
@@ -545,6 +546,7 @@int result = SCpnt->result;int this_count = SCpnt->bufflen >>9 ;request_queue_t *q = &SCpnt->device->request_queue; +struct request *req = &SCpnt->request;/* * We must do one of several things here:
@@ -574,7 +576,7 @@for (i =0 ; i < SCpnt->use_sg; i++) {if (sgpnt[i].alt_address) { -if (SCpnt->request.cmd ==READ ) { +if (req->cmd ==READ ) {memcpy (sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length);
@@ -584,10 +586,12 @@ }scsi_free (SCpnt->buffer, SCpnt->sglist_len); }else { -if (SCpnt->buffer != SCpnt->request.buffer) { -if (SCpnt->request.cmd ==READ ) { -memcpy (SCpnt->request.buffer, SCpnt->buffer, - SCpnt->bufflen); +if (SCpnt->buffer != req->buffer) { +if (req->cmd ==READ ) { +unsigned long flags; +char *to =bh_kmap_irq (req->bh, &flags); +memcpy (to, SCpnt->buffer, SCpnt->bufflen); +bh_kunmap_irq (to, &flags); }scsi_free (SCpnt->buffer, SCpnt->bufflen); }
drivers/scsi/scsi_merge.c renamed from opt/kernel/linux-2.4.9-pre4/drivers/scsi/scsi_merge.c +51 -84
296 lines not on this page · raw message
drivers/scsi/sym53c8xx.h renamed from opt/kernel/linux-2.4.9-pre4/drivers/scsi/sym53c8xx.h +2 -1
@@ -96,7 +96,8 @@ this_id: 7, \ sg_tablesize: SCSI_NCR_SG_TABLESIZE, \ cmd_per_lun: SCSI_NCR_CMD_PER_LUN, \ - use_clustering: DISABLE_CLUSTERING} + use_clustering: DISABLE_CLUSTERING, \ + can_dma_32: 1} #else
fs/buffer.c renamed from opt/kernel/linux-2.4.9-pre4/fs/buffer.c +5 -7
@@ -1327,13 +1327,11 @@ bh->b_page = page;if (offset >=PAGE_SIZE )BUG (); -if (PageHighMem (page)) -/* -* This catches illegal uses and preserves the offset: -*/ - bh->b_data = (char *)(0 + offset); -else - bh->b_data =page_address (page) + offset; +/* +* ->virtual is NULL on highmem pages, so we can catch the +* offset even though using page_address on it +*/ + bh->b_data =page_address (page) + offset; }/*
include/asm-i386/kmap_types.h renamed from opt/kernel/linux-2.4.9-pre4/include/asm-i386/kmap_types.h +1 -0
@@ -6,6 +6,7 @@KM_BOUNCE_WRITE ,KM_SKB_DATA ,KM_SKB_DATA_SOFTIRQ , +KM_BH_IRQ , KM_TYPE_NR };
include/linux/blkdev.h renamed from opt/kernel/linux-2.4.9-pre4/include/linux/blkdev.h +25 -3
@@ -36,7 +36,7 @@unsigned long hard_sector, hard_nr_sectors;unsigned int nr_segments;unsigned int nr_hw_segments; -unsigned long current_nr_sectors; +unsigned long current_nr_sectors, hard_cur_sectors;void * special;char * buffer;struct completion * waiting;
@@ -110,6 +110,8 @@*/ char head_active; +struct page *bounce_limit; +/* * Is meant to protect the queue in the future instead of * io_request_lock
@@ -122,6 +124,27 @@wait_queue_head_t wait_for_request; }; +extern unsigned long blk_max_low_pfn; + +#define BLK_BOUNCE_HIGH (blk_max_low_pfn * PAGE_SIZE) +#define BLK_BOUNCE_4G PCI_MAX_DMA32 + +extern void blk_queue_bounce_limit (request_queue_t *,unsigned long ); + +#ifdef CONFIG_HIGHMEM +extern struct buffer_head *create_bounce (int ,struct buffer_head *); +extern inline struct buffer_head *blk_queue_bounce (request_queue_t *q,int rw, +struct buffer_head *bh) +{ +if (bh->b_page <= q->bounce_limit) +return bh; + +return create_bounce (rw, bh); +} +#else +#define blk_queue_bounce (q, rw, bh) (bh) +#endif +struct blk_dev_struct {/* * queue_proc has to be atomic
@@ -149,8 +172,7 @@extern void grok_partitions (struct gendisk *dev,int drive,unsigned minors,long size);extern void register_disk (struct gendisk *dev,kdev_t first,unsigned minors,struct block_device_operations *ops,long size);extern void generic_make_request (int rw,struct buffer_head * bh); -extern request_queue_t *blk_get_queue (kdev_t dev); -extern inline request_queue_t *__blk_get_queue (kdev_t dev); +extern inline request_queue_t *blk_get_queue (kdev_t dev);extern void blkdev_release_request (struct request *);/*
include/linux/fs.h renamed from opt/kernel/linux-2.4.9-pre4/include/linux/fs.h +2 -0
@@ -277,6 +277,8 @@#define bh_offset (bh) ((unsigned long)(bh)->b_data & ~PAGE_MASK) +#define bh_bus (bh) (page_to_bus((bh)->b_page) + bh_offset((bh))) +extern void set_bh_page (struct buffer_head *bh,struct page *page,unsigned long offset);#define touch_buffer (bh) SetPageReferenced(bh->b_page)
include/linux/highmem.h renamed from opt/kernel/linux-2.4.9-pre4/include/linux/highmem.h +41 -4
63 lines not on this page · raw message
include/linux/ide.h renamed from opt/kernel/linux-2.4.9-pre4/include/linux/ide.h +17 -1
@@ -485,7 +485,7 @@ide_dmaproc_t *dmaproc;/* dma read/write/abort routine */ unsigned int *dmatable_cpu;/* dma physical region descriptor table (cpu view) */ dma_addr_t dmatable_dma;/* dma physical region descriptor table (dma view) */ -struct scatterlist *sg_table;/* Scatter-gather list used to build the above */ +struct sg_list *sg_table;/* Scatter-gather list used to build the above */ int sg_nents;/* Current number of entries in it */ int sg_dma_direction;/* dma transfer direction */ int sg_dma_active;/* is it in use */
@@ -507,6 +507,7 @@ unsigned reset : 1; /* reset after probe */ unsigned autodma : 1; /* automatically try to enable DMA at boot */ unsigned udma_four : 1; /* 1=ATA-66 capable, 0=default */ + unsigned highmem : 1; /* can do full 32-bit dma */byte channel;/* for dual-port chips: 0=primary, 1=secondary */ #ifdef CONFIG_BLK_DEV_IDEPCI struct pci_dev *pci_dev;/* for pci chipsets */
@@ -812,6 +813,21 @@ ide_preempt,/* insert rq in front of current request */ ide_end /* insert rq at end of list, but don't wait for it */ } ide_action_t; + +/* +* temporarily mapping a (possible) highmem bio +*/ +#define ide_rq_offset (rq) (((rq)->hard_cur_sectors - (rq)->current_nr_sectors) << 9) + +extern inline void *ide_map_buffer (struct request *rq,unsigned long *flags) +{ +return bh_kmap_irq (rq->bh, flags) +ide_rq_offset (rq); +} + +extern inline void ide_unmap_buffer (char *buffer,unsigned long *flags) +{ +bh_kunmap_irq (buffer, flags); +}/* * This function issues a special IDE device request
kernel/ksyms.c renamed from opt/kernel/linux-2.4.9-pre4/kernel/ksyms.c +2 -0
@@ -121,6 +121,8 @@EXPORT_SYMBOL (kunmap_high);EXPORT_SYMBOL (highmem_start_page);EXPORT_SYMBOL (create_bounce); +EXPORT_SYMBOL (kmap_prot); +EXPORT_SYMBOL (kmap_pte);#endif /* filesystem internal functions */
From: Jens Axboe <[email protected]>
Date: Wed, 15 Aug 2001 09:50:18 +0200
Dave, comments on that?
I think the new-style sg_list is slightly overkill, too much stuff. You need much less, in fact, especially on x86.
Take include/linux/skbuff.h:skb_frag_struct, rename it to sg_list and add a dma_addr_t. You should need nothing else. The bounce page, for example, is superfluous.
If you bounce, the bounce page can be determined later via the dma_addr_t right?
And Dave, should I add the 64-bit stuff I started again? :-)
Let me draft something up, and meanwhile you can think about the changes I suggest above. Ok?
Later,
David S. Miller
[email protected]
Quoted 11 lines · David S. Miller
From: Jens Axboe <[email protected]>
Date: Wed, 15 Aug 2001 09:50:18 +0200Dave, comments on that?
I think the new-style
sg_listis slightly overkill, too much stuff. You need much less, in fact, especially on x86.Take include/linux/skbuff.h:skb_frag_struct, rename it to
sg_listand add adma_addr_t. You should need nothing else. The bounce page, for example, is superfluous.
Ok agreed, fine with me.
Quoted 2 lines
If you bounce, the bounce page can be determined later via the
dma_addr_tright?
That's true.
Quoted 4 lines
And Dave, should I add the 64-bit stuff I started again? :-)
Let me draft something up, and meanwhile you can think about the changes I suggest above. Ok?
Ok done from my side :)
Signature · 1 line
Jens Axboe
Quoted 11 lines · David S. Miller
From: Jens Axboe <[email protected]>
Date: Wed, 15 Aug 2001 09:50:18 +0200Dave, comments on that?
I think the new-style
sg_listis slightly overkill, too much stuff. You need much less, in fact, especially on x86.Take include/linux/skbuff.h:skb_frag_struct, rename it to
sg_listand add adma_addr_t. You should need nothing else. The bounce page, for example, is superfluous.
Ok, here's an updated version. Maybe modulo the struct scatterlist changes, I'd like to see this included in 2.4.x soonish. Or at least the interface we agree on -- it'll make my life easier at least. And finally provide driver authors with something not quite as stupid as struct scatterlist.
Signature · 1 line
Jens Axboe
include/asm-i386/pci.h renamed from opt/kernel/linux-2.4.9-pre4/include/asm-i386/pci.h +68 -3
@@ -28,6 +28,7 @@#include <linux/types.h> #include <linux/slab.h> +#include <linux/highmem.h> #include <asm/scatterlist.h> #include <linux/string.h> #include <asm/io.h>
@@ -84,6 +85,27 @@/* Nothing to do */ } +/* +* pci_{map,unmap}_single_page maps a kernel page to a dma_addr_t. identical +* to pci_map_single, but takes a struct page instead of a virtual address +*/ +extern inline dma_addr_t pci_map_page (struct pci_dev *hwdev,struct page *page, +size_t size,int offset,int direction) +{ +if (direction ==PCI_DMA_NONE ) +BUG (); + +return (page - mem_map) *PAGE_SIZE + offset; +} + +extern inline void pci_unmap_page (struct pci_dev *hwdev,dma_addr_t dma_address, +size_t size,int direction) +{ +if (direction ==PCI_DMA_NONE ) +BUG (); +/* Nothing to do */ +} +/* Map a set of buffers described by scatterlist in streaming * mode for DMA. This is the scather-gather version of the * above pci_map_single interface. Here the scatter gather list
@@ -102,8 +124,26 @@static inline int pci_map_sg (struct pci_dev *hwdev,struct scatterlist *sg,int nents,int direction) { +int i; +if (direction ==PCI_DMA_NONE )BUG (); + +/* +* temporary 2.4 hack +*/ +for (i =0 ; i < nents; i++ ) { +if (sg[i].address && sg[i].page) +BUG (); +else if (!sg[i].address && !sg[i].page) +BUG (); + +if (sg[i].page) + sg[i].dma_address =page_to_bus (sg[i].page) + sg[i].offset; +else + sg[i].dma_address =virt_to_bus (sg[i].address); + } +return nents; }
@@ -119,6 +159,32 @@/* Nothing to do */ } +/* +* meant to replace the pci_map_sg api, new drivers should use this +* interface +*/ +extern inline int pci_map_sgl (struct pci_dev *hwdev,struct sg_list *sg, +int nents,int direction) +{ +int i; + +if (direction ==PCI_DMA_NONE ) +BUG (); + +for (i =0 ; i < nents; i++) + sg[i].dma_address =page_to_bus (sg[i].page) + sg[i].offset; + +return nents; +} + +extern inline void pci_unmap_sgl (struct pci_dev *hwdev,struct sg_list *sg, +int nents,int direction) +{ +if (direction ==PCI_DMA_NONE ) +BUG (); +/* Nothing to do */ +} +/* Make physical memory consistent for a single * streaming mode DMA translation after a transfer. *
@@ -173,10 +239,9 @@/* These macros should be used after a pci_map_sg call has been done * to get bus addresses of each of the SG entries and their lengths. * You should only work with the number of sg entries pci_map_sg -* returns, or alternatively stop on the first sg_dma_len(sg) which -* is 0. +* returns. */ -#define sg_dma_address (sg) (virt_to_bus((sg)->address)) +#define sg_dma_address (sg) ((sg)->dma_address)#define sg_dma_len (sg) ((sg)->length)/* Return the index of the PCI controller for device. */
include/asm-i386/scatterlist.h renamed from opt/kernel/linux-2.4.9-pre4/include/asm-i386/scatterlist.h +41 -1
53 lines not on this page · raw message
include/linux/pci.h renamed from opt/kernel/linux-2.4.9-pre4/include/linux/pci.h +2 -0
@@ -314,6 +314,8 @@#define PCI_DMA_FROMDEVICE 2#define PCI_DMA_NONE 3 +#define PCI_MAX_DMA32 (0xffffffff) +#define DEVICE_COUNT_COMPATIBLE 4#define DEVICE_COUNT_IRQ 2#define DEVICE_COUNT_DMA 2
From: Jens Axboe <[email protected]>
Date: Wed, 15 Aug 2001 11:26:21 +0200
Ok, here's an updated version. Maybe modulo the struct scatterlist changes, I'd like to see this included in 2.4.x soonish. Or at least the interface we agree on -- it'll make my life easier at least. And finally provide driver authors with something not quite as stupid as struct scatterlist.
Jens, have a look at the patch I have below. What do you think about it? Specifically the set of interfaces.
Andrea, I am very much interested in your input as well.
I would like to kill two birds with one stone here if
we can. The x86 versions of the asm/pci.h andasm/scatterlist.h bits are pretty mindless and left as an exercise to the reader :-)
pci/pci.c renamed from pci/pci.c.~1~ +7 -1
@@ -832,7 +832,7 @@ }int -pci_set_dma_mask (struct pci_dev *dev,dma_addr_t mask) +pci_set_dma_mask (struct pci_dev *dev,u64 mask) {if (!pci_dma_supported (dev, mask))return -EIO ;
@@ -842,6 +842,12 @@return 0 ; } +void +pci_change_dma_flag (struct pci_dev *dev,unsigned int on,unsigned int off) +{ + dev->dma_flags |= on; + dev->dma_flags &= ~off; +}/* * Translate the low bits of the PCI base
asm-sparc64/pci.h renamed from asm-sparc64/pci.h.~1~ +35 -4
@@ -28,6 +28,13 @@/* Dynamic DMA mapping stuff. */ +/* PCI 64-bit addressing works for all slots on all controller +* types on sparc64. However, it requires that the device +* can drive enough of the 64 bits. +*/ +#define pci_dac_cycles_ok (pci_dev) \ + (((pci_dev)->dma_mask & PCI64_ADDR_BASE) == PCI64_ADDR_BASE) +#include <asm/scatterlist.h> struct pci_dev ;
@@ -64,6 +71,20 @@*/ extern void pci_unmap_single (struct pci_dev *hwdev,dma_addr_t dma_addr,size_t size,int direction); +/* No highmem on sparc64, plus we have an IOMMU, so mapping pages is easy. */ +#define pci_map_page (dev, page, off, size, dir) \ + pci_map_single(dev, (page_address(page) + (off)), size, dir) +#define pci_unmap_page (dev,addr,sz,dir) pci_unmap_single(dev,addr,sz,dir) + +/* The 64-bit cases might have to do something interesting if +* PCI_DMA_FLAG_HUGE_MAPS is set in hwdev->dma_flags. +*/ +extern dma64_addr_t pci64_map_page (struct pci_dev *hwdev, +struct page *page,unsigned long offset, +size_t size,int direction); +extern void pci64_unmap_page (struct pci_dev *hwdev,dma64_addr_t dma_addr, +size_t size,int direction); +/* Map a set of buffers described by scatterlist in streaming * mode for DMA. This is the scather-gather version of the * above pci_map_single interface. Here the scatter gather list
@@ -79,13 +100,19 @@* Device ownership issues as mentioned above for pci_map_single are * the same here. */ -extern int pci_map_sg (struct pci_dev *hwdev,struct scatterlist *sg,int nents,int direction); +extern int pci_map_sg (struct pci_dev *hwdev,struct scatterlist *sg, +int nents,int direction); +extern int pci64_map_sg (struct pci_dev *hwdev,struct scatterlist *sg, +int nents,int direction);/* Unmap a set of streaming mode DMA translations. * Again, cpu read rules concerning calls here are the same as for * pci_unmap_single() above. */ -extern void pci_unmap_sg (struct pci_dev *hwdev,struct scatterlist *sg,int nhwents,int direction); +extern void pci_unmap_sg (struct pci_dev *hwdev,struct scatterlist *sg, +int nhwents,int direction); +extern void pci64_unmap_sg (struct pci_dev *hwdev,struct scatterlist *sg, +int nhwents,int direction);/* Make physical memory consistent for a single * streaming mode DMA translation after a transfer.
@@ -96,7 +123,10 @@* next point you give the PCI dma address back to the card, the * device again owns the buffer. */ -extern void pci_dma_sync_single (struct pci_dev *hwdev,dma_addr_t dma_handle,size_t size,int direction); +extern void pci_dma_sync_single (struct pci_dev *hwdev,dma_addr_t dma_handle, +size_t size,int direction); +extern void pci64_dma_sync_single (struct pci_dev *hwdev,dma64_addr_t dma_handle, +size_t size,int direction);/* Make physical memory consistent for a set of streaming * mode DMA translations after a transfer.
@@ -105,13 +135,14 @@* same rules and usage. */ extern void pci_dma_sync_sg (struct pci_dev *hwdev,struct scatterlist *sg,int nelems,int direction); +extern void pci64_dma_sync_sg (struct pci_dev *hwdev,struct scatterlist *sg,int nelems,int direction);/* Return whether the given PCI device DMA address mask can * be supported properly. For example, if your device can * only drive the low 24-bits during PCI bus mastering, then * you would pass 0x00ffffff as the mask to this function. */ -extern int pci_dma_supported (struct pci_dev *hwdev,dma_addr_t mask); +extern int pci_dma_supported (struct pci_dev *hwdev,u64 mask);/* Return the index of the PCI controller for device PDEV. */
asm-sparc64/scatterlist.h renamed from asm-sparc64/scatterlist.h.~1~ +17 -8
@@ -5,17 +5,26 @@#include <asm/page.h> struct scatterlist { -char * address;/* Location data is to be transferred to */ -char * alt_address;/* Location of actual if address is a -* dma indirect buffer. NULL otherwise */ -unsigned int length; +char *address; +char *alt_address; -__u32 dvma_address;/* A place to hang host-specific addresses at. */ -__u32 dvma_length; +struct page *page; +unsigned int offset; +unsigned int length; + +/* A place to hang host-specific addresses at. */ +union { +dma_addr_t dma32_address; +dma64_addr_t dma64_address; + } dma_u; +#define dvma_address dma_u.dma32_address + +__u32 dvma_length; }; -#define sg_dma_address (sg) ((sg)->dvma_address) -#define sg_dma_len (sg) ((sg)->dvma_length) +#define sg_dma_address (sg) ((sg)->dma_u.dma32_address) +#define sg_dma64_address (sg) ((sg)->dma_u.dma64_address) +#define sg_dma_len (sg) ((sg)->dvma_length)#define ISA_DMA_THRESHOLD (~0UL)
asm-sparc64/types.h renamed from asm-sparc64/types.h.~1~ +2 -1
@@ -45,9 +45,10 @@#define BITS_PER_LONG 64 -/* Dma addresses are 32-bits wide for now. */ +/* Dma addresses come in 32-bit and 64-bit flavours. */ typedef u32 dma_addr_t ; +typedef u64 dma64_addr_t ;#endif /* __KERNEL__ */
linux/pci.h renamed from linux/pci.h.~1~ +12 -3
@@ -314,6 +314,12 @@#define PCI_DMA_FROMDEVICE 2#define PCI_DMA_NONE 3 +/* These are the boolean attributes stored in pci_dev->dma_flags. */ +#define PCI_DMA_FLAG_HUGE_MAPS 0x00000001/* Device may hold an enormous number +* of mappings at once? +*/ +#define PCI_DMA_FLAG_ARCHMASK 0xf0000000/* Reserved for arch-specific flags */ +#define DEVICE_COUNT_COMPATIBLE 4#define DEVICE_COUNT_IRQ 2#define DEVICE_COUNT_DMA 2
@@ -353,11 +359,12 @@struct pci_driver *driver;/* which driver has allocated this device */ void *driver_data;/* data private to the driver */ -dma_addr_t dma_mask;/* Mask of the bits of bus address this +u64 dma_mask;/* Mask of the bits of bus address this device implements. Normally this is 0xffffffff. You only need to change this if your device has broken DMA or supports 64-bit transfers. */ +unsigned int dma_flags;/* See PCI_DMA_FLAG_* above */ u32 current_state;/* Current operating state. In ACPI-speak, this is D0-D3, D0 being fully functional,
@@ -559,7 +566,8 @@int pci_enable_device (struct pci_dev *dev);void pci_disable_device (struct pci_dev *dev);void pci_set_master (struct pci_dev *dev); -int pci_set_dma_mask (struct pci_dev *dev,dma_addr_t mask); +int pci_set_dma_mask (struct pci_dev *dev,u64 mask); +void pci_change_dma_flag (struct pci_dev *dev,unsigned int on,unsigned int off);int pci_assign_resource (struct pci_dev *dev,int i);/* Power management related routines */
@@ -641,7 +649,8 @@static inline int pci_enable_device (struct pci_dev *dev) {return -EIO ; }static inline void pci_disable_device (struct pci_dev *dev) { }static inline int pci_module_init (struct pci_driver *drv) {return -ENODEV ; } -static inline int pci_set_dma_mask (struct pci_dev *dev,dma_addr_t mask) {return -EIO ; } +static inline int pci_set_dma_mask (struct pci_dev *dev,u64 mask) {return -EIO ; } +static inline void pci_change_dma_flag (struct pci_dev *dev,unsigned int on,unsigned int off) { }static inline int pci_assign_resource (struct pci_dev *dev,int i) {return -EBUSY ;}static inline int pci_register_driver (struct pci_driver *drv) {return 0 ;}static inline void pci_unregister_driver (struct pci_driver *drv) { }
Quoted 9 lines · David S. Miller
From: Jens Axboe <[email protected]>
Date: Wed, 15 Aug 2001 11:26:21 +0200Ok, here's an updated version. Maybe modulo the struct scatterlist changes, I'd like to see this included in 2.4.x soonish. Or at least the interface we agree on -- it'll make my life easier at least. And finally provide driver authors with something not quite as stupid as struct scatterlist.
Quoted 4 lines
Jens, have a look at the patch I have below. What do you think about it? Specifically the set of interfaces.
Andrea, I am very much interested in your input as well.
Here is some input you donnot seem interested in. Too bad for you! :-)
Some drivers may want to allocate internal DMAable data structures in a 32 bit DMAable address range but also may want to support 64 bit DMA addressing for user data. This applies to the sym53c8xx driver (which is not quite ready for 64 bit DMA adressing for now) and to the aic7xxx driver which seems to be ready. The reason is for simplicity and may-be feasibility and given that driver internal data structures donnot require that much memory, this should not make memory pressure at all on the 32 bit DMAable range.
The current solution consists in tampering the dma_mask in the pci_dev structure prior to allocating DMAable memory. Not really clean... Some interface that would allow to provide some masks as argument would be cleaner, in my opinion. Btw, the pci_set_* interface does not seem cleaner to me than hacking the corresponding field in the pcidev structure directly.
Quoted 4 lines
I would like to kill two birds with one stone here if
we can. The x86 versions of theasm/pci.handasm/scatterlist.hbits are pretty mindless and left as an exercise to the reader :-)
[... b****ed patch removed since reader should already have it :) ...]
Later,
Gérard.
From: G廨ard Roudier <[email protected]>
Date: Wed, 15 Aug 2001 21:20:17 +0200 (CEST)
The current solution consists in tampering the dma_mask in the pci_dev structure prior to allocating DMAable memory. Not really clean... Some interface that would allow to provide some masks as argument would be cleaner, in my opinion. Btw, the pci_set_* interface does not seem cleaner to me than hacking the corresponding field in the pcidev structure directly.
pci_alloc_consistent will ONLY give you 32-bit DMA memory.
This will be true both before and after my changes. Does the IA64 gross hack behave differently?
Later,
David S. Miller
[email protected] �:.𣳾𤎖忷m賨▎a𪘁b習鮓wm�b嘅��捩滵嶵𪐴�𡟯蔰_�傂n嫑←屹��h膥霅�&�輈蹂z嫡𣚭+��+zfㄑ搬�坍��i����𡟯蔰_霈熝:+v��)舝鷰锭憃�剜𧙕��菈��蟳簏霈�i
Quoted 9 lines · David S. Miller
From: Jens Axboe <[email protected]>
Date: Wed, 15 Aug 2001 13:13:35 +0200Looks fine to me, exactly the interface I've used/wanted. But you want to add the extra page/offset to the existing scatterlist, and not scrap that one completely?
The idea is that address/alt_address disappear sometime in 2.5. Something like this right?
Ok so you just want to turn scatterlist into what I call sg_list in 2.5 time, fine with me too. Depends on whether we want to keep the pci_map_sg and struct scatterlist interface intact, or just break it and tell driver authors they must fix their stuff regardless of whether they want to support highmem. As I write this sentence, it's clear to me which way is the superior :-)
Quoted 2 lines
BTW, on x86 we can ifdef the
dma64_addressto u32 or u64 based uponCONFIG_HIGHMEMif we wish.
Yep. Want me to add in the x86 parts of your patch?
Signature · 1 line
Jens Axboe
From: Jens Axboe <[email protected]>
Date: Wed, 15 Aug 2001 14:07:40 +0200
Ok so you just want to turn scatterlist into what I call sg_list in 2.5 time, fine with me too. Depends on whether we want to keep the pci_map_sg and struct scatterlist interface intact, or just break it and tell driver authors they must fix their stuff regardless of whether they want to support highmem. As I write this sentence, it's clear to me which way is the superior :-)
pci_map_sg is pci_map_sg, if the internal representation of scatterlist is changed such that address/alt_address no longer exist, it will work on pages only. Right? The compatibility mode in 2.4.x is the "if (address != NULL) virt_to_bus(address);" stuff.
Understand that the pci64_{map,unmap}_sg is created for a seperate purpose, independant of whether scatterlist has the backwards compatability stuff or not. (There have been threads here about this, I can describe it quickly for you in quiet if you want to know).
Two more things to consider:
1) There is nobody who cannot be search&replace converted from sg->address = ptr
into
sg->page = virt_to_page(ptr) sg->offset = ((unsigned long)ptr & ~PAGE_MASK);
The only truly problematic area is the alt_address thing. It is would be a nice thing to rip this eyesore out of the scsi layer anyways.
2) I want to put scatterlist in to replace skb_frag_struct in skbuff.h and then have a zerocopy network driver do something like:
header_dma = pci_map_single(pdev, skb->data, skb->len, PCI_DMA_TODEVICE); data_nents = pci_map_sg(pdev, skb_shinfo(skb)->frag_list, skb_shinfo(skb)->nr_frags, PCI_DMA_TODEVICE);
See? :-)
Yep. Want me to add in the x86 parts of your patch?
Please let me finish up my prototype with sparc64 building and working, then I'll send you what I have ok?
Later,
David S. Miller
[email protected]
Quoted 8 lines · David S. Miller
From: "David S. Miller" <[email protected]>
Date: Wed, 15 Aug 2001 07:02:04 -0700 (PDT)> Yep. Want me to add in the x86 parts of your patch?
>
> Please let me finish up my prototype with sparc64 building and > working, then I'll send you what I have ok?
Quoted 5 lines
Fine
This is forthcoming.
As promised. I actually got bored during the build and tried to
Looks good! And works here too, even... ->
Quoted 1 line
quickly cook up the ix86 bits myself :-)
the boring x86 parts :-)
The only difference between your and my tree now is the PCI_MAX_DMA32 flag. Would you consider this? I already use this flag in the block stuff, I just updated the two references you had. Maybe PCI_MAX_DMA32_MASK is a better name.
I'll update the block-highmem patch later today -- and with this in place, there's nothing stopping zero-bounce from going beyond 4GB on the right hw. Yippi.
include/linux/pci.h renamed from include/linux/pci.h~ +2 -0
@@ -314,6 +314,8 @@#define PCI_DMA_FROMDEVICE 2#define PCI_DMA_NONE 3 +#define PCI_MAX_DMA32 0xffffffff +/* These are the boolean attributes stored in pci_dev->dma_flags. */ #define PCI_DMA_FLAG_HUGE_MAPS 0x00000001/* Device may hold an enormous number * of mappings at once?
drivers/scsi/sym53c8xx.c renamed from drivers/scsi/sym53c8xx.c~ +1 -1
@@ -13101,7 +13101,7 @@ (int) (PciDeviceFn(pdev) & 7));#ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING -if (pci_set_dma_mask (pdev,0xffffffff )) { +if (pci_set_dma_mask (pdev,PCI_MAX_DMA32 )) { printk(KERN_WARNING NAME53C8XX "32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");return -1 ;
drivers/scsi/sym53c8xx_comm.h renamed from drivers/scsi/sym53c8xx_comm.h~ +1 -1
@@ -2186,7 +2186,7 @@ (int) (PciDeviceFn(pdev) & 7));#ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING -if (!pci_dma_supported (pdev,0xffffffff )) { +if (!pci_dma_supported (pdev,PCI_MAX_DMA32 )) { printk(KERN_WARNING NAME53C8XX "32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");return -1 ;
Signature · 1 line
Jens Axboe
From: Jens Axboe <[email protected]>
Date: Thu, 16 Aug 2001 13:51:50 +0200
[ Hopefully this mail won't be encoded in Chinese-BIG5 :-) sorry
about that ]
The only difference between your and my tree now is the PCI_MAX_DMA32 flag. Would you consider this? I already use this flag in the block stuff, I just updated the two references you had. Maybe PCI_MAX_DMA32_MASK is a better name.
I didn't put it into my patch becuase there is no way you can use such a value in generic code.
What if my scsi controller's pci DMA mask is 0x7fffffff or something like this? You don't know at the generic layer, and you must provide some way for the block device to indicate stuff like this to you.
That is why PCI_MAX_DMA32, or whatever you would like to name it, does not make any sense. It can be a shorthand for drivers themselves, but that is it and personally I'd rather they just put the bits there explicitly.
I am just finishing up the "death of alt_address" patch right now.
Later,
David S. Miller
[email protected]
kill alt_address (Re: [patch] zero-bounce highmem I/O)
In reply to Jens Axboe From: Jens Axboe <[email protected]>
Date: Thu, 16 Aug 2001 13:51:50 +0200
Quoted 1 line · David S. Miller
As promised. I actually got bored during the build and tried to
Looks good! And works here too, even... ->
Ok, here is my current patch, it kills off alt_address as well as provide the new PCI dma interfaces.
I have no way to test the alt_address stuff here locally, and I'd be happy if someone would give it a go. All I guarentee is that it builds here on my machines :-)
arch/alpha/kernel/pci_iommu.c renamed from arch/alpha/kernel/pci_iommu.c.~1~ +1 -1
@@ -636,7 +636,7 @@supported properly. */ int -pci_dma_supported (struct pci_dev *pdev,dma_addr_t mask) +pci_dma_supported (struct pci_dev *pdev,u64 mask) {struct pci_controller *hose;struct pci_iommu_arena *arena;
arch/sparc64/kernel/pci_iommu.c renamed from arch/sparc64/kernel/pci_iommu.c.~1~ +117 -27
270 lines not on this page · raw message
arch/sparc64/kernel/iommu_common.c renamed from arch/sparc64/kernel/iommu_common.c.~1~ +23 -28
132 lines not on this page · raw message
arch/sparc64/kernel/sbus.c renamed from arch/sparc64/kernel/sbus.c.~1~ +30 -20
117 lines not on this page · raw message
arch/sparc64/kernel/iommu_common.h renamed from arch/sparc64/kernel/iommu_common.h.~1~ +2 -5
@@ -18,10 +18,7 @@#undef VERIFY_SG#ifdef VERIFY_SG -int verify_lengths (struct scatterlist *sg,int nents,int npages); -int verify_one_map (struct scatterlist *dma_sg,struct scatterlist **__sg,int nents,iopte_t **__iopte); -int verify_maps (struct scatterlist *sg,int nents,iopte_t *iopte); -void verify_sglist (struct scatterlist *sg,int nents,iopte_t *iopte,int npages); +extern void verify_sglist (struct scatterlist *sg,int nents,iopte_t *iopte,int npages);#endif /* Two addresses are "virtually contiguous" if and only if:
@@ -31,4 +28,4 @@#define VCONTIG (__X, __Y) (((__X) == (__Y)) || \ (((__X) | (__Y)) << (64UL - PAGE_SHIFT)) == 0UL) -unsigned long prepare_sg (struct scatterlist *sg,int nents); +extern unsigned long prepare_sg (struct scatterlist *sg,int nents);
arch/sparc64/kernel/sparc64_ksyms.c renamed from arch/sparc64/kernel/sparc64_ksyms.c.~1~ +6 -0
@@ -216,10 +216,16 @@EXPORT_SYMBOL (pci_free_consistent);EXPORT_SYMBOL (pci_map_single);EXPORT_SYMBOL (pci_unmap_single); +EXPORT_SYMBOL (pci64_map_page); +EXPORT_SYMBOL (pci64_unmap_page);EXPORT_SYMBOL (pci_map_sg);EXPORT_SYMBOL (pci_unmap_sg); +EXPORT_SYMBOL (pci64_map_sg); +EXPORT_SYMBOL (pci64_unmap_sg);EXPORT_SYMBOL (pci_dma_sync_single); +EXPORT_SYMBOL (pci64_dma_sync_single);EXPORT_SYMBOL (pci_dma_sync_sg); +EXPORT_SYMBOL (pci64_dma_sync_sg);EXPORT_SYMBOL (pci_dma_supported);#endif
arch/ia64/sn/io/pci_dma.c renamed from arch/ia64/sn/io/pci_dma.c.~1~ +1 -1
@@ -182,7 +182,7 @@ }/* -* On sn1 we use the alt_address entry of the scatterlist to store +* On sn1 we use the orig_address entry of the scatterlist to store * the physical address corresponding to the given virtual address */ int
arch/parisc/kernel/ccio-dma.c renamed from arch/parisc/kernel/ccio-dma.c.~1~ +1 -1
@@ -638,7 +638,7 @@ } -static int ccio_dma_supported (struct pci_dev *dev,dma_addr_t mask) +static int ccio_dma_supported (struct pci_dev *dev,u64 mask) {if (dev ==NULL ) {printk (MODULE_NAME ": EISA/ISA/et al not supported\n" );
arch/parisc/kernel/pci-dma.c renamed from arch/parisc/kernel/pci-dma.c.~1~ +1 -1
@@ -77,7 +77,7 @@static inline void dump_resmap (void ) {;}#endif -static int pa11_dma_supported (struct pci_dev *dev,dma_addr_t mask) +static int pa11_dma_supported (struct pci_dev *dev,u64 mask) {return 1 ; }
arch/parisc/kernel/ccio-rm-dma.c renamed from arch/parisc/kernel/ccio-rm-dma.c.~1~ +1 -1
@@ -93,7 +93,7 @@ } -static int ccio_dma_supported (struct pci_dev *dev,dma_addr_t mask) +static int ccio_dma_supported (struct pci_dev *dev,u64 mask) {if (dev ==NULL ) {printk (MODULE_NAME ": EISA/ISA/et al not supported\n" );
arch/parisc/kernel/sba_iommu.c renamed from arch/parisc/kernel/sba_iommu.c.~1~ +1 -1
@@ -779,7 +779,7 @@ }static int -sba_dma_supported (struct pci_dev *dev,dma_addr_t mask) +sba_dma_supported (struct pci_dev *dev,u64 mask) {if (dev ==NULL ) {printk (MODULE_NAME ": EISA/ISA/et al not supported\n" );
drivers/net/acenic.c renamed from drivers/net/acenic.c.~1~ +1 -5
@@ -202,6 +202,7 @@#define pci_free_consistent (cookie, size, ptr, dma_ptr) kfree(ptr)#define pci_map_single (cookie, address, size, dir) virt_to_bus(address)#define pci_unmap_single (cookie, address, size, dir) +#define pci_set_dma_mask (dev, mask) do { } while (0)#endif #if (LINUX_VERSION_CODE <0x02032b )
@@ -258,11 +259,6 @@#define ace_mark_net_bh () {do{} while(0);}#define ace_if_down (dev) {do{} while(0);}#endif - -#ifndef pci_set_dma_mask -#define pci_set_dma_mask (dev, mask) dev->dma_mask = mask; -#endif -#if (LINUX_VERSION_CODE >=0x02031b )#define NEW_NETINIT
drivers/pci/pci.c renamed from drivers/pci/pci.c.~1~ +8 -1
@@ -832,7 +832,7 @@ }int -pci_set_dma_mask (struct pci_dev *dev,dma_addr_t mask) +pci_set_dma_mask (struct pci_dev *dev,u64 mask) {if (!pci_dma_supported (dev, mask))return -EIO ;
@@ -842,6 +842,12 @@return 0 ; } +void +pci_change_dma_flag (struct pci_dev *dev,unsigned int on,unsigned int off) +{ + dev->dma_flags |= on; + dev->dma_flags &= ~off; +}/* * Translate the low bits of the PCI base
@@ -1954,6 +1960,7 @@EXPORT_SYMBOL (pci_find_subsys);EXPORT_SYMBOL (pci_set_master);EXPORT_SYMBOL (pci_set_dma_mask); +EXPORT_SYMBOL (pci_change_dma_flag);EXPORT_SYMBOL (pci_assign_resource);EXPORT_SYMBOL (pci_register_driver);EXPORT_SYMBOL (pci_unregister_driver);
drivers/scsi/sr.c renamed from drivers/scsi/sr.c.~1~ +18 -6
@@ -265,6 +265,7 @@struct scatterlist *sg, *old_sg =NULL ;int i, fsize, bsize, sg_ent, sg_count;char *front, *back; +void **bbpnt, **old_bbpnt =NULL ; back = front =NULL ; sg_ent = SCpnt->use_sg;
@@ -292,17 +293,25 @@* extend or allocate new scatter-gather table */ sg_count = SCpnt->use_sg; -if (sg_count) +if (sg_count) { old_sg = (struct scatterlist *) SCpnt->request_buffer; -else { + old_bbpnt = SCpnt->bounce_buffers; + }else { sg_count =1 ; sg_ent++; } - i = ((sg_ent *sizeof (struct scatterlist )) +511 ) & ~511 ; +/* Get space for scatterlist and bounce buffer array. */ + i = sg_ent *sizeof (struct scatterlist ); + i += sg_ent *sizeof (void *); + i = (i +511 ) & ~511 ; +if ((sg =scsi_malloc (i)) ==NULL ) goto no_mem; + bbpnt = (void **) + ((char *)sg + (sg_ent *sizeof (struct scatterlist ))); +/* * no more failing memory allocs possible, we can safely assign * SCpnt values now
@@ -313,13 +322,15 @@ i =0 ;if (fsize) { - sg[0 ].address = sg[0 ].alt_address = front; + sg[0 ].address = bbpnt[0 ] = front; sg[0 ].length = fsize; i++; }if (old_sg) {memcpy (sg + i, old_sg, SCpnt->use_sg *sizeof (struct scatterlist )); -scsi_free (old_sg, ((SCpnt->use_sg *sizeof (struct scatterlist )) +511 ) & ~511 ); +memcpy (bbpnt + i, old_bbpnt, SCpnt->use_sg *sizeof (void *)); +scsi_free (old_sg, (((SCpnt->use_sg *sizeof (struct scatterlist )) + + (SCpnt->use_sg *sizeof (void *))) +511 ) & ~511 ); }else { sg[i].address = SCpnt->request_buffer; sg[i].length = SCpnt->request_bufflen;
@@ -327,11 +338,12 @@ SCpnt->request_bufflen += (fsize + bsize); SCpnt->request_buffer = sg; + SCpnt->bounce_buffers = bbpnt; SCpnt->use_sg += i;if (bsize) { sg[SCpnt->use_sg].address = back; - sg[SCpnt->use_sg].alt_address = back; + bbpnt[SCpnt->use_sg] = back; sg[SCpnt->use_sg].length = bsize; SCpnt->use_sg++; }
drivers/scsi/sym53c8xx.c renamed from drivers/scsi/sym53c8xx.c.~1~ +1 -1
@@ -13101,7 +13101,7 @@ (int) (PciDeviceFn(pdev) & 7));#ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING -if (pci_set_dma_mask (pdev, (dma_addr_t) (0xffffffffUL ))) { +if (pci_set_dma_mask (pdev,0xffffffff )) { printk(KERN_WARNING NAME53C8XX "32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");return -1 ;
drivers/scsi/sym53c8xx_comm.h renamed from drivers/scsi/sym53c8xx_comm.h.~1~ +1 -1
@@ -2186,7 +2186,7 @@ (int) (PciDeviceFn(pdev) & 7));#ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING -if (!pci_dma_supported (pdev, (dma_addr_t) (0xffffffffUL ))) { +if (!pci_dma_supported (pdev,0xffffffff )) { printk(KERN_WARNING NAME53C8XX "32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");return -1 ;
drivers/scsi/aha1542.c renamed from drivers/scsi/aha1542.c.~1~ +2 -4
@@ -67,12 +67,10 @@ int nseg, int badseg) { -printk (KERN_CRIT "sgpnt[%d:%d] addr %p/0x%lx alt %p/0x%lx length %d\n" , +printk (KERN_CRIT "sgpnt[%d:%d] addr %p/0x%lx length %d\n" , badseg, nseg, sgpnt[badseg].address,SCSI_PA (sgpnt[badseg].address), - sgpnt[badseg].alt_address, - sgpnt[badseg].alt_address ?SCSI_PA (sgpnt[badseg].alt_address) :0 , sgpnt[badseg].length);/*
@@ -716,7 +714,7 @@unsigned char *ptr;printk (KERN_CRIT "Bad segment list supplied to aha1542.c (%d, %d)\n" , SCpnt->use_sg, i);for (i =0 ; i < SCpnt->use_sg; i++) { -printk (KERN_CRIT "%d: %x %x %d\n" , i, (unsigned int ) sgpnt[i].address, (unsigned int ) sgpnt[i].alt_address, +printk (KERN_CRIT "%d: %p %d\n" , i, sgpnt[i].address, sgpnt[i].length); };printk (KERN_CRIT "cptr %x: " , (unsigned int ) cptr);
drivers/scsi/osst.c renamed from drivers/scsi/osst.c.~1~ +0 -3
@@ -4933,7 +4933,6 @@ tb->sg[0 ].address = (unsigned char *)__get_free_pages (priority, order);if (tb->sg[0 ].address !=NULL ) { - tb->sg[0 ].alt_address =NULL ; tb->sg[0 ].length = b_size;break ; }
@@ -4969,7 +4968,6 @@ tb =NULL ;break ; } - tb->sg[segs].alt_address =NULL ; tb->sg[segs].length = b_size; got += b_size; segs++;
@@ -5043,7 +5041,6 @@normalize_buffer (STbuffer);return FALSE; } - STbuffer->sg[segs].alt_address =NULL ; STbuffer->sg[segs].length = b_size; STbuffer->sg_segs +=1 ; got += b_size;
drivers/scsi/scsi_debug.c renamed from drivers/scsi/scsi_debug.c.~1~ +1 -10
@@ -154,10 +154,7 @@if (SCpnt->use_sg) { sgpnt = (struct scatterlist *) SCpnt->buffer;for (i =0 ; i < SCpnt->use_sg; i++) { - lpnt = (int *) sgpnt[i].alt_address; -printk (":%p %p %d\n" , sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length); -if (lpnt) -printk (" (Alt %x) " , lpnt[15 ]); +printk (":%p %d\n" , sgpnt[i].address, sgpnt[i].length); }; }else { printk("nosg: %p %p %d\n", SCpnt->request.buffer, SCpnt->buffer,
@@ -175,12 +172,6 @@printk ("\n" );if (flag ==0 )return ; - lpnt = (unsigned int *) sgpnt[0 ].alt_address; -for (i =0 ; i <sizeof (Scsi_Cmnd) /4 +1 ; i++) { -if ((i &7 ) ==0 ) -printk ("\n" ); -printk ("%x " , *lpnt++); - };#if 0 printk ("\n" ); lpnt = (unsigned int *) sgpnt[0 ].address;
drivers/scsi/scsi.h renamed from drivers/scsi/scsi.h.~1~ +2 -1
@@ -745,7 +745,8 @@unsigned request_bufflen;/* Actual request size */ struct timer_list eh_timeout;/* Used to time out the command. */ -void *request_buffer;/* Actual requested buffer */ +void *request_buffer;/* Actual requested buffer */ +void **bounce_buffers;/* Array of bounce buffers when using scatter-gather */ /* These elements define the operation we ultimately want to perform */ unsigned char data_cmnd[MAX_COMMAND_SIZE ];
drivers/scsi/scsi_merge.c renamed from drivers/scsi/scsi_merge.c.~1~ +30 -12
97 lines not on this page · raw message
drivers/scsi/scsi_lib.c renamed from drivers/scsi/scsi_lib.c.~1~ +17 -10
@@ -496,13 +496,16 @@*/ if (SCpnt->use_sg) {struct scatterlist *sgpnt; +void **bbpnt;int i; sgpnt = (struct scatterlist *) SCpnt->request_buffer; + bbpnt = SCpnt->bounce_buffers; -for (i =0 ; i < SCpnt->use_sg; i++) { -if (sgpnt[i].alt_address) { -scsi_free (sgpnt[i].address, sgpnt[i].length); +if (bbpnt) { +for (i =0 ; i < SCpnt->use_sg; i++) { +if (bbpnt[i]) +scsi_free (sgpnt[i].address, sgpnt[i].length); } }scsi_free (SCpnt->request_buffer, SCpnt->sglist_len);
@@ -568,18 +571,22 @@*/ if (SCpnt->use_sg) {struct scatterlist *sgpnt; +void **bbpnt;int i; sgpnt = (struct scatterlist *) SCpnt->buffer; + bbpnt = SCpnt->bounce_buffers; -for (i =0 ; i < SCpnt->use_sg; i++) { -if (sgpnt[i].alt_address) { -if (SCpnt->request.cmd ==READ ) { -memcpy (sgpnt[i].alt_address, - sgpnt[i].address, - sgpnt[i].length); +if (bbpnt) { +for (i =0 ; i < SCpnt->use_sg; i++) { +if (bbpnt[i]) { +if (SCpnt->request.cmd ==READ ) { +memcpy (bbpnt[i], + sgpnt[i].address, + sgpnt[i].length); + } +scsi_free (sgpnt[i].address, sgpnt[i].length); } -scsi_free (sgpnt[i].address, sgpnt[i].length); } }scsi_free (SCpnt->buffer, SCpnt->sglist_len);
drivers/scsi/st.c renamed from drivers/scsi/st.c.~1~ +0 -3
@@ -3222,7 +3222,6 @@ tb->sg[0 ].address = (unsigned char *)__get_free_pages (priority, order);if (tb->sg[0 ].address !=NULL ) { - tb->sg[0 ].alt_address =NULL ; tb->sg[0 ].length = b_size;break ; }
@@ -3258,7 +3257,6 @@ tb =NULL ;break ; } - tb->sg[segs].alt_address =NULL ; tb->sg[segs].length = b_size; got += b_size; segs++;
@@ -3332,7 +3330,6 @@normalize_buffer (STbuffer);return FALSE; } - STbuffer->sg[segs].alt_address =NULL ; STbuffer->sg[segs].length = b_size; STbuffer->sg_segs +=1 ; got += b_size;
drivers/scsi/qlogicfc.c renamed from drivers/scsi/qlogicfc.c.~1~ +2 -1
@@ -65,7 +65,7 @@#if 1 /* Once pci64_ DMA mapping interface is in, kill this. */ -typedef dma_addr_t dma64_addr_t ; +#define dma64_addr_t dma_addr_t#define pci64_alloc_consistent (d,s,p) pci_alloc_consistent((d),(s),(p))#define pci64_free_consistent (d,s,c,a) pci_free_consistent((d),(s),(c),(a))#define pci64_map_single (d,c,s,dir) pci_map_single((d),(c),(s),(dir))
@@ -80,6 +80,7 @@#define pci64_dma_lo32 (a) (a)#endif /* BITS_PER_LONG */ #define pci64_dma_build (hi,lo) (lo) +#undef sg_dma64_address#define sg_dma64_address (s) sg_dma_address(s)#define sg_dma64_len (s) sg_dma_len(s)#if BITS_PER_LONG >32
include/asm-alpha/pci.h renamed from include/asm-alpha/pci.h.~1~ +1 -1
@@ -144,7 +144,7 @@only drive the low 24-bits during PCI bus mastering, then you would pass 0x00ffffff as the mask to this function. */ -extern int pci_dma_supported (struct pci_dev *hwdev,dma_addr_t mask); +extern int pci_dma_supported (struct pci_dev *hwdev,u64 mask);/* Return the index of the PCI controller for device PDEV. */ extern int pci_controller_num (struct pci_dev *pdev);
include/asm-alpha/scatterlist.h renamed from include/asm-alpha/scatterlist.h.~1~ +0 -2
@@ -5,8 +5,6 @@struct scatterlist {char *address;/* Source/target vaddr. */ -char *alt_address;/* Location of actual if address is a -dma indirect buffer, else NULL. */ dma_addr_t dma_address;unsigned int length;unsigned int dma_length;
include/asm-arm/pci.h renamed from include/asm-arm/pci.h.~1~ +1 -1
@@ -152,7 +152,7 @@* only drive the low 24-bits during PCI bus mastering, then * you would pass 0x00ffffff as the mask to this function. */ -static inline int pci_dma_supported (struct pci_dev *hwdev,dma_addr_t mask) +static inline int pci_dma_supported (struct pci_dev *hwdev,u64 mask) {return 1 ; }
include/asm-arm/scatterlist.h renamed from include/asm-arm/scatterlist.h.~1~ +0 -1
@@ -5,7 +5,6 @@struct scatterlist {char *address;/* virtual address */ -char *alt_address;/* indirect dma address, or NULL */ dma_addr_t dma_address;/* dma address */ unsigned int length;/* length */ };
include/asm-i386/pci.h renamed from include/asm-i386/pci.h.~1~ +71 -4
119 lines not on this page · raw message
include/asm-i386/scatterlist.h renamed from include/asm-i386/scatterlist.h.~1~ +6 -3
@@ -2,9 +2,12 @@#define _I386_SCATTERLIST_Hstruct scatterlist { -char * address;/* Location data is to be transferred to */ -char * alt_address;/* Location of actual if address is a -* dma indirect buffer. NULL otherwise */ +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 */ + +dma64_addr_t dma_address;unsigned int length; };
include/asm-i386/types.h renamed from include/asm-i386/types.h.~1~ +7 -0
@@ -27,6 +27,8 @@*/ #ifdef __KERNEL__ +#include <linux/config.h> +typedef signed char s8 ;typedef unsigned char u8 ;
@@ -44,6 +46,11 @@/* Dma addresses are 32-bits wide. */ typedef u32 dma_addr_t ; +#ifdef CONFIG_HIGHMEM +typedef u64 dma64_addr_t ; +#else +typedef u32 dma64_addr_t ; +#endif #endif /* __KERNEL__ */
include/asm-m68k/scatterlist.h renamed from include/asm-m68k/scatterlist.h.~1~ +0 -2
@@ -3,8 +3,6 @@struct scatterlist {char * address;/* Location data is to be transferred to */ -char * alt_address;/* Location of actual if address is a -* dma indirect buffer. NULL otherwise */ unsigned int length;unsigned long dvma_address; };
include/asm-mips/pci.h renamed from include/asm-mips/pci.h.~1~ +1 -1
@@ -206,7 +206,7 @@* only drive the low 24-bits during PCI bus mastering, then * you would pass 0x00ffffff as the mask to this function. */ -extern inline int pci_dma_supported (struct pci_dev *hwdev,dma_addr_t mask) +extern inline int pci_dma_supported (struct pci_dev *hwdev,u64 mask) {/* * we fall back to GFP_DMA when the mask isn't all 1s,
include/asm-mips/scatterlist.h renamed from include/asm-mips/scatterlist.h.~1~ +0 -2
@@ -3,8 +3,6 @@struct scatterlist {char * address;/* Location data is to be transferred to */ -char * alt_address;/* Location of actual if address is a -* dma indirect buffer. NULL otherwise */ unsigned int length;__u32 dvma_address;
include/asm-ppc/pci.h renamed from include/asm-ppc/pci.h.~1~ +1 -1
@@ -108,7 +108,7 @@* only drive the low 24-bits during PCI bus mastering, then * you would pass 0x00ffffff as the mask to this function. */ -extern inline int pci_dma_supported (struct pci_dev *hwdev,dma_addr_t mask) +extern inline int pci_dma_supported (struct pci_dev *hwdev,u64 mask) {return 1 ; }
include/asm-ppc/scatterlist.h renamed from include/asm-ppc/scatterlist.h.~1~ +0 -2
@@ -9,8 +9,6 @@struct scatterlist {char * address;/* Location data is to be transferred to */ -char * alt_address;/* Location of actual if address is a -* dma indirect buffer. NULL otherwise */ unsigned int length; };
include/asm-sparc/pci.h renamed from include/asm-sparc/pci.h.~1~ +1 -1
@@ -108,7 +108,7 @@* only drive the low 24-bits during PCI bus mastering, then * you would pass 0x00ffffff as the mask to this function. */ -extern inline int pci_dma_supported (struct pci_dev *hwdev,dma_addr_t mask) +extern inline int pci_dma_supported (struct pci_dev *hwdev,u64 mask) {return 1 ; }
include/asm-sparc/scatterlist.h renamed from include/asm-sparc/scatterlist.h.~1~ +0 -2
@@ -6,8 +6,6 @@struct scatterlist {char * address;/* Location data is to be transferred to */ -char * alt_address;/* Location of actual if address is a -* dma indirect buffer. NULL otherwise */ unsigned int length;__u32 dvma_address;/* A place to hang host-specific addresses at. */
include/asm-sparc64/types.h renamed from include/asm-sparc64/types.h.~1~ +2 -1
@@ -45,9 +45,10 @@#define BITS_PER_LONG 64 -/* Dma addresses are 32-bits wide for now. */ +/* Dma addresses come in 32-bit and 64-bit flavours. */ typedef u32 dma_addr_t ; +typedef u64 dma64_addr_t ;#endif /* __KERNEL__ */
include/asm-sparc64/pci.h renamed from include/asm-sparc64/pci.h.~1~ +37 -4
82 lines not on this page · raw message
include/asm-sparc64/scatterlist.h renamed from include/asm-sparc64/scatterlist.h.~1~ +15 -8
@@ -5,17 +5,24 @@#include <asm/page.h> struct scatterlist { -char * address;/* Location data is to be transferred to */ -char * alt_address;/* Location of actual if address is a -* dma indirect buffer. NULL otherwise */ -unsigned int length; +/* This will disappear in 2.5.x */ +char *address; -__u32 dvma_address;/* A place to hang host-specific addresses at. */ -__u32 dvma_length; +/* These two are only valid if ADDRESS member of this +* struct is NULL. +*/ +struct page *page; +unsigned int offset; + +unsigned int length; + +dma64_addr_t dma_address; +__u32 dma_length; }; -#define sg_dma_address (sg) ((sg)->dvma_address) -#define sg_dma_len (sg) ((sg)->dvma_length) +#define sg_dma_address (sg) ((dma_addr_t) ((sg)->dma_address)) +#define sg_dma64_address (sg) ((sg)->dma_address) +#define sg_dma_len (sg) ((sg)->dma_length)#define ISA_DMA_THRESHOLD (~0UL)
include/linux/pci.h renamed from include/linux/pci.h.~1~ +12 -3
@@ -314,6 +314,12 @@#define PCI_DMA_FROMDEVICE 2#define PCI_DMA_NONE 3 +/* These are the boolean attributes stored in pci_dev->dma_flags. */ +#define PCI_DMA_FLAG_HUGE_MAPS 0x00000001/* Device may hold an enormous number +* of mappings at once? +*/ +#define PCI_DMA_FLAG_ARCHMASK 0xf0000000/* Reserved for arch-specific flags */ +#define DEVICE_COUNT_COMPATIBLE 4#define DEVICE_COUNT_IRQ 2#define DEVICE_COUNT_DMA 2
@@ -353,11 +359,12 @@struct pci_driver *driver;/* which driver has allocated this device */ void *driver_data;/* data private to the driver */ -dma_addr_t dma_mask;/* Mask of the bits of bus address this +u64 dma_mask;/* Mask of the bits of bus address this device implements. Normally this is 0xffffffff. You only need to change this if your device has broken DMA or supports 64-bit transfers. */ +unsigned int dma_flags;/* See PCI_DMA_FLAG_* above */ u32 current_state;/* Current operating state. In ACPI-speak, this is D0-D3, D0 being fully functional,
@@ -559,7 +566,8 @@int pci_enable_device (struct pci_dev *dev);void pci_disable_device (struct pci_dev *dev);void pci_set_master (struct pci_dev *dev); -int pci_set_dma_mask (struct pci_dev *dev,dma_addr_t mask); +int pci_set_dma_mask (struct pci_dev *dev,u64 mask); +void pci_change_dma_flag (struct pci_dev *dev,unsigned int on,unsigned int off);int pci_assign_resource (struct pci_dev *dev,int i);/* Power management related routines */
@@ -641,7 +649,8 @@static inline int pci_enable_device (struct pci_dev *dev) {return -EIO ; }static inline void pci_disable_device (struct pci_dev *dev) { }static inline int pci_module_init (struct pci_driver *drv) {return -ENODEV ; } -static inline int pci_set_dma_mask (struct pci_dev *dev,dma_addr_t mask) {return -EIO ; } +static inline int pci_set_dma_mask (struct pci_dev *dev,u64 mask) {return -EIO ; } +static inline void pci_change_dma_flag (struct pci_dev *dev,unsigned int on,unsigned int off) { }static inline int pci_assign_resource (struct pci_dev *dev,int i) {return -EBUSY ;}static inline int pci_register_driver (struct pci_driver *drv) {return 0 ;}static inline void pci_unregister_driver (struct pci_driver *drv) { }
include/asm-sh/pci.h renamed from include/asm-sh/pci.h.~1~ +1 -1
@@ -167,7 +167,7 @@* only drive the low 24-bits during PCI bus mastering, then * you would pass 0x00ffffff as the mask to this function. */ -extern inline int pci_dma_supported (struct pci_dev *hwdev,dma_addr_t mask) +extern inline int pci_dma_supported (struct pci_dev *hwdev,u64 mask) {return 1 ; }
include/asm-sh/scatterlist.h renamed from include/asm-sh/scatterlist.h.~1~ +0 -2
@@ -3,8 +3,6 @@struct scatterlist {char * address;/* Location data is to be transferred to */ -char * alt_address;/* Location of actual if address is a -* dma indirect buffer. NULL otherwise */ unsigned int length; };
include/asm-s390/scatterlist.h renamed from include/asm-s390/scatterlist.h.~1~ +0 -2
@@ -3,8 +3,6 @@struct scatterlist {char * address;/* Location data is to be transferred to */ -char * alt_address;/* Location of actual if address is a -* dma indirect buffer. NULL otherwise */ unsigned int length; };
include/asm-ia64/pci.h renamed from include/asm-ia64/pci.h.~1~ +1 -1
@@ -52,7 +52,7 @@* you would pass 0x00ffffff as the mask to this function. */ static inline int -pci_dma_supported (struct pci_dev *hwdev,dma_addr_t mask) +pci_dma_supported (struct pci_dev *hwdev,u64 mask) {return 1 ; }
include/asm-ia64/scatterlist.h renamed from include/asm-ia64/scatterlist.h.~1~ +0 -5
@@ -8,11 +8,6 @@struct scatterlist {char *address;/* location data is to be transferred to */ -/* -* Location of actual buffer if ADDRESS points to a DMA -* indirection buffer, NULL otherwise: -*/ -char *alt_address;char *orig_address;/* Save away the original buffer address (used by pci-dma.c) */ unsigned int length;/* buffer length */ };
include/asm-mips64/pci.h renamed from include/asm-mips64/pci.h.~1~ +1 -1
@@ -195,7 +195,7 @@#endif } -extern inline int pci_dma_supported (struct pci_dev *hwdev,dma_addr_t mask) +extern inline int pci_dma_supported (struct pci_dev *hwdev,u64 mask) {/* * we fall back to GFP_DMA when the mask isn't all 1s,
include/asm-mips64/scatterlist.h renamed from include/asm-mips64/scatterlist.h.~1~ +0 -2
@@ -3,8 +3,6 @@struct scatterlist {char * address;/* Location data is to be transferred to */ -char * alt_address;/* Location of actual if address is a -* dma indirect buffer. NULL otherwise */ unsigned int length;__u32 dvma_address;
include/asm-parisc/pci.h renamed from include/asm-parisc/pci.h.~1~ +1 -1
@@ -113,7 +113,7 @@** See Documentation/DMA-mapping.txt */ struct pci_dma_ops { -int (*dma_supported)(struct pci_dev *dev,dma_addr_t mask); +int (*dma_supported)(struct pci_dev *dev,u64 mask);void *(*alloc_consistent)(struct pci_dev *dev,size_t size,dma_addr_t *iova);void (*free_consistent)(struct pci_dev *dev,size_t size,void *vaddr,dma_addr_t iova);dma_addr_t (*map_single)(struct pci_dev *dev,void *addr,size_t size,int direction);
include/asm-parisc/scatterlist.h renamed from include/asm-parisc/scatterlist.h.~1~ +0 -2
@@ -3,8 +3,6 @@struct scatterlist {char * address;/* Location data is to be transferred to */ -char * alt_address;/* Location of actual if address is a -* dma indirect buffer. NULL otherwise */ unsigned int length;/* an IOVA can be 64-bits on some PA-Risc platforms. */
include/asm-s390x/scatterlist.h renamed from include/asm-s390x/scatterlist.h.~1~ +0 -2
@@ -3,8 +3,6 @@struct scatterlist {char * address;/* Location data is to be transferred to */ -char * alt_address;/* Location of actual if address is a -* dma indirect buffer. NULL otherwise */ unsigned int length; };
net/ipv6/mcast.c renamed from net/ipv6/mcast.c.~1~ +3 -2
@@ -5,7 +5,7 @@* Authors: * Pedro Roque <[email protected]> * -* $Id: mcast.c,v 1.37 2001/04/25 20:46:34 davem Exp $ +* $Id: mcast.c,v 1.38 2001/08/15 07:36:31 davem Exp $ * * Based on linux/ipv4/igmp.c and linux/ipv4/ip_sockglue.c *
@@ -90,7 +90,6 @@ mc_lst->next =NULL ;memcpy (&mc_lst->addr, addr,sizeof (struct in6_addr )); - mc_lst->ifindex = ifindex;if (ifindex ==0 ) {struct rt6_info *rt;
@@ -107,6 +106,8 @@sock_kfree_s (sk, mc_lst,sizeof (*mc_lst));return -ENODEV ; } + + mc_lst->ifindex = dev->ifindex;/* * now add/increase the group membership on the device
Quoted 8 lines · David S. Miller
From: Jens Axboe <[email protected]>
Date: Thu, 16 Aug 2001 14:03:17 +0200Quoted 4 lines
That is why
PCI_MAX_DMA32, or whatever you would like to name it, does not make any sense. It can be a shorthand for drivers themselves, but that is it and personally I'd rather they just put the bits there explicitly.
Quoted 5 lines
Drivers, right. THe block stuff used it in _one_ place -- the
BLK_BOUNCE_4Gdefine, to indicated the need to bounce anything above 4G. But no problem, I can just define that to0xffffffffmyself.How can "the block stuff" (ie. generic code) make legal use of this
Block stuff is a crappy name, the block layer :-)
Quoted 3 lines
value? Which physical bits it may address, this is a device specific attribute and has nothing to with with 4GB and highmem and PCI standard specifications. :-)
It didn't make use of this value, it merely provided it for _drivers_ to use. Driver passes in a max dma address, block layer translates that into a page address. As for 4GB, see below.
Quoted 8 lines
In fact, this is not only a device specific attribute, it also has things to do with elements of the platform.
This is why we have things like
pci_dma_supported()and friends. Let me give an example, for most PCI controllers on Sparc64 if your device can address the upper 2GB of 32-bit PCI space, one may DMA to any physical memory location via the IOMMU these controllers have.
Quoted 6 lines
There may easily be HIGHMEM platforms which operate this way. So the result is that
CONFIG_HIGHMEMdoes _not_ mean ">=4GB memory must be bounced".Really,
0xffffffffis a meaningless value. You have to test against device indicated capabilities for bouncing decisions.
Ok, I see where we are not seeing eye to eye. Really, I meant for the PCI_MAX_DMA32 value to be 'Max address below 4GB' and not 'Max address we can DMA to with 32-bit PCI'. Does that make sense? Maybe my explanations weren't quite clear, and of course it didn't really help that I shoved it in pci.h :-)
Quoted 5 lines
You do not even know how "addressable bits" translates into "range of physical memory that may be DMA'd to/from by device". If an IOMMU is present on the platform, these two things have no relationship whatsoever. These two things happen to have a direct relationship on x86, but that is as far as it goes.
That's why I need you to sanity check the cross-platform stuff like that :-). I see what you mean, point taken. Clearly I need to change the blk_queue_bounce_limit stuff to check with the PCI capabilities.
Quoted 2 lines
Enough babbling on my part, I'll have a look at your bounce patch later today. :-)
Thanks!
Signature · 1 line
Jens Axboe
Quoted 2 lines · David S. Miller
Enough babbling on my part, I'll have a look at your bounce patch later today. :-)
Wait for the next version, I'll clean up the PCI DMA bounce value stuff first and post a new version.
Signature · 1 line
Jens Axboe
From: Jens Axboe <[email protected]>
Date: Thu, 16 Aug 2001 14:56:36 +0200
Quoted 2 lines · David S. Miller
Enough babbling on my part, I'll have a look at your bounce patch later today. :-)
Wait for the next version, I'll clean up the PCI DMA bounce value stuff first and post a new version.
Ok. I was thinking about the 4GB issue and we could describe it simply using one platform macro define that could be boolean tested in both your new block stuff and a fixed up version of the networking's current ugly HIGHMEM tests.
/* PCI address are equivalent to memory physical addresses.
* As a consequence, the lower 4GB of main memory may be
* addressable using PCI single-address cycles. The rest of
* memory requires the use of dual-address cycles. *
* If this is false, the kernel assumes that some hardware
* translation mechanism exists to allow all of physical
* memory to be accessed using single-address cycles. */
#define PCI_DMA_PHYS_IS_BUS (1)
So you'd get things like:
if (PCI_DMA_PHYS_IS_BUS) {
/* We might need to bounce this. */
if (! dev_dma_in_range(dev, address + len))
address = make_bounce_buffer(dev, address, len);
} else {
/* All physical memory is legal for DMA so there
* is nothing to check.
*/
}or whatever. You get the idea.
This is really interesting because it means things like the following.
A device which is only capable of 32-bit PCI addressing can still just use the pci_map_{single,sg}() interfaces yet DMA to all of system memory. The block and networking layers will never try to bounce stuff.
Basically, this is what happens today with non-CONFIG_HIGHMEM 64-bit platforms, with a particular cost for the cases where translation is done via bounce buffers (notably ia64).
What do you think?
Later,
David S. Miller
[email protected]
Quoted 13 lines · David S. Miller
From: Jens Axboe <[email protected]>
Date: Wed, 15 Aug 2001 15:10:52 +0200Quoted 3 lines · David S. Miller
The only truly problematic area is the
alt_addressthing. It is would be a nice thing to rip this eyesore out of the scsi layer anyways.The SCSI issue was exactly what was on my mind, and is indeed the reason why I didn't go all the way and did a complete conversion there. The SCSI layer is _not_ very clean in this regard, didn't exactly enjoy this part of the work...
Quoted 6 lines
I just took a quick look at this, and I think I can make this
alt_addressthing into a scsi-layer-specific mechanism and thus be able to safely remove it from struct scatterlist.Would you like me to whip up such a set of changes? I'll be more than happy to work on it.
Yes please, that'd be great.
Signature · 1 line
Jens Axboe
Quoted 11 lines · David S. Miller
From: Jens Axboe <[email protected]>
Date: Wed, 15 Aug 2001 11:26:21 +0200Ok, here's an updated version. Maybe modulo the struct scatterlist changes, I'd like to see this included in 2.4.x soonish. Or at least the interface we agree on -- it'll make my life easier at least. And finally provide driver authors with something not quite as stupid as struct scatterlist.
Jens, have a look at the patch I have below. What do you think about it? Specifically the set of interfaces.
Looks fine to me, exactly the interface I've used/wanted. But you want to add the extra page/offset to the existing scatterlist, and not scrap that one completely?
Quoted 3 lines
we can. The x86 versions of the
asm/pci.handasm/scatterlist.hbits are pretty mindless and left as an exercise to the reader :-)
:-)
Signature · 1 line
Jens Axboe
From: Jens Axboe <[email protected]>
Date: Wed, 15 Aug 2001 13:13:35 +0200
Looks fine to me, exactly the interface I've used/wanted. But you want to add the extra page/offset to the existing scatterlist, and not scrap that one completely?
The idea is that address/alt_address disappear sometime in 2.5. Something like this right?
BTW, on x86 we can ifdef the dma64_address to u32 or u64 based upon CONFIG_HIGHMEM if we wish.
Later,
David S. Miller
[email protected]
Quoted 10 lines · David S. Miller
From: Jens Axboe <[email protected]>
Date: Wed, 15 Aug 2001 14:07:40 +0200Ok so you just want to turn scatterlist into what I call
sg_listin 2.5 time, fine with me too. Depends on whether we want to keep thepci_map_sgand struct scatterlist interface intact, or just break it and tell driver authors they must fix their stuff regardless of whether they want to support highmem. As I write this sentence, it's clear to me which way is the superior :-)
Quoted 3 lines
pci_map_sgispci_map_sg, if the internal representation of scatterlist is changed such that address/alt_address no longer exist, it will work on pages only. Right? The compatibility mode in
Yes, the pci_* was not my worry. It's the *address case you list below, but I think you are right that it' not a big issue at that.
Quoted 1 line
2.4.x is the "if (address != NULL)
virt_to_bus(address);" stuff.
Yes, aka the horrible hack.
Quoted 4 lines
Understand that the pci64_{map,unmap}_sg is created for a seperate purpose, independant of whether scatterlist has the backwards compatability stuff or not. (There have been threads here about this, I can describe it quickly for you in quiet if you want to know).
I've read these now, been behind on traffic lately.
Quoted 11 lines
Two more things to consider:
1) There is nobody who cannot be search&replace converted from
sg->address= ptr
intosg->page = virt_to_page(ptr) sg->offset = ((unsigned long)ptr & ~PAGE_MASK);The only truly problematic area is the
alt_addressthing. It is would be a nice thing to rip this eyesore out of the scsi layer anyways.
The SCSI issue was exactly what was on my mind, and is indeed the reason why I didn't go all the way and did a complete conversion there. The SCSI layer is _not_ very clean in this regard, didn't exactly enjoy this part of the work...
Quoted 9 lines
2) I want to put scatterlist in to replace
skb_frag_structinskbuff.hand then have a zerocopy network driver do something like:header_dma = pci_map_single(pdev, skb->data, skb->len, PCI_DMA_TODEVICE); data_nents = pci_map_sg(pdev, skb_shinfo(skb)->frag_list, skb_shinfo(skb)->nr_frags, PCI_DMA_TODEVICE);See? :-)
Yep, I see where you are going :)
Quoted 4 lines
Yep. Want me to add in the x86 parts of your patch?
Please let me finish up my prototype with sparc64 building and working, then I'll send you what I have ok?
Fine
Signature · 1 line
Jens Axboe
From: Jens Axboe <[email protected]>
Date: Wed, 15 Aug 2001 15:10:52 +0200
Quoted 3 lines · David S. Miller
The only truly problematic area is the
alt_addressthing. It is would be a nice thing to rip this eyesore out of the scsi layer anyways.
The SCSI issue was exactly what was on my mind, and is indeed the reason why I didn't go all the way and did a complete conversion there. The SCSI layer is _not_ very clean in this regard, didn't exactly enjoy this part of the work...
I just took a quick look at this, and I think I can make this alt_address thing into a scsi-layer-specific mechanism and thus be able to safely remove it from struct scatterlist.
Would you like me to whip up such a set of changes? I'll be more than happy to work on it.
Quoted 4 lines
Yep. Want me to add in the x86 parts of your patch?
Please let me finish up my prototype with sparc64 building and working, then I'll send you what I have ok?
Fine
This is forthcoming.
Later,
David S. Miller
[email protected]
From: "David S. Miller" <[email protected]>
Date: Wed, 15 Aug 2001 07:02:04 -0700 (PDT)
> Yep. Want me to add in the x86 parts of your patch?
>
> Please let me finish up my prototype with sparc64 building and > working, then I'll send you what I have ok?
Fine
This is forthcoming.
As promised. I actually got bored during the build and tried to quickly cook up the ix86 bits myself :-)
arch/alpha/kernel/pci_iommu.c renamed from arch/alpha/kernel/pci_iommu.c.~1~ +1 -1
@@ -636,7 +636,7 @@supported properly. */ int -pci_dma_supported (struct pci_dev *pdev,dma_addr_t mask) +pci_dma_supported (struct pci_dev *pdev,u64 mask) {struct pci_controller *hose;struct pci_iommu_arena *arena;
arch/sparc64/kernel/pci_iommu.c renamed from arch/sparc64/kernel/pci_iommu.c.~1~ +117 -27
270 lines not on this page · raw message
arch/sparc64/kernel/iommu_common.c renamed from arch/sparc64/kernel/iommu_common.c.~1~ +23 -28
132 lines not on this page · raw message
arch/sparc64/kernel/sbus.c renamed from arch/sparc64/kernel/sbus.c.~1~ +30 -20
117 lines not on this page · raw message
arch/sparc64/kernel/iommu_common.h renamed from arch/sparc64/kernel/iommu_common.h.~1~ +2 -5
@@ -18,10 +18,7 @@#undef VERIFY_SG#ifdef VERIFY_SG -int verify_lengths (struct scatterlist *sg,int nents,int npages); -int verify_one_map (struct scatterlist *dma_sg,struct scatterlist **__sg,int nents,iopte_t **__iopte); -int verify_maps (struct scatterlist *sg,int nents,iopte_t *iopte); -void verify_sglist (struct scatterlist *sg,int nents,iopte_t *iopte,int npages); +extern void verify_sglist (struct scatterlist *sg,int nents,iopte_t *iopte,int npages);#endif /* Two addresses are "virtually contiguous" if and only if:
@@ -31,4 +28,4 @@#define VCONTIG (__X, __Y) (((__X) == (__Y)) || \ (((__X) | (__Y)) << (64UL - PAGE_SHIFT)) == 0UL) -unsigned long prepare_sg (struct scatterlist *sg,int nents); +extern unsigned long prepare_sg (struct scatterlist *sg,int nents);
arch/sparc64/kernel/sparc64_ksyms.c renamed from arch/sparc64/kernel/sparc64_ksyms.c.~1~ +6 -0
@@ -216,10 +216,16 @@EXPORT_SYMBOL (pci_free_consistent);EXPORT_SYMBOL (pci_map_single);EXPORT_SYMBOL (pci_unmap_single); +EXPORT_SYMBOL (pci64_map_page); +EXPORT_SYMBOL (pci64_unmap_page);EXPORT_SYMBOL (pci_map_sg);EXPORT_SYMBOL (pci_unmap_sg); +EXPORT_SYMBOL (pci64_map_sg); +EXPORT_SYMBOL (pci64_unmap_sg);EXPORT_SYMBOL (pci_dma_sync_single); +EXPORT_SYMBOL (pci64_dma_sync_single);EXPORT_SYMBOL (pci_dma_sync_sg); +EXPORT_SYMBOL (pci64_dma_sync_sg);EXPORT_SYMBOL (pci_dma_supported);#endif
arch/parisc/kernel/ccio-dma.c renamed from arch/parisc/kernel/ccio-dma.c.~1~ +1 -1
@@ -638,7 +638,7 @@ } -static int ccio_dma_supported (struct pci_dev *dev,dma_addr_t mask) +static int ccio_dma_supported (struct pci_dev *dev,u64 mask) {if (dev ==NULL ) {printk (MODULE_NAME ": EISA/ISA/et al not supported\n" );
arch/parisc/kernel/pci-dma.c renamed from arch/parisc/kernel/pci-dma.c.~1~ +1 -1
@@ -77,7 +77,7 @@static inline void dump_resmap (void ) {;}#endif -static int pa11_dma_supported (struct pci_dev *dev,dma_addr_t mask) +static int pa11_dma_supported (struct pci_dev *dev,u64 mask) {return 1 ; }
arch/parisc/kernel/ccio-rm-dma.c renamed from arch/parisc/kernel/ccio-rm-dma.c.~1~ +1 -1
@@ -93,7 +93,7 @@ } -static int ccio_dma_supported (struct pci_dev *dev,dma_addr_t mask) +static int ccio_dma_supported (struct pci_dev *dev,u64 mask) {if (dev ==NULL ) {printk (MODULE_NAME ": EISA/ISA/et al not supported\n" );
arch/parisc/kernel/sba_iommu.c renamed from arch/parisc/kernel/sba_iommu.c.~1~ +1 -1
@@ -779,7 +779,7 @@ }static int -sba_dma_supported (struct pci_dev *dev,dma_addr_t mask) +sba_dma_supported (struct pci_dev *dev,u64 mask) {if (dev ==NULL ) {printk (MODULE_NAME ": EISA/ISA/et al not supported\n" );
drivers/net/acenic.c renamed from drivers/net/acenic.c.~1~ +1 -5
@@ -202,6 +202,7 @@#define pci_free_consistent (cookie, size, ptr, dma_ptr) kfree(ptr)#define pci_map_single (cookie, address, size, dir) virt_to_bus(address)#define pci_unmap_single (cookie, address, size, dir) +#define pci_set_dma_mask (dev, mask) do { } while (0)#endif #if (LINUX_VERSION_CODE <0x02032b )
@@ -258,11 +259,6 @@#define ace_mark_net_bh () {do{} while(0);}#define ace_if_down (dev) {do{} while(0);}#endif - -#ifndef pci_set_dma_mask -#define pci_set_dma_mask (dev, mask) dev->dma_mask = mask; -#endif -#if (LINUX_VERSION_CODE >=0x02031b )#define NEW_NETINIT
drivers/pci/pci.c renamed from drivers/pci/pci.c.~1~ +8 -1
@@ -832,7 +832,7 @@ }int -pci_set_dma_mask (struct pci_dev *dev,dma_addr_t mask) +pci_set_dma_mask (struct pci_dev *dev,u64 mask) {if (!pci_dma_supported (dev, mask))return -EIO ;
@@ -842,6 +842,12 @@return 0 ; } +void +pci_change_dma_flag (struct pci_dev *dev,unsigned int on,unsigned int off) +{ + dev->dma_flags |= on; + dev->dma_flags &= ~off; +}/* * Translate the low bits of the PCI base
@@ -1954,6 +1960,7 @@EXPORT_SYMBOL (pci_find_subsys);EXPORT_SYMBOL (pci_set_master);EXPORT_SYMBOL (pci_set_dma_mask); +EXPORT_SYMBOL (pci_change_dma_flag);EXPORT_SYMBOL (pci_assign_resource);EXPORT_SYMBOL (pci_register_driver);EXPORT_SYMBOL (pci_unregister_driver);
drivers/scsi/sym53c8xx.c renamed from drivers/scsi/sym53c8xx.c.~1~ +1 -1
@@ -13101,7 +13101,7 @@ (int) (PciDeviceFn(pdev) & 7));#ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING -if (pci_set_dma_mask (pdev, (dma_addr_t) (0xffffffffUL ))) { +if (pci_set_dma_mask (pdev,0xffffffff )) { printk(KERN_WARNING NAME53C8XX "32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");return -1 ;
drivers/scsi/sym53c8xx_comm.h renamed from drivers/scsi/sym53c8xx_comm.h.~1~ +1 -1
@@ -2186,7 +2186,7 @@ (int) (PciDeviceFn(pdev) & 7));#ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING -if (!pci_dma_supported (pdev, (dma_addr_t) (0xffffffffUL ))) { +if (!pci_dma_supported (pdev,0xffffffff )) { printk(KERN_WARNING NAME53C8XX "32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");return -1 ;
drivers/scsi/qlogicfc.c renamed from drivers/scsi/qlogicfc.c.~1~ +2 -1
@@ -65,7 +65,7 @@#if 1 /* Once pci64_ DMA mapping interface is in, kill this. */ -typedef dma_addr_t dma64_addr_t ; +#define dma64_addr_t dma_addr_t#define pci64_alloc_consistent (d,s,p) pci_alloc_consistent((d),(s),(p))#define pci64_free_consistent (d,s,c,a) pci_free_consistent((d),(s),(c),(a))#define pci64_map_single (d,c,s,dir) pci_map_single((d),(c),(s),(dir))
@@ -80,6 +80,7 @@#define pci64_dma_lo32 (a) (a)#endif /* BITS_PER_LONG */ #define pci64_dma_build (hi,lo) (lo) +#undef sg_dma64_address#define sg_dma64_address (s) sg_dma_address(s)#define sg_dma64_len (s) sg_dma_len(s)#if BITS_PER_LONG >32
include/asm-alpha/pci.h renamed from include/asm-alpha/pci.h.~1~ +1 -1
@@ -144,7 +144,7 @@only drive the low 24-bits during PCI bus mastering, then you would pass 0x00ffffff as the mask to this function. */ -extern int pci_dma_supported (struct pci_dev *hwdev,dma_addr_t mask); +extern int pci_dma_supported (struct pci_dev *hwdev,u64 mask);/* Return the index of the PCI controller for device PDEV. */ extern int pci_controller_num (struct pci_dev *pdev);
include/asm-arm/pci.h renamed from include/asm-arm/pci.h.~1~ +1 -1
@@ -152,7 +152,7 @@* only drive the low 24-bits during PCI bus mastering, then * you would pass 0x00ffffff as the mask to this function. */ -static inline int pci_dma_supported (struct pci_dev *hwdev,dma_addr_t mask) +static inline int pci_dma_supported (struct pci_dev *hwdev,u64 mask) {return 1 ; }
include/asm-i386/pci.h renamed from include/asm-i386/pci.h.~1~ +71 -4
119 lines not on this page · raw message
include/asm-i386/scatterlist.h renamed from include/asm-i386/scatterlist.h.~1~ +6 -1
@@ -2,9 +2,14 @@#define _I386_SCATTERLIST_Hstruct scatterlist { -char * address;/* Location data is to be transferred to */ +char * address;/* Location data is to be transferred to, NULL for +* highmem page */ char * alt_address;/* Location of actual if address is a * dma indirect buffer. NULL otherwise */ +struct page * page;/* Location for highmem page, if any */ +unsigned int offset;/* for highmem, page offset */ + +dma64_addr_t dma_address;unsigned int length; };
include/asm-i386/types.h renamed from include/asm-i386/types.h.~1~ +7 -0
@@ -27,6 +27,8 @@*/ #ifdef __KERNEL__ +#include <linux/config.h> +typedef signed char s8 ;typedef unsigned char u8 ;
@@ -44,6 +46,11 @@/* Dma addresses are 32-bits wide. */ typedef u32 dma_addr_t ; +#ifdef CONFIG_HIGHMEM +typedef u64 dma64_addr_t ; +#else +typedef u32 dma64_addr_t ; +#endif #endif /* __KERNEL__ */
include/asm-mips/pci.h renamed from include/asm-mips/pci.h.~1~ +1 -1
@@ -206,7 +206,7 @@* only drive the low 24-bits during PCI bus mastering, then * you would pass 0x00ffffff as the mask to this function. */ -extern inline int pci_dma_supported (struct pci_dev *hwdev,dma_addr_t mask) +extern inline int pci_dma_supported (struct pci_dev *hwdev,u64 mask) {/* * we fall back to GFP_DMA when the mask isn't all 1s,
include/asm-ppc/pci.h renamed from include/asm-ppc/pci.h.~1~ +1 -1
@@ -108,7 +108,7 @@* only drive the low 24-bits during PCI bus mastering, then * you would pass 0x00ffffff as the mask to this function. */ -extern inline int pci_dma_supported (struct pci_dev *hwdev,dma_addr_t mask) +extern inline int pci_dma_supported (struct pci_dev *hwdev,u64 mask) {return 1 ; }
include/asm-sparc/pci.h renamed from include/asm-sparc/pci.h.~1~ +1 -1
@@ -108,7 +108,7 @@* only drive the low 24-bits during PCI bus mastering, then * you would pass 0x00ffffff as the mask to this function. */ -extern inline int pci_dma_supported (struct pci_dev *hwdev,dma_addr_t mask) +extern inline int pci_dma_supported (struct pci_dev *hwdev,u64 mask) {return 1 ; }
include/asm-sparc64/types.h renamed from include/asm-sparc64/types.h.~1~ +2 -1
@@ -45,9 +45,10 @@#define BITS_PER_LONG 64 -/* Dma addresses are 32-bits wide for now. */ +/* Dma addresses come in 32-bit and 64-bit flavours. */ typedef u32 dma_addr_t ; +typedef u64 dma64_addr_t ;#endif /* __KERNEL__ */
include/asm-sparc64/pci.h renamed from include/asm-sparc64/pci.h.~1~ +37 -4
82 lines not on this page · raw message
include/asm-sparc64/scatterlist.h renamed from include/asm-sparc64/scatterlist.h.~1~ +16 -8
@@ -5,17 +5,25 @@#include <asm/page.h> struct scatterlist { -char * address;/* Location data is to be transferred to */ -char * alt_address;/* Location of actual if address is a -* dma indirect buffer. NULL otherwise */ -unsigned int length; +/* These will disappear in 2.5.x */ +char *address; +char *alt_address; -__u32 dvma_address;/* A place to hang host-specific addresses at. */ -__u32 dvma_length; +/* These two are only valid if ADDRESS member of this +* struct is NULL. +*/ +struct page *page; +unsigned int offset; + +unsigned int length; + +dma64_addr_t dma_address; +__u32 dma_length; }; -#define sg_dma_address (sg) ((sg)->dvma_address) -#define sg_dma_len (sg) ((sg)->dvma_length) +#define sg_dma_address (sg) ((dma_addr_t) ((sg)->dma_address)) +#define sg_dma64_address (sg) ((sg)->dma_address) +#define sg_dma_len (sg) ((sg)->dma_length)#define ISA_DMA_THRESHOLD (~0UL)
include/linux/pci.h renamed from include/linux/pci.h.~1~ +12 -3
@@ -314,6 +314,12 @@#define PCI_DMA_FROMDEVICE 2#define PCI_DMA_NONE 3 +/* These are the boolean attributes stored in pci_dev->dma_flags. */ +#define PCI_DMA_FLAG_HUGE_MAPS 0x00000001/* Device may hold an enormous number +* of mappings at once? +*/ +#define PCI_DMA_FLAG_ARCHMASK 0xf0000000/* Reserved for arch-specific flags */ +#define DEVICE_COUNT_COMPATIBLE 4#define DEVICE_COUNT_IRQ 2#define DEVICE_COUNT_DMA 2
@@ -353,11 +359,12 @@struct pci_driver *driver;/* which driver has allocated this device */ void *driver_data;/* data private to the driver */ -dma_addr_t dma_mask;/* Mask of the bits of bus address this +u64 dma_mask;/* Mask of the bits of bus address this device implements. Normally this is 0xffffffff. You only need to change this if your device has broken DMA or supports 64-bit transfers. */ +unsigned int dma_flags;/* See PCI_DMA_FLAG_* above */ u32 current_state;/* Current operating state. In ACPI-speak, this is D0-D3, D0 being fully functional,
@@ -559,7 +566,8 @@int pci_enable_device (struct pci_dev *dev);void pci_disable_device (struct pci_dev *dev);void pci_set_master (struct pci_dev *dev); -int pci_set_dma_mask (struct pci_dev *dev,dma_addr_t mask); +int pci_set_dma_mask (struct pci_dev *dev,u64 mask); +void pci_change_dma_flag (struct pci_dev *dev,unsigned int on,unsigned int off);int pci_assign_resource (struct pci_dev *dev,int i);/* Power management related routines */
@@ -641,7 +649,8 @@static inline int pci_enable_device (struct pci_dev *dev) {return -EIO ; }static inline void pci_disable_device (struct pci_dev *dev) { }static inline int pci_module_init (struct pci_driver *drv) {return -ENODEV ; } -static inline int pci_set_dma_mask (struct pci_dev *dev,dma_addr_t mask) {return -EIO ; } +static inline int pci_set_dma_mask (struct pci_dev *dev,u64 mask) {return -EIO ; } +static inline void pci_change_dma_flag (struct pci_dev *dev,unsigned int on,unsigned int off) { }static inline int pci_assign_resource (struct pci_dev *dev,int i) {return -EBUSY ;}static inline int pci_register_driver (struct pci_driver *drv) {return 0 ;}static inline void pci_unregister_driver (struct pci_driver *drv) { }
include/asm-sh/pci.h renamed from include/asm-sh/pci.h.~1~ +1 -1
@@ -167,7 +167,7 @@* only drive the low 24-bits during PCI bus mastering, then * you would pass 0x00ffffff as the mask to this function. */ -extern inline int pci_dma_supported (struct pci_dev *hwdev,dma_addr_t mask) +extern inline int pci_dma_supported (struct pci_dev *hwdev,u64 mask) {return 1 ; }
include/asm-ia64/pci.h renamed from include/asm-ia64/pci.h.~1~ +1 -1
@@ -52,7 +52,7 @@* you would pass 0x00ffffff as the mask to this function. */ static inline int -pci_dma_supported (struct pci_dev *hwdev,dma_addr_t mask) +pci_dma_supported (struct pci_dev *hwdev,u64 mask) {return 1 ; }
include/asm-mips64/pci.h renamed from include/asm-mips64/pci.h.~1~ +1 -1
@@ -195,7 +195,7 @@#endif } -extern inline int pci_dma_supported (struct pci_dev *hwdev,dma_addr_t mask) +extern inline int pci_dma_supported (struct pci_dev *hwdev,u64 mask) {/* * we fall back to GFP_DMA when the mask isn't all 1s,
include/asm-parisc/pci.h renamed from include/asm-parisc/pci.h.~1~ +1 -1
@@ -113,7 +113,7 @@** See Documentation/DMA-mapping.txt */ struct pci_dma_ops { -int (*dma_supported)(struct pci_dev *dev,dma_addr_t mask); +int (*dma_supported)(struct pci_dev *dev,u64 mask);void *(*alloc_consistent)(struct pci_dev *dev,size_t size,dma_addr_t *iova);void (*free_consistent)(struct pci_dev *dev,size_t size,void *vaddr,dma_addr_t iova);dma_addr_t (*map_single)(struct pci_dev *dev,void *addr,size_t size,int direction);
net/ipv6/mcast.c renamed from net/ipv6/mcast.c.~1~ +3 -2
@@ -5,7 +5,7 @@* Authors: * Pedro Roque <[email protected]> * -* $Id: mcast.c,v 1.37 2001/04/25 20:46:34 davem Exp $ +* $Id: mcast.c,v 1.38 2001/08/15 07:36:31 davem Exp $ * * Based on linux/ipv4/igmp.c and linux/ipv4/ip_sockglue.c *
@@ -90,7 +90,6 @@ mc_lst->next =NULL ;memcpy (&mc_lst->addr, addr,sizeof (struct in6_addr )); - mc_lst->ifindex = ifindex;if (ifindex ==0 ) {struct rt6_info *rt;
@@ -107,6 +106,8 @@sock_kfree_s (sk, mc_lst,sizeof (*mc_lst));return -ENODEV ; } + + mc_lst->ifindex = dev->ifindex;/* * now add/increase the group membership on the device
Quoted 5 lines · David S. Miller
From: Jens Axboe <[email protected]>
Date: Thu, 16 Aug 2001 13:51:50 +0200[ Hopefully this mail won't be encoded in Chinese-BIG5 :-) sorry
about that ]
Looks good :)
Quoted 11 lines
The only difference between your and my tree now is the
PCI_MAX_DMA32flag. Would you consider this? I already use this flag in the block stuff, I just updated the two references you had. MaybePCI_MAX_DMA32_MASKis a better name.I didn't put it into my patch becuase there is no way you can use such a value in generic code.
What if my scsi controller's pci DMA mask is
0x7fffffffor something like this? You don't know at the generic layer, and you must provide some way for the block device to indicate stuff like this to you.
Then your SCSI controller will not use PCI_MAX_DMA32 but rather that particular mask? For block drivers, using 0x7fffffff for blk_queue_bounce_limit is perfectly fine too.
Quoted 4 lines
That is why
PCI_MAX_DMA32, or whatever you would like to name it, does not make any sense. It can be a shorthand for drivers themselves, but that is it and personally I'd rather they just put the bits there explicitly.
Drivers, right. THe block stuff used it in _one_ place -- the BLK_BOUNCE_4G define, to indicated the need to bounce anything above 4G. But no problem, I can just define that to 0xffffffff myself.
Quoted 1 line
I am just finishing up the "death of
alt_address" patch right now.
Excellent.
Signature · 1 line
Jens Axboe
From: Jens Axboe <[email protected]>
Date: Thu, 16 Aug 2001 14:03:17 +0200
Quoted 4 lines
That is why
PCI_MAX_DMA32, or whatever you would like to name it, does not make any sense. It can be a shorthand for drivers themselves, but that is it and personally I'd rather they just put the bits there explicitly.
Drivers, right. THe block stuff used it in _one_ place -- the BLK_BOUNCE_4G define, to indicated the need to bounce anything above 4G. But no problem, I can just define that to 0xffffffff myself.
How can "the block stuff" (ie. generic code) make legal use of this value? Which physical bits it may address, this is a device specific attribute and has nothing to with with 4GB and highmem and PCI standard specifications. :-)
In fact, this is not only a device specific attribute, it also has things to do with elements of the platform.
This is why we have things like pci_dma_supported() and friends. Let me give an example, for most PCI controllers on Sparc64 if your device can address the upper 2GB of 32-bit PCI space, one may DMA to any physical memory location via the IOMMU these controllers have.
There may easily be HIGHMEM platforms which operate this way. So the result is that CONFIG_HIGHMEM does _not_ mean ">=4GB memory must be bounced".
Really, 0xffffffff is a meaningless value. You have to test against device indicated capabilities for bouncing decisions.
You do not even know how "addressable bits" translates into "range of physical memory that may be DMA'd to/from by device". If an IOMMU is present on the platform, these two things have no relationship whatsoever. These two things happen to have a direct relationship on x86, but that is as far as it goes.
Enough babbling on my part, I'll have a look at your bounce patch later today. :-)
Later,
David S. Miller
[email protected]
Quoted 3 lines
What if my scsi controller's pci DMA mask is
0x7fffffffor something like this? You don't know at the generic layer, and you must provide some way for the block device to indicate stuff like this to you.
While we are at it: Is there some portable way to figure whenever I can do a PCI DMA transfer to some page? On ia32 I can simply look at the physical address and if it is behind 4G it doesn't work for 32bit PCI devices. But I think that is not true for architectures which have a iommu ...
Gerd
From: Gerd Knorr <[email protected]>
Date: 16 Aug 2001 12:14:40 GMT
While we are at it: Is there some portable way to figure whenever I can do a PCI DMA transfer to some page? On ia32 I can simply look at the physical address and if it is behind 4G it doesn't work for 32bit PCI devices. But I think that is not true for architectures which have a iommu ...
Currently this is lacking. The state of affairs for platforms I know something about is:
x86: "4GB test"
alpha/sparc64/ppc64: any physical memory whatsoever may be accessed
via 32-bit PCI addressing due to IOMMU
ia64: "software IOMMU" scheme causes DMA to >4GB addresses to
require bounce buffers when using 32-bit addressing Port posses broken 64-bit PCI addressing hack in an attempt to deal with limitations of software IOMMU scheme.
To be honest, you really shouldn't care about this. If you are writing a block device, the block/scsi/ide/whatever layer should take care to only give you memory that can be DMA'd to/from.
Same goes for the networking layer.
In some cases, the distinction being made is "highmem vs not-highmem" for something being DMA'able on PCI. This is on thing the networking references. But, while this will always lead to correct behavior, it is very inefficient.
Jens's and my work aims to directly address these kinds of issues. Whatever we finally end up in Jens's code as the "DMA'able test" will likely propagate into the networking bits.
Later,
David S. Miller
[email protected]
Quoted 5 lines
To be honest, you really shouldn't care about this. If you are writing a block device, the
block/scsi/ide/whateverlayer should take care to only give you memory that can be DMA'd to/from.Same goes for the networking layer.
bttv is neither blkdev nor networking ...
The current kernel's bttv (0.7.x) uses vmalloc_32() for video buffers and remaps these pages to userspace then. My current devel versions (0.8.x) use a completely different approach: mmap() simply returns shared anonymous memory, and bttv uses kiobufs then to lock pages for I/O.
This has the adwantage that the video buffers don't waste unswappable kernel memory any more. It also easy to write video data to any userspace address (read() does that for example, so I don't have to copy_to_user() the big video frames).
On the other hand I have a new problem now: I have to deal with highmem pages (that works with the highmem-I/O patches) and with pages which are outside the DMA-able memory area (hmm...).
Gerd
Signature · 1 line
Damn lot people confuse usability and eye-candy.
From: Gerd Knorr <[email protected]>
Date: Thu, 16 Aug 2001 15:35:41 +0200
Quoted 5 lines
To be honest, you really shouldn't care about this. If you are writing a block device, the
block/scsi/ide/whateverlayer should take care to only give you memory that can be DMA'd to/from.Same goes for the networking layer.
bttv is neither blkdev nor networking ...
It is video layer, and the video layer should be helping along with these sorts of issues.
The video layer should provide PCI device helpers which allow the drivers to just do something like:
struct scatterlist *video_pci_get_user_pages(struct pci_dev *pdev,
int npages);
void video_pci_put_user_pages(struct pci_dev *pdev,
struct scatterlist *sg, int npages);
The scatter list returned (NULL indicates failure, ala -ENOMEM) will tell the driver everything it needs to know. Let us define it as follows:
SG entry 0
address == base of vmalloc()'d area
SG entry 0 ... NPAGES
sg_dma_address(sg) = dma_address for that page sg_dma_len(sg) = dma_length, usually PAGE_SIZE
sg_dma_len could be something larger than PAGE_SIZE if the platform has a way of using virtual mappings in PCI space. You would simply give the device DMA address/len pairs from the SG array until you either hit the NPAGES entry or you see a dma_len of zero.
I realize this does not address the kiovec based scheme you are experimenting with now, but this does deal with the biggest problem the video layer has right now wrt. portability.
In fact, this isn't even a video layer issue, and the kernel ought to provide my suggested interfaces in some generic place.
Later,
David S. Miller
[email protected]