Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1880a8d7 authored by Bartlomiej Zolnierkiewicz's avatar Bartlomiej Zolnierkiewicz
Browse files

serverworks: always tune PIO



* Always set ->autotune so PIO gets correctly auto-tuned (previously
  ->autotune was only set when ->dma_base wasn't available, however
  ->ide_dma_check()/->speedproc() was always trying to tune PIO when
  tuning DMA).

* Move code responsible for programming chipset for PIO mode from
  svwks_tune_chipset() to svwks_tune_pio().  Don't tune PIO when tuning
  DMA (this is no longer needed since ->autotune is always set now).

* Handle PIO modes early in svwks_tune_chipset() so DMA configuration
  registers don't get cleared when programming PIO mode.

* Bump driver version.

Signed-off-by: default avatarBartlomiej Zolnierkiewicz <bzolnier@gmail.com>
parent a5d8c5c8
Loading
Loading
Loading
Loading
+36 −40
Original line number Diff line number Diff line
/*
 * linux/drivers/ide/pci/serverworks.c		Version 0.20	Jun 3 2007
 * linux/drivers/ide/pci/serverworks.c		Version 0.21	Jun 16 2007
 *
 * Copyright (C) 1998-2000 Michel Aubry
 * Copyright (C) 1998-2000 Andrzej Krzysztofowicz
@@ -123,23 +123,45 @@ static u8 svwks_csb_check (struct pci_dev *dev)
	}
	return 0;
}

static void svwks_tune_pio(ide_drive_t *drive, const u8 pio)
{
	static const u8 pio_modes[] = { 0x5d, 0x47, 0x34, 0x22, 0x20 };
	static const u8 drive_pci[] = { 0x41, 0x40, 0x43, 0x42 };

	struct pci_dev *dev = drive->hwif->pci_dev;

	pci_write_config_byte(dev, drive_pci[drive->dn], pio_modes[pio]);

	if (svwks_csb_check(dev)) {
		u16 csb_pio = 0;

		pci_read_config_word(dev, 0x4a, &csb_pio);

		csb_pio &= ~(0x0f << (4 * drive->dn));
		csb_pio |= (pio << (4 * drive->dn));

		pci_write_config_word(dev, 0x4a, csb_pio);
	}
}

static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed)
{
	static const u8 udma_modes[]		= { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
	static const u8 dma_modes[]		= { 0x77, 0x21, 0x20 };
	static const u8 pio_modes[]		= { 0x5d, 0x47, 0x34, 0x22, 0x20 };
	static const u8 drive_pci[]		= { 0x41, 0x40, 0x43, 0x42 };
	static const u8 drive_pci2[]		= { 0x45, 0x44, 0x47, 0x46 };

	ide_hwif_t *hwif	= HWIF(drive);
	struct pci_dev *dev	= hwif->pci_dev;
	u8 speed		= ide_rate_filter(drive, xferspeed);
	u8 pio			= ide_get_best_pio_mode(drive, 255, 4, NULL);
	u8 unit			= (drive->select.b.unit & 0x01);
	u8 csb5			= svwks_csb_check(dev);
	u8 ultra_enable		= 0, ultra_timing = 0;
	u8 dma_timing		= 0, pio_timing = 0;
	u16 csb5_pio		= 0;

	u8 ultra_enable	 = 0, ultra_timing = 0, dma_timing = 0;

	if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) {
		svwks_tune_pio(drive, speed - XFER_PIO_0);
		return ide_config_drive_speed(drive, speed);
	}

	/* If we are about to put a disk into UDMA mode we screwed up.
	   Our code assumes we never _ever_ do this on an OSB4 */
@@ -149,31 +171,15 @@ static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed)
			BUG();

	pci_read_config_byte(dev, (0x56|hwif->channel), &ultra_timing);
	pci_read_config_word(dev, 0x4A, &csb5_pio);
	pci_read_config_byte(dev, 0x54, &ultra_enable);

	ultra_timing	&= ~(0x0F << (4*unit));
	ultra_enable	&= ~(0x01 << drive->dn);
	csb5_pio	&= ~(0x0F << (4*drive->dn));

	switch(speed) {
		case XFER_PIO_4:
		case XFER_PIO_3:
		case XFER_PIO_2:
		case XFER_PIO_1:
		case XFER_PIO_0:
			pio_timing |= pio_modes[speed - XFER_PIO_0];
			csb5_pio   |= ((speed - XFER_PIO_0) << (4*drive->dn));
			break;

		case XFER_MW_DMA_2:
		case XFER_MW_DMA_1:
		case XFER_MW_DMA_0:
			/*
			 * TODO: always setup PIO mode so this won't be needed
			 */
			pio_timing |= pio_modes[pio];
			csb5_pio   |= (pio << (4*drive->dn));
			dma_timing |= dma_modes[speed - XFER_MW_DMA_0];
			break;

@@ -183,11 +189,6 @@ static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed)
		case XFER_UDMA_2:
		case XFER_UDMA_1:
		case XFER_UDMA_0:
			/*
			 * TODO: always setup PIO mode so this won't be needed
			 */
			pio_timing   |= pio_modes[pio];
			csb5_pio     |= (pio << (4*drive->dn));
			dma_timing   |= dma_modes[2];
			ultra_timing |= ((udma_modes[speed - XFER_UDMA_0]) << (4*unit));
			ultra_enable |= (0x01 << drive->dn);
@@ -195,10 +196,6 @@ static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed)
			break;
	}

	pci_write_config_byte(dev, drive_pci[drive->dn], pio_timing);
	if (csb5)
		pci_write_config_word(dev, 0x4A, csb5_pio);

	pci_write_config_byte(dev, drive_pci2[drive->dn], dma_timing);
	pci_write_config_byte(dev, (0x56|hwif->channel), ultra_timing);
	pci_write_config_byte(dev, 0x54, ultra_enable);
@@ -209,7 +206,8 @@ static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed)
static void svwks_tune_drive (ide_drive_t *drive, u8 pio)
{
	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
	(void)svwks_tune_chipset(drive, XFER_PIO_0 + pio);
	svwks_tune_pio(drive, pio);
	(void)ide_config_drive_speed(drive, XFER_PIO_0 + pio);
}

static int svwks_config_drive_xfer_rate (ide_drive_t *drive)
@@ -407,11 +405,11 @@ static void __devinit init_hwif_svwks (ide_hwif_t *hwif)

	hwif->autodma = 0;

	if (!hwif->dma_base) {
	hwif->drives[0].autotune = 1;
	hwif->drives[1].autotune = 1;

	if (!hwif->dma_base)
		return;
	}

	hwif->ide_dma_check = &svwks_config_drive_xfer_rate;
	if (hwif->pci_dev->device != PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
@@ -424,8 +422,6 @@ static void __devinit init_hwif_svwks (ide_hwif_t *hwif)
	dma_stat = inb(hwif->dma_status);
	hwif->drives[0].autodma = (dma_stat & 0x20);
	hwif->drives[1].autodma = (dma_stat & 0x40);
	hwif->drives[0].autotune = (!(dma_stat & 0x20));
	hwif->drives[1].autotune = (!(dma_stat & 0x40));
}

static int __devinit init_setup_svwks (struct pci_dev *dev, ide_pci_device_t *d)