diff options
| author | Bartlomiej Zolnierkiewicz <bzolnier@elka.pw.edu.pl> | 2004-09-09 21:03:20 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2004-09-09 21:03:20 -0700 |
| commit | 5f2d046a5529f4ded332ef3e8870ee696418d048 (patch) | |
| tree | f203747b06d066d8384207aaefd0f349b62f013a | |
| parent | cf3968c5b7ac7624af8b475d0c134af01122faf9 (diff) | |
[PATCH] ide: fix LBA48 support for ALi chipsets (rev < 0xC5)
Affected chipsets support LBA48 but not LBA48 DMA.
Just use DMA for area < 137GB and revert to PIO for > 137GB one.
Also disallow transfers > 256 sectors for better performance.
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@elka.pw.edu.pl>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
| -rw-r--r-- | drivers/ide/ide-disk.c | 39 | ||||
| -rw-r--r-- | drivers/ide/ide-probe.c | 8 | ||||
| -rw-r--r-- | drivers/ide/pci/alim15x3.c | 4 | ||||
| -rw-r--r-- | include/linux/ide.h | 1 |
4 files changed, 39 insertions, 13 deletions
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index 42e65df1f9cf..ed301e7a16d7 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -340,12 +340,18 @@ static ide_startstop_t multwrite_intr (ide_drive_t *drive) ide_startstop_t __ide_do_rw_disk (ide_drive_t *drive, struct request *rq, sector_t block) { ide_hwif_t *hwif = HWIF(drive); + unsigned int dma = drive->using_dma; u8 lba48 = (drive->addressing == 1) ? 1 : 0; task_ioreg_t command = WIN_NOP; ata_nsector_t nsectors; nsectors.all = (u16) rq->nr_sectors; + if (hwif->no_lba48_dma && lba48 && dma) { + if (rq->sector + rq->nr_sectors > 1ULL << 28) + dma = 0; + } + if (IDE_CONTROL_REG) hwif->OUTB(drive->ctl, IDE_CONTROL_REG); @@ -414,7 +420,7 @@ ide_startstop_t __ide_do_rw_disk (ide_drive_t *drive, struct request *rq, sector } if (rq_data_dir(rq) == READ) { - if (drive->using_dma && !hwif->ide_dma_read(drive)) + if (dma && !hwif->ide_dma_read(drive)) return ide_started; command = ((drive->mult_count) ? @@ -425,7 +431,7 @@ ide_startstop_t __ide_do_rw_disk (ide_drive_t *drive, struct request *rq, sector } else { ide_startstop_t startstop; - if (drive->using_dma && !(HWIF(drive)->ide_dma_write(drive))) + if (dma && !hwif->ide_dma_write(drive)) return ide_started; command = ((drive->mult_count) ? @@ -488,13 +494,19 @@ ide_startstop_t __ide_do_rw_disk (ide_drive_t *drive, struct request *rq, sector } EXPORT_SYMBOL_GPL(__ide_do_rw_disk); -static u8 get_command(ide_drive_t *drive, int cmd, ide_task_t *task) +static u8 get_command(ide_drive_t *drive, struct request *rq, ide_task_t *task) { unsigned int lba48 = (drive->addressing == 1) ? 1 : 0; + unsigned int dma = drive->using_dma; + + if (drive->hwif->no_lba48_dma && lba48 && dma) { + if (rq->sector + rq->nr_sectors > 1ULL << 28) + dma = 0; + } - if (cmd == READ) { + if (rq_data_dir(rq) == READ) { task->command_type = IDE_DRIVE_TASK_IN; - if (drive->using_dma) + if (dma) return lba48 ? WIN_READDMA_EXT : WIN_READDMA; if (drive->mult_count) { task->handler = &task_mulin_intr; @@ -504,7 +516,7 @@ static u8 get_command(ide_drive_t *drive, int cmd, ide_task_t *task) return lba48 ? WIN_READ_EXT : WIN_READ; } else { task->command_type = IDE_DRIVE_TASK_RAW_WRITE; - if (drive->using_dma) + if (dma) return lba48 ? WIN_WRITEDMA_EXT : WIN_WRITEDMA; if (drive->mult_count) { task->prehandler = &pre_task_mulout_intr; @@ -541,7 +553,7 @@ static ide_startstop_t chs_rw_disk (ide_drive_t *drive, struct request *rq, unsi args.tfRegister[IDE_HCYL_OFFSET] = (cyl>>8); args.tfRegister[IDE_SELECT_OFFSET] = head; args.tfRegister[IDE_SELECT_OFFSET] |= drive->select.all; - args.tfRegister[IDE_COMMAND_OFFSET] = get_command(drive, rq_data_dir(rq), &args); + args.tfRegister[IDE_COMMAND_OFFSET] = get_command(drive, rq, &args); args.rq = (struct request *) rq; rq->special = (ide_task_t *)&args; return do_rw_taskfile(drive, &args); @@ -565,7 +577,7 @@ static ide_startstop_t lba_28_rw_disk (ide_drive_t *drive, struct request *rq, u args.tfRegister[IDE_HCYL_OFFSET] = (block>>=8); args.tfRegister[IDE_SELECT_OFFSET] = ((block>>8)&0x0f); args.tfRegister[IDE_SELECT_OFFSET] |= drive->select.all; - args.tfRegister[IDE_COMMAND_OFFSET] = get_command(drive, rq_data_dir(rq), &args); + args.tfRegister[IDE_COMMAND_OFFSET] = get_command(drive, rq, &args); args.rq = (struct request *) rq; rq->special = (ide_task_t *)&args; return do_rw_taskfile(drive, &args); @@ -595,7 +607,7 @@ static ide_startstop_t lba_48_rw_disk (ide_drive_t *drive, struct request *rq, u args.tfRegister[IDE_LCYL_OFFSET] = (block>>=8); /* mid lba */ args.tfRegister[IDE_HCYL_OFFSET] = (block>>=8); /* hi lba */ args.tfRegister[IDE_SELECT_OFFSET] = drive->select.all; - args.tfRegister[IDE_COMMAND_OFFSET] = get_command(drive, rq_data_dir(rq), &args); + args.tfRegister[IDE_COMMAND_OFFSET] = get_command(drive, rq, &args); args.hobRegister[IDE_SECTOR_OFFSET] = (block>>=8); /* low lba */ args.hobRegister[IDE_LCYL_OFFSET] = (block>>=8); /* mid lba */ args.hobRegister[IDE_HCYL_OFFSET] = (block>>=8); /* hi lba */ @@ -1540,6 +1552,15 @@ static void idedisk_setup (ide_drive_t *drive) drive->capacity64 = 1ULL << 28; } + if (drive->hwif->no_lba48_dma && drive->addressing) { + if (drive->capacity64 > 1ULL << 28) { + printk(KERN_INFO "%s: cannot use LBA48 DMA - PIO mode will" + " be used for accessing sectors > %u\n", + drive->name, 1 << 28); + } else + drive->addressing = 0; + } + /* * if possible, give fdisk access to more of the drive, * by correcting bios_cyls: diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 6fc8ecd9258f..dd9229190f3f 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -904,8 +904,12 @@ static int ide_init_queue(ide_drive_t *drive) q->queuedata = drive; blk_queue_segment_boundary(q, 0xffff); - if (!hwif->rqsize) - hwif->rqsize = hwif->no_lba48 ? 256 : 65536; + if (!hwif->rqsize) { + if (hwif->no_lba48 || hwif->no_lba48_dma) + hwif->rqsize = 256; + else + hwif->rqsize = 65536; + } if (hwif->rqsize < max_sectors) max_sectors = hwif->rqsize; blk_queue_max_sectors(q, max_sectors); diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c index 12711cddbf2a..82a449dc8222 100644 --- a/drivers/ide/pci/alim15x3.c +++ b/drivers/ide/pci/alim15x3.c @@ -752,8 +752,8 @@ static void __init init_hwif_common_ali15x3 (ide_hwif_t *hwif) hwif->tuneproc = &ali15x3_tune_drive; hwif->speedproc = &ali15x3_tune_chipset; - /* Don't use LBA48 on ALi devices before rev 0xC5 */ - hwif->no_lba48 = (m5229_revision <= 0xC4) ? 1 : 0; + /* don't use LBA48 DMA on ALi devices before rev 0xC5 */ + hwif->no_lba48_dma = (m5229_revision <= 0xC4) ? 1 : 0; if (!hwif->dma_base) { hwif->drives[0].autotune = 1; diff --git a/include/linux/ide.h b/include/linux/ide.h index f7884a313f49..444af6321d19 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -986,6 +986,7 @@ typedef struct hwif_s { unsigned autodma : 1; /* auto-attempt using DMA at boot */ unsigned udma_four : 1; /* 1=ATA-66 capable, 0=default */ unsigned no_lba48 : 1; /* 1 = cannot do LBA48 */ + unsigned no_lba48_dma : 1; /* 1 = cannot do LBA48 DMA */ unsigned no_dsc : 1; /* 0 default, 1 dsc_overlap disabled */ unsigned auto_poll : 1; /* supports nop auto-poll */ |
