diff -Nur linux-2.4.19/drivers/ide/Config.in linux-2.4.19.new/drivers/ide/Config.in --- linux-2.4.19/drivers/ide/Config.in Sat Aug 3 02:39:44 2002 +++ linux-2.4.19.new/drivers/ide/Config.in Wed Nov 13 09:49:39 2002 @@ -65,14 +65,14 @@ dep_mbool ' ALI M15x3 WDC support (DANGEROUS)' CONFIG_WDC_ALI15X3 $CONFIG_BLK_DEV_ALI15X3 dep_bool ' AMD Viper support' CONFIG_BLK_DEV_AMD74XX $CONFIG_BLK_DEV_IDEDMA_PCI dep_mbool ' AMD Viper ATA-66 Override (WIP)' CONFIG_AMD74XX_OVERRIDE $CONFIG_BLK_DEV_AMD74XX $CONFIG_IDEDMA_PCI_WIP - dep_bool ' CMD64X chipset support' CONFIG_BLK_DEV_CMD64X $CONFIG_BLK_DEV_IDEDMA_PCI + dep_bool ' CMD64X and CMD680 chipset support' CONFIG_BLK_DEV_CMD64X $CONFIG_BLK_DEV_IDEDMA_PCI dep_bool ' CMD680 chipset tuning support' CONFIG_BLK_DEV_CMD680 $CONFIG_BLK_DEV_CMD64X dep_bool ' CY82C693 chipset support' CONFIG_BLK_DEV_CY82C693 $CONFIG_BLK_DEV_IDEDMA_PCI dep_bool ' Cyrix CS5530 MediaGX chipset support' CONFIG_BLK_DEV_CS5530 $CONFIG_BLK_DEV_IDEDMA_PCI dep_bool ' HPT34X chipset support' CONFIG_BLK_DEV_HPT34X $CONFIG_BLK_DEV_IDEDMA_PCI dep_mbool ' HPT34X AUTODMA support (WIP)' CONFIG_HPT34X_AUTODMA $CONFIG_BLK_DEV_HPT34X $CONFIG_IDEDMA_PCI_WIP dep_bool ' HPT366/368/370 chipset support' CONFIG_BLK_DEV_HPT366 $CONFIG_BLK_DEV_IDEDMA_PCI - if [ "$CONFIG_X86" = "y" -o "$CONFIG_IA64" = "y" ]; then + if [ "$CONFIG_X86" = "y" -o "$CONFIG_IA64" = "y" -o "$CONFIG_MIPS" = "y" ]; then dep_mbool ' Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX $CONFIG_BLK_DEV_IDEDMA_PCI dep_mbool ' PIIXn Tuning support' CONFIG_PIIX_TUNING $CONFIG_BLK_DEV_PIIX $CONFIG_IDEDMA_PCI_AUTO fi @@ -108,7 +108,7 @@ fi fi if [ "$CONFIG_SIBYTE_SWARM" = "y" ]; then - bool ' SWARM onboard IDE support' CONFIG_BLK_DEV_IDE_SWARM + bool ' Broadcom SiByte onboard IDE support' CONFIG_BLK_DEV_IDE_SIBYTE fi if [ "$CONFIG_ARCH_ACORN" = "y" ]; then dep_bool ' ICS IDE interface support' CONFIG_BLK_DEV_IDE_ICSIDE $CONFIG_ARCH_ACORN @@ -144,7 +144,8 @@ EXT_DIRECT CONFIG_IDE_EXT_DIRECT" 8xx_PCCARD fi - bool ' Other IDE chipset support' CONFIG_IDE_CHIPSETS + # no isa -> no vlb + dep_bool ' Other IDE chipset support' CONFIG_IDE_CHIPSETS $CONFIG_ISA if [ "$CONFIG_IDE_CHIPSETS" = "y" ]; then comment 'Note: most of these also require special kernel boot parameters' bool ' Generic 4 drives/port support' CONFIG_BLK_DEV_4DRIVES @@ -209,8 +210,8 @@ define_bool CONFIG_BLK_DEV_IDE_MODES n fi -dep_tristate 'Support for IDE Raid controllers' CONFIG_BLK_DEV_ATARAID $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL -dep_tristate ' Support Promise software RAID (Fasttrak(tm))' CONFIG_BLK_DEV_ATARAID_PDC $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL $CONFIG_BLK_DEV_ATARAID -dep_tristate ' Highpoint 370 software RAID' CONFIG_BLK_DEV_ATARAID_HPT $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL $CONFIG_BLK_DEV_ATARAID +dep_tristate 'Support for IDE Raid controllers (EXPERIMENTAL)' CONFIG_BLK_DEV_ATARAID $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL +dep_tristate ' Support Promise software RAID (Fasttrak(tm)) (EXPERIMENTAL)' CONFIG_BLK_DEV_ATARAID_PDC $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL $CONFIG_BLK_DEV_ATARAID +dep_tristate ' Highpoint 370 software RAID (EXPERIMENTAL)' CONFIG_BLK_DEV_ATARAID_HPT $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL $CONFIG_BLK_DEV_ATARAID endmenu diff -Nur linux-2.4.19/drivers/ide/Makefile linux-2.4.19.new/drivers/ide/Makefile --- linux-2.4.19/drivers/ide/Makefile Sat Aug 3 02:39:44 2002 +++ linux-2.4.19.new/drivers/ide/Makefile Wed Nov 13 09:49:39 2002 @@ -49,7 +49,7 @@ ide-obj-$(CONFIG_BLK_DEV_IDEPCI) += ide-pci.o ide-obj-$(CONFIG_BLK_DEV_ISAPNP) += ide-pnp.o ide-obj-$(CONFIG_BLK_DEV_IDE_PMAC) += ide-pmac.o -ide-obj-$(CONFIG_BLK_DEV_IDE_SWARM) += ide-swarm.o +ide-obj-$(CONFIG_BLK_DEV_IDE_SIBYTE) += ide-sibyte.o ide-obj-$(CONFIG_BLK_DEV_MAC_IDE) += macide.o ide-obj-$(CONFIG_BLK_DEV_NS87415) += ns87415.o ide-obj-$(CONFIG_BLK_DEV_OPTI621) += opti621.o diff -Nur linux-2.4.19/drivers/ide/ide-cd.c linux-2.4.19.new/drivers/ide/ide-cd.c --- linux-2.4.19/drivers/ide/ide-cd.c Sat Aug 3 02:39:44 2002 +++ linux-2.4.19.new/drivers/ide/ide-cd.c Wed Nov 13 09:49:39 2002 @@ -2194,6 +2194,8 @@ layer. the packet must be complete, as we do not touch it at all. */ memset(&pc, 0, sizeof(pc)); + if (cgc->sense) + memset(cgc->sense, 0, sizeof(struct request_sense)); memcpy(pc.c, cgc->cmd, CDROM_PACKET_SIZE); pc.buffer = cgc->buffer; pc.buflen = cgc->buflen; diff -Nur linux-2.4.19/drivers/ide/ide-cs.c linux-2.4.19.new/drivers/ide/ide-cs.c --- linux-2.4.19/drivers/ide/ide-cs.c Sat Aug 3 02:39:44 2002 +++ linux-2.4.19.new/drivers/ide/ide-cs.c Wed Nov 13 09:49:39 2002 @@ -15,7 +15,7 @@ rights and limitations under the License. The initial developer of the original code is David A. Hinds - . Portions created by David A. Hinds + . Portions created by David A. Hinds are Copyright (C) 1999 David A. Hinds. All Rights Reserved. Alternatively, the contents of this file may be used under the diff -Nur linux-2.4.19/drivers/ide/ide-disk.c linux-2.4.19.new/drivers/ide/ide-disk.c --- linux-2.4.19/drivers/ide/ide-disk.c Sat Aug 3 02:39:44 2002 +++ linux-2.4.19.new/drivers/ide/ide-disk.c Wed Nov 13 09:49:39 2002 @@ -29,6 +29,7 @@ * Version 1.10 request queue changes, Ultra DMA 100 * Version 1.11 added 48-bit lba * Version 1.12 adding taskfile io access method + * Highmem I/O support, Jens Axboe */ #define IDEDISK_VERSION "1.12" @@ -158,7 +159,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)) { @@ -169,8 +172,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) { @@ -179,14 +182,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) @@ -220,14 +224,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; } @@ -257,14 +263,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; @@ -278,7 +284,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; } } @@ -287,6 +293,7 @@ * re-entering us on the last transfer. */ idedisk_output_data(drive, buffer, nsect<<7); + ide_unmap_buffer(buffer, &flags); } while (mcount); return 0; @@ -695,8 +702,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; } diff -Nur linux-2.4.19/drivers/ide/ide-dma.c linux-2.4.19.new/drivers/ide/ide-dma.c --- linux-2.4.19/drivers/ide/ide-dma.c Sat Aug 3 02:39:44 2002 +++ linux-2.4.19.new/drivers/ide/ide-dma.c Wed Nov 13 09:49:39 2002 @@ -252,33 +252,53 @@ { struct buffer_head *bh; struct scatterlist *sg = hwif->sg_table; + unsigned long lastdataend = ~0UL; int nents = 0; if (hwif->sg_dma_active) BUG(); - + if (rq->cmd == READ) hwif->sg_dma_direction = PCI_DMA_FROMDEVICE; else hwif->sg_dma_direction = PCI_DMA_TODEVICE; + bh = rq->bh; do { - unsigned char *virt_addr = bh->b_data; - unsigned int size = bh->b_size; + struct scatterlist *sge; + + /* + * continue segment from before? + */ + if (bh_phys(bh) == lastdataend) { + sg[nents - 1].length += bh->b_size; + lastdataend += bh->b_size; + continue; + } + /* + * start new segment + */ 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; + sge = &sg[nents]; + memset(sge, 0, sizeof(*sge)); + + if (bh->b_page) { + sge->page = bh->b_page; + sge->offset = bh_offset(bh); + } else { + if (((unsigned long) bh->b_data) < PAGE_SIZE) + BUG(); + + sge->address = bh->b_data; } - memset(&sg[nents], 0, sizeof(*sg)); - sg[nents].address = virt_addr; - sg[nents].length = size; + + sge->length = bh->b_size; + lastdataend = bh_phys(bh) + bh->b_size; nents++; - } while (bh != NULL); + } while ((bh = bh->b_reqnext) != NULL); return pci_map_sg(hwif->pci_dev, sg, nents, hwif->sg_dma_direction); } @@ -340,7 +360,7 @@ return 0; sg = HWIF(drive)->sg_table; - while (i && sg_dma_len(sg)) { + while (i) { u32 cur_addr; u32 cur_len; @@ -354,36 +374,35 @@ */ while (cur_len) { - if (count++ >= PRD_ENTRIES) { - printk("%s: DMA table too small\n", drive->name); - goto use_pio_instead; - } else { - u32 xcount, bcount = 0x10000 - (cur_addr & 0xffff); - - if (bcount > cur_len) - bcount = cur_len; - *table++ = cpu_to_le32(cur_addr); - xcount = bcount & 0xffff; - if (is_trm290_chipset) - xcount = ((xcount >> 2) - 1) << 16; - if (xcount == 0x0000) { - /* - * Most chipsets correctly interpret a length of 0x0000 as 64KB, - * but at least one (e.g. CS5530) misinterprets it as zero (!). - * So here we break the 64KB entry into two 32KB entries instead. - */ - if (count++ >= PRD_ENTRIES) { - printk("%s: DMA table too small\n", drive->name); - goto use_pio_instead; - } - *table++ = cpu_to_le32(0x8000); - *table++ = cpu_to_le32(cur_addr + 0x8000); - xcount = 0x8000; - } - *table++ = cpu_to_le32(xcount); - cur_addr += bcount; - cur_len -= bcount; + u32 xcount, bcount = 0x10000 - (cur_addr & 0xffff); + + if (count++ >= PRD_ENTRIES) + BUG(); + + if (bcount > cur_len) + bcount = cur_len; + *table++ = cpu_to_le32(cur_addr); + xcount = bcount & 0xffff; + if (is_trm290_chipset) + xcount = ((xcount >> 2) - 1) << 16; + if (xcount == 0x0000) { + /* + * Most chipsets correctly interpret a length + * of 0x0000 as 64KB, but at least one + * (e.g. CS5530) misinterprets it as zero (!). + * So here we break the 64KB entry into two + * 32KB entries instead. + */ + if (count++ >= PRD_ENTRIES) + goto use_pio_instead; + + *table++ = cpu_to_le32(0x8000); + *table++ = cpu_to_le32(cur_addr + 0x8000); + xcount = 0x8000; } + *table++ = cpu_to_le32(xcount); + cur_addr += bcount; + cur_len -= bcount; } sg++; @@ -584,6 +603,23 @@ } #endif /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */ +static inline void ide_toggle_bounce(ide_drive_t *drive, int on) +{ + dma64_addr_t addr = BLK_BOUNCE_HIGH; + + if (HWIF(drive)->no_highio || HWIF(drive)->pci_dev == NULL) + return; + + if (on && drive->media == ide_disk) { + if (!PCI_DMA_BUS_IS_PHYS) + addr = BLK_BOUNCE_ANY; + else + addr = HWIF(drive)->pci_dev->dma_mask; + } + + blk_queue_bounce_limit(&drive->queue, addr); +} + /* * ide_dmaproc() initiates/aborts DMA read/write operations on a drive. * @@ -606,18 +642,20 @@ 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); case ide_dma_off_quietly: + set_high = 0; outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2); case ide_dma_on: drive->using_dma = (func == ide_dma_on); if (drive->using_dma) outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2); + ide_toggle_bounce(drive, set_high); return 0; case ide_dma_check: return config_drive_for_dma (drive); @@ -759,8 +797,8 @@ request_region(dma_base, num_ports, hwif->name); hwif->dma_base = dma_base; hwif->dmatable_cpu = pci_alloc_consistent(hwif->pci_dev, - PRD_ENTRIES * PRD_BYTES, - &hwif->dmatable_dma); + PRD_ENTRIES * PRD_BYTES, + &hwif->dmatable_dma); if (hwif->dmatable_cpu == NULL) goto dma_alloc_failure; diff -Nur linux-2.4.19/drivers/ide/ide-geometry.c linux-2.4.19.new/drivers/ide/ide-geometry.c --- linux-2.4.19/drivers/ide/ide-geometry.c Sat Aug 3 02:39:44 2002 +++ linux-2.4.19.new/drivers/ide/ide-geometry.c Wed Nov 13 09:49:39 2002 @@ -32,7 +32,7 @@ * for us during initialization. I have the necessary docs -- any takers? -ml */ /* - * I did this, but it doesnt work - there is no reasonable way to find the + * I did this, but it doesn't work - there is no reasonable way to find the * correspondence between the BIOS numbering of the disks and the Linux * numbering. -aeb * diff -Nur linux-2.4.19/drivers/ide/ide-pci.c linux-2.4.19.new/drivers/ide/ide-pci.c --- linux-2.4.19/drivers/ide/ide-pci.c Sat Aug 3 02:39:44 2002 +++ linux-2.4.19.new/drivers/ide/ide-pci.c Wed Nov 13 09:49:39 2002 @@ -405,7 +405,7 @@ #ifndef CONFIG_PDC202XX_FORCE {DEVID_PDC20246,"PDC20246", PCI_PDC202XX, NULL, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 16 }, {DEVID_PDC20262,"PDC20262", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 48 }, - {DEVID_PDC20265,"PDC20265", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 48 }, + {DEVID_PDC20265,"PDC20265", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 48 }, {DEVID_PDC20267,"PDC20267", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 48 }, #else /* !CONFIG_PDC202XX_FORCE */ {DEVID_PDC20246,"PDC20246", PCI_PDC202XX, NULL, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 16 }, @@ -623,8 +623,12 @@ } if (pci_enable_device(dev)) { - printk(KERN_WARNING "%s: (ide_setup_pci_device:) Could not enable device.\n", d->name); - return; + if(pci_enable_device_bars(dev, 1<<4)) + { + printk(KERN_WARNING "%s: (ide_setup_pci_device:) Could not enable device.\n", d->name); + return; + } + printk(KERN_INFO "%s: BIOS setup was incomplete.\n", d->name); } check_if_enabled: @@ -669,18 +673,27 @@ */ pciirq = dev->irq; -#ifdef CONFIG_PDC202XX_FORCE - if (dev->class >> 8 == PCI_CLASS_STORAGE_RAID) { - /* - * By rights we want to ignore Promise FastTrak and SuperTrak - * series here, those use own driver. + if (dev->class >> 8 == PCI_CLASS_STORAGE_RAID) + { + /* By rights we want to ignore these, but the Promise Fastrak + * people have some strange ideas about proprietary so we have + * to act otherwise on those. The supertrak however we need + * to skip */ - if (dev->vendor == PCI_VENDOR_ID_PROMISE) { - printk(KERN_INFO "ide: Skipping Promise RAID controller.\n"); - return; + if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20265)) + { + printk(KERN_INFO "ide: Found promise 20265 in RAID mode.\n"); + if(dev->bus->self && dev->bus->self->vendor == PCI_VENDOR_ID_INTEL && + dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960) + { + printk(KERN_INFO "ide: Skipping Promise PDC20265 attached to I2O RAID controller.\n"); + return; + } } + /* Its attached to something else, just a random bridge. + Suspect a fastrak and fall through */ } -#endif /* CONFIG_PDC202XX_FORCE */ + if ((dev->class & ~(0xfa)) != ((PCI_CLASS_STORAGE_IDE << 8) | 5)) { printk("%s: not 100%% native mode: will probe irqs later\n", d->name); /* diff -Nur linux-2.4.19/drivers/ide/ide-pmac.c linux-2.4.19.new/drivers/ide/ide-pmac.c --- linux-2.4.19/drivers/ide/ide-pmac.c Sat Aug 3 02:39:44 2002 +++ linux-2.4.19.new/drivers/ide/ide-pmac.c Wed Nov 13 09:49:39 2002 @@ -114,8 +114,7 @@ * well, despite a comment that would lead to think it has a * min value of 45ns. * Apple also add 60ns to the write data setup (or cycle time ?) on - * reads. I can't explain that, I tried it and it broke everything - * here. + * reads. */ #define TR_66_UDMA_MASK 0xfff00000 #define TR_66_UDMA_EN 0x00100000 /* Enable Ultra mode for DMA */ @@ -401,7 +400,6 @@ pmac_ide_do_setfeature(ide_drive_t *drive, byte command) { int result = 1; - unsigned long flags; ide_hwif_t *hwif = HWIF(drive); disable_irq(hwif->irq); /* disable_irq_nosync ?? */ @@ -420,10 +418,7 @@ OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG); OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG); udelay(1); - __save_flags(flags); /* local CPU only */ - ide__sti(); /* local CPU only -- for jiffies */ result = wait_for_ready(drive); - __restore_flags(flags); /* local CPU only */ OUT_BYTE(drive->ctl, IDE_CONTROL_REG); if (result) printk(KERN_ERR "pmac_ide_do_setfeature disk not ready after SET_FEATURE !\n"); @@ -956,6 +951,8 @@ hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET] || in_bay; hwif->udma_four = (pmhw->kind == controller_kl_ata4_80); hwif->pci_dev = pdev; + hwif->drives[0].unmask = 1; + hwif->drives[1].unmask = 1; #ifdef CONFIG_PMAC_PBOOK if (in_bay && check_media_bay_by_base(base, MB_CD) == 0) hwif->noprobe = 0; @@ -1032,33 +1029,48 @@ struct pmac_ide_hwif *pmif = &pmac_ide[ix]; struct buffer_head *bh; struct scatterlist *sg = pmif->sg_table; + unsigned long lastdataend = ~0UL; int nents = 0; if (hwif->sg_dma_active) BUG(); - + if (rq->cmd == READ) pmif->sg_dma_direction = PCI_DMA_FROMDEVICE; else pmif->sg_dma_direction = PCI_DMA_TODEVICE; + bh = rq->bh; do { - unsigned char *virt_addr = bh->b_data; + struct scatterlist *sge; unsigned int size = bh->b_size; + /* continue segment from before? */ + if (bh_phys(bh) == lastdataend) { + sg[nents-1].length += size; + lastdataend += size; + continue; + } + + /* start new segment */ if (nents >= MAX_DCMDS) return 0; - while ((bh = bh->b_reqnext) != NULL) { - if ((virt_addr + size) != (unsigned char *) bh->b_data) - break; - size += bh->b_size; + sge = &sg[nents]; + memset(sge, 0, sizeof(*sge)); + + if (bh->b_page) { + sge->page = bh->b_page; + sge->offset = bh_offset(bh); + } else { + if ((unsigned long)bh->b_data < PAGE_SIZE) + BUG(); + sge->address = bh->b_data; } - memset(&sg[nents], 0, sizeof(*sg)); - sg[nents].address = virt_addr; - sg[nents].length = size; + sge->length = size; + lastdataend = bh_phys(bh) + size; nents++; - } while (bh != NULL); + } while ((bh = bh->b_reqnext) != NULL); return pci_map_sg(hwif->pci_dev, sg, nents, pmif->sg_dma_direction); } @@ -1330,6 +1342,23 @@ return 0; } +static inline void pmac_ide_toggle_bounce(ide_drive_t *drive, int on) +{ + dma64_addr_t addr = BLK_BOUNCE_HIGH; + + if (HWIF(drive)->no_highio || HWIF(drive)->pci_dev == NULL) + return; + + if (on && drive->media == ide_disk) { + if (!PCI_DMA_BUS_IS_PHYS) + addr = BLK_BOUNCE_ANY; + else + addr = HWIF(drive)->pci_dev->dma_mask; + } + + blk_queue_bounce_limit(&drive->queue, addr); +} + static int __pmac pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive) { @@ -1354,10 +1383,13 @@ printk(KERN_INFO "%s: DMA disabled\n", drive->name); case ide_dma_off_quietly: drive->using_dma = 0; + pmac_ide_toggle_bounce(drive, 0); break; case ide_dma_on: case ide_dma_check: pmac_ide_check_dma(drive); + if (drive->using_dma) + pmac_ide_toggle_bounce(drive, 1); break; case ide_dma_read: reading = 1; @@ -1612,7 +1644,14 @@ /* Note: We support only master drives for now. This will have to be * improved if we want to handle sleep on the iMacDV where the CD-ROM - * is a slave + * is a slave. + * + * Well, actually, that sorta works on the iBook2 when the CD-ROM is + * a slave, though it will fail to spin_wait_hwgroup for the slave + * device as it is marked busy by the master sleep code. Well, it's + * probably not worth fixing now as we don't have sleep code for + * ATAPI devices anyway. Future kernels will hopefully deal with + * IDE PM in a more generic way. */ static int __pmac idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when) diff -Nur linux-2.4.19/drivers/ide/ide-probe.c linux-2.4.19.new/drivers/ide/ide-probe.c --- linux-2.4.19/drivers/ide/ide-probe.c Sat Aug 3 02:39:44 2002 +++ linux-2.4.19.new/drivers/ide/ide-probe.c Wed Nov 13 09:49:39 2002 @@ -785,6 +785,7 @@ gd = kmalloc (sizeof(struct gendisk), GFP_KERNEL); if (!gd) goto err_kmalloc_gd; + memset (gd, 0, sizeof(struct gendisk)); gd->sizes = kmalloc (minors * sizeof(int), GFP_KERNEL); if (!gd->sizes) goto err_kmalloc_gd_sizes; diff -Nur linux-2.4.19/drivers/ide/ide-sibyte.c linux-2.4.19.new/drivers/ide/ide-sibyte.c --- linux-2.4.19/drivers/ide/ide-sibyte.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19.new/drivers/ide/ide-sibyte.c Wed Nov 13 09:49:39 2002 @@ -0,0 +1,333 @@ +/* + * Copyright (C) 2001 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* Derived loosely from ide-pmac.c, so: + * + * Copyright (C) 1998 Paul Mackerras. + * Copyright (C) 1995-1998 Mark Lord + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* Note: this should be general for any board using IDE on GenBus */ + +extern struct ide_ops std_ide_ops; + +static ide_hwif_t *sb_ide_hwif = NULL; +static unsigned long ide_base; + +#define SIBYTE_IDE_BASE (KSEG1ADDR(ide_base)-mips_io_port_base) +#define SIBYTE_IDE_REG(pcaddr) (SIBYTE_IDE_BASE + ((pcaddr)<<5)) + +/* + * We are limiting the number of PCI-IDE devices to leave room for + * GenBus IDE (and possibly PCMCIA/CF?) + */ +static int sibyte_ide_default_irq(ide_ioreg_t base) +{ + return 0; +} + +static ide_ioreg_t sibyte_ide_default_io_base(int index) +{ + return 0; +} + +static void sibyte_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, + ide_ioreg_t ctrl_port, int *irq) +{ + std_ide_ops.ide_init_hwif_ports(hw, data_port, ctrl_port, irq); +} + +static int sibyte_ide_request_irq(unsigned int irq, + void (*handler)(int,void *, struct pt_regs *), + unsigned long flags, const char *device, + void *dev_id) +{ + return request_irq(irq, handler, flags, device, dev_id); +} + +static void sibyte_ide_free_irq(unsigned int irq, void *dev_id) +{ + free_irq(irq, dev_id); +} + +static inline int is_sibyte_ide(ide_ioreg_t from) +{ + return (sb_ide_hwif && + ((from == sb_ide_hwif->io_ports[IDE_DATA_OFFSET]) || + (from == sb_ide_hwif->io_ports[IDE_ERROR_OFFSET]) || + (from == sb_ide_hwif->io_ports[IDE_NSECTOR_OFFSET]) || + (from == sb_ide_hwif->io_ports[IDE_SECTOR_OFFSET]) || + (from == sb_ide_hwif->io_ports[IDE_LCYL_OFFSET]) || + (from == sb_ide_hwif->io_ports[IDE_HCYL_OFFSET]) || + (from == sb_ide_hwif->io_ports[IDE_SELECT_OFFSET]) || + (from == sb_ide_hwif->io_ports[IDE_STATUS_OFFSET]) || + (from == sb_ide_hwif->io_ports[IDE_CONTROL_OFFSET]))); +} + +static int sibyte_ide_check_region(ide_ioreg_t from, unsigned int extent) +{ + /* Figure out if it's the SiByte IDE; if so, don't do anything + since our I/O space is in a weird place. */ + if (is_sibyte_ide(from)) + return 0; + else +#ifdef CONFIG_BLK_DEV_IDE + return std_ide_ops.ide_check_region(from, extent); +#else + return 0; +#endif +} + +static void sibyte_ide_request_region(ide_ioreg_t from, unsigned int extent, + const char *name) +{ +#ifdef CONFIG_BLK_DEV_IDE + if (!is_sibyte_ide(from)) + std_ide_ops.ide_request_region(from, extent, name); +#endif +} + +static void sibyte_ide_release_region(ide_ioreg_t from, unsigned int extent) +{ +#ifdef CONFIG_BLK_DEV_IDE + if (!is_sibyte_ide(from)) + std_ide_ops.ide_release_region(from, extent); +#endif +} + +struct ide_ops sibyte_ide_ops = { + &sibyte_ide_default_irq, + &sibyte_ide_default_io_base, + &sibyte_ide_init_hwif_ports, + &sibyte_ide_request_irq, + &sibyte_ide_free_irq, + &sibyte_ide_check_region, + &sibyte_ide_request_region, + &sibyte_ide_release_region +}; + +/* + * I/O operations. The FPGA for SiByte generic bus IDE deals with + * byte-swapping for us, so we can't share the I/O macros with other + * IDE (e.g. PCI-IDE) devices. + */ + +#define sibyte_outb(val,port) \ +do { \ + *(volatile u8 *)(mips_io_port_base + (port)) = val; \ +} while(0) + +#define sibyte_outw(val,port) \ +do { \ + *(volatile u16 *)(mips_io_port_base + (port)) = val; \ +} while(0) + +#define sibyte_outl(val,port) \ +do { \ + *(volatile u32 *)(mips_io_port_base + (port)) = val; \ +} while(0) + +static inline unsigned char sibyte_inb(unsigned long port) +{ + return (*(volatile u8 *)(mips_io_port_base + (port))); +} + +static inline unsigned short sibyte_inw(unsigned long port) +{ + return (*(volatile u16 *)(mips_io_port_base + (port))); +} + +static inline unsigned int sibyte_inl(unsigned long port) +{ + return (*(volatile u32 *)(mips_io_port_base + (port))); +} + + +static inline void sibyte_outsb(unsigned long port, void *addr, unsigned int count) +{ + while (count--) { + sibyte_outb(*(u8 *)addr, port); + addr++; + } +} + +static inline void sibyte_insb(unsigned long port, void *addr, unsigned int count) +{ + while (count--) { + *(u8 *)addr = sibyte_inb(port); + addr++; + } +} + +static inline void sibyte_outsw(unsigned long port, void *addr, unsigned int count) +{ + while (count--) { + sibyte_outw(*(u16 *)addr, port); + addr += 2; + } +} + +static inline void sibyte_insw(unsigned long port, void *addr, unsigned int count) +{ + while (count--) { + *(u16 *)addr = sibyte_inw(port); + addr += 2; + } +} + +static inline void sibyte_outsl(unsigned long port, void *addr, unsigned int count) +{ + while (count--) { + sibyte_outl(*(u32 *)addr, port); + addr += 4; + } +} + +static inline void sibyte_insl(unsigned long port, void *addr, unsigned int count) +{ + while (count--) { + *(u32 *)addr = sibyte_inl(port); + addr += 4; + } +} + +static void sibyte_ideproc(ide_ide_action_t action, ide_drive_t *drive, + void *buffer, unsigned int count) +{ + /* slow? vlb_sync? */ + switch (action) { + case ideproc_ide_input_data: + if (drive->io_32bit) { + sibyte_insl(IDE_DATA_REG, buffer, count); + } else { + sibyte_insw(IDE_DATA_REG, buffer, count<<1); + } + break; + case ideproc_ide_output_data: + if (drive->io_32bit) { + sibyte_outsl(IDE_DATA_REG, buffer, count); + } else { + sibyte_outsw(IDE_DATA_REG, buffer, count<<1); + } + break; + case ideproc_atapi_input_bytes: + count++; + if (drive->io_32bit) { + sibyte_insl(IDE_DATA_REG, buffer, count>>2); + } else { + sibyte_insw(IDE_DATA_REG, buffer, count>>1); + } + if ((count & 3) >= 2) + sibyte_insw(IDE_DATA_REG, (char *)buffer + (count & ~3), 1); + break; + case ideproc_atapi_output_bytes: + count++; + if (drive->io_32bit) { + sibyte_outsl(IDE_DATA_REG, buffer, count>>2); + } else { + sibyte_outsw(IDE_DATA_REG, buffer, count>>1); + } + if ((count & 3) >= 2) + sibyte_outsw(IDE_DATA_REG, (char *)buffer + (count & ~3), 1); + break; + } +} + +/* + * selectproc and intrproc aren't really necessary, since + * byte-swapping doesn't affect byte ops; they are included for + * consistency. + */ +static void sibyte_selectproc(ide_drive_t *drive) +{ + sibyte_outb(drive->select.all, IDE_SELECT_REG); +} + +static void sibyte_intrproc(ide_drive_t *drive) +{ + sibyte_outb(drive->ctl|2, IDE_CONTROL_REG); +} + +void __init sibyte_ide_probe(void) +{ + int i; + ide_hwif_t *hwif; + /* + * Find the first untaken slot in hwifs + */ + for (i = 0; i < MAX_HWIFS; i++) { + if (!ide_hwifs[i].io_ports[IDE_DATA_OFFSET]) { + break; + } + } + if (i == MAX_HWIFS) { + printk("No space for SiByte onboard IDE driver in ide_hwifs[]. Not enabled.\n"); + return; + } + + /* Find memory base address */ +#ifdef __MIPSEL__ + /* Pass1 workaround (bug 1624) */ + if (sb1250_pass == K_SYS_REVISION_PASS1) + ide_base = G_IO_START_ADDR(csr_in32(4+(IO_SPACE_BASE|A_IO_EXT_REG(R_IO_EXT_REG(R_IO_EXT_START_ADDR, IDE_CS))))) << S_IO_ADDRBASE; + else +#endif + ide_base = G_IO_START_ADDR(csr_in32(IO_SPACE_BASE|A_IO_EXT_REG(R_IO_EXT_REG(R_IO_EXT_START_ADDR, IDE_CS)))) << S_IO_ADDRBASE; + + /* + * Set up our stuff; we're a little odd because our io_ports + * aren't in the usual place, and byte-swapping isn't + * necessary. + */ + hwif = &ide_hwifs[i]; + hwif->hw.io_ports[IDE_DATA_OFFSET] = SIBYTE_IDE_REG(0x1f0); + hwif->hw.io_ports[IDE_ERROR_OFFSET] = SIBYTE_IDE_REG(0x1f1); + hwif->hw.io_ports[IDE_NSECTOR_OFFSET] = SIBYTE_IDE_REG(0x1f2); + hwif->hw.io_ports[IDE_SECTOR_OFFSET] = SIBYTE_IDE_REG(0x1f3); + hwif->hw.io_ports[IDE_LCYL_OFFSET] = SIBYTE_IDE_REG(0x1f4); + hwif->hw.io_ports[IDE_HCYL_OFFSET] = SIBYTE_IDE_REG(0x1f5); + hwif->hw.io_ports[IDE_SELECT_OFFSET] = SIBYTE_IDE_REG(0x1f6); + hwif->hw.io_ports[IDE_STATUS_OFFSET] = SIBYTE_IDE_REG(0x1f7); + hwif->hw.io_ports[IDE_CONTROL_OFFSET] = SIBYTE_IDE_REG(0x3f6); + hwif->hw.irq = K_INT_GB_IDE; + hwif->irq = K_INT_GB_IDE; + hwif->noprobe = 0; + /* Use our own non-byte-swapping routines */ + hwif->ideproc = sibyte_ideproc; + hwif->selectproc = sibyte_selectproc; + hwif->intrproc = sibyte_intrproc; + + memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports)); + printk("SiByte onboard IDE configured as device %i\n", i); + sb_ide_hwif = hwif; +} diff -Nur linux-2.4.19/drivers/ide/ide-swarm.c linux-2.4.19.new/drivers/ide/ide-swarm.c --- linux-2.4.19/drivers/ide/ide-swarm.c Sat Aug 3 02:39:44 2002 +++ linux-2.4.19.new/drivers/ide/ide-swarm.c Thu Jan 1 01:00:00 1970 @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2001 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* Derived loosely from ide-pmac.c, so: - * - * Copyright (C) 1998 Paul Mackerras. - * Copyright (C) 1995-1998 Mark Lord - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -void __init swarm_ide_probe(void) -{ - int i; - ide_hwif_t *hwif; - /* - * Find the first untaken slot in hwifs - */ - for (i = 0; i < MAX_HWIFS; i++) { - if (!ide_hwifs[i].io_ports[IDE_DATA_OFFSET]) { - break; - } - } - if (i == MAX_HWIFS) { - printk("No space for SWARM onboard IDE driver in ide_hwifs[]. Not enabled.\n"); - return; - } - - /* Set up our stuff */ - hwif = &ide_hwifs[i]; - hwif->hw.io_ports[IDE_DATA_OFFSET] = SWARM_IDE_REG(0x1f0); - hwif->hw.io_ports[IDE_ERROR_OFFSET] = SWARM_IDE_REG(0x1f1); - hwif->hw.io_ports[IDE_NSECTOR_OFFSET] = SWARM_IDE_REG(0x1f2); - hwif->hw.io_ports[IDE_SECTOR_OFFSET] = SWARM_IDE_REG(0x1f3); - hwif->hw.io_ports[IDE_LCYL_OFFSET] = SWARM_IDE_REG(0x1f4); - hwif->hw.io_ports[IDE_HCYL_OFFSET] = SWARM_IDE_REG(0x1f5); - hwif->hw.io_ports[IDE_SELECT_OFFSET] = SWARM_IDE_REG(0x1f6); - hwif->hw.io_ports[IDE_STATUS_OFFSET] = SWARM_IDE_REG(0x1f7); - hwif->hw.io_ports[IDE_CONTROL_OFFSET] = SWARM_IDE_REG(0x3f6); - hwif->hw.io_ports[IDE_IRQ_OFFSET] = SWARM_IDE_REG(0x3f7); -// hwif->hw->ack_intr = swarm_ide_ack_intr; - hwif->hw.irq = SWARM_IDE_INT; - hwif->ideproc = swarm_ideproc; - - memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports)); - hwif->irq = hwif->hw.irq; - printk("SWARM onboard IDE configured as device %i\n", i); -} - diff -Nur linux-2.4.19/drivers/ide/ide.c linux-2.4.19.new/drivers/ide/ide.c --- linux-2.4.19/drivers/ide/ide.c Sat Aug 3 02:39:44 2002 +++ linux-2.4.19.new/drivers/ide/ide.c Wed Nov 13 09:49:39 2002 @@ -3418,7 +3418,7 @@ const char *ide_words[] = { "noprobe", "serialize", "autotune", "noautotune", "reset", "dma", "ata66", "minus8", "minus9", "minus10", - "four", "qd65xx", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", NULL }; + "four", "qd65xx", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", "nohighio", NULL }; hw = s[3] - '0'; hwif = &ide_hwifs[hw]; i = match_parm(&s[4], ide_words, vals, 3); @@ -3437,6 +3437,10 @@ } switch (i) { + case -19: /* nohighio */ + hwif->no_highio = 1; + printk("%s: disabled high i/o capability\n", hwif->name); + goto done; #ifdef CONFIG_BLK_DEV_PDC4030 case -18: /* "dc4030" */ { @@ -3616,12 +3620,12 @@ pmac_ide_probe(); } #endif /* CONFIG_BLK_DEV_IDE_PMAC */ -#ifdef CONFIG_BLK_DEV_IDE_SWARM +#ifdef CONFIG_BLK_DEV_IDE_SIBYTE { - extern void swarm_ide_probe(void); - swarm_ide_probe(); + extern void sibyte_ide_probe(void); + sibyte_ide_probe(); } -#endif /* CONFIG_BLK_DEV_IDE_SWARM */ +#endif /* CONFIG_BLK_DEV_IDE_SIBYTE */ #ifdef CONFIG_BLK_DEV_IDE_ICSIDE { extern void icside_init(void); diff -Nur linux-2.4.19/drivers/ide/q40ide.c linux-2.4.19.new/drivers/ide/q40ide.c --- linux-2.4.19/drivers/ide/q40ide.c Thu Oct 25 22:53:47 2001 +++ linux-2.4.19.new/drivers/ide/q40ide.c Wed Nov 13 09:49:39 2002 @@ -82,8 +82,8 @@ for (i = 0; i < Q40IDE_NUM_HWIFS; i++) { hw_regs_t hw; - ide_setup_ports(&hw,(ide_ioreg_t) pcide_bases[i], (int *)pcide_offsets, - pcide_bases[i]+0x206, + ide_setup_ports(&hw, (ide_ioreg_t)pcide_bases[i], (int *)pcide_offsets, + (ide_ioreg_t)pcide_bases[i]+0x206, 0, NULL, q40ide_default_irq(pcide_bases[i])); ide_register_hw(&hw, NULL); } diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/ide.h linux-2.4.20/include/linux/ide.h --- linux-2.4.19/include/linux/ide.h 2002-08-03 00:39:45.000000000 +0000 +++ linux-2.4.20/include/linux/ide.h 2002-10-29 11:18:34.000000000 +0000 @@ -552,6 +552,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 no_highio : 1; /* don't trust pci dma mask, bounce */ byte channel; /* for dual-port chips: 0=primary, 1=secondary */ #ifdef CONFIG_BLK_DEV_IDEPCI struct pci_dev *pci_dev; /* for pci chipsets */ @@ -874,6 +875,21 @@ } 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 * onto the request queue. * diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/blkdev.h linux-2.4.20/include/linux/blkdev.h --- linux-2.4.19/include/linux/blkdev.h 2002-08-03 00:39:45.000000000 +0000 +++ linux-2.4.20/include/linux/blkdev.h 2002-10-29 11:18:34.000000000 +0000 @@ -6,6 +6,9 @@ #include #include #include +#include + +#include struct request_queue; typedef struct request_queue request_queue_t; @@ -36,7 +39,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; @@ -123,6 +126,8 @@ */ char head_active; + unsigned long bounce_pfn; + /* * Is meant to protect the queue in the future instead of * io_request_lock @@ -135,6 +140,38 @@ wait_queue_head_t wait_for_requests[2]; }; +extern unsigned long blk_max_low_pfn, blk_max_pfn; + +#define BLK_BOUNCE_HIGH (blk_max_low_pfn << PAGE_SHIFT) +#define BLK_BOUNCE_ANY (blk_max_pfn << PAGE_SHIFT) + +extern void blk_queue_bounce_limit(request_queue_t *, u64); + +#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) +{ + struct page *page = bh->b_page; + +#ifndef CONFIG_DISCONTIGMEM + if (page - mem_map <= q->bounce_pfn) +#else + if ((page - page_zone(page)->zone_mem_map) + (page_zone(page)->zone_start_paddr >> PAGE_SHIFT) <= q->bounce_pfn) +#endif + return bh; + + return create_bounce(rw, bh); +} +#else +#define blk_queue_bounce(q, rw, bh) (bh) +#endif + +#define bh_phys(bh) (page_to_phys((bh)->b_page) + bh_offset((bh))) + +#define BH_CONTIG(b1, b2) (bh_phys((b1)) + (b1)->b_size == bh_phys((b2))) +#define BH_PHYS_4G(b1, b2) ((bh_phys((b1)) | 0xffffffff) == ((bh_phys((b2)) + (b2)->b_size - 1) | 0xffffffff)) + struct blk_dev_struct { /* * queue_proc has to be atomic @@ -174,6 +211,7 @@ extern void blk_queue_headactive(request_queue_t *, int); extern void blk_queue_make_request(request_queue_t *, make_request_fn *); extern void generic_unplug_device(void *); +extern inline int blk_seg_merge_ok(struct buffer_head *, struct buffer_head *); extern int * blk_size[MAX_BLKDEV]; diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/highmem.h linux-2.4.20/include/linux/highmem.h --- linux-2.4.19/include/linux/highmem.h 2002-08-03 00:39:45.000000000 +0000 +++ linux-2.4.20/include/linux/highmem.h 2002-10-29 11:18:34.000000000 +0000 @@ -13,8 +13,7 @@ /* declarations for linux/mm/highmem.c */ 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,42 @@ kunmap(bh->b_page); } +/* + * remember to add offset! and never ever reenable interrupts between a + * bh_kmap_irq and bh_kunmap_irq!! + */ +static inline char *bh_kmap_irq(struct buffer_head *bh, unsigned long *flags) +{ + unsigned long addr; + + __save_flags(*flags); + + /* + * could be low + */ + if (!PageHighMem(bh->b_page)) + return bh->b_data; + + /* + * it's a highmem page + */ + __cli(); + 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 *flags) +{ + unsigned long ptr = (unsigned long) buffer & PAGE_MASK; + + kunmap_atomic((void *) ptr, KM_BH_IRQ); + __restore_flags(*flags); +} + #else /* CONFIG_HIGHMEM */ static inline unsigned int nr_free_highpages(void) { return 0; } @@ -37,8 +72,10 @@ #define kmap_atomic(page,idx) kmap(page) #define kunmap_atomic(page,idx) kunmap(page) -#define bh_kmap(bh) ((bh)->b_data) -#define bh_kunmap(bh) do { } while (0) +#define bh_kmap(bh) ((bh)->b_data) +#define bh_kunmap(bh) do { } while (0) +#define bh_kmap_irq(bh, flags) ((bh)->b_data) +#define bh_kunmap_irq(bh, flags) do { *(flags) = 0; } while (0) #endif /* CONFIG_HIGHMEM */ diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-i386/kmap_types.h linux-2.4.20/include/asm-i386/kmap_types.h --- linux-2.4.19/include/asm-i386/kmap_types.h 2001-09-17 20:16:30.000000000 +0000 +++ linux-2.4.20/include/asm-i386/kmap_types.h 2002-10-29 11:18:49.000000000 +0000 @@ -3,10 +3,11 @@ enum km_type { KM_BOUNCE_READ, - KM_SKB_DATA, + KM_SKB_SUNRPC_DATA, KM_SKB_DATA_SOFTIRQ, KM_USER0, KM_USER1, + KM_BH_IRQ, KM_BIO_IRQ, KM_TYPE_NR }; diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/kmap_types.h linux-2.4.20/include/asm-ppc/kmap_types.h --- linux-2.4.19/include/asm-ppc/kmap_types.h 2001-09-17 20:16:30.000000000 +0000 +++ linux-2.4.20/include/asm-ppc/kmap_types.h 2002-10-29 11:18:34.000000000 +0000 @@ -7,10 +7,11 @@ enum km_type { KM_BOUNCE_READ, - KM_SKB_DATA, + KM_SKB_SUNRPC_DATA, KM_SKB_DATA_SOFTIRQ, KM_USER0, KM_USER1, + KM_BH_IRQ, KM_BIO_IRQ, KM_TYPE_NR }; diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-sparc/kmap_types.h linux-2.4.20/include/asm-sparc/kmap_types.h --- linux-2.4.19/include/asm-sparc/kmap_types.h 2001-09-17 20:16:30.000000000 +0000 +++ linux-2.4.20/include/asm-sparc/kmap_types.h 2002-10-29 11:18:34.000000000 +0000 @@ -3,10 +3,11 @@ enum km_type { KM_BOUNCE_READ, - KM_SKB_DATA, + KM_SKB_SUNRPC_DATA, KM_SKB_DATA_SOFTIRQ, KM_USER0, KM_USER1, + KM_BH_IRQ, KM_BIO_IRQ, KM_TYPE_NR }; diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/kmap_types.h linux-2.4.20/include/asm-x86_64/kmap_types.h --- linux-2.4.19/include/asm-x86_64/kmap_types.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.4.20/include/asm-x86_64/kmap_types.h 2002-10-29 11:18:39.000000000 +0000 @@ -0,0 +1,14 @@ +#ifndef _ASM_KMAP_TYPES_H +#define _ASM_KMAP_TYPES_H + +enum km_type { + KM_BOUNCE_READ, + KM_SKB_SUNRPC_DATA, + KM_SKB_DATA_SOFTIRQ, + KM_USER0, + KM_USER1, + KM_BH_IRQ, + KM_TYPE_NR +}; + +#endif diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/block/ll_rw_blk.c linux-2.4.20/drivers/block/ll_rw_blk.c --- linux-2.4.19/drivers/block/ll_rw_blk.c 2002-08-03 00:39:43.000000000 +0000 +++ linux-2.4.20/drivers/block/ll_rw_blk.c 2002-10-29 11:18:33.000000000 +0000 @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -117,6 +118,9 @@ */ int * max_sectors[MAX_BLKDEV]; +unsigned long blk_max_low_pfn, blk_max_pfn; +int blk_nohighio = 0; + static inline int get_max_sectors(kdev_t dev) { if (!max_sectors[MAJOR(dev)]) @@ -238,6 +242,55 @@ q->make_request_fn = mfn; } +/** + * blk_queue_bounce_limit - set bounce buffer limit for queue + * @q: the request queue for the device + * @dma_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. + **/ +void blk_queue_bounce_limit(request_queue_t *q, u64 dma_addr) +{ + unsigned long bounce_pfn = dma_addr >> PAGE_SHIFT; + unsigned long mb = dma_addr >> 20; + static request_queue_t *old_q; + + /* + * keep this for debugging for now... + */ + if (dma_addr != BLK_BOUNCE_HIGH && q != old_q) { + old_q = q; + printk("blk: queue %p, ", q); + if (dma_addr == BLK_BOUNCE_ANY) + printk("no I/O memory limit\n"); + else + printk("I/O limit %luMb (mask 0x%Lx)\n", mb, + (long long) dma_addr); + } + + q->bounce_pfn = bounce_pfn; +} + + +/* + * can we merge the two segments, or do we need to start a new one? + */ +inline int blk_seg_merge_ok(struct buffer_head *bh, struct buffer_head *nxt) +{ + /* + * if bh and nxt are contigous and don't cross a 4g boundary, it's ok + */ + if (BH_CONTIG(bh, nxt) && BH_PHYS_4G(bh, nxt)) + return 1; + + return 0; +} + static inline int ll_new_segment(request_queue_t *q, struct request *req, int max_segments) { if (req->nr_segments < max_segments) { @@ -250,16 +303,18 @@ 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 (blk_seg_merge_ok(req->bhtail, bh)) return 1; + return ll_new_segment(q, req, max_segments); } 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 (blk_seg_merge_ok(bh, req->bh)) return 1; + return ll_new_segment(q, req, max_segments); } @@ -268,9 +323,9 @@ { int total_segments = req->nr_segments + next->nr_segments; - if (req->bhtail->b_data + req->bhtail->b_size == next->bh->b_data) + if (blk_seg_merge_ok(req->bhtail, next->bh)) total_segments--; - + if (total_segments > max_segments) return 0; @@ -444,6 +499,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, queue); @@ -540,7 +597,7 @@ if (q->rq[rw].count == 0) schedule(); spin_lock_irq(&io_request_lock); - rq = get_request(q,rw); + rq = get_request(q, rw); spin_unlock_irq(&io_request_lock); } while (rq == NULL); remove_wait_queue(&q->wait_for_requests[rw], &wait); @@ -594,9 +651,14 @@ printk(KERN_ERR "drive_stat_acct: cmd not R/W?\n"); } -/* Return up to two hd_structs on which to do IO accounting for a given - * request. On a partitioned device, we want to account both against - * the partition and against the whole disk. */ +#ifdef CONFIG_BLK_STATS +/* + * Return up to two hd_structs on which to do IO accounting for a given + * request. + * + * On a partitioned device, we want to account both against the partition + * and against the whole disk. + */ static void locate_hd_struct(struct request *req, struct hd_struct **hd1, struct hd_struct **hd2) @@ -611,22 +673,26 @@ /* Mask out the partition bits: account for the entire disk */ int devnr = MINOR(req->rq_dev) >> gd->minor_shift; int whole_minor = devnr << gd->minor_shift; + *hd1 = &gd->part[whole_minor]; if (whole_minor != MINOR(req->rq_dev)) *hd2= &gd->part[MINOR(req->rq_dev)]; } } -/* Round off the performance stats on an hd_struct. The average IO - * queue length and utilisation statistics are maintained by observing - * the current state of the queue length and the amount of time it has - * been in this state for. Normally, that accounting is done on IO - * completion, but that can result in more than a second's worth of IO - * being accounted for within any one second, leading to >100% - * utilisation. To deal with that, we do a round-off before returning - * the results when reading /proc/partitions, accounting immediately for - * all queue usage up to the current jiffies and restarting the counters - * again. */ +/* + * Round off the performance stats on an hd_struct. + * + * The average IO queue length and utilisation statistics are maintained + * by observing the current state of the queue length and the amount of + * time it has been in this state for. + * Normally, that accounting is done on IO completion, but that can result + * in more than a second's worth of IO being accounted for within any one + * second, leading to >100% utilisation. To deal with that, we do a + * round-off before returning the results when reading /proc/partitions, + * accounting immediately for all queue usage up to the current jiffies and + * restarting the counters again. + */ void disk_round_stats(struct hd_struct *hd) { unsigned long now = jiffies; @@ -639,7 +705,6 @@ hd->last_idle_time = now; } - static inline void down_ios(struct hd_struct *hd) { disk_round_stats(hd); @@ -690,6 +755,7 @@ void req_new_io(struct request *req, int merge, int sectors) { struct hd_struct *hd1, *hd2; + locate_hd_struct(req, &hd1, &hd2); if (hd1) account_io_start(hd1, req, merge, sectors); @@ -697,15 +763,29 @@ account_io_start(hd2, req, merge, sectors); } +void req_merged_io(struct request *req) +{ + struct hd_struct *hd1, *hd2; + + locate_hd_struct(req, &hd1, &hd2); + if (hd1) + down_ios(hd1); + if (hd2) + down_ios(hd2); +} + void req_finished_io(struct request *req) { struct hd_struct *hd1, *hd2; + locate_hd_struct(req, &hd1, &hd2); if (hd1) account_io_end(hd1, req); if (hd2) account_io_end(hd2, req); } +EXPORT_SYMBOL(req_finished_io); +#endif /* CONFIG_BLK_STATS */ /* * add-request adds a request to the linked list. @@ -764,7 +844,6 @@ int max_segments) { struct request *next; - struct hd_struct *hd1, *hd2; next = blkdev_next_request(req); if (req->sector + req->nr_sectors != next->sector) @@ -791,12 +870,8 @@ /* One last thing: we have removed a request, so we now have one less expected IO to complete for accounting purposes. */ + req_merged_io(req); - locate_hd_struct(req, &hd1, &hd2); - if (hd1) - down_ios(hd1); - if (hd2) - down_ios(hd2); blkdev_release_request(next); } @@ -866,9 +941,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. */ /* @@ -900,7 +973,6 @@ insert_here = &req->queue; break; } - elevator->elevator_merge_cleanup_fn(q, req, count); req->bhtail->b_reqnext = bh; req->bhtail = bh; req->nr_sectors = req->hard_nr_sectors += count; @@ -915,11 +987,15 @@ insert_here = req->queue.prev; break; } - 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); @@ -978,7 +1054,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; @@ -1286,6 +1362,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"); @@ -1324,6 +1401,9 @@ memset(max_readahead, 0, sizeof(max_readahead)); memset(max_sectors, 0, sizeof(max_sectors)); + blk_max_low_pfn = max_low_pfn - 1; + blk_max_pfn = max_pfn - 1; + #ifdef CONFIG_AMIGA_Z2RAM z2_init(); #endif @@ -1439,5 +1519,9 @@ EXPORT_SYMBOL(blk_queue_make_request); EXPORT_SYMBOL(generic_make_request); EXPORT_SYMBOL(blkdev_release_request); -EXPORT_SYMBOL(req_finished_io); EXPORT_SYMBOL(generic_unplug_device); +EXPORT_SYMBOL(blk_queue_bounce_limit); +EXPORT_SYMBOL(blk_max_low_pfn); +EXPORT_SYMBOL(blk_max_pfn); +EXPORT_SYMBOL(blk_seg_merge_ok); +EXPORT_SYMBOL(blk_nohighio); diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/bootmem.h linux-2.4.20/include/linux/bootmem.h --- linux-2.4.19/include/linux/bootmem.h 2001-11-22 19:47:23.000000000 +0000 +++ linux-2.4.20/include/linux/bootmem.h 2002-10-29 11:18:49.000000000 +0000 @@ -16,6 +16,7 @@ extern unsigned long max_low_pfn; extern unsigned long min_low_pfn; +extern unsigned long max_pfn; /* * node_bootmem_map is a map pointer - the bits represent all physical