Commit 5f2d046a authored by Bartlomiej Zolnierkiewicz's avatar Bartlomiej Zolnierkiewicz Committed by Linus Torvalds

[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: default avatarBartlomiej Zolnierkiewicz <bzolnier@elka.pw.edu.pl>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent cf3968c5
...@@ -340,12 +340,18 @@ static ide_startstop_t multwrite_intr (ide_drive_t *drive) ...@@ -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_startstop_t __ide_do_rw_disk (ide_drive_t *drive, struct request *rq, sector_t block)
{ {
ide_hwif_t *hwif = HWIF(drive); ide_hwif_t *hwif = HWIF(drive);
unsigned int dma = drive->using_dma;
u8 lba48 = (drive->addressing == 1) ? 1 : 0; u8 lba48 = (drive->addressing == 1) ? 1 : 0;
task_ioreg_t command = WIN_NOP; task_ioreg_t command = WIN_NOP;
ata_nsector_t nsectors; ata_nsector_t nsectors;
nsectors.all = (u16) rq->nr_sectors; 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) if (IDE_CONTROL_REG)
hwif->OUTB(drive->ctl, 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 ...@@ -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 (rq_data_dir(rq) == READ) {
if (drive->using_dma && !hwif->ide_dma_read(drive)) if (dma && !hwif->ide_dma_read(drive))
return ide_started; return ide_started;
command = ((drive->mult_count) ? command = ((drive->mult_count) ?
...@@ -425,7 +431,7 @@ ide_startstop_t __ide_do_rw_disk (ide_drive_t *drive, struct request *rq, sector ...@@ -425,7 +431,7 @@ ide_startstop_t __ide_do_rw_disk (ide_drive_t *drive, struct request *rq, sector
} else { } else {
ide_startstop_t startstop; ide_startstop_t startstop;
if (drive->using_dma && !(HWIF(drive)->ide_dma_write(drive))) if (dma && !hwif->ide_dma_write(drive))
return ide_started; return ide_started;
command = ((drive->mult_count) ? command = ((drive->mult_count) ?
...@@ -488,13 +494,19 @@ ide_startstop_t __ide_do_rw_disk (ide_drive_t *drive, struct request *rq, sector ...@@ -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); 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 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; task->command_type = IDE_DRIVE_TASK_IN;
if (drive->using_dma) if (dma)
return lba48 ? WIN_READDMA_EXT : WIN_READDMA; return lba48 ? WIN_READDMA_EXT : WIN_READDMA;
if (drive->mult_count) { if (drive->mult_count) {
task->handler = &task_mulin_intr; task->handler = &task_mulin_intr;
...@@ -504,7 +516,7 @@ static u8 get_command(ide_drive_t *drive, int cmd, ide_task_t *task) ...@@ -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; return lba48 ? WIN_READ_EXT : WIN_READ;
} else { } else {
task->command_type = IDE_DRIVE_TASK_RAW_WRITE; task->command_type = IDE_DRIVE_TASK_RAW_WRITE;
if (drive->using_dma) if (dma)
return lba48 ? WIN_WRITEDMA_EXT : WIN_WRITEDMA; return lba48 ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
if (drive->mult_count) { if (drive->mult_count) {
task->prehandler = &pre_task_mulout_intr; 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 ...@@ -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_HCYL_OFFSET] = (cyl>>8);
args.tfRegister[IDE_SELECT_OFFSET] = head; args.tfRegister[IDE_SELECT_OFFSET] = head;
args.tfRegister[IDE_SELECT_OFFSET] |= drive->select.all; 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; args.rq = (struct request *) rq;
rq->special = (ide_task_t *)&args; rq->special = (ide_task_t *)&args;
return do_rw_taskfile(drive, &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 ...@@ -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_HCYL_OFFSET] = (block>>=8);
args.tfRegister[IDE_SELECT_OFFSET] = ((block>>8)&0x0f); args.tfRegister[IDE_SELECT_OFFSET] = ((block>>8)&0x0f);
args.tfRegister[IDE_SELECT_OFFSET] |= drive->select.all; 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; args.rq = (struct request *) rq;
rq->special = (ide_task_t *)&args; rq->special = (ide_task_t *)&args;
return do_rw_taskfile(drive, &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 ...@@ -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_LCYL_OFFSET] = (block>>=8); /* mid lba */
args.tfRegister[IDE_HCYL_OFFSET] = (block>>=8); /* hi lba */ args.tfRegister[IDE_HCYL_OFFSET] = (block>>=8); /* hi lba */
args.tfRegister[IDE_SELECT_OFFSET] = drive->select.all; 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_SECTOR_OFFSET] = (block>>=8); /* low lba */
args.hobRegister[IDE_LCYL_OFFSET] = (block>>=8); /* mid lba */ args.hobRegister[IDE_LCYL_OFFSET] = (block>>=8); /* mid lba */
args.hobRegister[IDE_HCYL_OFFSET] = (block>>=8); /* hi lba */ args.hobRegister[IDE_HCYL_OFFSET] = (block>>=8); /* hi lba */
...@@ -1540,6 +1552,15 @@ static void idedisk_setup (ide_drive_t *drive) ...@@ -1540,6 +1552,15 @@ static void idedisk_setup (ide_drive_t *drive)
drive->capacity64 = 1ULL << 28; 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, * if possible, give fdisk access to more of the drive,
* by correcting bios_cyls: * by correcting bios_cyls:
......
...@@ -904,8 +904,12 @@ static int ide_init_queue(ide_drive_t *drive) ...@@ -904,8 +904,12 @@ static int ide_init_queue(ide_drive_t *drive)
q->queuedata = drive; q->queuedata = drive;
blk_queue_segment_boundary(q, 0xffff); blk_queue_segment_boundary(q, 0xffff);
if (!hwif->rqsize) if (!hwif->rqsize) {
hwif->rqsize = hwif->no_lba48 ? 256 : 65536; if (hwif->no_lba48 || hwif->no_lba48_dma)
hwif->rqsize = 256;
else
hwif->rqsize = 65536;
}
if (hwif->rqsize < max_sectors) if (hwif->rqsize < max_sectors)
max_sectors = hwif->rqsize; max_sectors = hwif->rqsize;
blk_queue_max_sectors(q, max_sectors); blk_queue_max_sectors(q, max_sectors);
......
...@@ -752,8 +752,8 @@ static void __init init_hwif_common_ali15x3 (ide_hwif_t *hwif) ...@@ -752,8 +752,8 @@ static void __init init_hwif_common_ali15x3 (ide_hwif_t *hwif)
hwif->tuneproc = &ali15x3_tune_drive; hwif->tuneproc = &ali15x3_tune_drive;
hwif->speedproc = &ali15x3_tune_chipset; hwif->speedproc = &ali15x3_tune_chipset;
/* Don't use LBA48 on ALi devices before rev 0xC5 */ /* don't use LBA48 DMA on ALi devices before rev 0xC5 */
hwif->no_lba48 = (m5229_revision <= 0xC4) ? 1 : 0; hwif->no_lba48_dma = (m5229_revision <= 0xC4) ? 1 : 0;
if (!hwif->dma_base) { if (!hwif->dma_base) {
hwif->drives[0].autotune = 1; hwif->drives[0].autotune = 1;
......
...@@ -986,6 +986,7 @@ typedef struct hwif_s { ...@@ -986,6 +986,7 @@ typedef struct hwif_s {
unsigned autodma : 1; /* auto-attempt using DMA at boot */ unsigned autodma : 1; /* auto-attempt using DMA at boot */
unsigned udma_four : 1; /* 1=ATA-66 capable, 0=default */ unsigned udma_four : 1; /* 1=ATA-66 capable, 0=default */
unsigned no_lba48 : 1; /* 1 = cannot do LBA48 */ 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 no_dsc : 1; /* 0 default, 1 dsc_overlap disabled */
unsigned auto_poll : 1; /* supports nop auto-poll */ unsigned auto_poll : 1; /* supports nop auto-poll */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment