diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2001-03-09 20:33:35 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2001-03-09 20:33:35 +0000 |
commit | 116674acc97ba75a720329996877077d988443a2 (patch) | |
tree | 6a3f2ff0b612ae2ee8a3f3509370c9e6333a53b3 /drivers/ide | |
parent | 71118c319fcae4a138f16e35b4f7e0a6d53ce2ca (diff) |
Merge with Linux 2.4.2.
Diffstat (limited to 'drivers/ide')
-rw-r--r-- | drivers/ide/Config.in | 14 | ||||
-rw-r--r-- | drivers/ide/cmd640.c | 2 | ||||
-rw-r--r-- | drivers/ide/hd.c | 8 | ||||
-rw-r--r-- | drivers/ide/icside.c | 2 | ||||
-rw-r--r-- | drivers/ide/ide-cd.c | 5 | ||||
-rw-r--r-- | drivers/ide/ide-cs.c | 11 | ||||
-rw-r--r-- | drivers/ide/ide-disk.c | 80 | ||||
-rw-r--r-- | drivers/ide/ide-features.c | 6 | ||||
-rw-r--r-- | drivers/ide/ide-floppy.c | 2 | ||||
-rw-r--r-- | drivers/ide/ide-pmac.c | 332 | ||||
-rw-r--r-- | drivers/ide/ide-probe.c | 4 | ||||
-rw-r--r-- | drivers/ide/ide-tape.c | 2 | ||||
-rw-r--r-- | drivers/ide/ide-timing.h | 279 | ||||
-rw-r--r-- | drivers/ide/ide.c | 2 | ||||
-rw-r--r-- | drivers/ide/osb4.c | 2 | ||||
-rw-r--r-- | drivers/ide/pdc202xx.c | 14 | ||||
-rw-r--r-- | drivers/ide/rapide.c | 2 | ||||
-rw-r--r-- | drivers/ide/via82cxxx.c | 665 |
18 files changed, 876 insertions, 556 deletions
diff --git a/drivers/ide/Config.in b/drivers/ide/Config.in index a2c0a282c..4682996ea 100644 --- a/drivers/ide/Config.in +++ b/drivers/ide/Config.in @@ -82,12 +82,16 @@ if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then bool ' Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105 fi fi - if [ "$CONFIG_PMAC" = "y" -o "$CONFIG_ALL_PPC" = "y" ]; then + if [ "$CONFIG_ALL_PPC" = "y" ]; then bool ' Builtin PowerMac IDE support' CONFIG_BLK_DEV_IDE_PMAC dep_bool ' PowerMac IDE DMA support' CONFIG_BLK_DEV_IDEDMA_PMAC $CONFIG_BLK_DEV_IDE_PMAC - dep_bool ' Use DMA by default' CONFIG_IDEDMA_PMAC_AUTO $CONFIG_BLK_DEV_IDEDMA_PMAC - define_bool CONFIG_BLK_DEV_IDEDMA $CONFIG_BLK_DEV_IDEDMA_PMAC - define_bool CONFIG_BLK_DEV_IDEPCI $CONFIG_BLK_DEV_IDEDMA_PMAC + dep_bool ' Use DMA by default' CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO $CONFIG_BLK_DEV_IDEDMA_PMAC + if [ "$CONFIG_BLK_DEV_IDE_PMAC" = "y" ]; then + define_bool CONFIG_BLK_DEV_IDEDMA $CONFIG_BLK_DEV_IDEDMA_PMAC + fi + if [ "$CONFIG_BLK_DEV_IDEDMA_PMAC" = "y" ]; then + define_bool CONFIG_BLK_DEV_IDEPCI $CONFIG_BLK_DEV_IDEDMA_PMAC + fi fi if [ "$CONFIG_ARCH_ACORN" = "y" ]; then dep_bool ' ICS IDE interface support' CONFIG_BLK_DEV_IDE_ICSIDE $CONFIG_ARCH_ACORN @@ -130,7 +134,7 @@ else fi if [ "$CONFIG_IDEDMA_PCI_AUTO" = "y" -o \ - "$CONFIG_IDEDMA_PMAC_AUTO" = "y" -o \ + "$CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO" = "y" -o \ "$CONFIG_IDEDMA_ICS_AUTO" = "y" ]; then define_bool CONFIG_IDEDMA_AUTO y else diff --git a/drivers/ide/cmd640.c b/drivers/ide/cmd640.c index 3bf129932..cdb1df0a9 100644 --- a/drivers/ide/cmd640.c +++ b/drivers/ide/cmd640.c @@ -67,7 +67,7 @@ * * Version 0.09 Try to be smarter about 2nd port enabling. * Version 0.10 Be nice and don't reset 2nd port. - * Version 0.11 Try to handle more wierd situations. + * Version 0.11 Try to handle more weird situations. * * Version 0.12 Lots of bug fixes from Laszlo Peter * irq unmasking disabled for reliability. diff --git a/drivers/ide/hd.c b/drivers/ide/hd.c index bed5f6210..1174c972c 100644 --- a/drivers/ide/hd.c +++ b/drivers/ide/hd.c @@ -22,6 +22,9 @@ * This is now a lightweight ST-506 driver. (Paul Gortmaker) * * Modified 1995 Russell King for ARM processor. + * + * Bugfix: max_sectors must be <= 255 or the wheels tend to come + * off in a hurry once you queue things up - Paul G. 02/2001 */ /* Uncomment the following if you want verbose error reports. */ @@ -36,7 +39,7 @@ #include <linux/kernel.h> #include <linux/hdreg.h> #include <linux/genhd.h> -#include <linux/malloc.h> +#include <linux/slab.h> #include <linux/string.h> #include <linux/ioport.h> #include <linux/mc146818rtc.h> /* CMOS defines */ @@ -104,6 +107,7 @@ static struct hd_struct hd[MAX_HD<<6]; static int hd_sizes[MAX_HD<<6]; static int hd_blocksizes[MAX_HD<<6]; static int hd_hardsectsizes[MAX_HD<<6]; +static int hd_maxsect[MAX_HD<<6]; static struct timer_list device_timer; @@ -730,9 +734,11 @@ static void __init hd_geninit(void) for(drive=0; drive < (MAX_HD << 6); drive++) { hd_blocksizes[drive] = 1024; hd_hardsectsizes[drive] = 512; + hd_maxsect[drive]=255; } blksize_size[MAJOR_NR] = hd_blocksizes; hardsect_size[MAJOR_NR] = hd_hardsectsizes; + max_sectors[MAJOR_NR] = hd_maxsect; #ifdef __i386__ if (!NR_HD) { diff --git a/drivers/ide/icside.c b/drivers/ide/icside.c index c727cb889..ef46e91ed 100644 --- a/drivers/ide/icside.c +++ b/drivers/ide/icside.c @@ -14,7 +14,7 @@ #include <linux/string.h> #include <linux/module.h> #include <linux/ioport.h> -#include <linux/malloc.h> +#include <linux/slab.h> #include <linux/blkdev.h> #include <linux/errno.h> #include <linux/hdreg.h> diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 433951e95..16b0ade47 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -302,7 +302,7 @@ #include <linux/kernel.h> #include <linux/delay.h> #include <linux/timer.h> -#include <linux/malloc.h> +#include <linux/slab.h> #include <linux/interrupt.h> #include <linux/errno.h> #include <linux/cdrom.h> @@ -1872,6 +1872,9 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense) If it is, just return. */ (void) cdrom_check_status(drive, sense); + if (CDROM_STATE_FLAGS(drive)->toc_valid) + return 0; + /* First read just the header, so we know how long the TOC is. */ stat = cdrom_read_tocentry(drive, 0, 1, 0, (char *) &toc->hdr, sizeof(struct atapi_toc_header), sense); diff --git a/drivers/ide/ide-cs.c b/drivers/ide/ide-cs.c index bf4350f73..4a199ca71 100644 --- a/drivers/ide/ide-cs.c +++ b/drivers/ide/ide-cs.c @@ -19,7 +19,7 @@ are Copyright (C) 1999 David A. Hinds. All Rights Reserved. Alternatively, the contents of this file may be used under the - terms of the GNU Public License version 2 (the "GPL"), in which + terms of the GNU General Public License version 2 (the "GPL"), in which case the provisions of the GPL are applicable instead of the above. If you wish to allow the use of your version of this file only under the terms of the GPL and not to allow others to use @@ -36,7 +36,7 @@ #include <linux/init.h> #include <linux/sched.h> #include <linux/ptrace.h> -#include <linux/malloc.h> +#include <linux/slab.h> #include <linux/string.h> #include <linux/timer.h> #include <linux/ioport.h> @@ -95,7 +95,7 @@ static void ide_release(u_long arg); static int ide_event(event_t event, int priority, event_callback_args_t *args); -static dev_info_t dev_info = "ide_cs"; +static dev_info_t dev_info = "ide-cs"; static dev_link_t *ide_attach(void); static void ide_detach(dev_link_t *); @@ -387,6 +387,11 @@ void ide_release(u_long arg) ide_unregister(info->hd); MOD_DEC_USE_COUNT; } + + request_region(link->io.BasePort1, link->io.NumPorts1,"ide-cs"); + if (link->io.NumPorts2) + request_region(link->io.BasePort2, link->io.NumPorts2,"ide-cs"); + info->ndev = 0; link->dev = NULL; diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index 9d0fc8e74..d246487e9 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -44,7 +44,7 @@ #include <linux/major.h> #include <linux/errno.h> #include <linux/genhd.h> -#include <linux/malloc.h> +#include <linux/slab.h> #include <linux/delay.h> #include <linux/ide.h> @@ -223,67 +223,53 @@ static ide_startstop_t write_intr (ide_drive_t *drive) * ide_multwrite() transfers a block of up to mcount sectors of data * to a drive as part of a disk multiple-sector write operation. * - * Returns 0 if successful; returns 1 if request had to be aborted due to corrupted buffer list. + * Returns 0 on success. + * + * Note that we may be called from two contexts - the do_rw_disk context + * and IRQ context. The IRQ can happen any time after we've output the + * full "mcount" number of sectors, so we must make sure we update the + * state _before_ we output the final part of the data! */ int ide_multwrite (ide_drive_t *drive, unsigned int mcount) { ide_hwgroup_t *hwgroup= HWGROUP(drive); - - /* - * This may look a bit odd, but remember wrq is a copy of the - * request not the original. The pointers are real however so the - * bh's are not copies. Remember that or bad stuff will happen - * - * At the point we are called the drive has asked us for the - * data, and its our job to feed it, walking across bh boundaries - * if need be. - */ - struct request *rq = &hwgroup->wrq; - + do { - unsigned long flags; - unsigned int nsect = rq->current_nr_sectors; + char *buffer; + int nsect = rq->current_nr_sectors; + if (nsect > mcount) nsect = mcount; mcount -= nsect; + buffer = rq->buffer; - idedisk_output_data(drive, rq->buffer, nsect<<7); -#ifdef DEBUG - printk("%s: multwrite: sector %ld, buffer=0x%08lx, count=%d, remaining=%ld\n", - drive->name, rq->sector, (unsigned long) rq->buffer, - nsect, rq->nr_sectors - nsect); -#endif - spin_lock_irqsave(&io_request_lock, flags); /* Is this really necessary? */ -#ifdef CONFIG_BLK_DEV_PDC4030 rq->sector += nsect; -#endif - if (((long)(rq->nr_sectors -= nsect)) <= 0) { -#ifdef DEBUG - printk("%s: multwrite: count=%d, current=%ld\n", - drive->name, nsect, rq->nr_sectors); -#endif - spin_unlock_irqrestore(&io_request_lock, flags); - break; - } - if ((rq->current_nr_sectors -= nsect) == 0) { - if ((rq->bh = rq->bh->b_reqnext) != NULL) { - rq->current_nr_sectors = rq->bh->b_size>>9; - rq->buffer = rq->bh->b_data; + rq->buffer += nsect << 9; + rq->nr_sectors -= nsect; + rq->current_nr_sectors -= nsect; + + /* Do we move to the next bh after this? */ + if (!rq->current_nr_sectors) { + struct buffer_head *bh = rq->bh->b_reqnext; + + /* end early early we ran out of requests */ + if (!bh) { + mcount = 0; } else { - spin_unlock_irqrestore(&io_request_lock, flags); - printk("%s: buffer list corrupted (%ld, %ld, %d)\n", - drive->name, rq->current_nr_sectors, - rq->nr_sectors, nsect); - ide_end_request(0, hwgroup); - return 1; + rq->bh = bh; + rq->current_nr_sectors = bh->b_size >> 9; + rq->buffer = bh->b_data; } - } else { - /* Fix the pointer.. we ate data */ - rq->buffer += nsect << 9; } - spin_unlock_irqrestore(&io_request_lock, flags); + + /* + * Ok, we're all setup for the interrupt + * re-entering us on the last transfer. + */ + idedisk_output_data(drive, buffer, nsect<<7); } while (mcount); + return 0; } diff --git a/drivers/ide/ide-features.c b/drivers/ide/ide-features.c index 2dfef8bee..80a28c963 100644 --- a/drivers/ide/ide-features.c +++ b/drivers/ide/ide-features.c @@ -27,7 +27,7 @@ #include <linux/errno.h> #include <linux/genhd.h> #include <linux/blkpg.h> -#include <linux/malloc.h> +#include <linux/slab.h> #include <linux/pci.h> #include <linux/delay.h> #include <linux/hdreg.h> @@ -189,6 +189,10 @@ int ide_driveid_update (ide_drive_t *drive) __cli(); /* local CPU only; some systems need this */ SELECT_MASK(HWIF(drive), drive, 0); id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC); + if (!id) { + __restore_flags(flags); /* local CPU only */ + return 0; + } ide_input_data(drive, id, SECTOR_WORDS); (void) GET_STAT(); /* clear drive IRQ */ ide__sti(); /* local CPU only */ diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index b6258aad8..52343a5f3 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -45,7 +45,7 @@ #include <linux/major.h> #include <linux/errno.h> #include <linux/genhd.h> -#include <linux/malloc.h> +#include <linux/slab.h> #include <linux/cdrom.h> #include <linux/ide.h> diff --git a/drivers/ide/ide-pmac.c b/drivers/ide/ide-pmac.c index 83cea6ba2..117bf9e3e 100644 --- a/drivers/ide/ide-pmac.c +++ b/drivers/ide/ide-pmac.c @@ -159,10 +159,7 @@ void pmac_ide_init_hwif_ports(hw_regs_t *hw, /* Probably a PCI interface... */ for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; ++i) hw->io_ports[i] = data_port + i - IDE_DATA_OFFSET; - /* XXX is this right? */ - hw->io_ports[IDE_CONTROL_OFFSET] = 0; - if (irq != 0) - *irq = 0; + hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port; return; } @@ -175,12 +172,12 @@ void pmac_ide_init_hwif_ports(hw_regs_t *hw, ide_hwifs[ix].tuneproc = pmac_ide_tuneproc; ide_hwifs[ix].selectproc = pmac_ide_selectproc; + ide_hwifs[ix].speedproc = &pmac_ide_tune_chipset; if (pmac_ide[ix].dma_regs && pmac_ide[ix].dma_table) { ide_hwifs[ix].dmaproc = &pmac_ide_dmaproc; -#ifdef CONFIG_PMAC_IDEDMA_AUTO +#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO ide_hwifs[ix].autodma = 1; #endif -// ide_hwifs[ix].speedproc = &pmac_ide_tune_chipset; } } @@ -219,6 +216,61 @@ pmac_ide_selectproc(ide_drive_t *drive) #define SYSCLK_TICKS(t) (((t) + IDE_SYSCLK_NS - 1) / IDE_SYSCLK_NS) #define SYSCLK_TICKS_UDMA(t) (((t) + IDE_SYSCLK_ULTRA_PS - 1) / IDE_SYSCLK_ULTRA_PS) +static __inline__ int +wait_for_ready(ide_drive_t *drive) +{ + /* Timeout bumped for some powerbooks */ + int timeout = 2000; + byte stat; + + while(--timeout) { + stat = GET_STAT(); + if(!(stat & BUSY_STAT)) { + if (drive->ready_stat == 0) + break; + else if((stat & drive->ready_stat) || (stat & ERR_STAT)) + break; + } + mdelay(1); + } + if((stat & ERR_STAT) || timeout <= 0) { + if (stat & ERR_STAT) { + printk("ide_pmace: wait_for_ready, error status: %x\n", stat); + } + return 1; + } + return 0; +} + +static int +pmac_ide_do_setfeature(ide_drive_t *drive, byte command) +{ + unsigned long flags; + int result = 1; + + save_flags(flags); + cli(); + udelay(1); + SELECT_DRIVE(HWIF(drive), drive); + SELECT_MASK(HWIF(drive), drive, 0); + udelay(1); + if(wait_for_ready(drive)) { + printk("pmac_ide_do_setfeature disk not ready before SET_FEATURE!\n"); + goto out; + } + OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG); + OUT_BYTE(command, IDE_NSECTOR_REG); + OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG); + udelay(1); + result = wait_for_ready(drive); + if (result) + printk("pmac_ide_do_setfeature disk not ready after SET_FEATURE !\n"); +out: + restore_flags(flags); + + return result; +} + /* Calculate PIO timings */ static void pmac_ide_tuneproc(ide_drive_t *drive, byte pio) @@ -266,12 +318,149 @@ pmac_ide_tuneproc(ide_drive_t *drive, byte pio) pmac_ide_selectproc(drive); } +#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC +static int +set_timings_udma(int intf, u32 *timings, byte speed) +{ + int cycleTime, accessTime; + int rdyToPauseTicks, cycleTicks; + + if (pmac_ide[intf].kind != controller_kl_ata4) + return 1; + + cycleTime = udma_timings[speed & 0xf].cycleTime; + accessTime = udma_timings[speed & 0xf].accessTime; + + rdyToPauseTicks = SYSCLK_TICKS_UDMA(accessTime * 1000); + cycleTicks = SYSCLK_TICKS_UDMA(cycleTime * 1000); + + *timings = ((*timings) & 0xe00fffff) | + ((cycleTicks << 1) | (rdyToPauseTicks << 5) | 1) << 20; + + return 0; +} + +static int +set_timings_mdma(int intf, u32 *timings, byte speed) +{ + int cycleTime, accessTime; + int accessTicks, recTicks; + + /* Calculate accesstime and cycle time */ + cycleTime = mdma_timings[speed & 0xf].cycleTime; + accessTime = mdma_timings[speed & 0xf].accessTime; + if ((pmac_ide[intf].kind == controller_ohare) && (cycleTime < 150)) + cycleTime = 150; + + /* For ata-4 controller */ + if (pmac_ide[intf].kind == controller_kl_ata4) { + accessTicks = SYSCLK_TICKS_UDMA(accessTime * 1000); + recTicks = SYSCLK_TICKS_UDMA(cycleTime * 1000) - accessTicks; + *timings = ((*timings) & 0xffe003ff) | + (accessTicks | (recTicks << 5)) << 10; + } else { + int halfTick = 0; + int origAccessTime = accessTime; + int origCycleTime = cycleTime; + + accessTicks = SYSCLK_TICKS(accessTime); + if (accessTicks < 1) + accessTicks = 1; + accessTime = accessTicks * IDE_SYSCLK_NS; + recTicks = SYSCLK_TICKS(cycleTime - accessTime) - 1; + if (recTicks < 1) + recTicks = 1; + cycleTime = (recTicks + 1 + accessTicks) * IDE_SYSCLK_NS; + + /* KeyLargo ata-3 don't support the half-tick stuff */ + if ((pmac_ide[intf].kind != controller_kl_ata3) && + (accessTicks > 1) && + ((accessTime - IDE_SYSCLK_NS/2) >= origAccessTime) && + ((cycleTime - IDE_SYSCLK_NS) >= origCycleTime)) { + halfTick = 1; + accessTicks--; + } + *timings = ((*timings) & 0x7FF) | + (accessTicks | (recTicks << 5) | (halfTick << 10)) << 11; + } + return 0; +} +#endif /* #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC */ + +/* You may notice we don't use this function on normal operation, + * our, normal mdma function is supposed to be more precise + */ +static int +pmac_ide_tune_chipset (ide_drive_t *drive, byte speed) +{ + int intf = pmac_ide_find(drive); + int unit = (drive->select.all & 0x10) ? 1:0; + int ret = 0; + u32 *timings; + + if (intf < 0) + return 1; + + timings = &pmac_ide[intf].timings[unit]; + + switch(speed) { +#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC + case XFER_UDMA_4: + case XFER_UDMA_3: + case XFER_UDMA_2: + case XFER_UDMA_1: + case XFER_UDMA_0: + ret = set_timings_udma(intf, timings, speed); + break; + case XFER_MW_DMA_2: + case XFER_MW_DMA_1: + case XFER_MW_DMA_0: + case XFER_SW_DMA_2: + case XFER_SW_DMA_1: + case XFER_SW_DMA_0: + ret = set_timings_mdma(intf, timings, speed); + break; +#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ + case XFER_PIO_4: + case XFER_PIO_3: + case XFER_PIO_2: + case XFER_PIO_1: + case XFER_PIO_0: + pmac_ide_tuneproc(drive, speed & 0x07); + break; + default: + ret = 1; + } + if (ret) + return ret; + + ret = pmac_ide_do_setfeature(drive, speed); + if (ret) + return ret; + + pmac_ide_selectproc(drive); + drive->current_speed = speed; + + return 0; +} + ide_ioreg_t pmac_ide_get_base(int index) { return pmac_ide[index].regbase; } +int +pmac_ide_get_irq(ide_ioreg_t base) +{ + int ix; + + for (ix = 0; ix < MAX_HWIFS; ++ix) + if (base == pmac_ide[ix].regbase) + return pmac_ide[ix].irq; + return 0; +} + static int ide_majors[] = { 3, 22, 33, 34, 56, 57 }; kdev_t __init @@ -337,6 +526,7 @@ pmac_ide_probe(void) for (i = 0, np = atas; i < MAX_HWIFS && np != NULL; np = np->next) { struct device_node *tp; int *bidp; + int in_bay = 0; /* * If this node is not under a mac-io or dbdma node, @@ -395,7 +585,10 @@ pmac_ide_probe(void) if (np->parent && np->parent->name && strcasecmp(np->parent->name, "media-bay") == 0) { +#ifdef CONFIG_PMAC_PBOOK media_bay_set_ide_infos(np->parent,base,irq,i); +#endif /* CONFIG_PMAC_PBOOK */ + in_bay = 1; } else if (pmac_ide[i].kind == controller_ohare) { /* The code below is having trouble on some ohare machines * (timing related ?). Until I can put my hand on one of these @@ -436,8 +629,11 @@ pmac_ide_probe(void) pmac_ide_init_hwif_ports(&hwif->hw, base, 0, &hwif->irq); memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports)); hwif->chipset = ide_pmac; - hwif->noprobe = (!hwif->io_ports[IDE_DATA_OFFSET]) || - (check_media_bay_by_base(base, MB_CD) == -EINVAL); + hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET] || in_bay; +#ifdef CONFIG_PMAC_PBOOK + if (in_bay && check_media_bay_by_base(base, MB_CD) == 0) + hwif->noprobe = 0; +#endif /* CONFIG_PMAC_PBOOK */ #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC if (np->n_addrs >= 2) { @@ -479,7 +675,7 @@ pmac_ide_setup_dma(struct device_node *np, int ix) } ide_hwifs[ix].dmaproc = &pmac_ide_dmaproc; -#ifdef CONFIG_PMAC_IDEDMA_AUTO +#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO ide_hwifs[ix].autodma = 1; #endif } @@ -565,99 +761,34 @@ pmac_ide_build_dmatable(ide_drive_t *drive, int ix, int wr) } -/* This is fun. -DaveM */ -#define IDE_SETXFER 0x03 -#define IDE_SETFEATURE 0xef -#define IDE_DMA2_ENABLE 0x22 -#define IDE_DMA1_ENABLE 0x21 -#define IDE_DMA0_ENABLE 0x20 -#define IDE_UDMA4_ENABLE 0x44 -#define IDE_UDMA3_ENABLE 0x43 -#define IDE_UDMA2_ENABLE 0x42 -#define IDE_UDMA1_ENABLE 0x41 -#define IDE_UDMA0_ENABLE 0x40 - static __inline__ unsigned char dma_bits_to_command(unsigned char bits) { if(bits & 0x04) - return IDE_DMA2_ENABLE; + return XFER_MW_DMA_2; if(bits & 0x02) - return IDE_DMA1_ENABLE; - return IDE_DMA0_ENABLE; + return XFER_MW_DMA_1; + if(bits & 0x01) + return XFER_MW_DMA_0; + return 0; } static __inline__ unsigned char udma_bits_to_command(unsigned char bits) { if(bits & 0x10) - return IDE_UDMA4_ENABLE; + return XFER_UDMA_4; if(bits & 0x08) - return IDE_UDMA3_ENABLE; + return XFER_UDMA_3; if(bits & 0x04) - return IDE_UDMA2_ENABLE; + return XFER_UDMA_2; if(bits & 0x02) - return IDE_UDMA1_ENABLE; + return XFER_UDMA_1; if(bits & 0x01) - return IDE_UDMA0_ENABLE; + return XFER_UDMA_0; return 0; } -static __inline__ int -wait_for_ready(ide_drive_t *drive) -{ - /* Timeout bumped for some powerbooks */ - int timeout = 2000; - byte stat; - - while(--timeout) { - stat = GET_STAT(); - if(!(stat & BUSY_STAT)) { - if (drive->ready_stat == 0) - break; - else if((stat & drive->ready_stat) || (stat & ERR_STAT)) - break; - } - mdelay(1); - } - if((stat & ERR_STAT) || timeout <= 0) { - if (stat & ERR_STAT) { - printk("ide_pmace: wait_for_ready, error status: %x\n", stat); - } - return 1; - } - return 0; -} - -static int -pmac_ide_do_setfeature(ide_drive_t *drive, byte command) -{ - unsigned long flags; - byte old_select; - int result = 1; - - save_flags(flags); - cli(); - old_select = IN_BYTE(IDE_SELECT_REG); - OUT_BYTE(drive->select.all, IDE_SELECT_REG); - udelay(10); - OUT_BYTE(IDE_SETXFER, IDE_FEATURE_REG); - OUT_BYTE(command, IDE_NSECTOR_REG); - if(wait_for_ready(drive)) { - printk("pmac_ide_do_setfeature disk not ready before SET_FEATURE!\n"); - goto out; - } - OUT_BYTE(IDE_SETFEATURE, IDE_COMMAND_REG); - result = wait_for_ready(drive); - if (result) - printk("pmac_ide_do_setfeature disk not ready after SET_FEATURE !\n"); -out: - OUT_BYTE(old_select, IDE_SELECT_REG); - restore_flags(flags); - - return result; -} - /* Calculate MultiWord DMA timings */ static int pmac_ide_mdma_enable(ide_drive_t *drive, int idx) @@ -668,10 +799,12 @@ pmac_ide_mdma_enable(ide_drive_t *drive, int idx) int cycleTime, accessTime; int accessTicks, recTicks; struct hd_driveid *id = drive->id; - + int ret; + /* Set feature on drive */ printk("%s: Enabling MultiWord DMA %d\n", drive->name, feature & 0xf); - if (pmac_ide_do_setfeature(drive, feature)) { + ret = pmac_ide_do_setfeature(drive, feature); + if (ret) { printk("%s: Failed !\n", drive->name); return 0; } @@ -693,7 +826,7 @@ pmac_ide_mdma_enable(ide_drive_t *drive, int idx) if ((pmac_ide[idx].kind == controller_ohare) && (cycleTime < 150)) cycleTime = 150; - /* For ata-4 controller, we don't know the calculation */ + /* For ata-4 controller */ if (pmac_ide[idx].kind == controller_kl_ata4) { accessTicks = SYSCLK_TICKS_UDMA(accessTime * 1000); recTicks = SYSCLK_TICKS_UDMA(cycleTime * 1000) - accessTicks; @@ -741,10 +874,12 @@ pmac_ide_udma_enable(ide_drive_t *drive, int idx) int cycleTime, accessTime; int rdyToPauseTicks, cycleTicks; u32 *timings; - + int ret; + /* Set feature on drive */ printk("%s: Enabling Ultra DMA %d\n", drive->name, feature & 0xf); - if (pmac_ide_do_setfeature(drive, feature)) { + ret = pmac_ide_do_setfeature(drive, feature); + if (ret) { printk("%s: Failed !\n", drive->name); return 0; } @@ -772,10 +907,11 @@ pmac_ide_udma_enable(ide_drive_t *drive, int idx) } static int -pmac_ide_dma_onoff(ide_drive_t *drive, int enable) +pmac_ide_check_dma(ide_drive_t *drive) { int ata4, udma, idx; struct hd_driveid *id = drive->id; + int enable = 1; drive->using_dma = 0; @@ -807,15 +943,14 @@ pmac_ide_dma_onoff(ide_drive_t *drive, int enable) * machines */ OUT_BYTE(0, IDE_CONTROL_REG); - if (drive->select.all == IN_BYTE(IDE_SELECT_REG)) - pmac_ide_selectproc(drive); + /* Apply settings to controller */ + pmac_ide_selectproc(drive); } return 0; } int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); int ix, dstat; volatile struct dbdma_regs *dma; @@ -828,15 +963,14 @@ int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive) dma = pmac_ide[ix].dma_regs; switch (func) { - case ide_dma_on: case ide_dma_off: + printk("%s: DMA disabled\n", drive->name); case ide_dma_off_quietly: - pmac_ide_dma_onoff(drive, (func == ide_dma_on)); + drive->using_dma = 0; break; + case ide_dma_on: case ide_dma_check: - printk("IDE-DMA check !\n"); - if (hwif->autodma) - pmac_ide_dma_onoff(drive, 1); + pmac_ide_check_dma(drive); break; case ide_dma_read: case ide_dma_write: @@ -1026,7 +1160,7 @@ static int idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when) #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC if (hwif->drives[0].present && hwif->drives[0].using_dma) - pmac_ide_dma_onoff(&hwif->drives[0], 1); + pmac_ide_check_dma(&hwif->drives[0]); #endif } break; diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 64d9121c8..8b3a37914 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -40,7 +40,7 @@ #include <linux/major.h> #include <linux/errno.h> #include <linux/genhd.h> -#include <linux/malloc.h> +#include <linux/slab.h> #include <linux/delay.h> #include <linux/ide.h> #include <linux/spinlock.h> @@ -652,6 +652,8 @@ static int init_irq (ide_hwif_t *hwif) hwgroup = match->hwgroup; } else { hwgroup = kmalloc(sizeof(ide_hwgroup_t), GFP_KERNEL); + if (!hwgroup) + return 1; memset(hwgroup, 0, sizeof(ide_hwgroup_t)); hwgroup->hwif = hwif->next = hwif; hwgroup->rq = NULL; diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index 0e7a23994..774594bbc 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -399,7 +399,7 @@ #include <linux/devfs_fs_kernel.h> #include <linux/errno.h> #include <linux/genhd.h> -#include <linux/malloc.h> +#include <linux/slab.h> #include <linux/pci.h> #include <linux/ide.h> #include <linux/smp_lock.h> diff --git a/drivers/ide/ide-timing.h b/drivers/ide/ide-timing.h new file mode 100644 index 000000000..73fead8d8 --- /dev/null +++ b/drivers/ide/ide-timing.h @@ -0,0 +1,279 @@ +#ifndef _IDE_TIMING_H +#define _IDE_TIMING_H + +/* + * $Id: ide-timing.h,v 1.5 2001/01/15 21:48:56 vojtech Exp $ + * + * Copyright (c) 1999-2000 Vojtech Pavlik + * + * Sponsored by SuSE + */ + +/* + * 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 + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include <linux/hdreg.h> + +#ifndef XFER_PIO_5 +#define XFER_PIO_5 0x0d +#define XFER_UDMA_SLOW 0x4f +#endif + +struct ide_timing { + short mode; + short setup; /* t1 */ + short act8b; /* t2 for 8-bit io */ + short rec8b; /* t2i for 8-bit io */ + short cyc8b; /* t0 for 8-bit io */ + short active; /* t2 or tD */ + short recover; /* t2i or tK */ + short cycle; /* t0 */ + short udma; /* t2CYCTYP/2 */ +}; + +/* + * PIO 0-5, MWDMA 0-2 and UDMA 0-5 timings (in nanoseconds). + * These were taken from ATA/ATAPI-6 standard, rev 0a, except + * for PIO 5, which is a nonstandard extension. + */ + +static struct ide_timing ide_timing[] = { + + { XFER_UDMA_5, 0, 0, 0, 0, 0, 0, 0, 20 }, + { XFER_UDMA_4, 0, 0, 0, 0, 0, 0, 0, 30 }, + { XFER_UDMA_3, 0, 0, 0, 0, 0, 0, 0, 45 }, + + { XFER_UDMA_2, 0, 0, 0, 0, 0, 0, 0, 60 }, + { XFER_UDMA_1, 0, 0, 0, 0, 0, 0, 0, 80 }, + { XFER_UDMA_0, 0, 0, 0, 0, 0, 0, 0, 120 }, + + { XFER_UDMA_SLOW, 0, 0, 0, 0, 0, 0, 0, 150 }, + + { XFER_MW_DMA_2, 25, 0, 0, 0, 70, 25, 120, 0 }, + { XFER_MW_DMA_1, 45, 0, 0, 0, 80, 50, 150, 0 }, + { XFER_MW_DMA_0, 60, 0, 0, 0, 215, 215, 480, 0 }, + + { XFER_SW_DMA_2, 60, 0, 0, 0, 120, 120, 240, 0 }, + { XFER_SW_DMA_1, 90, 0, 0, 0, 240, 240, 480, 0 }, + { XFER_SW_DMA_0, 120, 0, 0, 0, 480, 480, 960, 0 }, + + { XFER_PIO_5, 20, 50, 30, 100, 50, 30, 100, 0 }, + { XFER_PIO_4, 25, 70, 25, 120, 70, 25, 120, 0 }, + { XFER_PIO_3, 30, 80, 70, 180, 80, 70, 180, 0 }, + + { XFER_PIO_2, 30, 290, 40, 330, 100, 90, 240, 0 }, + { XFER_PIO_1, 50, 290, 93, 383, 125, 100, 383, 0 }, + { XFER_PIO_0, 70, 290, 240, 600, 165, 150, 600, 0 }, + + { XFER_PIO_SLOW, 120, 290, 240, 960, 290, 240, 960, 0 }, + + { -1 } +}; + +#define IDE_TIMING_SETUP 0x01 +#define IDE_TIMING_ACT8B 0x02 +#define IDE_TIMING_REC8B 0x04 +#define IDE_TIMING_CYC8B 0x08 +#define IDE_TIMING_8BIT 0x0e +#define IDE_TIMING_ACTIVE 0x10 +#define IDE_TIMING_RECOVER 0x20 +#define IDE_TIMING_CYCLE 0x40 +#define IDE_TIMING_UDMA 0x80 +#define IDE_TIMING_ALL 0xff + +#define MIN(a,b) ((a)<(b)?(a):(b)) +#define MAX(a,b) ((a)>(b)?(a):(b)) +#define FIT(v,min,max) MAX(MIN(v,max),min) +#define ENOUGH(v,unit) (((v)-1)/(unit)+1) +#define EZ(v,unit) ((v)?ENOUGH(v,unit):0) + +#define XFER_MODE 0xf0 +#define XFER_UDMA_100 0x44 +#define XFER_UDMA_66 0x42 +#define XFER_UDMA 0x40 +#define XFER_MWDMA 0x20 +#define XFER_SWDMA 0x10 +#define XFER_EPIO 0x01 +#define XFER_PIO 0x00 + +static short ide_find_best_mode(ide_drive_t *drive, int map) +{ + struct hd_driveid *id = drive->id; + short best = 0; + + if (!id) + return XFER_PIO_SLOW; + + if ((map & XFER_UDMA) && (id->field_valid & 4)) { /* Want UDMA and UDMA bitmap valid */ + + if ((map & XFER_UDMA_100) == XFER_UDMA_100) + if ((best = (id->dma_ultra & 0x0020) ? XFER_UDMA_5 : 0)) return best; + + if ((map & XFER_UDMA_66) == XFER_UDMA_66) + if ((best = (id->dma_ultra & 0x0010) ? XFER_UDMA_4 : + (id->dma_ultra & 0x0008) ? XFER_UDMA_3 : 0)) return best; + + if ((best = (id->dma_ultra & 0x0004) ? XFER_UDMA_2 : + (id->dma_ultra & 0x0002) ? XFER_UDMA_1 : + (id->dma_ultra & 0x0001) ? XFER_UDMA_0 : 0)) return best; + } + + if ((map & XFER_MWDMA) && (id->field_valid & 2)) { /* Want MWDMA and drive has EIDE fields */ + + if ((best = (id->dma_mword & 0x0004) ? XFER_MW_DMA_2 : + (id->dma_mword & 0x0002) ? XFER_MW_DMA_1 : + (id->dma_mword & 0x0001) ? XFER_MW_DMA_0 : 0)) return best; + } + + if (map & XFER_SWDMA) { /* Want SWDMA */ + + if (id->field_valid & 2) { /* EIDE SWDMA */ + + if ((best = (id->dma_1word & 0x0004) ? XFER_SW_DMA_2 : + (id->dma_1word & 0x0002) ? XFER_SW_DMA_1 : + (id->dma_1word & 0x0001) ? XFER_SW_DMA_0 : 0)) return best; + } + + if (id->capability & 1) { /* Pre-EIDE style SWDMA */ + + if ((best = (id->tDMA == 2) ? XFER_SW_DMA_2 : + (id->tDMA == 1) ? XFER_SW_DMA_1 : + (id->tDMA == 0) ? XFER_SW_DMA_0 : 0)) return best; + } + } + + + if ((map & XFER_EPIO) && (id->field_valid & 2)) { /* EIDE PIO modes */ + + if ((best = (drive->id->eide_pio_modes & 4) ? XFER_PIO_5 : + (drive->id->eide_pio_modes & 2) ? XFER_PIO_4 : + (drive->id->eide_pio_modes & 1) ? XFER_PIO_3 : 0)) return best; + } + + return (drive->id->tPIO == 2) ? XFER_PIO_2 : + (drive->id->tPIO == 1) ? XFER_PIO_1 : + (drive->id->tPIO == 0) ? XFER_PIO_0 : XFER_PIO_SLOW; +} + +static void ide_timing_quantize(struct ide_timing *t, struct ide_timing *q, int T, int UT) +{ + q->setup = EZ(t->setup, T); + q->act8b = EZ(t->act8b, T); + q->rec8b = EZ(t->rec8b, T); + q->cyc8b = EZ(t->cyc8b, T); + q->active = EZ(t->active, T); + q->recover = EZ(t->recover, T); + q->cycle = EZ(t->cycle, T); + q->udma = EZ(t->udma, UT); +} + +static void ide_timing_merge(struct ide_timing *a, struct ide_timing *b, struct ide_timing *m, unsigned int what) +{ + if (what & IDE_TIMING_SETUP ) m->setup = MAX(a->setup, b->setup); + if (what & IDE_TIMING_ACT8B ) m->act8b = MAX(a->act8b, b->act8b); + if (what & IDE_TIMING_REC8B ) m->rec8b = MAX(a->rec8b, b->rec8b); + if (what & IDE_TIMING_CYC8B ) m->cyc8b = MAX(a->cyc8b, b->cyc8b); + if (what & IDE_TIMING_ACTIVE ) m->active = MAX(a->active, b->active); + if (what & IDE_TIMING_RECOVER) m->recover = MAX(a->recover, b->recover); + if (what & IDE_TIMING_CYCLE ) m->cycle = MAX(a->cycle, b->cycle); + if (what & IDE_TIMING_UDMA ) m->udma = MAX(a->udma, b->udma); +} + +static struct ide_timing* ide_timing_find_mode(short speed) +{ + struct ide_timing *t; + + for (t = ide_timing; t->mode != speed; t++) + if (t->mode < 0) + return NULL; + return t; +} + +static int ide_timing_compute(ide_drive_t *drive, short speed, struct ide_timing *t, int T, int UT) +{ + struct hd_driveid *id = drive->id; + struct ide_timing *s, p; + +/* + * Find the mode. + */ + + if (!(s = ide_timing_find_mode(speed))) + return -EINVAL; + +/* + * If the drive is an EIDE drive, it can tell us it needs extended + * PIO/MWDMA cycle timing. + */ + + if (id && id->field_valid & 2) { /* EIDE drive */ + + memset(&p, 0, sizeof(p)); + + switch (speed & XFER_MODE) { + + case XFER_PIO: + if (speed <= XFER_PIO_2) p.cycle = p.cyc8b = id->eide_pio; + else p.cycle = p.cyc8b = id->eide_pio_iordy; + break; + + case XFER_MWDMA: + p.cycle = id->eide_dma_min; + break; + } + + ide_timing_merge(&p, t, t, IDE_TIMING_CYCLE | IDE_TIMING_CYC8B); + } + +/* + * Convert the timing to bus clock counts. + */ + + ide_timing_quantize(s, t, T, UT); + +/* + * Even in DMA/UDMA modes we still use PIO access for IDENTIFY, S.M.A.R.T + * and some other commands. We have to ensure that the DMA cycle timing is + * slower/equal than the fastest PIO timing. + */ + + if ((speed & XFER_MODE) != XFER_PIO) { + ide_timing_compute(drive, ide_find_best_mode(drive, XFER_PIO | XFER_EPIO), &p, T, UT); + ide_timing_merge(&p, t, t, IDE_TIMING_ALL); + } + +/* + * Lenghten active & recovery time so that cycle time is correct. + */ + + if (t->act8b + t->rec8b < t->cyc8b) { + t->act8b += (t->cyc8b - (t->act8b + t->rec8b)) / 2; + t->rec8b = t->cyc8b - t->act8b; + } + + if (t->active + t->recover < t->cycle) { + t->active += (t->cycle - (t->active + t->recover)) / 2; + t->recover = t->cycle - t->active; + } + + return 0; +} + +#endif diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 95640895a..5dd08aea7 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -140,7 +140,7 @@ #include <linux/errno.h> #include <linux/genhd.h> #include <linux/blkpg.h> -#include <linux/malloc.h> +#include <linux/slab.h> #ifndef MODULE #include <linux/init.h> #endif /* MODULE */ diff --git a/drivers/ide/osb4.c b/drivers/ide/osb4.c index 308a8089c..11c14b04c 100644 --- a/drivers/ide/osb4.c +++ b/drivers/ide/osb4.c @@ -46,8 +46,8 @@ #include <linux/hdreg.h> #include <linux/ide.h> #include <linux/init.h> +#include <linux/delay.h> -#include <asm/delay.h> #include <asm/io.h> #include "ide_modes.h" diff --git a/drivers/ide/pdc202xx.c b/drivers/ide/pdc202xx.c index 72dd50134..3aae2a3eb 100644 --- a/drivers/ide/pdc202xx.c +++ b/drivers/ide/pdc202xx.c @@ -747,14 +747,11 @@ void pdc202xx_reset (ide_drive_t *drive) { unsigned long high_16 = pci_resource_start(HWIF(drive)->pci_dev, 4); byte udma_speed_flag = inb(high_16 + 0x001f); - int i = 0; OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f); - ide_delay_50ms(); - ide_delay_50ms(); + mdelay(100); OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f); - for (i = 0; i < 40; i++) - ide_delay_50ms(); + mdelay(2000); /* 2 seconds ?! */ } unsigned int __init pci_init_pdc202xx (struct pci_dev *dev, const char *name) @@ -767,7 +764,6 @@ unsigned int __init pci_init_pdc202xx (struct pci_dev *dev, const char *name) if ((dev->device == PCI_DEVICE_ID_PROMISE_20262) || (dev->device == PCI_DEVICE_ID_PROMISE_20265) || (dev->device == PCI_DEVICE_ID_PROMISE_20267)) { - int i = 0; /* * software reset - this is required because the bios * will set UDMA timing on if the hdd supports it. The @@ -779,11 +775,9 @@ unsigned int __init pci_init_pdc202xx (struct pci_dev *dev, const char *name) */ OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f); - ide_delay_50ms(); - ide_delay_50ms(); + mdelay(100); OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f); - for (i=0; i<40; i++) - ide_delay_50ms(); + mdelay(2000); /* 2 seconds ?! */ } if (dev->resource[PCI_ROM_RESOURCE].start) { diff --git a/drivers/ide/rapide.c b/drivers/ide/rapide.c index a842a3287..4976e49dc 100644 --- a/drivers/ide/rapide.c +++ b/drivers/ide/rapide.c @@ -9,7 +9,7 @@ */ #include <linux/module.h> -#include <linux/malloc.h> +#include <linux/slab.h> #include <linux/blkdev.h> #include <linux/errno.h> #include <linux/ide.h> diff --git a/drivers/ide/via82cxxx.c b/drivers/ide/via82cxxx.c index 356e7a4cc..e9574ab96 100644 --- a/drivers/ide/via82cxxx.c +++ b/drivers/ide/via82cxxx.c @@ -1,7 +1,7 @@ /* - * $Id: via82cxxx.c,v 2.1e 2000/10/03 10:01:00 vojtech Exp $ + * $Id: via82cxxx.c,v 3.20 2001/01/27 10:13:60 vojtech Exp $ * - * Copyright (c) 2000 Vojtech Pavlik + * Copyright (c) 2000-2001 Vojtech Pavlik * * Based on the work of: * Michel Aubry @@ -12,23 +12,34 @@ */ /* - * VIA vt82c586 IDE driver for Linux. Supports + * VIA IDE driver for Linux. Supports * - * vt82c586, vt82c586a, vt82c586b, vt82c596a, vt82c596b, vt82c686a, vt8231 + * vt82c586, vt82c586a, vt82c586b, vt82c596a, vt82c596b, + * vt82c686, vt82c686a, vt82c686b, vt8231, vt8233 * * southbridges, which can be found in * - * VIA Apollo VP, VPX, VPX/97, VP2, VP2/97, VP3, MVP3, MVP4 - * VIA Apollo Pro, Pro Plus, Pro 133, Pro 133A, ProMedia 601, ProSavage 605 - * VIA Apollo KX133, KT133 - * AMD-640, AMD-750 IronGate + * VIA Apollo VP, VPX, VPX/97, VP2, VP2/97, VP3, MVP3, MVP4, P6, Pro, + * Pro Plus, Pro 133, Pro 133A, ProMedia PM601, ProSavage PM133, PLE133, + * Pro 266, KX133, KT133, ProSavage KM133, KT133A, KT266 + * PC-Chips VXPro, VXPro+, TXPro-III, TXPro-AGP, ViaGra, BXToo, BXTel + * AMD 640, 640 AGP, 750 IronGate + * ETEQ 6618, 6628, 6638 + * Micron Samurai * - * chipsets. Supports PIO 0-5, MWDMA 0-2, SWDMA 0-2 and - * UDMA 0-5 (includes UDMA33, 66 and 100) modes. UDMA100 isn't possible - * on any of the supported chipsets yet. + * chipsets. Supports * - * UDMA66 and higher modes are autodetected only in case the BIOS has enabled them. - * To force UDMA66, use 'ide0=ata66' or 'ide1=ata66' on the kernel command line. + * PIO 0-5, MWDMA 0-2, SWDMA 0-2 and UDMA 0-5 + * + * (this includes UDMA33, 66 and 100) modes. UDMA66 and higher modes are + * autodetected only in case the BIOS has detected a 80 wire cable. To ignore + * the BIOS data, use 'ide0=ata66' or 'ide1=ata66' on the kernel command line. + * + * For correct operation it's needed to tell the driver the speed of the PCI + * bus. The default, and most common value is 33 MHz. Most likely, your system + * is using this value and you don't need to use any command line options. If + * you run your PCI bus speed at 25, 30, 37, 40 or 42 MHz, use the 'idebus=xx' + * option of the IDE driver. Note that this has nothing to do with UDMA66. */ /* @@ -52,23 +63,16 @@ */ #include <linux/config.h> -#include <linux/types.h> #include <linux/kernel.h> -#include <linux/timer.h> -#include <linux/mm.h> #include <linux/ioport.h> -#include <linux/interrupt.h> #include <linux/blkdev.h> -#include <linux/hdreg.h> #include <linux/pci.h> #include <linux/init.h> -#include <linux/delay.h> #include <linux/ide.h> #include <asm/io.h> -#include "ide_modes.h" +#include "ide-timing.h" -#define VIA_BM_BASE 0x20 #define VIA_IDE_ENABLE 0x40 #define VIA_IDE_CONFIG 0x41 #define VIA_FIFO_CONFIG 0x43 @@ -76,90 +80,49 @@ #define VIA_MISC_2 0x45 #define VIA_MISC_3 0x46 #define VIA_DRIVE_TIMING 0x48 +#define VIA_8BIT_TIMING 0x4e #define VIA_ADDRESS_SETUP 0x4c #define VIA_UDMA_TIMING 0x50 -#define VIA_PRI_SECTOR_SIZE 0x60 -#define VIA_SEC_SECTOR_SIZE 0x68 + +#define VIA_UDMA 0x07 +#define VIA_UDMA_NONE 0x00 +#define VIA_UDMA_33 0x01 +#define VIA_UDMA_66 0x02 +#define VIA_UDMA_100 0x03 +#define VIA_BAD_PREQ 0x10 +#define VIA_BAD_CLK66 0x20 +#define VIA_SET_FIFO 0x40 +#define VIA_SET_THRESH 0x80 /* * VIA SouthBridge chips. */ -static const struct { +static struct via_isa_bridge { char *name; unsigned short id; - unsigned char speed; + unsigned char rev_min; + unsigned char rev_max; + unsigned char flags; } via_isa_bridges[] = { - { "vt8231", PCI_DEVICE_ID_VIA_8231, XFER_UDMA_4 }, - { "vt82c686a", PCI_DEVICE_ID_VIA_82C686, XFER_UDMA_4 }, - { "vt82c596b", PCI_DEVICE_ID_VIA_82C596, XFER_UDMA_4 }, - { "vt82c596a", PCI_DEVICE_ID_VIA_82C596, XFER_UDMA_2 }, - { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, XFER_UDMA_2 }, - { "vt82c586a", PCI_DEVICE_ID_VIA_82C586_0, XFER_UDMA_2 }, - { "vt82c586", PCI_DEVICE_ID_VIA_82C586_0, XFER_MW_DMA_2 }, - { "Unknown SouthBridge", 0, XFER_UDMA_2 }, + { "vt8233", PCI_DEVICE_ID_VIA_8233_0, 0x00, 0x2f, VIA_UDMA_100 }, + { "vt8231", PCI_DEVICE_ID_VIA_8231, 0x00, 0x2f, VIA_UDMA_66 }, + { "vt82c686b", PCI_DEVICE_ID_VIA_82C686, 0x40, 0x4f, VIA_UDMA_100 }, + { "vt82c686a", PCI_DEVICE_ID_VIA_82C686, 0x10, 0x2f, VIA_UDMA_66 }, + { "vt82c686", PCI_DEVICE_ID_VIA_82C686, 0x00, 0x0f, VIA_UDMA_66 }, + { "vt82c596b", PCI_DEVICE_ID_VIA_82C596, 0x10, 0x2f, VIA_UDMA_66 }, + { "vt82c596a", PCI_DEVICE_ID_VIA_82C596, 0x00, 0x0f, VIA_UDMA_33 | VIA_BAD_CLK66 }, + { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x40, 0x4f, VIA_UDMA_33 | VIA_SET_FIFO | VIA_BAD_PREQ }, + { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x30, 0x3f, VIA_UDMA_33 | VIA_SET_FIFO }, + { "vt82c586a", PCI_DEVICE_ID_VIA_82C586_0, 0x20, 0x2f, VIA_UDMA_33 | VIA_SET_FIFO }, + { "vt82c586", PCI_DEVICE_ID_VIA_82C586_0, 0x00, 0x0f, VIA_UDMA_NONE | VIA_SET_FIFO }, + { NULL } }; -static unsigned char via_config; +static struct via_isa_bridge *via_config; static unsigned char via_enabled; -static unsigned int via_ata66; - -/* - * PIO 0-5, MWDMA 0-2 and UDMA 0-5 timings (in nanoseconds). - * These were taken from ATA/ATAPI-6 standard, rev 0a, except - * for PIO 5, which is a nonstandard extension. - * - * Dilemma: 8-bit (register) PIO accesses need more relaxed timing. - * Hopefully the chipset is taking care of that. If it doesn't - * do so, define VIA_USE_8_BIT_TIMING to see if it helps. - */ - -#ifndef XFER_PIO_5 -#define XFER_PIO_5 0x0d -#endif - -static const struct { - int mode; - char *name; - short setup; /* t1 */ - short active; /* t2 or tD */ - short recover; /* t2i or tK */ - short cycle; /* t0 */ - short udma; /* t2CYCTYP/2 */ -} via_timing[] = { - { XFER_UDMA_5, "UDMA5", 25, 70, 25, 120, 20 }, - { XFER_UDMA_4, "UDMA4", 25, 70, 25, 120, 30 }, - { XFER_UDMA_3, "UDMA3", 25, 70, 25, 120, 45 }, - - { XFER_UDMA_2, "UDMA2", 25, 70, 25, 120, 60 }, - { XFER_UDMA_1, "UDMA1", 25, 70, 25, 120, 80 }, - { XFER_UDMA_0, "UDMA0", 25, 70, 25, 120, 120 }, - - { XFER_MW_DMA_2, "MDMA2", 25, 70, 25, 120, 0 }, - { XFER_MW_DMA_1, "MDMA1", 45, 80, 50, 150, 0 }, - { XFER_MW_DMA_0, "MDMA0", 60, 215, 215, 480, 0 }, - - { XFER_SW_DMA_2, "SDMA2", 60, 120, 120, 240, 0 }, - { XFER_SW_DMA_1, "SDMA1", 90, 240, 240, 480, 0 }, - { XFER_SW_DMA_0, "SDMA0",120, 480, 480, 960, 0 }, - - { XFER_PIO_5, "PIO5", 20, 50, 30, 100, 0 }, - { XFER_PIO_4, "PIO4", 25, 70, 25, 120, 0 }, - { XFER_PIO_3, "PIO3", 30, 80, 70, 180, 0 }, - -#ifdef VIA_USE_8_BIT_TIMING - { XFER_PIO_2, "PIO2", 30, 290, 60, 330, 0 }, - { XFER_PIO_1, "PIO1", 50, 290, 100, 383, 0 }, - { XFER_PIO_0, "PIO0", 70, 290, 300, 600, 0 }, -#else - { XFER_PIO_2, "PIO2", 30, 100, 90, 240, 0 }, - { XFER_PIO_1, "PIO1", 50, 125, 100, 383, 0 }, - { XFER_PIO_0, "PIO0", 70, 165, 150, 600, 0 }, -#endif - - { XFER_PIO_SLOW, "SLOW", 120, 290, 240, 960, 0 }, - { 0 } -}; +static unsigned int via_80w; +static unsigned int via_clock; /* * VIA /proc entry. @@ -170,11 +133,10 @@ static const struct { #include <linux/stat.h> #include <linux/proc_fs.h> -int via_proc = 0; +int via_proc, via_base; static struct pci_dev *bmide_dev, *isa_dev; extern int (*via_display_info)(char *, char **, off_t, int); /* ide-proc.c */ -static char *via_fifo[] = { " 1 ", "3/4", "1/2", "1/4" }; static char *via_control3[] = { "No limit", "64", "128", "192" }; #define via_print(format, arg...) p += sprintf(p, format "\n" , ## arg) @@ -183,89 +145,89 @@ static char *via_control3[] = { "No limit", "64", "128", "192" }; static int via_get_info(char *buffer, char **addr, off_t offset, int count) { - short pci_clock, speed[4], cycle[4], setup[4], active[4], recover[4], umul[4], uen[4], udma[4]; + short speed[4], cycle[4], setup[4], active[4], + recover[4], uen[4], udma[4], active8b[4], recover8b[4]; struct pci_dev *dev = bmide_dev; - unsigned int v, u, i, base; - unsigned short c, size0, size1; - unsigned char t, c0, c1; + unsigned int v, u, i; + unsigned short c, w; + unsigned char t, x; char *p = buffer; via_print("----------VIA BusMastering IDE Configuration----------------"); - via_print("Driver Version: 2.1e"); + via_print("Driver Version: 3.20"); + via_print("South Bridge: VIA %s", via_config->name); pci_read_config_byte(isa_dev, PCI_REVISION_ID, &t); - via_print("South Bridge: VIA %s rev %#x", via_isa_bridges[via_config].name, t); - - pci_read_config_word(dev, PCI_COMMAND, &c); - via_print("Command register: %#x", c); + pci_read_config_byte(dev, PCI_REVISION_ID, &x); + via_print("Revision: ISA %#x IDE %#x", t, x); - pci_read_config_byte(dev, PCI_LATENCY_TIMER, &t); - via_print("Latency timer: %d", t); - - pci_clock = system_bus_clock(); - via_print("PCI clock: %dMHz", pci_clock); + via_print("BM-DMA base: %#x", via_base); + via_print("PCI clock: %dMHz", via_clock); pci_read_config_byte(dev, VIA_MISC_1, &t); - via_print("Master Read Cycle IRDY: %dws", (t & 64) >>6 ); - via_print("Master Write Cycle IRDY: %dws", (t & 32) >> 5 ); - via_print("FIFO Output Data 1/2 Clock Advance: %s", (t & 16) ? "on" : "off" ); - via_print("BM IDE Status Register Read Retry: %s", (t & 8) ? "on" : "off" ); + via_print("Master Read Cycle IRDY: %dws", (t & 64) >> 6); + via_print("Master Write Cycle IRDY: %dws", (t & 32) >> 5); + via_print("BM IDE Status Register Read Retry: %s", (t & 8) ? "yes" : "no"); pci_read_config_byte(dev, VIA_MISC_3, &t); - via_print("Max DRDY Pulse Width: %s%s", via_control3[(t & 0x03)], (t & 0x03) ? "PCI clocks" : ""); + via_print("Max DRDY Pulse Width: %s%s", via_control3[(t & 0x03)], (t & 0x03) ? " PCI clocks" : ""); via_print("-----------------------Primary IDE-------Secondary IDE------"); - via_print("Read DMA FIFO flush: %10s%20s", (t & 0x80) ? "on" : "off", (t & 0x40) ? "on" : "off" ); - via_print("End Sect. FIFO flush: %10s%20s", (t & 0x20) ? "on" : "off", (t & 0x10) ? "on" : "off" ); + via_print("Read DMA FIFO flush: %10s%20s", (t & 0x80) ? "yes" : "no", (t & 0x40) ? "yes" : "no"); + via_print("End Sector FIFO flush: %10s%20s", (t & 0x20) ? "yes" : "no", (t & 0x10) ? "yes" : "no"); pci_read_config_byte(dev, VIA_IDE_CONFIG, &t); - via_print("Prefetch Buffer: %10s%20s", (t & 0x80) ? "on" : "off", (t & 0x20) ? "on" : "off" ); - via_print("Post Write Buffer: %10s%20s", (t & 0x40) ? "on" : "off", (t & 0x10) ? "on" : "off" ); - - pci_read_config_byte(dev, VIA_FIFO_CONFIG, &t); - via_print("FIFO size: %10d%20d", 16 - (((t >> 5) & 1) + ((t >> 6) & 1)) * 8, - (((t >> 5) & 1) + ((t >> 6) & 1)) * 8); - via_print("Threshold Prim.: %10s%20s", via_fifo[(t >> 2) & 3], via_fifo[t & 3]); - - pci_read_config_word(dev, VIA_PRI_SECTOR_SIZE, &size0); - pci_read_config_word(dev, VIA_SEC_SECTOR_SIZE, &size1); - via_print("Bytes Per Sector: %10d%20d", size0 & 0xfff, size1 & 0xfff); + via_print("Prefetch Buffer: %10s%20s", (t & 0x80) ? "yes" : "no", (t & 0x20) ? "yes" : "no"); + via_print("Post Write Buffer: %10s%20s", (t & 0x40) ? "yes" : "no", (t & 0x10) ? "yes" : "no"); - pci_read_config_dword(dev, VIA_BM_BASE, &base); - base = (base & 0xfff0) ; + pci_read_config_byte(dev, VIA_IDE_ENABLE, &t); + via_print("Enabled: %10s%20s", (t & 0x02) ? "yes" : "no", (t & 0x01) ? "yes" : "no"); - c0 = inb((unsigned short)base + 0x02); - c1 = inb((unsigned short)base + 0x0a); + c = inb(via_base + 0x02) | (inb(via_base + 0x0a) << 8); + via_print("Simplex only: %10s%20s", (c & 0x80) ? "yes" : "no", (c & 0x8000) ? "yes" : "no"); - via_print("Both channels togth: %10s%20s", (c0 & 0x80) ? "no" : "yes", (c1 & 0x80) ? "no" : "yes" ); + via_print("Cable Type: %10s%20s", (via_80w & 1) ? "80w" : "40w", (via_80w & 2) ? "80w" : "40w"); via_print("-------------------drive0----drive1----drive2----drive3-----"); - via_print("BMDMA enabled: %10s%10s%10s%10s", (c0 & 0x20) ? "yes" : "no", (c0 & 0x40) ? "yes" : "no", - (c1 & 0x20) ? "yes" : "no", (c1 & 0x40) ? "yes" : "no" ); - pci_read_config_byte(dev, VIA_ADDRESS_SETUP, &t); pci_read_config_dword(dev, VIA_DRIVE_TIMING, &v); - pci_read_config_dword(dev, VIA_UDMA_TIMING, &u); + pci_read_config_word(dev, VIA_8BIT_TIMING, &w); + + if (via_config->flags & VIA_UDMA) + pci_read_config_dword(dev, VIA_UDMA_TIMING, &u); + else u = 0; for (i = 0; i < 4; i++) { - setup[i] = ((t >> ((3 - i) << 1) ) & 0x3) + 1; - active[i] = ((v >> (((3 - i) << 3) + 4)) & 0xf) + 1; - recover[i] = ((v >> ((3 - i) << 3) ) & 0xf) + 1; - udma[i] = ((u >> ((3 - i) << 3) ) & 0x7) + 2; - umul[i] = ((u >> (((3 - i) & 2) << 3)) & 0x8) ? 2 : 1; - uen[i] = ((u >> ((3 - i) << 3)) & 0x20) ? 1 : 0; - speed[i] = uen[i] ? 20 * pci_clock * umul[i] / udma[i] : - 20 * pci_clock / (active[i] + recover[i]); - cycle[i] = uen[i] ? 1000 / (pci_clock * umul[i]) * udma[i] : - 1000 / pci_clock * (active[i] + recover[i]); + setup[i] = ((t >> ((3 - i) << 1)) & 0x3) + 1; + recover8b[i] = ((w >> ((1 - (i >> 1)) << 3)) & 0xf) + 1; + active8b[i] = ((w >> (((1 - (i >> 1)) << 3) + 4)) & 0xf) + 1; + active[i] = ((v >> (((3 - i) << 3) + 4)) & 0xf) + 1; + recover[i] = ((v >> ((3 - i) << 3)) & 0xf) + 1; + udma[i] = ((u >> ((3 - i) << 3)) & 0x7) + 2; + + if ((via_config->flags & VIA_UDMA) == VIA_UDMA_100) { + speed[i] = 2000 / udma[i]; + cycle[i] = 10 * udma[i]; + continue; + } + + uen[i] = (u >> ((3 - i) << 3)) & 0x20; + udma[i] *= ((u >> (((3 - i) & 2) << 3)) & 0x8) ? 1 : 2; + + speed[i] = 40 * via_clock / (uen[i] ? udma[i] : (active[i] + recover[i]) * 2); + cycle[i] = 1000 / via_clock * (uen[i] ? udma[i] : (active[i] + recover[i]) * 2) / 2; } - via_print_drive("Transfer Mode: ", "%10s", uen[i] ? "UDMA" : "DMA/PIO"); - via_print_drive("Address Setup: ", "%8dns", (1000 / pci_clock) * setup[i]); - via_print_drive("Active Pulse: ", "%8dns", (1000 / pci_clock) * active[i]); - via_print_drive("Recovery Time: ", "%8dns", (1000 / pci_clock) * recover[i]); + via_print_drive("Transfer Mode: ", "%10s", + (c & ((i & 1) ? 0x40 : 0x20) << ((i & 2) << 2)) ? (uen[i] ? "UDMA" : "DMA") : "PIO"); + + via_print_drive("Address Setup: ", "%8dns", (1000 / via_clock) * setup[i]); + via_print_drive("Cmd Active: ", "%8dns", (1000 / via_clock) * active8b[i]); + via_print_drive("Cmd Recovery: ", "%8dns", (1000 / via_clock) * recover8b[i]); + via_print_drive("Data Active: ", "%8dns", (1000 / via_clock) * active[i]); + via_print_drive("Data Recovery: ", "%8dns", (1000 / via_clock) * recover[i]); via_print_drive("Cycle Time: ", "%8dns", cycle[i]); via_print_drive("Transfer Rate: ", "%4d.%dMB/s", speed[i] / 10, speed[i] % 10); @@ -274,302 +236,243 @@ static int via_get_info(char *buffer, char **addr, off_t offset, int count) #endif -#define FIT(v,min,max) ((v)>(max)?(max):((v)<(min)?(min):(v))) -#define ENOUGH(v,un) (((v)-1)/(un)+1) - -#ifdef DEBUG -#define via_write_config_byte(dev,number,value) do {\ - printk(KERN_DEBUG "VP_IDE: Setting register %#x to %#x\n", number, value);\ - pci_write_config_byte(dev,number,value); } while (0) -#else -#define via_write_config_byte pci_write_config_byte -#endif +/* + * via_set_speed() writes timing values to the chipset registers + */ -static int via_set_speed(ide_drive_t *drive, byte speed) +static void via_set_speed(struct pci_dev *dev, unsigned char dn, struct ide_timing *timing) { - struct pci_dev *dev = HWIF(drive)->pci_dev; - int i, T, err = 0; - unsigned char t, setup, active, recover, cycle; + unsigned char t; - if (drive->dn > 3) return -1; - - T = 1000 / system_bus_clock(); - - if (speed > via_isa_bridges[via_config].speed) - speed = via_isa_bridges[via_config].speed; + pci_read_config_byte(dev, VIA_ADDRESS_SETUP, &t); + t = (t & ~(3 << ((3 - dn) << 1))) | ((FIT(timing->setup, 1, 4) - 1) << ((3 - dn) << 1)); + pci_write_config_byte(dev, VIA_ADDRESS_SETUP, t); - for (i = 0; via_timing[i].mode && via_timing[i].mode != speed; i++); + pci_write_config_byte(dev, VIA_8BIT_TIMING + (1 - (dn >> 1)), + ((FIT(timing->act8b, 1, 16) - 1) << 4) | (FIT(timing->rec8b, 1, 16) - 1)); -#ifdef DEBUG - printk(KERN_DEBUG "VP_IDE: Setting drive %d to %s\n", drive->dn, via_timing[i].name); -#endif + pci_write_config_byte(dev, VIA_DRIVE_TIMING + (3 - dn), + ((FIT(timing->active, 1, 16) - 1) << 4) | (FIT(timing->recover, 1, 16) - 1)); - setup = ENOUGH(via_timing[i].setup, T); - active = ENOUGH(via_timing[i].active, T); - recover = ENOUGH(via_timing[i].recover, T); - cycle = ENOUGH(via_timing[i].cycle, T); - - if (active + recover < cycle) { - active += (cycle - (active + recover)) / 2; - recover = cycle - active; + switch (via_config->flags & VIA_UDMA) { + case VIA_UDMA_33: t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 5) - 2)) : 0x03; break; + case VIA_UDMA_66: t = timing->udma ? (0xe8 | (FIT(timing->udma, 2, 9) - 2)) : 0x0f; break; + case VIA_UDMA_100: t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 9) - 2)) : 0x07; break; + default: return; } -/* - * PIO address setup - */ - - pci_read_config_byte(dev, VIA_ADDRESS_SETUP, &t); - t = (t & ~(3 << ((3 - drive->dn) << 1))) | (FIT(setup - 1, 0, 3) << ((3 - drive->dn) << 1)); - via_write_config_byte(dev, VIA_ADDRESS_SETUP, t); + pci_write_config_byte(dev, VIA_UDMA_TIMING + (3 - dn), t); +} /* - * PIO active & recover + * via_set_drive() computes timing values configures the drive and + * the chipset to a desired transfer mode. It also can be called + * by upper layers. */ - via_write_config_byte(dev, VIA_DRIVE_TIMING + (3 - drive->dn), - (FIT(active - 1, 0, 0xf) << 4) | FIT(recover - 1, 0, 0xf)); - -/* - * UDMA cycle - */ +static int via_set_drive(ide_drive_t *drive, unsigned char speed) +{ + ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1); + struct ide_timing t, p; + int T, UT; + + if (speed != XFER_PIO_SLOW && speed != drive->current_speed) + if (ide_config_drive_speed(drive, speed)) + printk(KERN_WARNING "ide%d: Drive %d didn't accept speed setting. Oh, well.\n", + drive->dn >> 1, drive->dn & 1); + + T = 1000 / via_clock; + + switch (via_config->flags & VIA_UDMA) { + case VIA_UDMA_33: UT = T; break; + case VIA_UDMA_66: UT = T/2; break; + case VIA_UDMA_100: UT = 10; break; + default: UT = T; break; + } - switch(via_isa_bridges[via_config].speed) { - case XFER_UDMA_2: t = via_timing[i].udma ? (0xe0 | (FIT(ENOUGH(via_timing[i].udma, T), 2, 5) - 2)) : 0x03; break; - case XFER_UDMA_4: t = via_timing[i].udma ? (0xe8 | (FIT(ENOUGH(via_timing[i].udma, T/2), 2, 9) - 2)) : 0x0f; break; - } + ide_timing_compute(drive, speed, &t, T, UT); - if (via_isa_bridges[via_config].speed != XFER_MW_DMA_2) - via_write_config_byte(dev, VIA_UDMA_TIMING + (3 - drive->dn), t); + if (peer->present) { + ide_timing_compute(peer, peer->current_speed, &p, T, UT); + ide_timing_merge(&p, &t, &t, IDE_TIMING_8BIT); + } -/* - * Drive init - */ + via_set_speed(HWIF(drive)->pci_dev, drive->dn, &t); - if (!drive->init_speed) drive->init_speed = speed; - if ((err = ide_config_drive_speed(drive, speed))) - return err; + if (!drive->init_speed) + drive->init_speed = speed; drive->current_speed = speed; return 0; } -static void config_chipset_for_pio(ide_drive_t *drive) -{ - short eide_pio_timing[] = {600, 383, 240, 180, 120, 100}; - signed char pio, ide_pio; - - if (drive->id->eide_pio_iordy > 0) { /* Has timing table */ - for (pio = 5; pio >= 0; pio--) - if (drive->id->eide_pio_iordy <= eide_pio_timing[pio]) - break; - } else { /* No timing table -> use mode capabilities */ - pio = (drive->id->eide_pio_modes & 4) ? 5 : - (drive->id->eide_pio_modes & 2) ? 4 : - (drive->id->eide_pio_modes & 1) ? 3 : - (drive->id->tPIO == 2) ? 2 : - (drive->id->tPIO == 1) ? 1 : 0; - } - - ide_pio = ide_get_best_pio_mode(drive, 255, 5, NULL); - pio = (pio >= ide_pio) ? pio : ide_pio; /* Phew. What about the blacklist? */ - - if (!pio) pio = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW; - else pio += XFER_PIO_0; - - /* Fixup because of broken ide-probe.c */ - drive->dn = HWIF(drive)->channel * 2 + (drive->select.b.unit & 1); - - via_set_speed(drive, pio); -} +/* + * via82cxxx_tune_drive() is a callback from upper layers for + * PIO-only tuning. + */ -static void via82cxxx_tune_drive(ide_drive_t *drive, byte pio) +static void via82cxxx_tune_drive(ide_drive_t *drive, unsigned char pio) { + if (!((via_enabled >> HWIF(drive)->channel) & 1)) + return; + if (pio == 255) { - config_chipset_for_pio(drive); + via_set_drive(drive, ide_find_best_mode(drive, XFER_PIO | XFER_EPIO)); return; } - - if (pio > 5) pio = 5; - - via_set_speed(drive, XFER_PIO_0 + pio); + + via_set_drive(drive, XFER_PIO_0 + MIN(pio, 5)); } #ifdef CONFIG_BLK_DEV_IDEDMA -static int config_chipset_for_dma(ide_drive_t *drive) -{ - struct hd_driveid *id = drive->id; - unsigned char ultra66 = eighty_ninty_three(drive); - unsigned char speed = - - ((id->dma_ultra & 0x0010) && ultra66) ? XFER_UDMA_4 : - ((id->dma_ultra & 0x0008) && ultra66) ? XFER_UDMA_3 : - (id->dma_ultra & 0x0004) ? XFER_UDMA_2 : - (id->dma_ultra & 0x0002) ? XFER_UDMA_1 : - (id->dma_ultra & 0x0001) ? XFER_UDMA_0 : - (id->dma_mword & 0x0004) ? XFER_MW_DMA_2 : - (id->dma_mword & 0x0002) ? XFER_MW_DMA_1 : - (id->dma_mword & 0x0001) ? XFER_MW_DMA_0 : - (id->dma_1word & 0x0004) ? XFER_SW_DMA_2 : - (id->dma_1word & 0x0002) ? XFER_SW_DMA_1 : - (id->dma_1word & 0x0001) ? XFER_SW_DMA_0 : 0; - - if (!speed) return (int) ide_dma_off_quietly; - - via_set_speed(drive, speed); - - return (int) ide_dma_on; -} - /* - * Almost a library function. + * via82cxxx_dmaproc() is a callback from upper layers that can do + * a lot, but we use it for DMA/PIO tuning only, delegating everything + * else to the default ide_dmaproc(). */ -static int config_drive_xfer_rate(ide_drive_t *drive) +int via82cxxx_dmaproc(ide_dma_action_t func, ide_drive_t *drive) { - struct hd_driveid *id = drive->id; - ide_dma_action_t dma_func = ide_dma_on; - - if (id && (id->capability & 1) && HWIF(drive)->autodma) { - /* Consult the list of known "bad" drives */ - if (ide_dmaproc(ide_dma_bad_drive, drive)) { - dma_func = ide_dma_off; - goto fast_ata_pio; - } - dma_func = ide_dma_off_quietly; - if (id->field_valid & 4) { - if (id->dma_ultra & 0x002F) { - /* Force if Capable UltraDMA */ - dma_func = config_chipset_for_dma(drive); - if ((id->field_valid & 2) && - (dma_func != ide_dma_on)) - goto try_dma_modes; - } - } else if (id->field_valid & 2) { -try_dma_modes: - if (id->dma_mword & 0x0007) { - /* Force if Capable regular DMA modes */ - dma_func = config_chipset_for_dma(drive); - if (dma_func != ide_dma_on) - goto no_dma_set; - } - } else if (ide_dmaproc(ide_dma_good_drive, drive)) { - if (id->eide_dma_time > 150) { - goto no_dma_set; - } - /* Consult the list of known "good" drives */ - dma_func = config_chipset_for_dma(drive); - if (dma_func != ide_dma_on) - goto no_dma_set; - } else { - goto fast_ata_pio; - } - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: - dma_func = ide_dma_off_quietly; -no_dma_set: - config_chipset_for_pio(drive); - } - return HWIF(drive)->dmaproc(dma_func, drive); -} + if (func == ide_dma_check) { + + short w80 = HWIF(drive)->udma_four; + + short speed = ide_find_best_mode(drive, + XFER_PIO | XFER_EPIO | XFER_SWDMA | XFER_MWDMA | + (via_config->flags & VIA_UDMA ? XFER_UDMA : 0) | + (w80 && (via_config->flags & VIA_UDMA) == VIA_UDMA_66 ? XFER_UDMA_66 : 0) | + (w80 && (via_config->flags & VIA_UDMA) == VIA_UDMA_100 ? XFER_UDMA_100 : 0)); + + func = ((speed & XFER_MODE) != XFER_PIO) ? ide_dma_on : ide_dma_off_quietly; + + via_set_drive(drive, speed); + } -int via82cxxx_dmaproc(ide_dma_action_t func, ide_drive_t *drive) -{ - if (func == ide_dma_check) - return config_drive_xfer_rate(drive); return ide_dmaproc(func, drive); } + #endif /* CONFIG_BLK_DEV_IDEDMA */ +/* + * The initialization callback. Here we determine the IDE chip type + * and initialize its drive independent registers. + */ + unsigned int __init pci_init_via82cxxx(struct pci_dev *dev, const char *name) { struct pci_dev *isa = NULL; - unsigned char f, t, m; - unsigned int u, i; + unsigned char t, v; + unsigned int u; + int i; /* - * Find ISA bridge to see how good the IDE is. + * Find the ISA bridge to see how good the IDE is. */ - for (via_config = 0; via_isa_bridges[via_config].id; via_config++) - if ((isa = pci_find_device(PCI_VENDOR_ID_VIA, via_isa_bridges[via_config].id, NULL))) - break; -/* - * Read revision. - */ - - if (via_isa_bridges[via_config].id == PCI_DEVICE_ID_VIA_82C586_0) { - pci_read_config_byte(isa, PCI_REVISION_ID, &t); - if (t < 0x30) via_config++; /* vt82c586a */ - if (t < 0x20) via_config++; /* vt82c586 */ - } + for (via_config = via_isa_bridges; via_config->id; via_config++) + if ((isa = pci_find_device(PCI_VENDOR_ID_VIA, via_config->id, NULL))) { + pci_read_config_byte(isa, PCI_REVISION_ID, &t); + if (t >= via_config->rev_min && t <= via_config->rev_max) + break; + } - if (via_isa_bridges[via_config].id == PCI_DEVICE_ID_VIA_82C596) { - pci_read_config_byte(isa, PCI_REVISION_ID, &t); - if (t < 0x10) via_config++; /* vt82c596a */ + if (!via_config->id) { + printk(KERN_WARNING "VP_IDE: Unknown VIA SouthBridge, contact Vojtech Pavlik <vojtech@suse.cz>\n"); + return -ENODEV; } /* - * Check UDMA66 mode set by BIOS. + * Check 80-wire cable presence and setup Clk66. */ - pci_read_config_dword(dev, VIA_UDMA_TIMING, &u); + switch (via_config->flags & VIA_UDMA) { - for (i = 0; i < 4; i++) { - pci_read_config_byte(dev, VIA_UDMA_TIMING + (3 - i), &t); - if ((u & (0x80000 >> ((i >> 1) << 4))) && ((t & 7) < 2)) via_ata66 |= (1 << (i >> 1)); - } + case VIA_UDMA_100: -#ifdef DEBUG - printk(KERN_DEBUG "VP_IDE: BIOS enabled ATA66: primary: %s, secondary: %s\n", - via_ata66 & 1 ? "yes" : "no", via_ata66 & 2 ? "yes" : "no"); -#endif + pci_read_config_dword(dev, VIA_UDMA_TIMING, &u); + for (i = 24; i >= 0; i -= 8) + if (((u >> i) & 0x10) || (((u >> i) & 0x20) && (((u >> i) & 7) < 3))) + via_80w |= (1 << (1 - (i >> 4))); /* BIOS 80-wire bit or UDMA w/ < 50ns/cycle */ + break; + + case VIA_UDMA_66: + + pci_read_config_dword(dev, VIA_UDMA_TIMING, &u); /* Enable Clk66 */ + pci_write_config_dword(dev, VIA_UDMA_TIMING, u | 0x80008); + for (i = 24; i >= 0; i -= 8) + if (((u >> (i & 16)) & 8) && ((u >> i) & 0x20) && (((u >> i) & 7) < 2)) + via_80w |= (1 << (1 - (i >> 4))); /* 2x PCI clock and UDMA w/ < 3T/cycle */ + break; + } + + if (via_config->flags & VIA_BAD_CLK66) { /* Disable Clk66 */ + pci_read_config_dword(dev, VIA_UDMA_TIMING, &u); /* Would cause trouble on 596a */ + pci_write_config_dword(dev, VIA_UDMA_TIMING, u & ~0x80008); + } /* - * Set UDMA66 double clock bits. + * Check whether interfaces are enabled. */ - if (via_isa_bridges[via_config].speed == XFER_UDMA_4) - pci_write_config_dword(dev, VIA_UDMA_TIMING, u | 0x80008); + + pci_read_config_byte(dev, VIA_IDE_ENABLE, &v); + via_enabled = ((v & 1) ? 2 : 0) | ((v & 2) ? 1 : 0); /* - * Set up FIFO, flush, prefetch and post-writes. + * Set up FIFO sizes and thresholds. */ - pci_read_config_dword(dev, VIA_IDE_ENABLE, &u); - pci_read_config_byte(dev, VIA_FIFO_CONFIG, &f); - pci_read_config_byte(dev, VIA_IDE_CONFIG, &t); - pci_read_config_byte(dev, VIA_MISC_3, &m); + pci_read_config_byte(dev, VIA_FIFO_CONFIG, &t); - f &= 0x90; t &= 0x0f; m &= 0x0f; + if (via_config->flags & VIA_BAD_PREQ) /* Disable PREQ# till DDACK# */ + t &= 0x7f; /* Would crash on 586b rev 41 */ - switch (u & 3) { - case 2: via_enabled = 1; f |= 0x06; t |= 0xc0; m |= 0xa0; break; /* primary only, 3/4 */ - case 1: via_enabled = 2; f |= 0x69; t |= 0x30; m |= 0x50; break; /* secondary only, 3/4 */ - case 3: via_enabled = 3; - default: f |= 0x2a; t |= 0xf0; m |= 0xf0; break; /* fifo evenly distributed */ + if (via_config->flags & VIA_SET_FIFO) { /* Fix FIFO split between channels */ + t &= (t & 0x9f); + switch (via_enabled) { + case 1: t |= 0x00; break; /* 16 on primary */ + case 2: t |= 0x60; break; /* 16 on secondary */ + case 3: t |= 0x20; break; /* 8 pri 8 sec */ + } } - via_write_config_byte(dev, VIA_FIFO_CONFIG, f); - via_write_config_byte(dev, VIA_IDE_CONFIG, t); - via_write_config_byte(dev, VIA_MISC_3, m); + if (via_config->flags & VIA_SET_THRESH) /* 1/2 FIFO full to trigger xmit */ + t = (t & 0xf0) | 0x0a; + + pci_write_config_byte(dev, VIA_FIFO_CONFIG, t); + +/* + * Determine system bus clock. + */ + + via_clock = system_bus_clock(); + if (via_clock < 20 || via_clock > 50) { + printk(KERN_WARNING "VP_IDE: User given PCI clock speed impossible (%d), using 33 MHz instead.\n", via_clock); + printk(KERN_WARNING "VP_IDE: Use ide0=ata66 if you want to force UDMA66/UDMA100.\n"); + via_clock = 33; + } /* * Print the boot message. */ - printk(KERN_INFO "VP_IDE: VIA %s IDE %s controller on pci%d:%d.%d\n", - via_isa_bridges[via_config].name, - via_isa_bridges[via_config].speed >= XFER_UDMA_4 ? "UDMA66" : - via_isa_bridges[via_config].speed >= XFER_UDMA_2 ? "UDMA33" : "MWDMA16", - dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); + pci_read_config_byte(isa, PCI_REVISION_ID, &t); + printk(KERN_INFO "VP_IDE: VIA %s (rev %02x) IDE %s controller on pci%s\n", + via_config->name, t, + (via_config->flags & VIA_UDMA) == VIA_UDMA_100 ? "UDMA100" : + (via_config->flags & VIA_UDMA) == VIA_UDMA_66 ? "UDMA66" : + (via_config->flags & VIA_UDMA) == VIA_UDMA_33 ? "UDMA33" : "MWDMA16", + dev->slot_name); + /* - * Register /proc/ide/via entry + * Setup /proc/ide/via entry. */ -#if defined(CONFIG_PROC_FS) +#ifdef CONFIG_PROC_FS if (!via_proc) { via_proc = 1; + via_base = pci_resource_start(dev, 4); bmide_dev = dev; isa_dev = isa; via_display_info = &via_get_info; @@ -579,26 +482,26 @@ unsigned int __init pci_init_via82cxxx(struct pci_dev *dev, const char *name) return 0; } -/* - * Since we don't have a way to detect the 80-wire ribbon cable - * we rely on the BIOS detection. We also check the IDENTIFY byte - * 93 to check the drive's point of view. I think we could return - * '1' here - */ - unsigned int __init ata66_via82cxxx(ide_hwif_t *hwif) { - return ((via_enabled & via_ata66) >> hwif->channel) & 1; + return ((via_enabled & via_80w) >> hwif->channel) & 1; } void __init ide_init_via82cxxx(ide_hwif_t *hwif) { + int i; + hwif->tuneproc = &via82cxxx_tune_drive; - hwif->speedproc = &via_set_speed; - hwif->drives[0].autotune = 1; - hwif->drives[1].autotune = 1; + hwif->speedproc = &via_set_drive; hwif->autodma = 0; + for (i = 0; i < 2; i++) { + hwif->drives[i].io_32bit = 1; + hwif->drives[i].unmask = 1; + hwif->drives[i].autotune = 1; + hwif->drives[i].dn = hwif->channel * 2 + i; + } + #ifdef CONFIG_BLK_DEV_IDEDMA if (hwif->dma_base) { hwif->dmaproc = &via82cxxx_dmaproc; @@ -610,7 +513,7 @@ void __init ide_init_via82cxxx(ide_hwif_t *hwif) } /* - * We allow the BM-DMA driver only work on enabled interfaces. + * We allow the BM-DMA driver to only work on enabled interfaces. */ void __init ide_dmacapable_via82cxxx(ide_hwif_t *hwif, unsigned long dmabase) |