patch-2.4.19 linux-2.4.19/drivers/ide/sis5513.c

Next file: linux-2.4.19/drivers/ide/slc90e66.c
Previous file: linux-2.4.19/drivers/ide/serverworks.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.18/drivers/ide/sis5513.c linux-2.4.19/drivers/ide/sis5513.c
@@ -1,11 +1,35 @@
 /*
- * linux/drivers/ide/sis5513.c		Version 0.11	June 9, 2000
+ * linux/drivers/ide/sis5513.c		Version 0.13	March 6, 2002
  *
  * Copyright (C) 1999-2000	Andre Hedrick <andre@linux-ide.org>
+ * Copyright (C) 2002		Lionel Bouton <Lionel.Bouton@inet6.fr>, Maintainer
  * May be copied or modified under the terms of the GNU General Public License
  *
- * Thanks to SIS Taiwan for direct support and hardware.
- * Tested and designed on the SiS620/5513 chipset.
+ *
+ * Thanks :
+ *
+ * SiS Taiwan		: for direct support and hardware.
+ * Daniela Engert	: for initial ATA100 advices and numerous others.
+ * John Fremlin, Manfred Spraul :
+ *			  for checking code correctness, providing patches.
+ *
+ *
+ * Original tests and design on the SiS620/5513 chipset.
+ * ATA100 tests and design on the SiS735/5513 chipset.
+ * ATA16/33 design from specs
+ */
+
+/*
+ * TODO:
+ *	- Get ridden of SisHostChipInfo[] completness dependancy.
+ *	- Get ATA-133 datasheets, implement ATA-133 init code.
+ *	- Study drivers/ide/ide-timing.h.
+ *	- Are there pre-ATA_16 SiS5513 chips ? -> tune init code for them
+ *	  or remove ATA_00 define
+ *	- More checks in the config registers (force values instead of
+ *	  relying on the BIOS setting them correctly).
+ *	- Further optimisations ?
+ *	  . for example ATA66+ regs 0x48 & 0x4A
  */
 
 #include <linux/config.h>
@@ -28,88 +52,165 @@
 
 #include "ide_modes.h"
 
+/* When DEBUG is defined it outputs initial PCI config register
+   values and changes made to them by the driver */   
+// #define DEBUG
+/* When BROKEN_LEVEL is defined it limits the DMA mode
+   at boot time to its value */
+// #define BROKEN_LEVEL XFER_SW_DMA_0
 #define DISPLAY_SIS_TIMINGS
-#define SIS5513_DEBUG_DRIVE_INFO	0
 
-static struct pci_dev *host_dev = NULL;
+/* Miscellaneaous flags */
+#define SIS5513_LATENCY		0x01
+
+/* registers layout and init values are chipset family dependant */
+/* 1/ define families */
+#define ATA_00		0x00
+#define ATA_16		0x01
+#define ATA_33		0x02
+#define ATA_66		0x03
+#define ATA_100a	0x04 // SiS730 is ATA100 with ATA66 layout
+#define ATA_100		0x05
+#define ATA_133		0x06
+/* 2/ variable holding the controller chipset family value */
+static unsigned char chipset_family;
+
+
+/*
+ * Debug code: following IDE config registers' changes
+ */
+#ifdef DEBUG
+/* Copy of IDE Config registers 0x00 -> 0x57
+   Fewer might be used depending on the actual chipset */
+static unsigned char ide_regs_copy[0x58];
+
+static byte sis5513_max_config_register(void) {
+	switch(chipset_family) {
+		case ATA_00:
+		case ATA_16:	return 0x4f;
+		case ATA_33:	return 0x52;
+		case ATA_66:
+		case ATA_100a:
+		case ATA_100:
+		case ATA_133:
+		default:	return 0x57;
+	}
+}
+
+/* Read config registers, print differences from previous read */
+static void sis5513_load_verify_registers(struct pci_dev* dev, char* info) {
+	int i;
+	byte reg_val;
+	byte changed=0;
+	byte max = sis5513_max_config_register();
+
+	printk("SIS5513: %s, changed registers:\n", info);
+	for(i=0; i<=max; i++) {
+		pci_read_config_byte(dev, i, &reg_val);
+		if (reg_val != ide_regs_copy[i]) {
+			printk("%0#x: %0#x -> %0#x\n",
+			       i, ide_regs_copy[i], reg_val);
+			ide_regs_copy[i]=reg_val;
+			changed=1;
+		}
+	}
+
+	if (!changed) {
+		printk("none\n");
+	}
+}
 
-#define SIS5513_FLAG_ATA_00		0x00000000
-#define SIS5513_FLAG_ATA_16		0x00000001
-#define SIS5513_FLAG_ATA_33		0x00000002
-#define SIS5513_FLAG_ATA_66		0x00000004
-#define SIS5513_FLAG_LATENCY		0x00000010
+/* Load config registers, no printing */
+static void sis5513_load_registers(struct pci_dev* dev) {
+	int i;
+	byte max = sis5513_max_config_register();
 
+	for(i=0; i<=max; i++) {
+		pci_read_config_byte(dev, i, &(ide_regs_copy[i]));
+	}
+}
+
+/* Print a register */
+static void sis5513_print_register(int reg) {
+	printk(" %0#x:%0#x", reg, ide_regs_copy[reg]);
+}
+
+/* Print valuable registers */
+static void sis5513_print_registers(struct pci_dev* dev, char* marker) {
+	int i;
+	byte max = sis5513_max_config_register();
+
+	sis5513_load_registers(dev);
+	printk("SIS5513 %s\n", marker);
+	printk("SIS5513 dump:");
+	for(i=0x00; i<0x40; i++) {
+		if ((i % 0x10)==0) printk("\n             ");
+		sis5513_print_register(i);
+	}
+	for(; i<49; i++) {
+		sis5513_print_register(i);
+	}
+	printk("\n             ");
+
+	for(; i<=max; i++) {
+		sis5513_print_register(i);
+	}
+	printk("\n");
+}
+#endif
+
+
+/*
+ * Devices supported
+ */
 static const struct {
 	const char *name;
 	unsigned short host_id;
-	unsigned int flags;
+	unsigned char chipset_family;
+	unsigned char flags;
 } SiSHostChipInfo[] = {
-	{ "SiS530",	PCI_DEVICE_ID_SI_530,	SIS5513_FLAG_ATA_66, },
-	{ "SiS540",	PCI_DEVICE_ID_SI_540,	SIS5513_FLAG_ATA_66, },
-	{ "SiS620",	PCI_DEVICE_ID_SI_620,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
-	{ "SiS630",	PCI_DEVICE_ID_SI_630,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
-	{ "SiS635",	PCI_DEVICE_ID_SI_635,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
-	{ "SiS640",	PCI_DEVICE_ID_SI_640,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
-	{ "SiS645",	PCI_DEVICE_ID_SI_645,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
-	{ "SiS650",	PCI_DEVICE_ID_SI_650,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
-	{ "SiS730",	PCI_DEVICE_ID_SI_730,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
-	{ "SiS735",	PCI_DEVICE_ID_SI_735,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
-	{ "SiS740",	PCI_DEVICE_ID_SI_740,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
-	{ "SiS745",	PCI_DEVICE_ID_SI_745,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
-	{ "SiS750",	PCI_DEVICE_ID_SI_750,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
-	{ "SiS5591",	PCI_DEVICE_ID_SI_5591,	SIS5513_FLAG_ATA_33, },
-	{ "SiS5597",	PCI_DEVICE_ID_SI_5597,	SIS5513_FLAG_ATA_33, },
-	{ "SiS5600",	PCI_DEVICE_ID_SI_5600,	SIS5513_FLAG_ATA_33, },
-	{ "SiS5511",	PCI_DEVICE_ID_SI_5511,	SIS5513_FLAG_ATA_16, },
+//	{ "SiS750",	PCI_DEVICE_ID_SI_750,	ATA_100,	SIS5513_LATENCY },
+//	{ "SiS745",	PCI_DEVICE_ID_SI_745,	ATA_100,	SIS5513_LATENCY },
+	{ "SiS740",	PCI_DEVICE_ID_SI_740,	ATA_100,	SIS5513_LATENCY },
+	{ "SiS735",	PCI_DEVICE_ID_SI_735,	ATA_100,	SIS5513_LATENCY },
+	{ "SiS730",	PCI_DEVICE_ID_SI_730,	ATA_100a,	SIS5513_LATENCY },
+//	{ "SiS650",	PCI_DEVICE_ID_SI_650,	ATA_100,	SIS5513_LATENCY },
+//	{ "SiS645",	PCI_DEVICE_ID_SI_645,	ATA_100,	SIS5513_LATENCY },
+	{ "SiS635",	PCI_DEVICE_ID_SI_635,	ATA_100,	SIS5513_LATENCY },
+	{ "SiS640",	PCI_DEVICE_ID_SI_640,	ATA_66,		SIS5513_LATENCY },
+	{ "SiS630",	PCI_DEVICE_ID_SI_630,	ATA_66,		SIS5513_LATENCY },
+	{ "SiS620",	PCI_DEVICE_ID_SI_620,	ATA_66,		SIS5513_LATENCY },
+	{ "SiS540",	PCI_DEVICE_ID_SI_540,	ATA_66,		0},
+	{ "SiS530",	PCI_DEVICE_ID_SI_530,	ATA_66,		0},
+	{ "SiS5600",	PCI_DEVICE_ID_SI_5600,	ATA_33,		0},
+	{ "SiS5598",	PCI_DEVICE_ID_SI_5598,	ATA_33,		0},
+	{ "SiS5597",	PCI_DEVICE_ID_SI_5597,	ATA_33,		0},
+	{ "SiS5591",	PCI_DEVICE_ID_SI_5591,	ATA_33,		0},
+	{ "SiS5513",	PCI_DEVICE_ID_SI_5513,	ATA_16,		0},
+	{ "SiS5511",	PCI_DEVICE_ID_SI_5511,	ATA_16,		0},
 };
 
-#if 0
-
-static struct _pio_mode_mapping {
-	byte data_active;
-	byte recovery;
-	byte pio_mode;
-} pio_mode_mapping[] = {
-	{ 8, 12, 0 },
-	{ 6,  7, 1 },
-	{ 4,  4, 2 },
-	{ 3,  3, 3 },
-	{ 3,  1, 4 }
+/* Cycle time bits and values vary accross chip dma capabilities
+   These three arrays hold the register layout and the values to set.
+   Indexed by chipset_family and (dma_mode - XFER_UDMA_0) */
+static byte cycle_time_offset[] = {0,0,5,4,4,0,0};
+static byte cycle_time_range[] = {0,0,2,3,3,4,4};
+static byte cycle_time_value[][XFER_UDMA_5 - XFER_UDMA_0 + 1] = {
+	{0,0,0,0,0,0}, /* no udma */
+	{0,0,0,0,0,0}, /* no udma */
+	{3,2,1,0,0,0},
+	{7,5,3,2,1,0},
+	{7,5,3,2,1,0},
+	{11,7,5,4,2,1},
+	{0,0,0,0,0,0} /* not yet known, ask SiS */
 };
 
-static struct _dma_mode_mapping {
-	byte data_active;
-	byte recovery;
-	byte dma_mode;
-} dma_mode_mapping[] = {
-	{ 8, 8, 0 },
-	{ 3, 2, 1 },
-	{ 3, 1, 2 }
-};
-
-static struct _udma_mode_mapping {
-	byte cycle_time;
-	char * udma_mode;
-} udma_mode_mapping[] = {
-	{ 8, "Mode 0" },
-	{ 6, "Mode 1" },
-	{ 4, "Mode 2" }, 
-	{ 3, "Mode 3" },
-	{ 2, "Mode 4" },
-	{ 0, "Mode 5" }
-};
+static struct pci_dev *host_dev = NULL;
 
-static __inline__ char * find_udma_mode (byte cycle_time)
-{
-	int n;
-	
-	for (n = 0; n <= 4; n++)
-		if (udma_mode_mapping[n].cycle_time <= cycle_time)
-			return udma_mode_mapping[n].udma_mode;
-	return udma_mode_mapping[4].udma_mode;
-}
-#endif
 
+/*
+ * Printing configuration
+ */
 #if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS)
 #include <linux/stat.h>
 #include <linux/proc_fs.h>
@@ -118,12 +219,12 @@
 extern int (*sis_display_info)(char *, char **, off_t, int); /* ide-proc.c */
 static struct pci_dev *bmide_dev;
 
-static char *cable_type[] = {
+static char* cable_type[] = {
 	"80 pins",
 	"40 pins"
 };
 
-static char *recovery_time [] ={
+static char* recovery_time[] ={
 	"12 PCICLK", "1 PCICLK",
 	"2 PCICLK", "3 PCICLK",
 	"4 PCICLK", "5 PCICLCK",
@@ -134,101 +235,184 @@
 	"15 PCICLK", "15 PCICLK"
 };
 
-static char * cycle_time [] = {
-	"2 CLK", "2 CLK",
-	"3 CLK", "4 CLK",
-	"5 CLK", "6 CLK",
-	"7 CLK", "8 CLK"
-};
-
-static char * active_time [] = {
+static char* active_time[] = {
 	"8 PCICLK", "1 PCICLCK",
-	"2 PCICLK", "2 PCICLK",
+	"2 PCICLK", "3 PCICLK",
 	"4 PCICLK", "5 PCICLK",
 	"6 PCICLK", "12 PCICLK"
 };
 
+static char* cycle_time[] = {
+	"Reserved", "2 CLK",
+	"3 CLK", "4 CLK",
+	"5 CLK", "6 CLK",
+	"7 CLK", "8 CLK",
+	"9 CLK", "10 CLK",
+	"11 CLK", "12 CLK",
+	"Reserved", "Reserved",
+	"Reserved", "Reserved"
+};
+
+/* Generic add master or slave info function */
+static char* get_drives_info (char *buffer, byte pos)
+{
+	byte reg00, reg01, reg10, reg11; /* timing registers */
+	char* p = buffer;
+
+/* Postwrite/Prefetch */
+	pci_read_config_byte(bmide_dev, 0x4b, &reg00);
+	p += sprintf(p, "Drive %d:        Postwrite %s \t \t Postwrite %s\n",
+		     pos, (reg00 & (0x10 << pos)) ? "Enabled" : "Disabled",
+		     (reg00 & (0x40 << pos)) ? "Enabled" : "Disabled");
+	p += sprintf(p, "                Prefetch  %s \t \t Prefetch  %s\n",
+		     (reg00 & (0x01 << pos)) ? "Enabled" : "Disabled",
+		     (reg00 & (0x04 << pos)) ? "Enabled" : "Disabled");
+
+	pci_read_config_byte(bmide_dev, 0x40+2*pos, &reg00);
+	pci_read_config_byte(bmide_dev, 0x41+2*pos, &reg01);
+	pci_read_config_byte(bmide_dev, 0x44+2*pos, &reg10);
+	pci_read_config_byte(bmide_dev, 0x45+2*pos, &reg11);
+
+/* UDMA */
+	if (chipset_family >= ATA_33) {
+		p += sprintf(p, "                UDMA %s \t \t \t UDMA %s\n",
+			     (reg01 & 0x80)  ? "Enabled" : "Disabled",
+			     (reg11 & 0x80) ? "Enabled" : "Disabled");
+
+		p += sprintf(p, "                UDMA Cycle Time    ");
+		switch(chipset_family) {
+			case ATA_33:	p += sprintf(p, cycle_time[(reg01 & 0x60) >> 5]); break;
+			case ATA_66:
+			case ATA_100a:	p += sprintf(p, cycle_time[(reg01 & 0x70) >> 4]); break;
+			case ATA_100:	p += sprintf(p, cycle_time[reg01 & 0x0F]); break;
+			case ATA_133:
+			default:	p += sprintf(p, "133+ ?"); break;
+		}
+		p += sprintf(p, " \t UDMA Cycle Time    ");
+		switch(chipset_family) {
+			case ATA_33:	p += sprintf(p, cycle_time[(reg11 & 0x60) >> 5]); break;
+			case ATA_66:
+			case ATA_100a:	p += sprintf(p, cycle_time[(reg11 & 0x70) >> 4]); break;
+			case ATA_100:	p += sprintf(p, cycle_time[reg11 & 0x0F]); break;
+			case ATA_133:
+			default:	p += sprintf(p, "133+ ?"); break;
+		}
+		p += sprintf(p, "\n");
+	}
+
+/* Data Active */
+	p += sprintf(p, "                Data Active Time   ");
+	switch(chipset_family) {
+		case ATA_00:
+		case ATA_16: /* confirmed */
+		case ATA_33:
+		case ATA_66:
+		case ATA_100a: p += sprintf(p, active_time[reg01 & 0x07]); break;
+		case ATA_100: p += sprintf(p, active_time[(reg00 & 0x70) >> 4]); break;
+		case ATA_133:
+		default: p += sprintf(p, "133+ ?"); break;
+	}
+	p += sprintf(p, " \t Data Active Time   ");
+	switch(chipset_family) {
+		case ATA_00:
+		case ATA_16:
+		case ATA_33:
+		case ATA_66:
+		case ATA_100a: p += sprintf(p, active_time[reg11 & 0x07]); break;
+		case ATA_100: p += sprintf(p, active_time[(reg10 & 0x70) >> 4]); break;
+		case ATA_133:
+		default: p += sprintf(p, "133+ ?"); break;
+	}
+	p += sprintf(p, "\n");
+
+/* Data Recovery */
+	/* warning: may need (reg&0x07) for pre ATA66 chips */
+	p += sprintf(p, "                Data Recovery Time %s \t Data Recovery Time %s\n",
+		     recovery_time[reg00 & 0x0f], recovery_time[reg10 & 0x0f]);
+
+	return p;
+}
+
+static char* get_masters_info(char* buffer)
+{
+	return get_drives_info(buffer, 0);
+}
+
+static char* get_slaves_info(char* buffer)
+{
+	return get_drives_info(buffer, 1);
+}
+
+/* Main get_info, called on /proc/ide/sis reads */
 static int sis_get_info (char *buffer, char **addr, off_t offset, int count)
 {
-	int rc;
 	char *p = buffer;
-	byte reg,reg1;
+	byte reg;
 	u16 reg2, reg3;
 
+	p += sprintf(p, "\nSiS 5513 ");
+	switch(chipset_family) {
+		case ATA_00: p += sprintf(p, "Unknown???"); break;
+		case ATA_16: p += sprintf(p, "DMA 16"); break;
+		case ATA_33: p += sprintf(p, "Ultra 33"); break;
+		case ATA_66: p += sprintf(p, "Ultra 66"); break;
+		case ATA_100a:
+		case ATA_100: p += sprintf(p, "Ultra 100"); break;
+		case ATA_133:
+		default: p+= sprintf(p, "Ultra 133+"); break;
+	}
+	p += sprintf(p, " chipset\n");
 	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
-	rc = pci_read_config_byte(bmide_dev, 0x4a, &reg);
-	p += sprintf(p, "Channel Status: %s \t \t \t \t %s \n",
-		     (reg & 0x02) ? "On" : "Off",
-		     (reg & 0x04) ? "On" : "Off");
-		     
-	rc = pci_read_config_byte(bmide_dev, 0x09, &reg);
+
+/* Status */
+	pci_read_config_byte(bmide_dev, 0x4a, &reg);
+	p += sprintf(p, "Channel Status: ");
+	if (chipset_family < ATA_66) {
+		p += sprintf(p, "%s \t \t \t \t %s\n",
+			     (reg & 0x04) ? "On" : "Off",
+			     (reg & 0x02) ? "On" : "Off");
+	} else {
+		p += sprintf(p, "%s \t \t \t \t %s \n",
+			     (reg & 0x02) ? "On" : "Off",
+			     (reg & 0x04) ? "On" : "Off");
+	}
+
+/* Operation Mode */
+	pci_read_config_byte(bmide_dev, 0x09, &reg);
 	p += sprintf(p, "Operation Mode: %s \t \t \t %s \n",
 		     (reg & 0x01) ? "Native" : "Compatible",
 		     (reg & 0x04) ? "Native" : "Compatible");
-		     	     
-	rc = pci_read_config_byte(bmide_dev, 0x48, &reg);
-	p += sprintf(p, "Cable Type:     %s \t \t \t %s\n",
-		     (reg & 0x10) ? cable_type[1] : cable_type[0],
-		     (reg & 0x20) ? cable_type[1] : cable_type[0]);
-		     
-	rc = pci_read_config_word(bmide_dev, 0x4c, &reg2);
-	rc = pci_read_config_word(bmide_dev, 0x4e, &reg3);
-	p += sprintf(p, "Prefetch Count: %d \t \t \t \t %d\n",
-		     reg2, reg3);
-
-	rc = pci_read_config_byte(bmide_dev, 0x4b, &reg);	     
-	p += sprintf(p, "Drive 0:        Postwrite %s \t \t Postwrite %s\n",
-		     (reg & 0x10) ? "Enabled" : "Disabled",
-		     (reg & 0x40) ? "Enabled" : "Disabled");
-	p += sprintf(p, "                Prefetch  %s \t \t Prefetch  %s\n",
-		     (reg & 0x01) ? "Enabled" : "Disabled",
-		     (reg & 0x04) ? "Enabled" : "Disabled");
-		          
-	rc = pci_read_config_byte(bmide_dev, 0x41, &reg);
-	rc = pci_read_config_byte(bmide_dev, 0x45, &reg1);
-	p += sprintf(p, "                UDMA %s \t \t \t UDMA %s\n",
-		     (reg & 0x80)  ? "Enabled" : "Disabled",
-		     (reg1 & 0x80) ? "Enabled" : "Disabled");
-	p += sprintf(p, "                UDMA Cycle Time    %s \t UDMA Cycle Time    %s\n",
-		     cycle_time[(reg & 0x70) >> 4], cycle_time[(reg1 & 0x70) >> 4]);
-	p += sprintf(p, "                Data Active Time   %s \t Data Active Time   %s\n",
-		     active_time[(reg & 0x07)], active_time[(reg1 &0x07)] ); 
-
-	rc = pci_read_config_byte(bmide_dev, 0x40, &reg);
-	rc = pci_read_config_byte(bmide_dev, 0x44, &reg1);
-	p += sprintf(p, "                Data Recovery Time %s \t Data Recovery Time %s\n",
-		     recovery_time[(reg & 0x0f)], recovery_time[(reg1 & 0x0f)]);
 
+/* 80-pin cable ? */
+	if (chipset_family > ATA_33) {
+		pci_read_config_byte(bmide_dev, 0x48, &reg);
+		p += sprintf(p, "Cable Type:     %s \t \t \t %s\n",
+			     (reg & 0x10) ? cable_type[1] : cable_type[0],
+			     (reg & 0x20) ? cable_type[1] : cable_type[0]);
+	}
 
-	rc = pci_read_config_byte(bmide_dev, 0x4b, &reg);	     
-	p += sprintf(p, "Drive 1:        Postwrite %s \t \t Postwrite %s\n",
-		     (reg & 0x20) ? "Enabled" : "Disabled",
-		     (reg & 0x80) ? "Enabled" : "Disabled");
-	p += sprintf(p, "                Prefetch  %s \t \t Prefetch  %s\n",
-		     (reg & 0x02) ? "Enabled" : "Disabled",
-		     (reg & 0x08) ? "Enabled" : "Disabled");
+/* Prefetch Count */
+	pci_read_config_word(bmide_dev, 0x4c, &reg2);
+	pci_read_config_word(bmide_dev, 0x4e, &reg3);
+	p += sprintf(p, "Prefetch Count: %d \t \t \t \t %d\n",
+		     reg2, reg3);
 
-	rc = pci_read_config_byte(bmide_dev, 0x43, &reg);
-	rc = pci_read_config_byte(bmide_dev, 0x47, &reg1);
-	p += sprintf(p, "                UDMA %s \t \t \t UDMA %s\n",
-		     (reg & 0x80)  ? "Enabled" : "Disabled",
-		     (reg1 & 0x80) ? "Enabled" : "Disabled");
-	p += sprintf(p, "                UDMA Cycle Time    %s \t UDMA Cycle Time    %s\n",
-		     cycle_time[(reg & 0x70) >> 4], cycle_time[(reg1 & 0x70) >> 4]);
-	p += sprintf(p, "                Data Active Time   %s \t Data Active Time   %s\n",
-		     active_time[(reg & 0x07)], active_time[(reg1 &0x07)] ); 
+	p = get_masters_info(p);
+	p = get_slaves_info(p);
 
-	rc = pci_read_config_byte(bmide_dev, 0x42, &reg);
-	rc = pci_read_config_byte(bmide_dev, 0x46, &reg1);
-	p += sprintf(p, "                Data Recovery Time %s \t Data Recovery Time %s\n",
-		     recovery_time[(reg & 0x0f)], recovery_time[(reg1 & 0x0f)]);
 	return p-buffer;
 }
 #endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) */
 
+
 byte sis_proc = 0;
 extern char *ide_xfer_verbose (byte xfer_rate);
 
+
+/*
+ * Configuration functions
+ */
+/* Enables per-drive prefetch and postwrite */
 static void config_drive_art_rwp (ide_drive_t *drive)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
@@ -237,14 +421,24 @@
 	byte reg4bh		= 0;
 	byte rw_prefetch	= (0x11 << drive->dn);
 
-	pci_read_config_byte(dev, 0x4b, &reg4bh);
+#ifdef DEBUG
+	printk("SIS5513: config_drive_art_rwp, drive %d\n", drive->dn);
+	sis5513_load_verify_registers(dev, "config_drive_art_rwp start");
+#endif
+
 	if (drive->media != ide_disk)
 		return;
-	
+	pci_read_config_byte(dev, 0x4b, &reg4bh);
+
 	if ((reg4bh & rw_prefetch) != rw_prefetch)
 		pci_write_config_byte(dev, 0x4b, reg4bh|rw_prefetch);
+#ifdef DEBUG
+	sis5513_load_verify_registers(dev, "config_drive_art_rwp end");
+#endif
 }
 
+
+/* Set per-drive active and recovery time */
 static void config_art_rwp_pio (ide_drive_t *drive, byte pio)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
@@ -255,6 +449,10 @@
 	unsigned short eide_pio_timing[6] = {600, 390, 240, 180, 120, 90};
 	unsigned short xfer_pio = drive->id->eide_pio_modes;
 
+#ifdef DEBUG
+	sis5513_load_verify_registers(dev, "config_drive_art_rwp_pio start");
+#endif
+
 	config_drive_art_rwp(drive);
 	pio = ide_get_best_pio_mode(drive, 255, pio, NULL);
 
@@ -263,8 +461,8 @@
 
 	if (drive->id->eide_pio_iordy > 0) {
 		for (xfer_pio = 5;
-			xfer_pio>0 &&
-			drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
+			(xfer_pio > 0) &&
+			(drive->id->eide_pio_iordy > eide_pio_timing[xfer_pio]);
 			xfer_pio--);
 	} else {
 		xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
@@ -274,14 +472,10 @@
 
 	timing = (xfer_pio >= pio) ? xfer_pio : pio;
 
-/*
- *               Mode 0       Mode 1     Mode 2     Mode 3     Mode 4
- * Active time    8T (240ns)  6T (180ns) 4T (120ns) 3T  (90ns) 3T  (90ns)
- * 0x41 2:0 bits  000          110        100        011        011
- * Recovery time 12T (360ns)  7T (210ns) 4T (120ns) 3T  (90ns) 1T  (30ns)
- * 0x40 3:0 bits 0000         0111       0100       0011       0001
- * Cycle time    20T (600ns) 13T (390ns) 8T (240ns) 6T (180ns) 4T (120ns)
- */
+#ifdef DEBUG
+	printk("SIS5513: config_drive_art_rwp_pio, drive %d, pio %d, timing %d\n",
+	       drive->dn, pio, timing);
+#endif
 
 	switch(drive->dn) {
 		case 0:		drive_pci = 0x40; break;
@@ -291,31 +485,43 @@
 		default:	return;
 	}
 
-	pci_read_config_byte(dev, drive_pci, &test1);
-	pci_read_config_byte(dev, drive_pci|0x01, &test2);
-
-	/*
-	 * Do a blanket clear of active and recovery timings.
-	 */
-
-	test1 &= ~0x07;
-	test2 &= ~0x0F;
-
-	switch(timing) {
-		case 4:		test1 |= 0x01; test2 |= 0x03; break;
-		case 3:		test1 |= 0x03; test2 |= 0x03; break;
-		case 2:		test1 |= 0x04; test2 |= 0x04; break;
-		case 1:		test1 |= 0x07; test2 |= 0x06; break;
-		default:	break;
+	/* register layout changed with newer ATA100 chips */
+	if (chipset_family < ATA_100) {
+		pci_read_config_byte(dev, drive_pci, &test1);
+		pci_read_config_byte(dev, drive_pci+1, &test2);
+
+		/* Clear active and recovery timings */
+		test1 &= ~0x0F;
+		test2 &= ~0x07;
+
+		switch(timing) {
+			case 4:		test1 |= 0x01; test2 |= 0x03; break;
+			case 3:		test1 |= 0x03; test2 |= 0x03; break;
+			case 2:		test1 |= 0x04; test2 |= 0x04; break;
+			case 1:		test1 |= 0x07; test2 |= 0x06; break;
+			default:	break;
+		}
+		pci_write_config_byte(dev, drive_pci, test1);
+		pci_write_config_byte(dev, drive_pci+1, test2);
+	} else {
+		switch(timing) { /*   active  recovery
+					  v     v */
+			case 4:		test1 = 0x30|0x01; break;
+			case 3:		test1 = 0x30|0x03; break;
+			case 2:		test1 = 0x40|0x04; break;
+			case 1:		test1 = 0x60|0x07; break;
+			default:	break;
+		}
+		pci_write_config_byte(dev, drive_pci, test1);
 	}
 
-	pci_write_config_byte(dev, drive_pci, test1);
-	pci_write_config_byte(dev, drive_pci|0x01, test2);
+#ifdef DEBUG
+	sis5513_load_verify_registers(dev, "config_drive_art_rwp_pio start");
+#endif
 }
 
 static int config_chipset_for_pio (ide_drive_t *drive, byte pio)
 {
-	int err;
 	byte speed;
 
 	switch(pio) {
@@ -328,8 +534,7 @@
 
 	config_art_rwp_pio(drive, pio);
 	drive->current_speed = speed;
-	err = ide_config_drive_speed(drive, speed);
-	return err;
+	return ide_config_drive_speed(drive, speed);
 }
 
 static int sis5513_tune_chipset (ide_drive_t *drive, byte speed)
@@ -337,82 +542,73 @@
 	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev *dev	= hwif->pci_dev;
 
-	byte			drive_pci, test1, test2;
-	byte			unmask, four_two, mask = 0;
-
-	if (host_dev) {
-		switch(host_dev->device) {
-			case PCI_DEVICE_ID_SI_530:
-			case PCI_DEVICE_ID_SI_540:
-			case PCI_DEVICE_ID_SI_620:
-			case PCI_DEVICE_ID_SI_630:
-			case PCI_DEVICE_ID_SI_635:
-			case PCI_DEVICE_ID_SI_640:
-			case PCI_DEVICE_ID_SI_645:
-			case PCI_DEVICE_ID_SI_650:
-			case PCI_DEVICE_ID_SI_730:
-			case PCI_DEVICE_ID_SI_735:
-			case PCI_DEVICE_ID_SI_740:
-			case PCI_DEVICE_ID_SI_745:
-			case PCI_DEVICE_ID_SI_750:
-				unmask   = 0xF0;
-				four_two = 0x01;
-				break;
-			default:
-				unmask   = 0xE0;
-				four_two = 0x00;
-				break;
-		}
-	} else {
-		unmask   = 0xE0;
-		four_two = 0x00;
-	}
+	byte			drive_pci, reg;
 
+#ifdef DEBUG
+	sis5513_load_verify_registers(dev, "sis5513_tune_chipset start");
+	printk("SIS5513: sis5513_tune_chipset, drive %d, speed %d\n",
+	       drive->dn, speed);
+#endif
 	switch(drive->dn) {
-		case 0:		drive_pci = 0x40;break;
-		case 1:		drive_pci = 0x42;break;
-		case 2:		drive_pci = 0x44;break;
-		case 3:		drive_pci = 0x46;break;
+		case 0:		drive_pci = 0x40; break;
+		case 1:		drive_pci = 0x42; break;
+		case 2:		drive_pci = 0x44; break;
+		case 3:		drive_pci = 0x46; break;
 		default:	return ide_dma_off;
 	}
 
-	pci_read_config_byte(dev, drive_pci, &test1);
-	pci_read_config_byte(dev, drive_pci|0x01, &test2);
+#ifdef BROKEN_LEVEL
+#ifdef DEBUG
+	printk("SIS5513: BROKEN_LEVEL activated, speed=%d -> speed=%d\n", speed, BROKEN_LEVEL);
+#endif
+	if (speed > BROKEN_LEVEL) speed = BROKEN_LEVEL;
+#endif
 
-	if ((speed <= XFER_MW_DMA_2) && (test2 & 0x80)) {
-		pci_write_config_byte(dev, drive_pci|0x01, test2 & ~0x80);
-		pci_read_config_byte(dev, drive_pci|0x01, &test2);
-	} else {
-		pci_write_config_byte(dev, drive_pci|0x01, test2 & ~unmask);
+	pci_read_config_byte(dev, drive_pci+1, &reg);
+	/* Disable UDMA bit for non UDMA modes on UDMA chips */
+	if ((speed < XFER_UDMA_0) && (chipset_family > ATA_16)) {
+		reg &= 0x7F;
+		pci_write_config_byte(dev, drive_pci+1, reg);
 	}
 
+	/* Config chip for mode */
 	switch(speed) {
 #ifdef CONFIG_BLK_DEV_IDEDMA
-		case XFER_UDMA_5: mask = 0x80; break;
-		case XFER_UDMA_4: mask = 0x90; break;
-		case XFER_UDMA_3: mask = 0xA0; break;
-		case XFER_UDMA_2: mask = (four_two) ? 0xB0 : 0xA0; break;
-		case XFER_UDMA_1: mask = (four_two) ? 0xD0 : 0xC0; break;
-		case XFER_UDMA_0: mask = unmask; break;
+		case XFER_UDMA_5:
+		case XFER_UDMA_4:
+		case XFER_UDMA_3:
+		case XFER_UDMA_2:
+		case XFER_UDMA_1:
+		case XFER_UDMA_0:
+			/* Force the UDMA bit on if we want to use UDMA */
+			reg |= 0x80;
+			/* clean reg cycle time bits */
+			reg &= ~((0xFF >> (8 - cycle_time_range[chipset_family]))
+				 << cycle_time_offset[chipset_family]);
+			/* set reg cycle time bits */
+			reg |= cycle_time_value[chipset_family-ATA_00][speed-XFER_UDMA_0]
+				<< cycle_time_offset[chipset_family];
+			pci_write_config_byte(dev, drive_pci+1, reg);
+			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: break;
+		case XFER_SW_DMA_0:
+			break;
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 		case XFER_PIO_4: return((int) config_chipset_for_pio(drive, 4));
 		case XFER_PIO_3: return((int) config_chipset_for_pio(drive, 3));
 		case XFER_PIO_2: return((int) config_chipset_for_pio(drive, 2));
 		case XFER_PIO_1: return((int) config_chipset_for_pio(drive, 1));
 		case XFER_PIO_0:
-		default:	 return((int) config_chipset_for_pio(drive, 0));
+		default:	 return((int) config_chipset_for_pio(drive, 0));	
 	}
-
-	if (speed > XFER_MW_DMA_2)
-		pci_write_config_byte(dev, drive_pci|0x01, test2|mask);
-
 	drive->current_speed = speed;
+#ifdef DEBUG
+	sis5513_load_verify_registers(dev, "sis5513_tune_chipset end");
+#endif
 	return ((int) ide_config_drive_speed(drive, speed));
 }
 
@@ -430,47 +626,27 @@
 	struct hd_driveid *id	= drive->id;
 	ide_hwif_t *hwif	= HWIF(drive);
 
-	byte			four_two = 0, speed = 0;
-	int			err;
+	byte			speed = 0;
 
 	byte unit		= (drive->select.b.unit & 0x01);
 	byte udma_66		= eighty_ninty_three(drive);
-	byte ultra_100		= 0;
 
-	if (host_dev) {
-		switch(host_dev->device) {
-			case PCI_DEVICE_ID_SI_635:
-			case PCI_DEVICE_ID_SI_640:
-			case PCI_DEVICE_ID_SI_645:
-			case PCI_DEVICE_ID_SI_650:
-			case PCI_DEVICE_ID_SI_730:
-			case PCI_DEVICE_ID_SI_735:
-			case PCI_DEVICE_ID_SI_740:
-			case PCI_DEVICE_ID_SI_745:
-			case PCI_DEVICE_ID_SI_750:
-				ultra_100 = 1;
-			case PCI_DEVICE_ID_SI_530:
-			case PCI_DEVICE_ID_SI_540:
-			case PCI_DEVICE_ID_SI_620:
-			case PCI_DEVICE_ID_SI_630:
-				four_two = 0x01;
-				break;
-			default:
-				four_two = 0x00; break;
-		}
-	}
+#ifdef DEBUG
+	printk("SIS5513: config_chipset_for_dma, drive %d, ultra %d\n",
+	       drive->dn, ultra);
+#endif
 
-	if ((id->dma_ultra & 0x0020) && (ultra) && (udma_66) && (four_two) && (ultra_100))
+	if ((id->dma_ultra & 0x0020) && ultra && udma_66 && (chipset_family >= ATA_100a))
 		speed = XFER_UDMA_5;
-	else if ((id->dma_ultra & 0x0010) && (ultra) && (udma_66) && (four_two))
+	else if ((id->dma_ultra & 0x0010) && ultra && udma_66 && (chipset_family >= ATA_66))
 		speed = XFER_UDMA_4;
-	else if ((id->dma_ultra & 0x0008) && (ultra) && (udma_66) && (four_two))
+	else if ((id->dma_ultra & 0x0008) && ultra && udma_66 && (chipset_family >= ATA_66))
 		speed = XFER_UDMA_3;
-	else if ((id->dma_ultra & 0x0004) && (ultra))
+	else if ((id->dma_ultra & 0x0004) && ultra && (chipset_family >= ATA_33))
 		speed = XFER_UDMA_2;
-	else if ((id->dma_ultra & 0x0002) && (ultra))
+	else if ((id->dma_ultra & 0x0002) && ultra && (chipset_family >= ATA_33))
 		speed = XFER_UDMA_1;
-	else if ((id->dma_ultra & 0x0001) && (ultra))
+	else if ((id->dma_ultra & 0x0001) && ultra && (chipset_family >= ATA_33))
 		speed = XFER_UDMA_0;
 	else if (id->dma_mword & 0x0004)
 		speed = XFER_MW_DMA_2;
@@ -489,11 +665,7 @@
 
 	outb(inb(hwif->dma_base+2)|(1<<(5+unit)), hwif->dma_base+2);
 
-	err = sis5513_tune_chipset(drive, speed);
-
-#if SIS5513_DEBUG_DRIVE_INFO
-	printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive->dn);
-#endif /* SIS5513_DEBUG_DRIVE_INFO */
+	sis5513_tune_chipset(drive, speed);
 
 	return ((int)	((id->dma_ultra >> 11) & 7) ? ide_dma_on :
 			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
@@ -507,6 +679,8 @@
 	struct hd_driveid *id		= drive->id;
 	ide_dma_action_t dma_func	= ide_dma_off_quietly;
 
+	(void) config_chipset_for_pio(drive, 5);
+
 	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
 		/* Consult the list of known "bad" drives */
 		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
@@ -550,9 +724,7 @@
 	return HWIF(drive)->dmaproc(dma_func, drive);
 }
 
-/*
- * sis5513_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
- */
+/* initiates/aborts (U)DMA read/write operations on a drive. */
 int sis5513_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
 {
 	switch (func) {
@@ -567,15 +739,14 @@
 }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
+/* Chip detection and general config */
 unsigned int __init pci_init_sis5513 (struct pci_dev *dev, const char *name)
 {
 	struct pci_dev *host;
 	int i = 0;
-	byte latency = 0;
 
-	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &latency);
-
-	for (i = 0; i < ARRAY_SIZE (SiSHostChipInfo) && !host_dev; i++) {
+	/* Find the chip */
+	for (i = 0; i < ARRAY_SIZE(SiSHostChipInfo) && !host_dev; i++) {
 		host = pci_find_device (PCI_VENDOR_ID_SI,
 					SiSHostChipInfo[i].host_id,
 					NULL);
@@ -583,30 +754,71 @@
 			continue;
 
 		host_dev = host;
+		chipset_family = SiSHostChipInfo[i].chipset_family;
 		printk(SiSHostChipInfo[i].name);
 		printk("\n");
-		if (SiSHostChipInfo[i].flags & SIS5513_FLAG_LATENCY) {
-			if (latency != 0x10)
-				pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x10);
+
+#ifdef DEBUG
+		sis5513_print_registers(dev, "pci_init_sis5513 start");
+#endif
+
+		if (SiSHostChipInfo[i].flags & SIS5513_LATENCY) {
+			byte latency = (chipset_family == ATA_100)? 0x80 : 0x10; /* Lacking specs */
+			pci_write_config_byte(dev, PCI_LATENCY_TIMER, latency);
 		}
 	}
 
+	/* Make general config ops here
+	   1/ tell IDE channels to operate in Compabitility mode only
+	   2/ tell old chips to allow per drive IDE timings */
 	if (host_dev) {
-		byte reg52h = 0;
-
-		pci_read_config_byte(dev, 0x52, &reg52h);
-		if (!(reg52h & 0x04)) {
-			/* set IDE controller to operate in Compabitility mode only */
-			pci_write_config_byte(dev, 0x52, reg52h|0x04);
+		byte reg;
+		switch(chipset_family) {
+			case ATA_133:
+			case ATA_100:
+				/* Set compatibility bit */
+				pci_read_config_byte(dev, 0x49, &reg);
+				if (!(reg & 0x01)) {
+					pci_write_config_byte(dev, 0x49, reg|0x01);
+				}
+				break;
+			case ATA_100a:
+			case ATA_66:
+				/* On ATA_66 chips the bit was elsewhere */
+				pci_read_config_byte(dev, 0x52, &reg);
+				if (!(reg & 0x04)) {
+					pci_write_config_byte(dev, 0x52, reg|0x04);
+				}
+				break;
+			case ATA_33:
+				/* On ATA_33 we didn't have a single bit to set */
+				pci_read_config_byte(dev, 0x09, &reg);
+				if ((reg & 0x0f) != 0x00) {
+					pci_write_config_byte(dev, 0x09, reg&0xf0);
+				}
+			case ATA_16:
+				/* force per drive recovery and active timings
+				   needed on ATA_33 and below chips */
+				pci_read_config_byte(dev, 0x52, &reg);
+				if (!(reg & 0x08)) {
+					pci_write_config_byte(dev, 0x52, reg|0x08);
+				}
+				break;
+			case ATA_00:
+			default: break;
 		}
+
 #if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS)
 		if (!sis_proc) {
 			sis_proc = 1;
 			bmide_dev = dev;
 			sis_display_info = &sis_get_info;
 		}
-#endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) */
+#endif
 	}
+#ifdef DEBUG
+	sis5513_load_verify_registers(dev, "pci_init_sis5513 end");
+#endif
 	return 0;
 }
 
@@ -616,27 +828,10 @@
 	byte mask = hwif->channel ? 0x20 : 0x10;
 	pci_read_config_byte(hwif->pci_dev, 0x48, &reg48h);
 
-	if (host_dev) {
-		switch(host_dev->device) {
-			case PCI_DEVICE_ID_SI_530:
-			case PCI_DEVICE_ID_SI_540:
-			case PCI_DEVICE_ID_SI_620:
-			case PCI_DEVICE_ID_SI_630:
-			case PCI_DEVICE_ID_SI_635:
-			case PCI_DEVICE_ID_SI_640:
-			case PCI_DEVICE_ID_SI_645:
-			case PCI_DEVICE_ID_SI_650:
-			case PCI_DEVICE_ID_SI_730:
-			case PCI_DEVICE_ID_SI_735:
-			case PCI_DEVICE_ID_SI_740:
-			case PCI_DEVICE_ID_SI_745:
-			case PCI_DEVICE_ID_SI_750:
-				ata66 = (reg48h & mask) ? 0 : 1;
-			default:
-				break;
-		}
+	if (chipset_family >= ATA_66) {
+		ata66 = (reg48h & mask) ? 0 : 1;
 	}
-        return (ata66);
+        return ata66;
 }
 
 void __init ide_init_sis5513 (ide_hwif_t *hwif)
@@ -651,33 +846,16 @@
 		return;
 
 	if (host_dev) {
-		switch(host_dev->device) {
 #ifdef CONFIG_BLK_DEV_IDEDMA
-			case PCI_DEVICE_ID_SI_530:
-			case PCI_DEVICE_ID_SI_540:
-			case PCI_DEVICE_ID_SI_620:
-			case PCI_DEVICE_ID_SI_630:
-			case PCI_DEVICE_ID_SI_635:
-			case PCI_DEVICE_ID_SI_640:
-			case PCI_DEVICE_ID_SI_645:
-			case PCI_DEVICE_ID_SI_650:
-			case PCI_DEVICE_ID_SI_730:
-			case PCI_DEVICE_ID_SI_735:
-			case PCI_DEVICE_ID_SI_740:
-			case PCI_DEVICE_ID_SI_745:
-			case PCI_DEVICE_ID_SI_750:
-			case PCI_DEVICE_ID_SI_5600:
-			case PCI_DEVICE_ID_SI_5597:
-			case PCI_DEVICE_ID_SI_5591:
-				if (!noautodma)
-					hwif->autodma = 1;
-				hwif->dmaproc = &sis5513_dmaproc;
-				break;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-			default:
-				hwif->autodma = 0;
-				break;
+		if (chipset_family > ATA_16) {
+			hwif->autodma = noautodma ? 0 : 1;
+			hwif->dmaproc = &sis5513_dmaproc;
+		} else {
+#endif
+			hwif->autodma = 0;
+#ifdef CONFIG_BLK_DEV_IDEDMA
 		}
+#endif
 	}
 	return;
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)