lkml.org 
[lkml]   [2001]   [Jun]   [26]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subjectpatch: highmem zero-bounce
    Hi,

    I updated the patches to 2.4.6-pre5, and removed the zone-dma32
    addition. This means that machines with > 4GB of RAM will need to go all
    the way to low mem for bounces. I did this for several reasons:

    - Linus didn't like the extra zone, so I'm probably redoing it the way
    he suggested.
    - The current version had a bug that prevented 64GB highmem working.

    The core has received no other updates that removal of GFP_DMA32 parts
    and gfp_mask for bouncing.

    I can't put the patch on kernel.org atm, so I've just attached it here.
    It's not that big anyway. As soon as I can log back in, I'll post it
    there too.

    --
    Jens Axboe

    diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.4.6-pre5/drivers/block/cciss.c linux/drivers/block/cciss.c
    --- /opt/kernel/linux-2.4.6-pre5/drivers/block/cciss.c Tue May 22 19:23:16 2001
    +++ linux/drivers/block/cciss.c Mon May 28 02:32:42 2001
    @@ -1124,7 +1124,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);
    @@ -1220,7 +1220,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);
    }
    @@ -1228,7 +1228,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);
    }
    @@ -1238,7 +1238,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)
    @@ -1259,7 +1259,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;
    @@ -1267,10 +1267,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;
    }
    @@ -1318,12 +1323,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;
    @@ -1331,9 +1336,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;
    @@ -1342,9 +1348,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;
    diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.4.6-pre5/drivers/block/cciss.h linux/drivers/block/cciss.h
    --- /opt/kernel/linux-2.4.6-pre5/drivers/block/cciss.h Tue May 22 19:23:16 2001
    +++ linux/drivers/block/cciss.h Mon May 28 02:29:48 2001
    @@ -16,8 +16,9 @@
    #define MAJOR_NR COMPAQ_CISS_MAJOR

    struct my_sg {
    - int len;
    - char *start_addr;
    + struct page *page;
    + unsigned short len;
    + unsigned short offset;
    };

    struct ctlr_info;
    diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.4.6-pre5/drivers/block/cpqarray.c linux/drivers/block/cpqarray.c
    --- /opt/kernel/linux-2.4.6-pre5/drivers/block/cpqarray.c Tue May 22 19:23:16 2001
    +++ linux/drivers/block/cpqarray.c Mon May 28 02:33:10 2001
    @@ -363,7 +363,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);
    }
    @@ -371,7 +371,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);
    }
    @@ -381,7 +381,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)
    @@ -528,6 +528,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);
    @@ -919,17 +920,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;
    }
    @@ -969,19 +975,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;
    @@ -990,9 +997,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);
    }
    @@ -1099,7 +1106,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);
    }
    diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.4.6-pre5/drivers/block/cpqarray.h linux/drivers/block/cpqarray.h
    --- /opt/kernel/linux-2.4.6-pre5/drivers/block/cpqarray.h Tue May 22 19:23:16 2001
    +++ linux/drivers/block/cpqarray.h Mon May 28 02:25:18 2001
    @@ -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;
    diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.4.6-pre5/drivers/block/elevator.c linux/drivers/block/elevator.c
    --- /opt/kernel/linux-2.4.6-pre5/drivers/block/elevator.c Fri Feb 16 01:58:34 2001
    +++ linux/drivers/block/elevator.c Mon May 28 17:56:24 2001
    @@ -110,7 +110,6 @@
    break;
    } else if (__rq->sector - count == bh->b_rsector) {
    ret = ELEVATOR_FRONT_MERGE;
    - __rq->elevator_sequence -= count;
    *req = __rq;
    break;
    }
    diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.4.6-pre5/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
    --- /opt/kernel/linux-2.4.6-pre5/drivers/block/ll_rw_blk.c Tue Jun 26 00:15:57 2001
    +++ linux/drivers/block/ll_rw_blk.c Tue Jun 26 18:01:02 2001
    @@ -22,6 +22,7 @@
    #include <linux/swap.h>
    #include <linux/init.h>
    #include <linux/smp_lock.h>
    +#include <linux/bootmem.h>

    #include <asm/system.h>
    #include <asm/io.h>
    @@ -129,6 +130,7 @@
    static int high_queued_sectors, low_queued_sectors;
    static int batch_requests, queue_nr_requests;
    static DECLARE_WAIT_QUEUE_HEAD(blk_buffers_wait);
    +unsigned long blk_max_low_pfn;

    static inline int get_max_sectors(kdev_t dev)
    {
    @@ -267,6 +269,24 @@
    q->make_request_fn = mfn;
    }

    +/**
    + * blk_queue_bounce_limit - set bounce buffer limit for queue
    + * @q: the request queue for the device
    + * @bus_addr: bus address limit
    + *
    + * Description:
    + * Different hardware can have different requirements as to what pages
    + * it can do I/O directly to. A low level driver can call
    + * blk_queue_bounce_limit to have lower memory pages allocated as bounce
    + * buffers for doing I/O to pages residing above @page. By default
    + * the block layer sets this to the highest numbered "low" memory page, ie
    + * one the driver can still call bio_page() and get a valid address on.
    + **/
    +void blk_queue_bounce_limit(request_queue_t *q, unsigned long dma_addr)
    +{
    + q->bounce_limit = mem_map + (dma_addr >> PAGE_SHIFT);
    +}
    +
    static inline int ll_new_segment(request_queue_t *q, struct request *req, int max_segments)
    {
    if (req->nr_segments < max_segments) {
    @@ -279,7 +299,7 @@
    static int ll_back_merge_fn(request_queue_t *q, struct request *req,
    struct buffer_head *bh, int max_segments)
    {
    - if (req->bhtail->b_data + req->bhtail->b_size == bh->b_data)
    + if (bh_bus(req->bhtail) + req->bhtail->b_size == bh_bus(bh))
    return 1;
    return ll_new_segment(q, req, max_segments);
    }
    @@ -287,7 +307,7 @@
    static int ll_front_merge_fn(request_queue_t *q, struct request *req,
    struct buffer_head *bh, int max_segments)
    {
    - if (bh->b_data + bh->b_size == req->bh->b_data)
    + if (bh_bus(bh) + bh->b_size == bh_bus(req->bh))
    return 1;
    return ll_new_segment(q, req, max_segments);
    }
    @@ -297,7 +317,7 @@
    {
    int total_segments = req->nr_segments + next->nr_segments;

    - if (req->bhtail->b_data + req->bhtail->b_size == next->bh->b_data)
    + if (bh_bus(req->bhtail) + req->bhtail->b_size == bh_bus(next->bh))
    total_segments--;

    if (total_segments > max_segments)
    @@ -431,6 +451,8 @@
    */
    q->plug_device_fn = generic_plug_device;
    q->head_active = 1;
    +
    + blk_queue_bounce_limit(q, BLK_BOUNCE_HIGH);
    }

    #define blkdev_free_rq(list) list_entry((list)->next, struct request, table);
    @@ -621,7 +643,7 @@
    if (req->cmd != next->cmd
    || req->rq_dev != next->rq_dev
    || req->nr_sectors + next->nr_sectors > max_sectors
    - || next->sem)
    + || next->sem || req->special)
    return;
    /*
    * If we are not allowed to merge these requests, then
    @@ -704,9 +726,7 @@
    * driver. Create a bounce buffer if the buffer data points into
    * high memory - keep the original buffer otherwise.
    */
    -#if CONFIG_HIGHMEM
    - bh = create_bounce(rw, bh);
    -#endif
    + bh = blk_queue_bounce(q, rw, bh);

    /* look for a free request. */
    /*
    @@ -751,8 +771,13 @@
    elevator->elevator_merge_cleanup_fn(q, req, count);
    bh->b_reqnext = req->bh;
    req->bh = bh;
    + /*
    + * may not be valid, but queues not having bounce
    + * enabled for highmem pages must not look at
    + * ->buffer anyway
    + */
    req->buffer = bh->b_data;
    - req->current_nr_sectors = count;
    + req->current_nr_sectors = req->hard_cur_sectors = count;
    req->sector = req->hard_sector = sector;
    req->nr_sectors = req->hard_nr_sectors += count;
    blk_started_io(count);
    @@ -802,7 +827,7 @@
    req->errors = 0;
    req->hard_sector = req->sector = sector;
    req->hard_nr_sectors = req->nr_sectors = count;
    - req->current_nr_sectors = count;
    + req->current_nr_sectors = req->hard_cur_sectors = count;
    req->nr_segments = 1; /* Always 1 for a new request. */
    req->nr_hw_segments = 1; /* Always 1 for a new request. */
    req->buffer = bh->b_data;
    @@ -1130,6 +1155,7 @@
    req->nr_sectors = req->hard_nr_sectors;

    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("end_request: buffer-list destroyed\n");
    @@ -1207,6 +1233,8 @@
    low_queued_sectors / 2,
    queue_nr_requests);

    + blk_max_low_pfn = max_low_pfn;
    +
    #ifdef CONFIG_AMIGA_Z2RAM
    z2_init();
    #endif
    @@ -1327,3 +1355,5 @@
    EXPORT_SYMBOL(blkdev_release_request);
    EXPORT_SYMBOL(generic_unplug_device);
    EXPORT_SYMBOL(queued_sectors);
    +EXPORT_SYMBOL(blk_queue_bounce_limit);
    +EXPORT_SYMBOL(blk_max_low_pfn);
    diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.4.6-pre5/drivers/block/loop.c linux/drivers/block/loop.c
    --- /opt/kernel/linux-2.4.6-pre5/drivers/block/loop.c Tue Jun 26 00:15:57 2001
    +++ linux/drivers/block/loop.c Tue Jun 26 17:59:04 2001
    @@ -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
    diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.4.6-pre5/drivers/ide/hpt34x.c linux/drivers/ide/hpt34x.c
    --- /opt/kernel/linux-2.4.6-pre5/drivers/ide/hpt34x.c Sun May 20 02:43:06 2001
    +++ linux/drivers/ide/hpt34x.c Sun May 27 17:50:26 2001
    @@ -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;
    diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.4.6-pre5/drivers/ide/hpt366.c linux/drivers/ide/hpt366.c
    --- /opt/kernel/linux-2.4.6-pre5/drivers/ide/hpt366.c Sun May 20 02:43:06 2001
    +++ linux/drivers/ide/hpt366.c Sun May 27 17:50:26 2001
    @@ -710,6 +710,7 @@
    hwif->autodma = 1;
    else
    hwif->autodma = 0;
    + hwif->highmem = 1;
    } else {
    hwif->autodma = 0;
    hwif->drives[0].autotune = 1;
    diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.4.6-pre5/drivers/ide/ide-disk.c linux/drivers/ide/ide-disk.c
    --- /opt/kernel/linux-2.4.6-pre5/drivers/ide/ide-disk.c Fri Feb 9 20:30:23 2001
    +++ linux/drivers/ide/ide-disk.c Mon May 28 02:10:44 2001
    @@ -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 <axboe@suse.de>
    */

    -#define IDEDISK_VERSION "1.10"
    +#define IDEDISK_VERSION "1.11"

    #undef REALLY_SLOW_IO /* most systems can safely undef this */

    @@ -140,6 +141,7 @@
    int i;
    unsigned int msect, nsect;
    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 +152,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 +162,15 @@
    msect -= nsect;
    } else
    nsect = 1;
    - idedisk_input_data(drive, rq->buffer, nsect * SECTOR_WORDS);
    + to = ide_map_buffer(rq);
    + 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);
    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 +204,15 @@
    #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);
    + char *to = ide_map_buffer(rq);
    + idedisk_output_data (drive, to, SECTOR_WORDS);
    + ide_unmap_buffer(to);
    ide_set_handler (drive, &write_intr, WAIT_CMD, NULL);
    return ide_started;
    }
    @@ -238,14 +242,13 @@
    do {
    char *buffer;
    int nsect = rq->current_nr_sectors;
    -
    +
    if (nsect > mcount)
    nsect = mcount;
    mcount -= nsect;
    - buffer = rq->buffer;

    + buffer = ide_map_buffer(rq);
    rq->sector += nsect;
    - rq->buffer += nsect << 9;
    rq->nr_sectors -= nsect;
    rq->current_nr_sectors -= nsect;

    @@ -259,7 +262,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 +271,7 @@
    * re-entering us on the last transfer.
    */
    idedisk_output_data(drive, buffer, nsect<<7);
    + ide_unmap_buffer(buffer);
    } while (mcount);

    return 0;
    @@ -451,8 +455,10 @@
    return ide_stopped;
    }
    } else {
    + char *buffer = ide_map_buffer(rq);
    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);
    }
    return ide_started;
    }
    diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.4.6-pre5/drivers/ide/ide-dma.c linux/drivers/ide/ide-dma.c
    --- /opt/kernel/linux-2.4.6-pre5/drivers/ide/ide-dma.c Mon Jan 15 22:08:15 2001
    +++ linux/drivers/ide/ide-dma.c Tue May 29 15:42:32 2001
    @@ -215,30 +215,37 @@
    {
    struct buffer_head *bh;
    struct scatterlist *sg = hwif->sg_table;
    + unsigned long lastdataend;
    int nents = 0;

    if (rq->cmd == READ)
    hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;
    else
    hwif->sg_dma_direction = PCI_DMA_TODEVICE;
    +
    bh = rq->bh;
    + lastdataend = 0;
    do {
    - unsigned char *virt_addr = bh->b_data;
    - unsigned int size = bh->b_size;
    -
    - if (nents >= PRD_ENTRIES)
    - return 0;
    -
    - while ((bh = bh->b_reqnext) != NULL) {
    - if ((virt_addr + size) != (unsigned char *) bh->b_data)
    - break;
    - size += bh->b_size;
    + /*
    + * continue segment from before?
    + */
    + if (bh_bus(bh) == lastdataend) {
    + sg[nents - 1].length += bh->b_size;
    + lastdataend += bh->b_size;
    + } else {
    + struct scatterlist *sge;
    + /*
    + * start new segment
    + */
    + if (nents >= PRD_ENTRIES)
    + return 0;
    +
    + sge = &sg[nents];
    + set_bh_sg(sge, bh);
    + lastdataend = bh_bus(bh) + bh->b_size;
    + nents++;
    }
    - memset(&sg[nents], 0, sizeof(*sg));
    - sg[nents].address = virt_addr;
    - sg[nents].length = size;
    - nents++;
    - } while (bh != NULL);
    + } while ((bh = bh->b_reqnext) != NULL);

    return pci_map_sg(hwif->pci_dev, sg, nents, hwif->sg_dma_direction);
    }
    @@ -450,6 +457,24 @@
    return 0;
    }

    +#ifdef CONFIG_HIGHMEM
    +static inline void ide_toggle_bounce(ide_drive_t *drive, int on)
    +{
    + unsigned long flags, addr = BLK_BOUNCE_HIGH;
    +
    + if (on && drive->media == ide_disk && HWIF(drive)->highmem) {
    + printk("%s: enabling highmem I/O\n", drive->name);
    + addr = BLK_BOUNCE_4G;
    + }
    +
    + spin_lock_irqsave(&io_request_lock, flags);
    + blk_queue_bounce_limit(&drive->queue, addr);
    + spin_unlock_irqrestore(&io_request_lock, flags);
    +}
    +#else
    +#define ide_toggle_bounce(drive, on)
    +#endif
    +
    /*
    * ide_dmaproc() initiates/aborts DMA read/write operations on a drive.
    *
    @@ -471,15 +496,17 @@
    ide_hwif_t *hwif = HWIF(drive);
    unsigned long dma_base = hwif->dma_base;
    byte unit = (drive->select.b.unit & 0x01);
    - unsigned int count, reading = 0;
    + unsigned int count, reading = 0, set_high = 1;
    byte dma_stat;

    switch (func) {
    case ide_dma_off:
    printk("%s: DMA disabled\n", drive->name);
    + set_high = 0;
    case ide_dma_off_quietly:
    outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
    case ide_dma_on:
    + ide_toggle_bounce(drive, set_high);
    drive->using_dma = (func == ide_dma_on);
    if (drive->using_dma)
    outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
    diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.4.6-pre5/drivers/ide/pdc202xx.c linux/drivers/ide/pdc202xx.c
    --- /opt/kernel/linux-2.4.6-pre5/drivers/ide/pdc202xx.c Wed May 2 01:05:00 2001
    +++ linux/drivers/ide/pdc202xx.c Sun May 27 17:50:26 2001
    @@ -855,6 +855,7 @@
    #ifdef CONFIG_BLK_DEV_IDEDMA
    if (hwif->dma_base) {
    hwif->dmaproc = &pdc202xx_dmaproc;
    + hwif->highmem = 1;
    if (!noautodma)
    hwif->autodma = 1;
    } else {
    diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.4.6-pre5/drivers/ide/piix.c linux/drivers/ide/piix.c
    --- /opt/kernel/linux-2.4.6-pre5/drivers/ide/piix.c Tue Jun 26 00:15:58 2001
    +++ linux/drivers/ide/piix.c Tue Jun 26 17:59:04 2001
    @@ -512,6 +512,7 @@
    if (!hwif->dma_base)
    return;

    + hwif->highmem = 1;
    #ifndef CONFIG_BLK_DEV_IDEDMA
    hwif->autodma = 0;
    #else /* CONFIG_BLK_DEV_IDEDMA */
    diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.4.6-pre5/drivers/scsi/aic7xxx/aic7xxx_linux_host.h linux/drivers/scsi/aic7xxx/aic7xxx_linux_host.h
    --- /opt/kernel/linux-2.4.6-pre5/drivers/scsi/aic7xxx/aic7xxx_linux_host.h Sat May 5 00:16:28 2001
    +++ linux/drivers/scsi/aic7xxx/aic7xxx_linux_host.h Sun May 27 17:50:26 2001
    @@ -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_ */
    diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.4.6-pre5/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c
    --- /opt/kernel/linux-2.4.6-pre5/drivers/scsi/hosts.c Mon Oct 30 23:44:29 2000
    +++ linux/drivers/scsi/hosts.c Sun May 27 17:50:26 2001
    @@ -230,6 +230,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;

    diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.4.6-pre5/drivers/scsi/hosts.h linux/drivers/scsi/hosts.h
    --- /opt/kernel/linux-2.4.6-pre5/drivers/scsi/hosts.h Sat May 26 03:02:21 2001
    +++ linux/drivers/scsi/hosts.h Tue Jun 26 18:05:42 2001
    @@ -286,6 +286,8 @@
    */
    unsigned emulated:1;

    + unsigned can_dma_32:1;
    +
    /*
    * Name of proc directory
    */
    @@ -384,6 +386,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
    */
    diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.4.6-pre5/drivers/scsi/qlogicfc.h linux/drivers/scsi/qlogicfc.h
    --- /opt/kernel/linux-2.4.6-pre5/drivers/scsi/qlogicfc.h Mon Jun 26 21:02:16 2000
    +++ linux/drivers/scsi/qlogicfc.h Thu Jun 7 14:22:13 2001
    @@ -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 */
    diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.4.6-pre5/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
    --- /opt/kernel/linux-2.4.6-pre5/drivers/scsi/scsi.c Tue Jun 26 00:15:59 2001
    +++ linux/drivers/scsi/scsi.c Tue Jun 26 17:59:03 2001
    @@ -176,10 +176,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
    diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.4.6-pre5/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h
    --- /opt/kernel/linux-2.4.6-pre5/drivers/scsi/scsi.h Sat May 26 03:02:21 2001
    +++ linux/drivers/scsi/scsi.h Tue Jun 26 18:05:42 2001
    @@ -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


    diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.4.6-pre5/drivers/scsi/scsi_lib.c linux/drivers/scsi/scsi_lib.c
    --- /opt/kernel/linux-2.4.6-pre5/drivers/scsi/scsi_lib.c Sat May 5 00:16:28 2001
    +++ linux/drivers/scsi/scsi_lib.c Wed May 30 16:13:00 2001
    @@ -360,37 +360,21 @@
    int frequeue)
    {
    struct request *req;
    - struct buffer_head *bh;
    Scsi_Device * SDpnt;
    - int nsect;

    ASSERT_LOCK(&io_request_lock, 0);

    req = &SCpnt->request;
    - req->errors = 0;
    - if (!uptodate) {
    - printk(" I/O error: dev %s, sector %lu\n",
    - kdevname(req->rq_dev), req->sector);
    - }
    +
    do {
    - if ((bh = req->bh) != NULL) {
    - nsect = bh->b_size >> 9;
    - blk_finished_io(nsect);
    - req->bh = bh->b_reqnext;
    - req->nr_sectors -= nsect;
    - req->sector += nsect;
    - bh->b_reqnext = NULL;
    - sectors -= nsect;
    - bh->b_end_io(bh, uptodate);
    - if ((bh = req->bh) != NULL) {
    - req->current_nr_sectors = bh->b_size >> 9;
    - if (req->nr_sectors < req->current_nr_sectors) {
    - req->nr_sectors = req->current_nr_sectors;
    - printk("scsi_end_request: buffer-list destroyed\n");
    - }
    - }
    + if (!req->bh) {
    + printk("scsi_end_request: missing bh\n");
    + break;
    }
    - } while (sectors && bh);
    + sectors -= req->bh->b_size >> 9;
    + if (!end_that_request_first(req, 1, "scsi"))
    + break;
    + } while (sectors > 0);

    /*
    * If there are blocks left over at the end, set up the command
    @@ -406,7 +390,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.
    @@ -485,6 +468,8 @@
    */
    static void scsi_release_buffers(Scsi_Cmnd * SCpnt)
    {
    + struct request *req = &SCpnt->request;
    +
    ASSERT_LOCK(&io_request_lock, 0);

    /*
    @@ -503,9 +488,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);
    }

    /*
    @@ -541,6 +525,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:
    @@ -570,7 +555,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);
    @@ -580,10 +565,11 @@
    }
    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) {
    + char *to = bh_kmap_irq(req->bh);
    + memcpy(to, SCpnt->buffer, SCpnt->bufflen);
    + bh_kunmap_irq(to);
    }
    scsi_free(SCpnt->buffer, SCpnt->bufflen);
    }
    diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.4.6-pre5/drivers/scsi/scsi_merge.c linux/drivers/scsi/scsi_merge.c
    --- /opt/kernel/linux-2.4.6-pre5/drivers/scsi/scsi_merge.c Fri Feb 9 20:30:23 2001
    +++ linux/drivers/scsi/scsi_merge.c Tue May 29 15:42:48 2001
    @@ -6,6 +6,7 @@
    * Based upon conversations with large numbers
    * of people at Linux Expo.
    * Support for dynamic DMA mapping: Jakub Jelinek (jakub@redhat.com).
    + * Support for highmem I/O: Jens Axboe <axboe@suse.de>
    */

    /*
    @@ -95,7 +96,7 @@
    printk("Segment 0x%p, blocks %d, addr 0x%lx\n",
    bh,
    bh->b_size >> 9,
    - virt_to_phys(bh->b_data - 1));
    + bh_bus(bh) - 1);
    }
    panic("Ththththaats all folks. Too dangerous to continue.\n");
    }
    @@ -223,8 +224,7 @@
    * DMA capable host, make sure that a segment doesn't span
    * the DMA threshold boundary.
    */
    - if (dma_host &&
    - virt_to_phys(bhnext->b_data) - 1 == ISA_DMA_THRESHOLD) {
    + if (dma_host && bh_bus(bhnext) - 1 == ISA_DMA_THRESHOLD) {
    ret++;
    reqsize = bhnext->b_size;
    } else if (CONTIGUOUS_BUFFERS(bh, bhnext)) {
    @@ -241,8 +241,7 @@
    * kind of screwed and we need to start
    * another segment.
    */
    - if( dma_host
    - && virt_to_phys(bh->b_data) - 1 >= ISA_DMA_THRESHOLD
    + if( dma_host && bh_bus(bh) - 1 >= ISA_DMA_THRESHOLD
    && reqsize + bhnext->b_size > PAGE_SIZE )
    {
    ret++;
    @@ -304,7 +303,7 @@
    }

    #define MERGEABLE_BUFFERS(X,Y) \
    -(((((long)(X)->b_data+(X)->b_size)|((long)(Y)->b_data)) & \
    +(((((long)bh_bus((X))+(X)->b_size)|((long)bh_bus((Y)))) & \
    (DMA_CHUNK_SIZE - 1)) == 0)

    #ifdef DMA_CHUNK_SIZE
    @@ -424,14 +423,11 @@
    * DMA capable host, make sure that a segment doesn't span
    * the DMA threshold boundary.
    */
    - if (dma_host &&
    - virt_to_phys(req->bhtail->b_data) - 1 == ISA_DMA_THRESHOLD) {
    + if (dma_host && bh_bus(req->bhtail) - 1 == ISA_DMA_THRESHOLD)
    goto new_end_segment;
    - }
    if (CONTIGUOUS_BUFFERS(req->bhtail, bh)) {
    #ifdef DMA_SEGMENT_SIZE_LIMITED
    - if( dma_host
    - && virt_to_phys(bh->b_data) - 1 >= ISA_DMA_THRESHOLD ) {
    + if (dma_host && bh_bus(bh) - 1 >= ISA_DMA_THRESHOLD) {
    segment_size = 0;
    count = __count_segments(req, use_clustering, dma_host, &segment_size);
    if( segment_size + bh->b_size > PAGE_SIZE ) {
    @@ -480,14 +476,12 @@
    * DMA capable host, make sure that a segment doesn't span
    * the DMA threshold boundary.
    */
    - if (dma_host &&
    - virt_to_phys(bh->b_data) - 1 == ISA_DMA_THRESHOLD) {
    + if (dma_host && bh_bus(bh) - 1 == ISA_DMA_THRESHOLD) {
    goto new_start_segment;
    }
    if (CONTIGUOUS_BUFFERS(bh, req->bh)) {
    #ifdef DMA_SEGMENT_SIZE_LIMITED
    - if( dma_host
    - && virt_to_phys(bh->b_data) - 1 >= ISA_DMA_THRESHOLD ) {
    + if (dma_host && bh_bus(bh) - 1 >= ISA_DMA_THRESHOLD) {
    segment_size = bh->b_size;
    count = __count_segments(req, use_clustering, dma_host, &segment_size);
    if( count != req->nr_segments ) {
    @@ -635,10 +629,8 @@
    * DMA capable host, make sure that a segment doesn't span
    * the DMA threshold boundary.
    */
    - if (dma_host &&
    - virt_to_phys(req->bhtail->b_data) - 1 == ISA_DMA_THRESHOLD) {
    + if (dma_host && bh_bus(req->bhtail) - 1 == ISA_DMA_THRESHOLD)
    goto dont_combine;
    - }
    #ifdef DMA_SEGMENT_SIZE_LIMITED
    /*
    * We currently can only allocate scatter-gather bounce
    @@ -646,7 +638,7 @@
    */
    if (dma_host
    && CONTIGUOUS_BUFFERS(req->bhtail, next->bh)
    - && virt_to_phys(req->bhtail->b_data) - 1 >= ISA_DMA_THRESHOLD )
    + && bh_bus(req->bhtail) - 1 >= ISA_DMA_THRESHOLD )
    {
    int segment_size = 0;
    int count = 0;
    @@ -791,29 +783,6 @@
    struct scatterlist * sgpnt;
    int this_count;

    - /*
    - * FIXME(eric) - don't inline this - it doesn't depend on the
    - * integer flags. Come to think of it, I don't think this is even
    - * needed any more. Need to play with it and see if we hit the
    - * panic. If not, then don't bother.
    - */
    - if (!SCpnt->request.bh) {
    - /*
    - * Case of page request (i.e. raw device), or unlinked buffer
    - * Typically used for swapping, but this isn't how we do
    - * swapping any more.
    - */
    - panic("I believe this is dead code. If we hit this, I was wrong");
    -#if 0
    - SCpnt->request_bufflen = SCpnt->request.nr_sectors << 9;
    - SCpnt->request_buffer = SCpnt->request.buffer;
    - SCpnt->use_sg = 0;
    - /*
    - * FIXME(eric) - need to handle DMA here.
    - */
    -#endif
    - return 1;
    - }
    req = &SCpnt->request;
    /*
    * First we need to know how many scatter gather segments are needed.
    @@ -830,24 +799,16 @@
    * buffer.
    */
    if (dma_host && scsi_dma_free_sectors <= 10) {
    - this_count = SCpnt->request.current_nr_sectors;
    - goto single_segment;
    - }
    - /*
    - * Don't bother with scatter-gather if there is only one segment.
    - */
    - if (count == 1) {
    - this_count = SCpnt->request.nr_sectors;
    + this_count = req->current_nr_sectors;
    goto single_segment;
    }
    - SCpnt->use_sg = count;

    /*
    * Allocate the actual scatter-gather table itself.
    * scsi_malloc can only allocate in chunks of 512 bytes
    */
    - SCpnt->sglist_len = (SCpnt->use_sg
    - * sizeof(struct scatterlist) + 511) & ~511;
    + SCpnt->use_sg = count;
    + SCpnt->sglist_len = (count * sizeof(struct scatterlist) + 511) & ~511;

    sgpnt = (struct scatterlist *) scsi_malloc(SCpnt->sglist_len);

    @@ -860,7 +821,7 @@
    * simply write the first buffer all by itself.
    */
    printk("Warning - running *really* short on DMA buffers\n");
    - this_count = SCpnt->request.current_nr_sectors;
    + this_count = req->current_nr_sectors;
    goto single_segment;
    }
    /*
    @@ -872,11 +833,9 @@
    SCpnt->request_bufflen = 0;
    bhprev = NULL;

    - for (count = 0, bh = SCpnt->request.bh;
    - bh; bh = bh->b_reqnext) {
    + for (count = 0, bh = req->bh; bh; bh = bh->b_reqnext) {
    if (use_clustering && bhprev != NULL) {
    - if (dma_host &&
    - virt_to_phys(bhprev->b_data) - 1 == ISA_DMA_THRESHOLD) {
    + if (dma_host && bh_bus(bhprev) - 1 == ISA_DMA_THRESHOLD) {
    /* Nothing - fall through */
    } else if (CONTIGUOUS_BUFFERS(bhprev, bh)) {
    /*
    @@ -887,7 +846,7 @@
    */
    if( dma_host ) {
    #ifdef DMA_SEGMENT_SIZE_LIMITED
    - if( virt_to_phys(bh->b_data) - 1 < ISA_DMA_THRESHOLD
    + if (bh_bus(bh) - 1 < ISA_DMA_THRESHOLD
    || sgpnt[count - 1].length + bh->b_size <= PAGE_SIZE ) {
    sgpnt[count - 1].length += bh->b_size;
    bhprev = bh;
    @@ -906,12 +865,12 @@
    }
    }
    }
    - count++;
    - sgpnt[count - 1].address = bh->b_data;
    - sgpnt[count - 1].length += bh->b_size;
    - if (!dma_host) {
    +
    + set_bh_sg(&sgpnt[count], bh);
    + if (!dma_host)
    SCpnt->request_bufflen += bh->b_size;
    - }
    +
    + count++;
    bhprev = bh;
    }

    @@ -934,6 +893,10 @@
    for (i = 0; i < count; i++) {
    sectors = (sgpnt[i].length >> 9);
    SCpnt->request_bufflen += sgpnt[i].length;
    + /*
    + * only done for dma_host, in which case .page is not
    + * set since it's guarenteed to be a low memory page
    + */
    if (virt_to_phys(sgpnt[i].address) + sgpnt[i].length - 1 >
    ISA_DMA_THRESHOLD) {
    if( scsi_dma_free_sectors - sectors <= 10 ) {
    @@ -969,7 +932,7 @@
    }
    break;
    }
    - if (SCpnt->request.cmd == WRITE) {
    + if (req->cmd == WRITE) {
    memcpy(sgpnt[i].address, sgpnt[i].alt_address,
    sgpnt[i].length);
    }
    @@ -1014,8 +977,7 @@
    * single-block requests if we had hundreds of free sectors.
    */
    if( scsi_dma_free_sectors > 30 ) {
    - for (this_count = 0, bh = SCpnt->request.bh;
    - bh; bh = bh->b_reqnext) {
    + for (this_count = 0, bh = req->bh; bh; bh = bh->b_reqnext) {
    if( scsi_dma_free_sectors - this_count < 30
    || this_count == sectors )
    {
    @@ -1028,7 +990,7 @@
    /*
    * Yow! Take the absolute minimum here.
    */
    - this_count = SCpnt->request.current_nr_sectors;
    + this_count = req->current_nr_sectors;
    }

    /*
    @@ -1041,28 +1003,30 @@
    * segment. Possibly the entire request, or possibly a small
    * chunk of the entire request.
    */
    - bh = SCpnt->request.bh;
    - buff = SCpnt->request.buffer;
    + bh = req->bh;
    + buff = req->buffer = bh->b_data;

    - if (dma_host) {
    + if (dma_host || PageHighMem(bh->b_page)) {
    /*
    * Allocate a DMA bounce buffer. If the allocation fails, fall
    * back and allocate a really small one - enough to satisfy
    * the first buffer.
    */
    - if (virt_to_phys(SCpnt->request.bh->b_data)
    - + (this_count << 9) - 1 > ISA_DMA_THRESHOLD) {
    + if (bh_bus(bh) + (this_count << 9) - 1 > ISA_DMA_THRESHOLD) {
    buff = (char *) scsi_malloc(this_count << 9);
    if (!buff) {
    printk("Warning - running low on DMA memory\n");
    - this_count = SCpnt->request.current_nr_sectors;
    + this_count = req->current_nr_sectors;
    buff = (char *) scsi_malloc(this_count << 9);
    if (!buff) {
    dma_exhausted(SCpnt, 0);
    }
    }
    - if (SCpnt->request.cmd == WRITE)
    - memcpy(buff, (char *) SCpnt->request.buffer, this_count << 9);
    + if (req->cmd == WRITE) {
    + char *buf = bh_kmap_irq(bh);
    + memcpy(buff, buf, this_count << 9);
    + bh_kunmap_irq(buf);
    + }
    }
    }
    SCpnt->request_bufflen = this_count << 9;
    @@ -1110,14 +1074,6 @@
    q = &SDpnt->request_queue;

    /*
    - * If the host has already selected a merge manager, then don't
    - * pick a new one.
    - */
    -#if 0
    - if (q->back_merge_fn && q->front_merge_fn)
    - return;
    -#endif
    - /*
    * If this host has an unlimited tablesize, then don't bother with a
    * merge manager. The whole point of the operation is to make sure
    * that requests don't grow too large, and this host isn't picky.
    @@ -1149,4 +1105,16 @@
    q->merge_requests_fn = scsi_merge_requests_fn_dc;
    SDpnt->scsi_init_io_fn = scsi_init_io_vdc;
    }
    +
    + /*
    + * now enable highmem I/O, if appropriate
    + */
    +#ifdef CONFIG_HIGHMEM
    + if (SHpnt->can_dma_32 && (SDpnt->type == TYPE_DISK)) {
    + blk_queue_bounce_limit(q, BLK_BOUNCE_4G);
    + printk("SCSI: channel %d, id %d: enabling highmem I/O\n",
    + SDpnt->channel, SDpnt->id);
    + } else
    + blk_queue_bounce_limit(q, BLK_BOUNCE_HIGH);
    +#endif
    }
    diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.4.6-pre5/drivers/scsi/sym53c8xx.h linux/drivers/scsi/sym53c8xx.h
    --- /opt/kernel/linux-2.4.6-pre5/drivers/scsi/sym53c8xx.h Sat May 26 03:03:07 2001
    +++ linux/drivers/scsi/sym53c8xx.h Sun May 27 17:50:26 2001
    @@ -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

    diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.4.6-pre5/fs/buffer.c linux/fs/buffer.c
    --- /opt/kernel/linux-2.4.6-pre5/fs/buffer.c Tue Jun 26 00:15:59 2001
    +++ linux/fs/buffer.c Tue Jun 26 17:59:02 2001
    @@ -1270,13 +1270,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;
    }

    /*
    diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.4.6-pre5/include/asm-i386/kmap_types.h linux/include/asm-i386/kmap_types.h
    --- /opt/kernel/linux-2.4.6-pre5/include/asm-i386/kmap_types.h Thu Apr 12 21:11:39 2001
    +++ linux/include/asm-i386/kmap_types.h Mon May 28 01:28:29 2001
    @@ -6,6 +6,7 @@
    KM_BOUNCE_WRITE,
    KM_SKB_DATA,
    KM_SKB_DATA_SOFTIRQ,
    + KM_BH_IRQ,
    KM_TYPE_NR
    };

    diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.4.6-pre5/include/asm-i386/page.h linux/include/asm-i386/page.h
    --- /opt/kernel/linux-2.4.6-pre5/include/asm-i386/page.h Sat May 26 03:01:26 2001
    +++ linux/include/asm-i386/page.h Sun May 27 18:26:59 2001
    @@ -116,7 +116,8 @@
    #define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET))
    #define virt_to_page(kaddr) (mem_map + (__pa(kaddr) >> PAGE_SHIFT))
    #define VALID_PAGE(page) ((page - mem_map) < max_mapnr)
    -
    +#define page_to_phys(page) (((page) - mem_map) * PAGE_SIZE)
    +#define page_to_bus(page) page_to_phys((page))

    #endif /* __KERNEL__ */

    diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.4.6-pre5/include/asm-i386/pci.h linux/include/asm-i386/pci.h
    --- /opt/kernel/linux-2.4.6-pre5/include/asm-i386/pci.h Tue Jun 26 00:15:59 2001
    +++ linux/include/asm-i386/pci.h Tue Jun 26 18:02:14 2001
    @@ -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 @@
    extern 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;
    }

    @@ -173,10 +213,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. */
    diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.4.6-pre5/include/asm-i386/scatterlist.h linux/include/asm-i386/scatterlist.h
    --- /opt/kernel/linux-2.4.6-pre5/include/asm-i386/scatterlist.h Mon Dec 30 12:01:10 1996
    +++ linux/include/asm-i386/scatterlist.h Mon May 28 02:02:36 2001
    @@ -1,12 +1,34 @@
    #ifndef _I386_SCATTERLIST_H
    #define _I386_SCATTERLIST_H

    +/*
    + * temporary measure, include a page and offset.
    + */
    struct scatterlist {
    - char * address; /* Location data is to be transferred to */
    + struct page * page; /* Location for highmem page, if any */
    + 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 */
    + dma_addr_t dma_address;
    unsigned int length;
    + unsigned int offset;/* for highmem, page offset */
    };
    +
    +extern inline void set_bh_sg(struct scatterlist *sg, struct buffer_head *bh)
    +{
    + if (PageHighMem(bh->b_page)) {
    + sg->page = bh->b_page;
    + sg->offset = bh_offset(bh);
    + sg->address = NULL;
    + } else {
    + sg->page = NULL;
    + sg->offset = 0;
    + sg->address = bh->b_data;
    + }
    +
    + sg->length = bh->b_size;
    +}

    #define ISA_DMA_THRESHOLD (0x00ffffff)

    diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.4.6-pre5/include/linux/blkdev.h linux/include/linux/blkdev.h
    --- /opt/kernel/linux-2.4.6-pre5/include/linux/blkdev.h Sat May 26 03:01:40 2001
    +++ linux/include/linux/blkdev.h Tue Jun 26 18:02:49 2001
    @@ -38,7 +38,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 semaphore * sem;
    @@ -112,6 +112,8 @@
    */
    char head_active;

    + struct page *bounce_limit;
    +
    /*
    * Is meant to protect the queue in the future instead of
    * io_request_lock
    @@ -123,6 +125,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 {
    /*
    diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.4.6-pre5/include/linux/fs.h linux/include/linux/fs.h
    --- /opt/kernel/linux-2.4.6-pre5/include/linux/fs.h Tue Jun 26 00:16:00 2001
    +++ linux/include/linux/fs.h Tue Jun 26 18:00:35 2001
    @@ -278,6 +278,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)
    diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.4.6-pre5/include/linux/highmem.h linux/include/linux/highmem.h
    --- /opt/kernel/linux-2.4.6-pre5/include/linux/highmem.h Sat May 26 03:01:28 2001
    +++ linux/include/linux/highmem.h Tue Jun 26 18:02:00 2001
    @@ -13,8 +13,7 @@
    /* declarations for linux/mm/highmem.c */
    FASTCALL(unsigned int nr_free_highpages(void));

    -extern struct buffer_head * create_bounce(int rw, struct buffer_head * bh_orig);
    -
    +extern struct buffer_head *create_bounce(int rw, struct buffer_head * bh_orig);

    static inline char *bh_kmap(struct buffer_head *bh)
    {
    @@ -26,6 +25,26 @@
    kunmap(bh->b_page);
    }

    +/*
    + * remember to add offset!
    + */
    +static inline char *bh_kmap_irq(struct buffer_head *bh)
    +{
    + unsigned long addr = (unsigned long) kmap_atomic(bh->b_page, KM_BH_IRQ);
    +
    + if (addr & ~PAGE_MASK)
    + BUG();
    +
    + return (char *) addr + bh_offset(bh);
    +}
    +
    +static inline void bh_kunmap_irq(char *buffer)
    +{
    + unsigned long ptr = (unsigned long) buffer & PAGE_MASK;
    +
    + kunmap_atomic((void *) ptr, KM_BH_IRQ);
    +}
    +
    #else /* CONFIG_HIGHMEM */

    static inline unsigned int nr_free_highpages(void) { return 0; }
    @@ -39,6 +58,8 @@

    #define bh_kmap(bh) ((bh)->b_data)
    #define bh_kunmap(bh) do { } while (0)
    +#define bh_kmap_irq(bh) ((bh)->b_data)
    +#define bh_kunmap_irq(bh) do { } while (0)

    #endif /* CONFIG_HIGHMEM */

    diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.4.6-pre5/include/linux/ide.h linux/include/linux/ide.h
    --- /opt/kernel/linux-2.4.6-pre5/include/linux/ide.h Sat May 26 03:02:42 2001
    +++ linux/include/linux/ide.h Tue Jun 26 18:03:30 2001
    @@ -457,6 +457,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 */
    @@ -752,6 +753,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)
    +{
    + return bh_kmap_irq(rq->bh) + ide_rq_offset(rq);
    +}
    +
    +extern inline void ide_unmap_buffer(char *buffer)
    +{
    + bh_kunmap_irq(buffer);
    +}

    /*
    * This function issues a special IDE device request
    diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.4.6-pre5/include/linux/pci.h linux/include/linux/pci.h
    --- /opt/kernel/linux-2.4.6-pre5/include/linux/pci.h Tue Jun 26 00:16:00 2001
    +++ linux/include/linux/pci.h Tue Jun 26 18:02:50 2001
    @@ -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
    diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.4.6-pre5/kernel/ksyms.c linux/kernel/ksyms.c
    --- /opt/kernel/linux-2.4.6-pre5/kernel/ksyms.c Tue Jun 26 00:16:00 2001
    +++ linux/kernel/ksyms.c Tue Jun 26 17:59:02 2001
    @@ -122,6 +122,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 */
    \
     
     \ /
      Last update: 2005-03-22 12:55    [W:3.281 / U:0.768 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site