X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fide%2Fpci%2Fpiix.c;h=c5ec6f1990433c04a1d646e2c7c157c89f98187f;hb=refs%2Fheads%2Fvserver;hp=e9b83e1a30287adf49475ab729b95c7b3d4c380c;hpb=76828883507a47dae78837ab5dec5a5b4513c667;p=linux-2.6.git diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c index e9b83e1a3..c5ec6f199 100644 --- a/drivers/ide/pci/piix.c +++ b/drivers/ide/pci/piix.c @@ -1,13 +1,14 @@ /* - * linux/drivers/ide/pci/piix.c Version 0.44 March 20, 2003 + * linux/drivers/ide/pci/piix.c Version 0.45 May 12, 2006 * * Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer * Copyright (C) 1998-2000 Andre Hedrick * Copyright (C) 2003 Red Hat Inc + * Copyright (C) 2006 MontaVista Software, Inc. * * May be copied or modified under the terms of the GNU General Public License * - * PIO mode setting function for Intel chipsets. + * PIO mode setting function for Intel chipsets. * For use instead of BIOS settings. * * 40-41 @@ -25,7 +26,7 @@ * sitre = word42 & 0x4000; secondary * * 44 8421|8421 hdd|hdb - * + * * 48 8421 hdd|hdc|hdb|hda udma enabled * * 0001 hda @@ -90,7 +91,6 @@ * ICH3 errata #18 - Don't use native mode */ -#include #include #include #include @@ -222,35 +222,56 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio) unsigned long flags; u16 master_data; u8 slave_data; + static DEFINE_SPINLOCK(tune_lock); + int control = 0; + /* ISP RTC */ - u8 timings[][2] = { { 0, 0 }, - { 0, 0 }, - { 1, 0 }, - { 2, 1 }, - { 2, 3 }, }; + static const u8 timings[][2]= { + { 0, 0 }, + { 0, 0 }, + { 1, 0 }, + { 2, 1 }, + { 2, 3 }, }; pio = ide_get_best_pio_mode(drive, pio, 5, NULL); - spin_lock_irqsave(&ide_lock, flags); + + /* + * Master vs slave is synchronized above us but the slave register is + * shared by the two hwifs so the corner case of two slave timeouts in + * parallel must be locked. + */ + spin_lock_irqsave(&tune_lock, flags); pci_read_config_word(dev, master_port, &master_data); + + if (pio >= 2) + control |= 1; /* Programmable timing on */ + if (drive->media == ide_disk) + control |= 4; /* Prefetch, post write */ + if (pio >= 3) + control |= 2; /* IORDY */ if (is_slave) { master_data = master_data | 0x4000; - if (pio > 1) + if (pio > 1) { /* enable PPE, IE and TIME */ - master_data = master_data | 0x0070; + master_data = master_data | (control << 4); + } else { + master_data &= ~0x0070; + } pci_read_config_byte(dev, slave_port, &slave_data); slave_data = slave_data & (hwif->channel ? 0x0f : 0xf0); slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) << (hwif->channel ? 4 : 0)); } else { master_data = master_data & 0xccf8; - if (pio > 1) + if (pio > 1) { /* enable PPE, IE and TIME */ - master_data = master_data | 0x0007; + master_data = master_data | control; + } master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8); } pci_write_config_word(dev, master_port, master_data); if (is_slave) pci_write_config_byte(dev, slave_port, slave_data); - spin_unlock_irqrestore(&ide_lock, flags); + spin_unlock_irqrestore(&tune_lock, flags); } /** @@ -332,57 +353,25 @@ static int piix_tune_chipset (ide_drive_t *drive, u8 xferspeed) return (ide_config_drive_speed(drive, speed)); } -/** - * piix_faulty_dma0 - check for DMA0 errata - * @hwif: IDE interface to check - * - * If an ICH/ICH0/ICH2 interface is is operating in multi-word - * DMA mode with 600nS cycle time the IDE PIO prefetch buffer will - * inadvertently provide an extra piece of secondary data to the primary - * device resulting in data corruption. - * - * With such a device this test function returns true. This allows - * our tuning code to follow Intel recommendations and use PIO on - * such devices. - */ - -static int piix_faulty_dma0(ide_hwif_t *hwif) -{ - switch(hwif->pci_dev->device) - { - case PCI_DEVICE_ID_INTEL_82801AA_1: /* ICH */ - case PCI_DEVICE_ID_INTEL_82801AB_1: /* ICH0 */ - case PCI_DEVICE_ID_INTEL_82801BA_8: /* ICH2 */ - case PCI_DEVICE_ID_INTEL_82801BA_9: /* ICH2 */ - return 1; - } - return 0; -} - /** * piix_config_drive_for_dma - configure drive for DMA * @drive: IDE drive to configure * * Set up a PIIX interface channel for the best available speed. - * We prefer UDMA if it is available and then MWDMA. If DMA is - * not available we switch to PIO and return 0. + * We prefer UDMA if it is available and then MWDMA. If DMA is + * not available we switch to PIO and return 0. */ static int piix_config_drive_for_dma (ide_drive_t *drive) { u8 speed = ide_dma_speed(drive, piix_ratemask(drive)); - - /* Some ICH devices cannot support DMA mode 0 */ - if(speed == XFER_MW_DMA_0 && piix_faulty_dma0(HWIF(drive))) - speed = 0; - - /* If no DMA speed was available or the chipset has DMA bugs - then disable DMA and use PIO */ - - if (!speed || no_piix_dma) { - u8 tspeed = ide_get_best_pio_mode(drive, 255, 5, NULL); - speed = piix_dma_2_pio(XFER_PIO_0 + tspeed); - } + + /* + * If no DMA speed was available or the chipset has DMA bugs + * then disable DMA and use PIO + */ + if (!speed || no_piix_dma) + return 0; (void) piix_tune_chipset(drive, speed); return ide_dma_enable(drive); @@ -405,17 +394,16 @@ static int piix_config_drive_xfer_rate (ide_drive_t *drive) if ((id->capability & 1) && drive->autodma) { - if (ide_use_dma(drive)) { - if (piix_config_drive_for_dma(drive)) - return hwif->ide_dma_on(drive); - } + if (ide_use_dma(drive) && piix_config_drive_for_dma(drive)) + return hwif->ide_dma_on(drive); goto fast_ata_pio; } else if ((id->capability & 8) || (id->field_valid & 2)) { fast_ata_pio: /* Find best PIO mode. */ - hwif->tuneproc(drive, 255); + (void) hwif->speedproc(drive, XFER_PIO_0 + + ide_get_best_pio_mode(drive, 255, 4, NULL)); return hwif->ide_dma_off_quietly(drive); } /* IORDY not supported */ @@ -423,17 +411,14 @@ fast_ata_pio: } /** - * init_chipset_piix - set up the PIIX chipset - * @dev: PCI device to set up - * @name: Name of the device + * piix_is_ichx - check if ICHx + * @dev: PCI device to check * - * Initialize the PCI device as required. For the PIIX this turns - * out to be nice and simple + * returns 1 if ICHx, 0 otherwise. */ - -static unsigned int __devinit init_chipset_piix (struct pci_dev *dev, const char *name) +static int piix_is_ichx(struct pci_dev *dev) { - switch(dev->device) { + switch (dev->device) { case PCI_DEVICE_ID_INTEL_82801EB_1: case PCI_DEVICE_ID_INTEL_82801AA_1: case PCI_DEVICE_ID_INTEL_82801AB_1: @@ -451,18 +436,50 @@ static unsigned int __devinit init_chipset_piix (struct pci_dev *dev, const char case PCI_DEVICE_ID_INTEL_ICH7_21: case PCI_DEVICE_ID_INTEL_ESB2_18: case PCI_DEVICE_ID_INTEL_ICH8_6: - { - unsigned int extra = 0; - pci_read_config_dword(dev, 0x54, &extra); - pci_write_config_dword(dev, 0x54, extra|0x400); - } - default: - break; + return 1; } return 0; } +/** + * init_chipset_piix - set up the PIIX chipset + * @dev: PCI device to set up + * @name: Name of the device + * + * Initialize the PCI device as required. For the PIIX this turns + * out to be nice and simple + */ + +static unsigned int __devinit init_chipset_piix (struct pci_dev *dev, const char *name) +{ + if (piix_is_ichx(dev)) { + unsigned int extra = 0; + pci_read_config_dword(dev, 0x54, &extra); + pci_write_config_dword(dev, 0x54, extra|0x400); + } + + return 0; +} + +/** + * piix_dma_clear_irq - clear BMDMA status + * @drive: IDE drive to clear + * + * Called from ide_intr() for PIO interrupts + * to clear BMDMA status as needed by ICHx + */ +static void piix_dma_clear_irq(ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + u8 dma_stat; + + /* clear the INTR & ERROR bits */ + dma_stat = hwif->INB(hwif->dma_status); + /* Should we force the bit as well ? */ + hwif->OUTB(dma_stat, hwif->dma_status); +} + /** * init_hwif_piix - fill in the hwif for the PIIX * @hwif: IDE interface @@ -495,6 +512,10 @@ static void __devinit init_hwif_piix(ide_hwif_t *hwif) if (!hwif->dma_base) return; + /* ICHx need to clear the bmdma status for all interrupts */ + if (piix_is_ichx(hwif->pci_dev)) + hwif->ide_dma_clear_irq = &piix_dma_clear_irq; + hwif->atapi_dma = 1; hwif->ultra_mask = 0x3f; hwif->mwdma_mask = 0x06; @@ -608,7 +629,7 @@ static void __devinit piix_check_450nx(void) struct pci_dev *pdev = NULL; u16 cfg; u8 rev; - while((pdev=pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, pdev))!=NULL) + while((pdev=pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, pdev))!=NULL) { /* Look for 450NX PXB. Check for problem configurations A PCI quirk checks bit 6 already */