Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
Bug 109358 - nForce4 with poor SATA performance and 16 bit compatibility emulation in kernel SATA and IDE driver on AMD64
Summary: nForce4 with poor SATA performance and 16 bit compatibility emulation in kern...
Status: RESOLVED FIXED
Alias: None
Product: Gentoo Linux
Classification: Unclassified
Component: [OLD] Core system (show other bugs)
Hardware: AMD64 Linux
: High enhancement (vote)
Assignee: Gentoo Kernel Bug Wranglers and Kernel Maintainers
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2005-10-15 05:21 UTC by Georg Sahli
Modified: 2005-10-29 11:22 UTC (History)
0 users

See Also:
Package list:
Runtime testing required: ---


Attachments
dmesg output for nforce4 SATA chipset CK804 (dmesg_2.6.14-rc5.txt,20.72 KB, text/plain)
2005-10-26 06:10 UTC, Georg Sahli
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Georg Sahli 2005-10-15 05:21:55 UTC
Many nForce4 and some nForce3 chipsets do run their SATA and IDE drivers in 16
bit compatibility mode, we're unable to use DMA, which results in related
systems poor performance.

The problem first was reported by a different person in our "Kernel & Hardware"
Forum. And I did add me there.

Personally I discovered a workaround in a kernel driver, which is described at
an AMD bugs page.
For myself it works better but not perfect.
My Gentoo forums account is UTgamer.
This is our thread where we did report and compared readings:
http://forums.gentoo.org/viewtopic-p-2767330.html#2767330

This is the related nVidia bugs page 
(caption "Older distributions missing nForce3/4 storage controller device IDs"):
http://download.nvidia.com/XFree86/nforce/1.0-0301/KnownProblems.html

From this page I did get the "how to" to resolve it:
http://www.thisishull.net/showthread.php?t=3734

To specify it correctly, SATA is in 16 bit compatibility mode and for my new MSI
nForce4 board I have now chance without a patch to switch back to the DMA
activated IDE driver.

This is my new nForce4 board (all components do work at least):
http://www.msi-technology.de/produkte/main_idx_view.php?Prod_id=466

The IDE/SATA chipset is:
IDE interface: nVidia Corporation CK804 IDE (rev f2)
IDE interface: nVidia Corporation CK804 Serial ATA Controller (rev f3)
IDE interface: nVidia Corporation CK804 Serial ATA Controller (rev f3) 

The related driver in Kernel is to find here:
/usr/src/linux-2.6.13-gentoo-r*/drivers/ide/pci/amd74xx.c

When I use this patch my system will have a 32 bit driver with DMA activated, on
my 64 bit HW.


Here is my working solution:
===========================================================================
/*
 * Version 2.13
 *
 * AMD 755/756/766/8111 and nVidia nForce/2/2s/3/3s/CK804/MCP04
 * IDE driver for Linux.
 *
 * Copyright (c) 2000-2002 Vojtech Pavlik
 *
 * Based on the work of:
 *      Andre Hedrick
 */

/*
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published by
 * the Free Software Foundation.
 */

#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <linux/blkdev.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/ide.h>
#include <asm/io.h>

#include "ide-timing.h"

#define DISPLAY_AMD_TIMINGS

#define AMD_IDE_ENABLE		(0x00 + amd_config->base)
#define AMD_IDE_CONFIG		(0x01 + amd_config->base)
#define AMD_CABLE_DETECT	(0x02 + amd_config->base)
#define AMD_DRIVE_TIMING	(0x08 + amd_config->base)
#define AMD_8BIT_TIMING		(0x0e + amd_config->base)
#define AMD_ADDRESS_SETUP	(0x0c + amd_config->base)
#define AMD_UDMA_TIMING		(0x10 + amd_config->base)

#define AMD_UDMA		0x07
#define AMD_UDMA_33		0x01
#define AMD_UDMA_66		0x02
#define AMD_UDMA_100		0x03
#define AMD_UDMA_133		0x04
#define AMD_CHECK_SWDMA		0x08
#define AMD_BAD_SWDMA		0x10
#define AMD_BAD_FIFO		0x20
#define AMD_CHECK_SERENADE	0x40


#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE 0x0035
#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA 0x0036
#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2 0x003e
#define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE 0x0053
#define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA 0x0054
#define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2 0x0055

/*
 * AMD SouthBridge chips.
 */

static struct amd_ide_chip {
	unsigned short id;
	unsigned long base;
	unsigned char flags;
} amd_ide_chips[] = {
	{ PCI_DEVICE_ID_AMD_COBRA_7401,		0x40, AMD_UDMA_33 | AMD_BAD_SWDMA },
	{ PCI_DEVICE_ID_AMD_VIPER_7409,		0x40, AMD_UDMA_66 | AMD_CHECK_SWDMA },
	{ PCI_DEVICE_ID_AMD_VIPER_7411,		0x40, AMD_UDMA_100 | AMD_BAD_FIFO },
	{ PCI_DEVICE_ID_AMD_OPUS_7441,		0x40, AMD_UDMA_100 },
	{ PCI_DEVICE_ID_AMD_8111_IDE,		0x40, AMD_UDMA_133 | AMD_CHECK_SERENADE },
	{ PCI_DEVICE_ID_NVIDIA_NFORCE_IDE,	0x50, AMD_UDMA_100 },
	{ PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE,	0x50, AMD_UDMA_133 },
	{ PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE,	0x50, AMD_UDMA_133 },
	{ PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA,	0x50, AMD_UDMA_133 },
	{ PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE,	0x50, AMD_UDMA_133 },
	{ PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE,	0x50, AMD_UDMA_133 },
	{ PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA,	0x50, AMD_UDMA_133 },
	{ PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2,	0x50, AMD_UDMA_133 },
	{ PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE, 0x50, AMD_UDMA_133 },
	{ PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA, 0x50, AMD_UDMA_133 },
	{ PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2, 0x50, AMD_UDMA_133 },
	{ PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, 0x50, AMD_UDMA_133 },
	{ PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA, 0x50, AMD_UDMA_133 },
	{ PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2, 0x50, AMD_UDMA_133 },
	{ 0 }
};

static struct amd_ide_chip *amd_config;
static ide_pci_device_t *amd_chipset;
static unsigned int amd_80w;
static unsigned int amd_clock;

static char *amd_dma[] = { "MWDMA16", "UDMA33", "UDMA66", "UDMA100", "UDMA133" };
static unsigned char amd_cyc2udma[] = { 6, 6, 5, 4, 0, 1, 1, 2, 2, 3, 3, 3, 3,
3, 3, 7 };

/*
 * AMD /proc entry.
 */

#ifdef CONFIG_PROC_FS

#include <linux/stat.h>
#include <linux/proc_fs.h>

static u8 amd74xx_proc;

static unsigned char amd_udma2cyc[] = { 4, 6, 8, 10, 3, 2, 1, 15 };
static unsigned long amd_base;
static struct pci_dev *bmide_dev;
extern int (*amd74xx_display_info)(char *, char **, off_t, int); /* ide-proc.c */

#define amd_print(format, arg...) p += sprintf(p, format "\n" , ## arg)
#define amd_print_drive(name, format, arg...)\
	p += sprintf(p, name); for (i = 0; i < 4; i++) p += sprintf(p, format, ## arg);
p += sprintf(p, "\n");

static int amd74xx_get_info(char *buffer, char **addr, off_t offset, int count)
{
	int speed[4], cycle[4], setup[4], active[4], recover[4], den[4],
		 uen[4], udma[4], active8b[4], recover8b[4];
	struct pci_dev *dev = bmide_dev;
	unsigned int v, u, i;
	unsigned short c, w;
	unsigned char t;
	int len;
	char *p = buffer;

	amd_print("----------AMD BusMastering IDE Configuration----------------");

	amd_print("Driver Version:                     2.13");
	amd_print("South Bridge:                       %s", pci_name(bmide_dev));

	pci_read_config_byte(dev, PCI_REVISION_ID, &t);
	amd_print("Revision:                           IDE %#x", t);
	amd_print("Highest DMA rate:                   %s", amd_dma[amd_config->flags &
AMD_UDMA]);

	amd_print("BM-DMA base:                        %#lx", amd_base);
	amd_print("PCI clock:                          %d.%dMHz", amd_clock / 1000,
amd_clock / 100 % 10);
	
	amd_print("-----------------------Primary IDE-------Secondary IDE------");

	pci_read_config_byte(dev, AMD_IDE_CONFIG, &t);
	amd_print("Prefetch Buffer:       %10s%20s", (t & 0x80) ? "yes" : "no", (t &
0x20) ? "yes" : "no");
	amd_print("Post Write Buffer:     %10s%20s", (t & 0x40) ? "yes" : "no", (t &
0x10) ? "yes" : "no");

	pci_read_config_byte(dev, AMD_IDE_ENABLE, &t);
	amd_print("Enabled:               %10s%20s", (t & 0x02) ? "yes" : "no", (t &
0x01) ? "yes" : "no");

	c = inb(amd_base + 0x02) | (inb(amd_base + 0x0a) << 8);
	amd_print("Simplex only:          %10s%20s", (c & 0x80) ? "yes" : "no", (c &
0x8000) ? "yes" : "no");

	amd_print("Cable Type:            %10s%20s", (amd_80w & 1) ? "80w" : "40w",
(amd_80w & 2) ? "80w" : "40w");

	if (!amd_clock)
                return p - buffer;

	amd_print("-------------------drive0----drive1----drive2----drive3-----");

	pci_read_config_byte(dev, AMD_ADDRESS_SETUP, &t);
	pci_read_config_dword(dev, AMD_DRIVE_TIMING, &v);
	pci_read_config_word(dev, AMD_8BIT_TIMING, &w);
	pci_read_config_dword(dev, AMD_UDMA_TIMING, &u);

	for (i = 0; i < 4; 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] = amd_udma2cyc[((u >> ((3 - i) << 3)) & 0x7)];
		uen[i]  = ((u >> ((3 - i) << 3)) & 0x40) ? 1 : 0;
		den[i]  = (c & ((i & 1) ? 0x40 : 0x20) << ((i & 2) << 2));

		if (den[i] && uen[i] && udma[i] == 1) {
			speed[i] = amd_clock * 3;
			cycle[i] = 666666 / amd_clock;
			continue;
		}

		if (den[i] && uen[i] && udma[i] == 15) {
			speed[i] = amd_clock * 4;
			cycle[i] = 500000 / amd_clock;
			continue;
		}

		speed[i] = 4 * amd_clock / ((den[i] && uen[i]) ? udma[i] : (active[i] +
recover[i]) * 2);
		cycle[i] = 1000000 * ((den[i] && uen[i]) ? udma[i] : (active[i] + recover[i])
* 2) / amd_clock / 2;
	}

	amd_print_drive("Transfer Mode: ", "%10s", den[i] ? (uen[i] ? "UDMA" : "DMA") :
"PIO");

	amd_print_drive("Address Setup: ", "%8dns", 1000000 * setup[i] / amd_clock);
	amd_print_drive("Cmd Active:    ", "%8dns", 1000000 * active8b[i] / amd_clock);
	amd_print_drive("Cmd Recovery:  ", "%8dns", 1000000 * recover8b[i] / amd_clock);
	amd_print_drive("Data Active:   ", "%8dns", 1000000 * active[i] / amd_clock);
	amd_print_drive("Data Recovery: ", "%8dns", 1000000 * recover[i] / amd_clock);
	amd_print_drive("Cycle Time:    ", "%8dns", cycle[i]);
	amd_print_drive("Transfer Rate: ", "%4d.%dMB/s", speed[i] / 1000, speed[i] /
100 % 10);

	/* hoping p - buffer is less than 4K... */
	len = (p - buffer) - offset;
	*addr = buffer + offset;
	
	return len > count ? count : len;
}

#endif

/*
 * amd_set_speed() writes timing values to the chipset registers
 */

static void amd_set_speed(struct pci_dev *dev, unsigned char dn, struct
ide_timing *timing)
{
	unsigned char t;

	pci_read_config_byte(dev, AMD_ADDRESS_SETUP, &t);
	t = (t & ~(3 << ((3 - dn) << 1))) | ((FIT(timing->setup, 1, 4) - 1) << ((3 -
dn) << 1));
	pci_write_config_byte(dev, AMD_ADDRESS_SETUP, t);

	pci_write_config_byte(dev, AMD_8BIT_TIMING + (1 - (dn >> 1)),
		((FIT(timing->act8b, 1, 16) - 1) << 4) | (FIT(timing->rec8b, 1, 16) - 1));

	pci_write_config_byte(dev, AMD_DRIVE_TIMING + (3 - dn),
		((FIT(timing->active, 1, 16) - 1) << 4) | (FIT(timing->recover, 1, 16) - 1));

	switch (amd_config->flags & AMD_UDMA) {
		case AMD_UDMA_33:  t = timing->udma ? (0xc0 | (FIT(timing->udma, 2, 5) - 2)) :
0x03; break;
		case AMD_UDMA_66:  t = timing->udma ? (0xc0 | amd_cyc2udma[FIT(timing->udma,
2, 10)]) : 0x03; break;
		case AMD_UDMA_100: t = timing->udma ? (0xc0 | amd_cyc2udma[FIT(timing->udma,
1, 10)]) : 0x03; break;
		case AMD_UDMA_133: t = timing->udma ? (0xc0 | amd_cyc2udma[FIT(timing->udma,
1, 15)]) : 0x03; break;
		default: return;
	}

	pci_write_config_byte(dev, AMD_UDMA_TIMING + (3 - dn), t);
}

/*
 * amd_set_drive() computes timing values configures the drive and
 * the chipset to a desired transfer mode. It also can be called
 * by upper layers.
 */

static int amd_set_drive(ide_drive_t *drive, u8 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 = 1000000000 / amd_clock;
	UT = T / min_t(int, max_t(int, amd_config->flags & AMD_UDMA, 1), 2);

	ide_timing_compute(drive, speed, &t, T, UT);

	if (peer->present) {
		ide_timing_compute(peer, peer->current_speed, &p, T, UT);
		ide_timing_merge(&p, &t, &t, IDE_TIMING_8BIT);
	}

	if (speed == XFER_UDMA_5 && amd_clock <= 33333) t.udma = 1;
	if (speed == XFER_UDMA_6 && amd_clock <= 33333) t.udma = 15;

	amd_set_speed(HWIF(drive)->pci_dev, drive->dn, &t);

	if (!drive->init_speed)	
		drive->init_speed = speed;
	drive->current_speed = speed;

	return 0;
}

/*
 * amd74xx_tune_drive() is a callback from upper layers for
 * PIO-only tuning.
 */

static void amd74xx_tune_drive(ide_drive_t *drive, u8 pio)
{
	if (pio == 255) {
		amd_set_drive(drive, ide_find_best_mode(drive, XFER_PIO | XFER_EPIO));
		return;
	}

	amd_set_drive(drive, XFER_PIO_0 + min_t(byte, pio, 5));
}

/*
 * amd74xx_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 amd74xx_ide_dma_check(ide_drive_t *drive)
{
	int w80 = HWIF(drive)->udma_four;

	u8 speed = ide_find_best_mode(drive,
		XFER_PIO | XFER_EPIO | XFER_MWDMA | XFER_UDMA |
		((amd_config->flags & AMD_BAD_SWDMA) ? 0 : XFER_SWDMA) |
		(w80 && (amd_config->flags & AMD_UDMA) >= AMD_UDMA_66 ? XFER_UDMA_66 : 0) |
		(w80 && (amd_config->flags & AMD_UDMA) >= AMD_UDMA_100 ? XFER_UDMA_100 : 0) |
		(w80 && (amd_config->flags & AMD_UDMA) >= AMD_UDMA_133 ? XFER_UDMA_133 : 0));

	amd_set_drive(drive, speed);

	if (drive->autodma && (speed & XFER_MODE) != XFER_PIO)
		return HWIF(drive)->ide_dma_on(drive);
	return HWIF(drive)->ide_dma_off_quietly(drive);
}

/*
 * The initialization callback. Here we determine the IDE chip type
 * and initialize its drive independent registers.
 */

static unsigned int __devinit init_chipset_amd74xx(struct pci_dev *dev, const
char *name)
{
	unsigned char t;
	unsigned int u;
	int i;

/*
 * Check for bad SWDMA.
 */

	if (amd_config->flags & AMD_CHECK_SWDMA) {
		pci_read_config_byte(dev, PCI_REVISION_ID, &t);
		if (t <= 7)
			amd_config->flags |= AMD_BAD_SWDMA;
	}

/*
 * Check 80-wire cable presence.
 */

	switch (amd_config->flags & AMD_UDMA) {

		case AMD_UDMA_133:
		case AMD_UDMA_100:
			pci_read_config_byte(dev, AMD_CABLE_DETECT, &t);
			pci_read_config_dword(dev, AMD_UDMA_TIMING, &u);
			amd_80w = ((t & 0x3) ? 1 : 0) | ((t & 0xc) ? 2 : 0);
			for (i = 24; i >= 0; i -= 8)
				if (((u >> i) & 4) && !(amd_80w & (1 << (1 - (i >> 4))))) {
					printk(KERN_WARNING "%s: BIOS didn't set cable bits correctly. Enabling
workaround.\n",
						amd_chipset->name);
					amd_80w |= (1 << (1 - (i >> 4)));
				}
			break;

		case AMD_UDMA_66:
			pci_read_config_dword(dev, AMD_UDMA_TIMING, &u);
			for (i = 24; i >= 0; i -= 8)
				if ((u >> i) & 4)
					amd_80w |= (1 << (1 - (i >> 4)));
			break;
	}

/*
 * Take care of prefetch & postwrite.
 */

	pci_read_config_byte(dev, AMD_IDE_CONFIG, &t);
	pci_write_config_byte(dev, AMD_IDE_CONFIG,
		(amd_config->flags & AMD_BAD_FIFO) ? (t & 0x0f) : (t | 0xf0));

/*
 * Take care of incorrectly wired Serenade mainboards.
 */

	if ((amd_config->flags & AMD_CHECK_SERENADE) &&
		dev->subsystem_vendor == PCI_VENDOR_ID_AMD &&
		dev->subsystem_device == PCI_DEVICE_ID_AMD_SERENADE)
			amd_config->flags = AMD_UDMA_100;

/*
 * Determine the system bus clock.
 */

	amd_clock = system_bus_clock() * 1000;

	switch (amd_clock) {
		case 33000: amd_clock = 33333; break;
		case 37000: amd_clock = 37500; break;
		case 41000: amd_clock = 41666; break;
	}

	if (amd_clock < 20000 || amd_clock > 50000) {
		printk(KERN_WARNING "%s: User given PCI clock speed impossible (%d), using 33
MHz instead.\n",
			amd_chipset->name, amd_clock);
		printk(KERN_WARNING "%s: Use ide0=ata66 if you want to assume 80-wire cable\n",
			amd_chipset->name);
		amd_clock = 33333;
	}

/*
 * Print the boot message.
 */

	pci_read_config_byte(dev, PCI_REVISION_ID, &t);
	printk(KERN_INFO "%s: %s (rev %02x) %s controller\n",
		amd_chipset->name, pci_name(dev), t, amd_dma[amd_config->flags & AMD_UDMA]);

/*
 * Register /proc/ide/amd74xx entry
 */

#if defined(DISPLAY_AMD_TIMINGS) && defined(CONFIG_PROC_FS)
        if (!amd74xx_proc) {
                amd_base = pci_resource_start(dev, 4);
                bmide_dev = dev;
		ide_pci_create_host_proc("amd74xx", amd74xx_get_info);
                amd74xx_proc = 1;
        }
#endif /* DISPLAY_AMD_TIMINGS && CONFIG_PROC_FS */

	return dev->irq;
}

static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif)
{
	int i;

	if (hwif->irq == 0) /* 0 is bogus but will do for now */
		hwif->irq = pci_get_legacy_ide_irq(hwif->pci_dev, hwif->channel);

	hwif->autodma = 0;

	hwif->tuneproc = &amd74xx_tune_drive;
	hwif->speedproc = &amd_set_drive;

	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;
	}

	if (!hwif->dma_base)
		return;

        hwif->atapi_dma = 1;
        hwif->ultra_mask = 0x7f;
        hwif->mwdma_mask = 0x07;
        hwif->swdma_mask = 0x07;

	if (!hwif->udma_four)
		hwif->udma_four = (amd_80w >> hwif->channel) & 1;
        hwif->ide_dma_check = &amd74xx_ide_dma_check;
        if (!noautodma)
                hwif->autodma = 1;
        hwif->drives[0].autodma = hwif->autodma;
        hwif->drives[1].autodma = hwif->autodma;
}

#define DECLARE_AMD_DEV(name_str)					\
	{								\
		.name		= name_str,				\
		.init_chipset	= init_chipset_amd74xx,			\
		.init_hwif	= init_hwif_amd74xx,			\
		.channels	= 2,					\
		.autodma	= AUTODMA,				\
		.enablebits	= {{0x40,0x02,0x02}, {0x40,0x01,0x01}},	\
		.bootable	= ON_BOARD,				\
	}

#define DECLARE_NV_DEV(name_str)					\
	{								\
		.name		= name_str,				\
		.init_chipset	= init_chipset_amd74xx,			\
		.init_hwif	= init_hwif_amd74xx,			\
		.channels	= 2,					\
		.autodma	= AUTODMA,				\
		.enablebits	= {{0x50,0x02,0x02}, {0x50,0x01,0x01}},	\
		.bootable	= ON_BOARD,				\
	}

static ide_pci_device_t amd74xx_chipsets[] __devinitdata = {
	/*  0 */ DECLARE_AMD_DEV("AMD7401"),
	/*  1 */ DECLARE_AMD_DEV("AMD7409"),
	/*  2 */ DECLARE_AMD_DEV("AMD7411"),
	/*  3 */ DECLARE_AMD_DEV("AMD7441"),
	/*  4 */ DECLARE_AMD_DEV("AMD8111"),

	/*  5 */ DECLARE_NV_DEV("NFORCE"),
	/*  6 */ DECLARE_NV_DEV("NFORCE2"),
	/*  7 */ DECLARE_NV_DEV("NFORCE2-U400R"),
	/*  8 */ DECLARE_NV_DEV("NFORCE2-U400R-SATA"),
	/*  9 */ DECLARE_NV_DEV("NFORCE3-150"),
	/* 10 */ DECLARE_NV_DEV("NFORCE3-250"),
	/* 11 */ DECLARE_NV_DEV("NFORCE3-250-SATA"),
	/* 12 */ DECLARE_NV_DEV("NFORCE3-250-SATA2"),
	/* 13 */ DECLARE_NV_DEV("NFORCE-CK804"),
	/* 14 */ DECLARE_NV_DEV("NFORCE-CK804-SATA"),
	/* 15 */ DECLARE_NV_DEV("NFORCE-CK804-SATA2"),
	/* 16 */ DECLARE_NV_DEV("NFORCE-MCP04"),
	/* 17 */ DECLARE_NV_DEV("NFORCE-MCP04-SATA"),
	/* 18 */ DECLARE_NV_DEV("NFORCE-MCP04-SATA2")
};

static int __devinit amd74xx_probe(struct pci_dev *dev, const struct
pci_device_id *id)
{
	amd_chipset = amd74xx_chipsets + id->driver_data;
	amd_config = amd_ide_chips + id->driver_data;
	if (dev->device != amd_config->id) {
		printk(KERN_ERR "%s: assertion 0x%02x == 0x%02x failed !\n",
		       pci_name(dev), dev->device, amd_config->id);
		return -ENODEV;
	}
	return ide_setup_pci_device(dev, amd_chipset);
}

static struct pci_device_id amd74xx_pci_tbl[] = {
	{ PCI_VENDOR_ID_AMD,	PCI_DEVICE_ID_AMD_COBRA_7401,		PCI_ANY_ID, PCI_ANY_ID, 0,
0,  0 },
	{ PCI_VENDOR_ID_AMD,	PCI_DEVICE_ID_AMD_VIPER_7409,		PCI_ANY_ID, PCI_ANY_ID, 0,
0,  1 },
	{ PCI_VENDOR_ID_AMD,	PCI_DEVICE_ID_AMD_VIPER_7411,		PCI_ANY_ID, PCI_ANY_ID, 0,
0,  2 },
	{ PCI_VENDOR_ID_AMD,	PCI_DEVICE_ID_AMD_OPUS_7441,		PCI_ANY_ID, PCI_ANY_ID, 0,
0,  3 },
	{ PCI_VENDOR_ID_AMD,	PCI_DEVICE_ID_AMD_8111_IDE,		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 4 },
	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_IDE,	PCI_ANY_ID,
PCI_ANY_ID, 0, 0,  5 },
	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE,	PCI_ANY_ID,
PCI_ANY_ID, 0, 0,  6 },
	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE,	PCI_ANY_ID,
PCI_ANY_ID, 0, 0,  7 },
#ifdef CONFIG_BLK_DEV_IDE_SATA
	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA,	PCI_ANY_ID,
PCI_ANY_ID, 0, 0,  8 },
#endif
	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE,	PCI_ANY_ID,
PCI_ANY_ID, 0, 0,  9 },
	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE,	PCI_ANY_ID,
PCI_ANY_ID, 0, 0, 10 },
#ifdef CONFIG_BLK_DEV_IDE_SATA
	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA,	PCI_ANY_ID,
PCI_ANY_ID, 0, 0, 11 },
	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2,	PCI_ANY_ID,
PCI_ANY_ID, 0, 0, 12 },
#endif
	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE, PCI_ANY_ID,
PCI_ANY_ID, 0, 0, 13 },
#ifdef CONFIG_BLK_DEV_IDE_SATA
	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA, PCI_ANY_ID ,
PCI_ANY_ID, 0, 0, 14 },
	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2, PCI_ANY_ID,
PCI_ANY_ID, 0, 0, 15 },
#endif
	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, PCI_ANY_ID,
PCI_ANY_ID, 0, 0, 16 },
#ifdef CONFIG_BLK_DEV_IDE_SATA
	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA, PCI_ANY_ID ,
PCI_ANY_ID, 0, 0, 17 },
	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2, PCI_ANY_ID,
PCI_ANY_ID, 0, 0, 18 },
#endif
	{ 0, },
};
MODULE_DEVICE_TABLE(pci, amd74xx_pci_tbl);

static struct pci_driver driver = {
	.name		= "AMD_IDE",
	.id_table	= amd74xx_pci_tbl,
	.probe		= amd74xx_probe,
};

static int amd74xx_ide_init(void)
{
	return ide_pci_register_driver(&driver);
}

module_init(amd74xx_ide_init);

MODULE_AUTHOR("Vojtech Pavlik");
MODULE_DESCRIPTION("AMD PCI IDE driver");
MODULE_LICENSE("GPL");

===========================================================================

I know that this driver is called "deprecated" in kernel menu, but it isn't as
long as the SATA driver will work without DMA activation and in slow performance.

Please have a look over my working changes and patch next kernel version with it
or with a modified version.

It is not fine for us to patch every new kernelversion ourself to get DMA
activated. I'm a user how is able to do it myself, but many other nForce4 users
not, and it is nervous to do it every update again.

Thank you for notice.
^
^
^
^
Readings before patching (IDE driver not working at all) SATA only:
hdparm /dev/sda

/dev/sda:
 IO_support   =  0 (default 16-bit)
 readonly     =  0 (off)
 readahead    = 256 (on)
 geometry     = 24321/255/63, sectors = 200049647616, start = 0 
^
^
^
^
Readings after patching and alternative patched IDE driver use:
hdparm /dev/hde

/dev/hde:
 multcount    =  0 (off)
 IO_support   =  1 (32-bit)
 unmaskirq    =  1 (on)
 using_dma    =  1 (on)
 keepsettings =  0 (off)
 readonly     =  0 (off)
 readahead    = 256 (on)
 geometry     = 24321/255/63, sectors = 200049647616, start = 0

Reproducible: Always
Steps to Reproduce:
1.
2.
3.

Actual Results:  
Got harddrives DMA activation.

Expected Results:  
32 bit DMA activation instead of 16 bit compatibility mode.

Kernel driver problem,

you will not need emerge info, but here it is:
=================================================================================
Portage 2.0.51.22-r3 (default-linux/amd64/2005.1, gcc-3.4.4, glibc-2.3.5-r2,
2.6.13-gentoo-r2 x86_64)
=================================================================
System uname: 2.6.13-gentoo-r2 x86_64 AMD Athlon(tm) 64 X2 Dual Core Processor 3800+
Gentoo Base System version 1.6.13
ccache version 2.3 [enabled]
dev-lang/python:     2.3.5-r2, 2.4.1-r1
sys-apps/sandbox:    1.2.12
sys-devel/autoconf:  2.13, 2.59-r6
sys-devel/automake:  1.4_p6, 1.5, 1.6.3, 1.7.9-r1, 1.8.5-r3, 1.9.6-r1
sys-devel/binutils:  2.15.92.0.2-r10
sys-devel/libtool:   1.5.20
virtual/os-headers:  2.6.11-r2
ACCEPT_KEYWORDS="amd64"
AUTOCLEAN="yes"
CBUILD="x86_64-pc-linux-gnu"
CFLAGS="-march=athlon64 -O2 -pipe -ffast-math"
CHOST="x86_64-pc-linux-gnu"
CONFIG_PROTECT="/etc /usr/kde/2/share/config /usr/kde/3.4/env
/usr/kde/3.4/share/config /usr/kde/3.4/shutdown /usr/kde/3/share/config
/usr/lib/X11/xkb /usr/lib64/mozilla/defaults/pref /usr/share/config
/usr/share/texmf/dvipdfm/config/ /usr/share/texmf/dvips/config/
/usr/share/texmf/tex/generic/config/ /usr/share/texmf/tex/platex/config/
/usr/share/texmf/xdvi/ /var/qmail/control"
CONFIG_PROTECT_MASK="/etc/gconf /etc/terminfo /etc/env.d"
CXXFLAGS="-march=athlon64 -O2 -pipe -ffast-math"
DISTDIR="/usr/portage/distfiles"
FEATURES="autoconfig ccache distlocks sandbox sfperms strict"
GENTOO_MIRRORS="ftp://sunsite.informatik.rwth-aachen.de/pub/Linux/gentoo/
ftp://gd.tuwien.ac.at/opsys/linux/gentoo/
http://gd.tuwien.ac.at/opsys/linux/gentoo/ http://gentoo.inode.at/"
LC_ALL="de_DE@euro"
LINGUAS="de"
MAKEOPTS="-j3"
PKGDIR="/usr/portage/packages"
PORTAGE_TMPDIR="/var/tmp"
PORTDIR="/usr/portage"
PORTDIR_OVERLAY="/usr/local/portage"
SYNC="rsync://rsync.gentoo.org/gentoo-portage"
USE="amd64 X Xaw3d aalib alsa amd apache2 apm audiofile avi bitmap-fonts
cdparanoia cdr cgi cups curl dga directfb doc dv dvb dvd emacs emboss encode fam
fbcon ffmpeg fftw flac flash foomaticdb foreign-package fortran freetype ftp
gdbm gif glut gphoto2 gpm gtk gtk2 hal icq ieee1394 imagemagick imlib jack
javascript joystick jpeg kde ladcca lcms ldap leim libg++ libwww lzw lzw-tiff
mad mikmod mime mng motif mozilla mp3 mpeg nas ncurses nls nosendmail nptl
nptlonly nvidia oav ogg oggvorbis ooo-kde openal opengl openssh opie osc oss pam
pdflib perl png portaudio posix profile python qt qtmt quicktime readline
rp-pppoe samba sasl scanner sdl shorten simplexml slang sndfile sockets socks5
sox speex spell ssl svg tcltk tcpd tetex tiff truetype truetype-fonts
type1-fonts unicode usb userlocales v4l vcd videos vorbis wxwindows xface xine
xinerama xml xml2 xmms xpm xv xvid zlib linguas_de userland_GNU kernel_linux
elibc_glibc"
Unset:  ASFLAGS, CTARGET, LANG, LDFLAGS
=================================================================================
Comment 1 Daniel Drake (RETIRED) gentoo-dev 2005-10-15 08:25:04 UTC
Please use the attachment feature to attach large files.

Patching the amd74xx driver to support SATA is the wrong solution as it was
rejected upstream.

Please try applying this patch against vanilla-sources-2.6.14_rc3, and using the
sata_nv driver:
http://www.kernel.org/git/gitweb.cgi?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff_plain;h=9621904012de3c8d0d4e2904dcc7170b3012119e;hp=3c92c2ba33cd7d666c5f83cc32aa590e794e91b0
Comment 2 Georg Sahli 2005-10-15 16:53:11 UTC
Sorry, didn't know that this was to long (next time I will do).

Will have a look into tomorrow or in 2 days. Thank you for your quick replay, but:

"Please try applying this patch against vanilla-sources-2.6.14_rc3, and using the
sata_nv driver:"

Looks like this patch is for a different Chipset = "MCP**" instead of "CK804", or?
Comment 3 Daniel Drake (RETIRED) gentoo-dev 2005-10-25 12:44:59 UTC
Yeah, it probably won't help. The most important part is you testing the latest
development kernel (currently vanilla-sources-2.6.14_rc5) so that we can report
the bug to the developers.
Comment 4 Daniel Drake (RETIRED) gentoo-dev 2005-10-25 12:45:18 UTC
(and that patch is already applied to 2.6.14-rc5 so no need to apply it manually)
Comment 5 Georg Sahli 2005-10-25 15:15:50 UTC
Thank you, will try it tomorrow and report back.
Comment 6 Georg Sahli 2005-10-26 06:10:18 UTC
Created attachment 71504 [details]
dmesg output for nforce4 SATA chipset CK804
Comment 7 Georg Sahli 2005-10-26 06:13:15 UTC
Did test this new Vanilla kernel version 2.6.14-rc5, I am still in 16bit
compatibility mode without DMA.

There is no SATA improvement at all for my nforce4 chipset: 
IDE interface: nVidia Corporation CK804 IDE (rev f2)
IDE interface: nVidia Corporation CK804 Serial ATA Controller (rev f3)
IDE interface: nVidia Corporation CK804 Serial ATA Controller (rev f3) 

Here some outputs:

# hdparm -tT /dev/sda

/dev/sda:
 Timing cached reads:   3604 MB in  2.00 seconds = 1800.47 MB/sec
HDIO_DRIVE_CMD(null) (wait for flush complete) failed: Inappropriate ioctl for
device
 Timing buffered disk reads:  168 MB in  3.03 seconds =  55.53 MB/sec
HDIO_DRIVE_CMD(null) (wait for flush complete) failed: Inappropriate ioctl for
device

# sdparm /dev/sda
    /dev/sda: ATA       SAMSUNG SP2004C   VM10
Read write error recovery mode page:
  AWRE        1  [ sav:  1]
  ARRE        1  [ sav:  1]
  PER         0  [ sav:  0]
Caching (SBC) mode page:
  WCE         1  [ sav:  1]
  RCD         0  [ sav:  0]
Control mode page:
  SWP         0  [ sav:  0]
Comment 8 Daniel Drake (RETIRED) gentoo-dev 2005-10-29 06:56:34 UTC
Your speed outputs look really good. Is there actually a problem with system
performance which goes away when you make the modification you mentioned earlier
and use the old driver?

hdparm is for ide disks, not for SATA disks - its no suprise if it gives results
that aren't quite right. Theres no way you could get 55mb/sec if DMA wasnt
enabled, and plus, most of the SATA drivers do not support PIO - DMA is the only
option.
Comment 9 Georg Sahli 2005-10-29 11:16:14 UTC
The standard BIOS settings for my board is at the point: "Cell Menu" > "SATA
Spread Spectrum" > "disabled".
Spread spectrum is not a DMA switch, it is to make sure the EMV-radiation (GHz
Microwave) do not disturb other things.

With standard settings I do have 30mb/s.

But when I switch to "down spread" I will get the 55mb/s.

So as this point has nothing to do with DMA, I believe that with a better
support for CK804 like MCP51 / MCP55, I will get much more speed, especialy when
I will use more than one harddisk (a second HD is scheduled).

And due to the older MCP51 / MCP55 driver speed is similar to CK804, and the
other had to be improved I am not happy with this 'low speed' compatibility driver.

Yes, the older IDE driver had no speed improvements, it was only to see that DMA
support is possible.

I will try to ask other persons with MCP51/55 chipset which speed they do have
with MCP**. Currently asking these persons is not easy, because momently is
2.6.14 rare installed.

Do you like to close this request, or do we wait until 2.6.14-gentoo-r1 is
released, distributed and in use by persons?
Comment 10 Daniel Drake (RETIRED) gentoo-dev 2005-10-29 11:22:00 UTC
Your performance is fine and the hdparm output can be completely ignored. You'll
be lucky to get more speed in the future, at least not until hard disks
themselves get quicker.

I guess that means there are no problems here so I'll close the bug.