lkml.org 
[lkml]   [2001]   [Oct]   [31]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patches in this message
/
Date
From
Subject[PATCH] IDE: hpt366.c and serverworks.c
Andre,
Attached you'll find the patch to hpt366.c (against your base you sent me)
and serverworks.c. Both of these have been in use for some time.



Tim




--
Tim Hockin
Systems Software Engineer
Sun Microsystems, Cobalt Server Appliances
thockin@sun.com--- /home/thockin/andre-hpt366.c Tue Oct 30 16:30:08 2001
+++ drivers/ide/hpt366.c Wed Oct 31 13:56:44 2001
@@ -1,7 +1,8 @@
/*
- * linux/drivers/ide/hpt366.c Version 0.18 June. 9, 2000
+ * linux/drivers/ide/hpt366.c Version 0.22 20 Sep 2001
*
* Copyright (C) 1999-2000 Andre Hedrick <andre@linux-ide.org>
+ * Portions Copyright (C) 2001 Sun Microsystems, Inc.
* May be copied or modified under the terms of the GNU General Public License
*
* Thanks to HighPoint Technologies for their assistance, and hardware.
@@ -11,6 +12,34 @@
*
* Note that final HPT370 support was done by force extraction of GPL.
*
+ * - add function for getting/setting power status of drive
+ * - the HPT370's state machine can get confused. reset it before each dma
+ * xfer to prevent that from happening.
+ * - reset state engine whenever we get an error.
+ * - check for busmaster state at end of dma.
+ * - use new highpoint timings.
+ * - detect bus speed using highpoint register.
+ * - use pll if we don't have a clock table. added a 66MHz table that's
+ * just 2x the 33MHz table.
+ * - removed turnaround. NOTE: we never want to switch between pll and
+ * pci clocks as the chip can glitch in those cases. the highpoint
+ * approved workaround slows everything down too much to be useful. in
+ * addition, we would have to serialize access to each chip.
+ * Adrian Sun <a.sun@sun.com>
+ *
+ * add drive timings for 66MHz PCI bus,
+ * fix ATA Cable signal detection, fix incorrect /proc info
+ * add /proc display for per-drive PIO/DMA/UDMA mode and
+ * per-channel ATA-33/66 Cable detect.
+ * Duncan Laurie <void@sun.com>
+ *
+ * fixup /proc output for multiple controllers
+ * Tim Hockin <thockin@sun.com>
+ *
+ * On hpt366:
+ * Reset the hpt366 on error, reset on dma
+ * Fix disabling Fast Interrupt hpt366.
+ * Mike Waychison <crlf@sun.com>
*/

#include <linux/config.h>
@@ -28,6 +57,7 @@
#include <linux/init.h>
#include <linux/ide.h>

+#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/irq.h>

@@ -35,6 +65,11 @@

#define DISPLAY_HPT366_TIMINGS

+/* various tuning parameters */
+#define HPT_RESET_STATE_ENGINE
+/*#define HPT_DELAY_INTERRUPT*/
+/*#define HPT_SERIALIZE_IO*/
+
#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
#include <linux/stat.h>
#include <linux/proc_fs.h>
@@ -106,146 +141,302 @@

struct chipset_bus_clock_list_entry {
byte xfer_speed;
- unsigned int chipset_settings_write;
- unsigned int chipset_settings_read;
+ unsigned int chipset_settings;
};

+/* key for bus clock timings
+ * bit
+ * 0:3 data_high_time. inactive time of DIOW_/DIOR_ for PIO and MW
+ * DMA. cycles = value + 1
+ * 4:8 data_low_time. active time of DIOW_/DIOR_ for PIO and MW
+ * DMA. cycles = value + 1
+ * 9:12 cmd_high_time. inactive time of DIOW_/DIOR_ during task file
+ * register access.
+ * 13:17 cmd_low_time. active time of DIOW_/DIOR_ during task file
+ * register access.
+ * 18:21 udma_cycle_time. clock freq and clock cycles for UDMA xfer.
+ * during task file register access.
+ * 22:24 pre_high_time. time to initialize 1st cycle for PIO and MW DMA
+ * xfer.
+ * 25:27 cmd_pre_high_time. time to initialize 1st PIO cycle for task
+ * register access.
+ * 28 UDMA enable
+ * 29 DMA enable
+ * 30 PIO_MST enable. if set, the chip is in bus master mode during
+ * PIO.
+ * 31 FIFO enable.
+ */
struct chipset_bus_clock_list_entry forty_base [] = {

- { XFER_UDMA_4, 0x900fd943, 0x900fd943 },
- { XFER_UDMA_3, 0x900ad943, 0x900ad943 },
- { XFER_UDMA_2, 0x900bd943, 0x900bd943 },
- { XFER_UDMA_1, 0x9008d943, 0x9008d943 },
- { XFER_UDMA_0, 0x9008d943, 0x9008d943 },
-
- { XFER_MW_DMA_2, 0xa008d943, 0xa008d943 },
- { XFER_MW_DMA_1, 0xa010d955, 0xa010d955 },
- { XFER_MW_DMA_0, 0xa010d9fc, 0xa010d9fc },
-
- { XFER_PIO_4, 0xc008d963, 0xc008d963 },
- { XFER_PIO_3, 0xc010d974, 0xc010d974 },
- { XFER_PIO_2, 0xc010d997, 0xc010d997 },
- { XFER_PIO_1, 0xc010d9c7, 0xc010d9c7 },
- { XFER_PIO_0, 0xc018d9d9, 0xc018d9d9 },
- { 0, 0x0120d9d9, 0x0120d9d9 }
+ { XFER_UDMA_4, 0x900fd943 },
+ { XFER_UDMA_3, 0x900ad943 },
+ { XFER_UDMA_2, 0x900bd943 },
+ { XFER_UDMA_1, 0x9008d943 },
+ { XFER_UDMA_0, 0x9008d943 },
+
+ { XFER_MW_DMA_2, 0xa008d943 },
+ { XFER_MW_DMA_1, 0xa010d955 },
+ { XFER_MW_DMA_0, 0xa010d9fc },
+
+ { XFER_PIO_4, 0xc008d963 },
+ { XFER_PIO_3, 0xc010d974 },
+ { XFER_PIO_2, 0xc010d997 },
+ { XFER_PIO_1, 0xc010d9c7 },
+ { XFER_PIO_0, 0xc018d9d9 },
+ { 0, 0x0120d9d9 }
};

struct chipset_bus_clock_list_entry thirty_three_base [] = {

- { XFER_UDMA_4, 0x90c9a731, 0x90c9a731 },
- { XFER_UDMA_3, 0x90cfa731, 0x90cfa731 },
- { XFER_UDMA_2, 0x90caa731, 0x90caa731 },
- { XFER_UDMA_1, 0x90cba731, 0x90cba731 },
- { XFER_UDMA_0, 0x90c8a731, 0x90c8a731 },
-
- { XFER_MW_DMA_2, 0xa0c8a731, 0xa0c8a731 },
- { XFER_MW_DMA_1, 0xa0c8a732, 0xa0c8a732 }, /* 0xa0c8a733 */
- { XFER_MW_DMA_0, 0xa0c8a797, 0xa0c8a797 },
-
- { XFER_PIO_4, 0xc0c8a731, 0xc0c8a731 },
- { XFER_PIO_3, 0xc0c8a742, 0xc0c8a742 },
- { XFER_PIO_2, 0xc0d0a753, 0xc0d0a753 },
- { XFER_PIO_1, 0xc0d0a7a3, 0xc0d0a7a3 }, /* 0xc0d0a793 */
- { XFER_PIO_0, 0xc0d0a7aa, 0xc0d0a7aa }, /* 0xc0d0a7a7 */
- { 0, 0x0120a7a7, 0x0120a7a7 }
+ { XFER_UDMA_4, 0x90c9a731 },
+ { XFER_UDMA_3, 0x90cfa731 },
+ { XFER_UDMA_2, 0x90caa731 },
+ { XFER_UDMA_1, 0x90cba731 },
+ { XFER_UDMA_0, 0x90c8a731 },
+
+ { XFER_MW_DMA_2, 0xa0c8a731 },
+ { XFER_MW_DMA_1, 0xa0c8a732 }, /* 0xa0c8a733 */
+ { XFER_MW_DMA_0, 0xa0c8a797 },
+
+ { XFER_PIO_4, 0xc0c8a731 },
+ { XFER_PIO_3, 0xc0c8a742 },
+ { XFER_PIO_2, 0xc0d0a753 },
+ { XFER_PIO_1, 0xc0d0a7a3 }, /* 0xc0d0a793 */
+ { XFER_PIO_0, 0xc0d0a7aa }, /* 0xc0d0a7a7 */
+ { 0, 0x0120a7a7 }
};

struct chipset_bus_clock_list_entry twenty_five_base [] = {

- { XFER_UDMA_4, 0x90c98521, 0x90c98521 },
- { XFER_UDMA_3, 0x90cf8521, 0x90cf8521 },
- { XFER_UDMA_2, 0x90cf8521, 0x90cf8521 },
- { XFER_UDMA_1, 0x90cb8521, 0x90cb8521 },
- { XFER_UDMA_0, 0x90cb8521, 0x90cb8521 },
-
- { XFER_MW_DMA_2, 0xa0ca8521, 0xa0ca8521 },
- { XFER_MW_DMA_1, 0xa0ca8532, 0xa0ca8532 },
- { XFER_MW_DMA_0, 0xa0ca8575, 0xa0ca8575 },
-
- { XFER_PIO_4, 0xc0ca8521, 0xc0ca8521 },
- { XFER_PIO_3, 0xc0ca8532, 0xc0ca8532 },
- { XFER_PIO_2, 0xc0ca8542, 0xc0ca8542 },
- { XFER_PIO_1, 0xc0d08572, 0xc0d08572 },
- { XFER_PIO_0, 0xc0d08585, 0xc0d08585 },
- { 0, 0x01208585, 0x01208585 }
+ { XFER_UDMA_4, 0x90c98521 },
+ { XFER_UDMA_3, 0x90cf8521 },
+ { XFER_UDMA_2, 0x90cf8521 },
+ { XFER_UDMA_1, 0x90cb8521 },
+ { XFER_UDMA_0, 0x90cb8521 },
+
+ { XFER_MW_DMA_2, 0xa0ca8521 },
+ { XFER_MW_DMA_1, 0xa0ca8532 },
+ { XFER_MW_DMA_0, 0xa0ca8575 },
+
+ { XFER_PIO_4, 0xc0ca8521 },
+ { XFER_PIO_3, 0xc0ca8532 },
+ { XFER_PIO_2, 0xc0ca8542 },
+ { XFER_PIO_1, 0xc0d08572 },
+ { XFER_PIO_0, 0xc0d08585 },
+ { 0, 0x01208585 }
+};
+
+#if 1
+/* these are the current (4 sep 2001) timings from highpoint */
+struct chipset_bus_clock_list_entry thirty_three_base_hpt370[] = {
+ { XFER_UDMA_5, 0x12446231 },
+ { XFER_UDMA_4, 0x12446231 },
+ { XFER_UDMA_3, 0x126c6231 },
+ { XFER_UDMA_2, 0x12486231 },
+ { XFER_UDMA_1, 0x124c6233 },
+ { XFER_UDMA_0, 0x12506297 },
+
+ { XFER_MW_DMA_2, 0x22406c31 },
+ { XFER_MW_DMA_1, 0x22406c33 },
+ { XFER_MW_DMA_0, 0x22406c97 },
+
+ { XFER_PIO_4, 0x06414e31 },
+ { XFER_PIO_3, 0x06414e42 },
+ { XFER_PIO_2, 0x06414e53 },
+ { XFER_PIO_1, 0x06814e93 },
+ { XFER_PIO_0, 0x06814ea7 },
+ { 0, 0x06814ea7 }
};

+/* 2x 33MHz timings */
+struct chipset_bus_clock_list_entry sixty_six_base_hpt370[] = {
+ { XFER_UDMA_5, 0x1488e673 },
+ { XFER_UDMA_4, 0x1488e673 },
+ { XFER_UDMA_3, 0x1498e673 },
+ { XFER_UDMA_2, 0x1490e673 },
+ { XFER_UDMA_1, 0x1498e677 },
+ { XFER_UDMA_0, 0x14a0e73f },
+
+ { XFER_MW_DMA_2, 0x2480fa73 },
+ { XFER_MW_DMA_1, 0x2480fa77 },
+ { XFER_MW_DMA_0, 0x2480fb3f },
+
+ { XFER_PIO_4, 0x0c82be73 },
+ { XFER_PIO_3, 0x0c82be95 },
+ { XFER_PIO_2, 0x0c82beb7 },
+ { XFER_PIO_1, 0x0d02bf37 },
+ { XFER_PIO_0, 0x0d02bf5f },
+ { 0, 0x0d02bf5f }
+};
+#else
+/* from highpoint documentation. these are old values */
struct chipset_bus_clock_list_entry thirty_three_base_hpt370[] = {
- { XFER_UDMA_5, 0x1A85F442, 0x16454e31 },
- { XFER_UDMA_4, 0x16454e31, 0x16454e31 },
- { XFER_UDMA_3, 0x166d4e31, 0x166d4e31 },
- { XFER_UDMA_2, 0x16494e31, 0x16494e31 },
- { XFER_UDMA_1, 0x164d4e31, 0x164d4e31 },
- { XFER_UDMA_0, 0x16514e31, 0x16514e31 },
-
- { XFER_MW_DMA_2, 0x26514e21, 0x26514e21 },
- { XFER_MW_DMA_1, 0x26514e33, 0x26514e33 },
- { XFER_MW_DMA_0, 0x26514e97, 0x26514e97 },
-
- { XFER_PIO_4, 0x06514e21, 0x06514e21 },
- { XFER_PIO_3, 0x06514e22, 0x06514e22 },
- { XFER_PIO_2, 0x06514e33, 0x06514e33 },
- { XFER_PIO_1, 0x06914e43, 0x06914e43 },
- { XFER_PIO_0, 0x06914e57, 0x06914e57 },
- { 0, 0x06514e57, 0x06514e57 }
+ { XFER_UDMA_5, 0x16454e31 },
+ { XFER_UDMA_4, 0x16454e31 },
+ { XFER_UDMA_3, 0x166d4e31 },
+ { XFER_UDMA_2, 0x16494e31 },
+ { XFER_UDMA_1, 0x164d4e31 },
+ { XFER_UDMA_0, 0x16514e31 },
+
+ { XFER_MW_DMA_2, 0x26514e21 },
+ { XFER_MW_DMA_1, 0x26514e33 },
+ { XFER_MW_DMA_0, 0x26514e97 },
+
+ { XFER_PIO_4, 0x06514e21 },
+ { XFER_PIO_3, 0x06514e22 },
+ { XFER_PIO_2, 0x06514e33 },
+ { XFER_PIO_1, 0x06914e43 },
+ { XFER_PIO_0, 0x06914e57 },
+ { 0, 0x06514e57 }
+};
+
+struct chipset_bus_clock_list_entry sixty_six_base_hpt370[] = {
+ { XFER_UDMA_5, 0x14846231 },
+ { XFER_UDMA_4, 0x14886231 },
+ { XFER_UDMA_3, 0x148c6231 },
+ { XFER_UDMA_2, 0x148c6231 },
+ { XFER_UDMA_1, 0x14906231 },
+ { XFER_UDMA_0, 0x14986231 },
+
+ { XFER_MW_DMA_2, 0x26514e21 },
+ { XFER_MW_DMA_1, 0x26514e33 },
+ { XFER_MW_DMA_0, 0x26514e97 },
+
+ { XFER_PIO_4, 0x06514e21 },
+ { XFER_PIO_3, 0x06514e22 },
+ { XFER_PIO_2, 0x06514e33 },
+ { XFER_PIO_1, 0x06914e43 },
+ { XFER_PIO_0, 0x06914e57 },
+ { 0, 0x06514e57 }
+};
+#endif
+
+struct chipset_bus_clock_list_entry fifty_base_hpt370[] = {
+ { XFER_UDMA_5, 0x12848242 },
+ { XFER_UDMA_4, 0x12ac8242 },
+ { XFER_UDMA_3, 0x128c8242 },
+ { XFER_UDMA_2, 0x120c8242 },
+ { XFER_UDMA_1, 0x12148254 },
+ { XFER_UDMA_0, 0x121882ea },
+
+ { XFER_MW_DMA_2, 0x22808242 },
+ { XFER_MW_DMA_1, 0x22808254 },
+ { XFER_MW_DMA_0, 0x228082ea },
+
+ { XFER_PIO_4, 0x0a81f442 },
+ { XFER_PIO_3, 0x0a81f443 },
+ { XFER_PIO_2, 0x0a81f454 },
+ { XFER_PIO_1, 0x0ac1f465 },
+ { XFER_PIO_0, 0x0ac1f48a },
+ { 0, 0x0ac1f48a }
};

#define HPT366_DEBUG_DRIVE_INFO 0
#define HPT370_ALLOW_ATA100_5 1
#define HPT366_ALLOW_ATA66_4 1
#define HPT366_ALLOW_ATA66_3 1
+#define HPT366_MAX_DEVS 8
+
+#define F_LOW_PCI_33 0x23
+#define F_LOW_PCI_40 0x29
+#define F_LOW_PCI_50 0x2d
+#define F_LOW_PCI_66 0x42
+
+static struct pci_dev *hpt_devs[HPT366_MAX_DEVS];
+static int n_hpt_devs;
+
+static unsigned int pci_rev_check_hpt3xx(struct pci_dev *dev);
+static unsigned int pci_rev2_check_hpt3xx(struct pci_dev *dev);
+byte hpt366_proc = 0;
+byte hpt363_shared_irq;
+byte hpt363_shared_pin;
+extern char *ide_xfer_verbose (byte xfer_rate);

#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
static int hpt366_get_info(char *, char **, off_t, int);
extern int (*hpt366_display_info)(char *, char **, off_t, int); /* ide-proc.c */
extern char *ide_media_verbose(ide_drive_t *);
-static struct pci_dev *bmide_dev;
-static struct pci_dev *bmide2_dev;

static int hpt366_get_info (char *buffer, char **addr, off_t offset, int count)
{
- char *p = buffer;
- u32 bibma = bmide_dev->resource[4].start;
- u32 bibma2 = bmide2_dev->resource[4].start;
- char *chipset_names[] = {"HPT366", "HPT366", "HPT368", "HPT370", "HPT370A"};
- u8 c0 = 0, c1 = 0;
- u32 class_rev;
-
- pci_read_config_dword(bmide_dev, PCI_CLASS_REVISION, &class_rev);
- class_rev &= 0xff;
-
- /*
- * at that point bibma+0x2 et bibma+0xa are byte registers
- * to investigate:
- */
- c0 = inb_p((unsigned short)bibma + 0x02);
- if (bmide2_dev)
- c1 = inb_p((unsigned short)bibma2 + 0x02);
-
- p += sprintf(p, "\n %s Chipset.\n", chipset_names[class_rev]);
- p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
- p += sprintf(p, " %sabled %sabled\n",
- (c0&0x80) ? "dis" : " en",
- (c1&0x80) ? "dis" : " en");
- p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
- p += sprintf(p, "DMA enabled: %s %s %s %s\n",
- (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ",
- (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " );
-
- p += sprintf(p, "UDMA\n");
- p += sprintf(p, "DMA\n");
- p += sprintf(p, "PIO\n");
+ char *p = buffer;
+ char *chipset_nums[] = {"366", "366", "368", "370", "370A"};
+ int i;
+
+ p += sprintf(p, "\n "
+ "HighPoint HPT366/368/370\n");
+ for (i = 0; i < n_hpt_devs; i++) {
+ struct pci_dev *dev = hpt_devs[i];
+ unsigned short iobase = dev->resource[4].start;
+ u32 class_rev;
+ u8 c0, c1;
+
+ pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+ class_rev &= 0xff;
+
+ p += sprintf(p, "\nController: %d\n", i);
+ p += sprintf(p, "Chipset: HPT%s\n", chipset_nums[class_rev]);
+ p += sprintf(p, "--------------- Primary Channel "
+ "--------------- Secondary Channel "
+ "--------------\n");
+
+ /* get the bus master status registers */
+ c0 = inb_p(iobase + 0x2);
+ c1 = inb_p(iobase + 0xa);
+ p += sprintf(p, "Enabled: %s"
+ " %s\n",
+ (c0 & 0x80) ? "no" : "yes",
+ (c1 & 0x80) ? "no" : "yes");
+
+ if (pci_rev_check_hpt3xx(dev)) {
+ u8 cbl;
+ cbl = inb_p(iobase + 0x7b);
+ outb_p(cbl | 1, iobase + 0x7b);
+ outb_p(cbl & ~1, iobase + 0x7b);
+ cbl = inb_p(iobase + 0x7a);
+ p += sprintf(p, "Cable: ATA-%d"
+ " ATA-%d\n",
+ (cbl & 0x02) ? 33 : 66,
+ (cbl & 0x01) ? 33 : 66);
+ p += sprintf(p, "\n");
+ }

+ p += sprintf(p, "--------------- drive0 --------- drive1 "
+ "------- drive0 ---------- drive1 -------\n");
+ p += sprintf(p, "DMA capable: %s %s"
+ " %s %s\n",
+ (c0 & 0x20) ? "yes" : "no ",
+ (c0 & 0x40) ? "yes" : "no ",
+ (c1 & 0x20) ? "yes" : "no ",
+ (c1 & 0x40) ? "yes" : "no ");
+
+ {
+ u8 c2, c3;
+ /* older revs don't have these registers mapped
+ * into io space */
+ pci_read_config_byte(dev, 0x43, &c0);
+ pci_read_config_byte(dev, 0x47, &c1);
+ pci_read_config_byte(dev, 0x4b, &c2);
+ pci_read_config_byte(dev, 0x4f, &c3);
+
+ p += sprintf(p, "Mode: %s %s"
+ " %s %s\n",
+ (c0 & 0x10) ? "UDMA" : (c0 & 0x20) ? "DMA " :
+ (c0 & 0x80) ? "PIO " : "off ",
+ (c1 & 0x10) ? "UDMA" : (c1 & 0x20) ? "DMA " :
+ (c1 & 0x80) ? "PIO " : "off ",
+ (c2 & 0x10) ? "UDMA" : (c2 & 0x20) ? "DMA " :
+ (c2 & 0x80) ? "PIO " : "off ",
+ (c3 & 0x10) ? "UDMA" : (c3 & 0x20) ? "DMA " :
+ (c3 & 0x80) ? "PIO " : "off ");
+ }
+ }
+ p += sprintf(p, "\n");
+
return p-buffer;/* => must be less than 4k! */
}
#endif /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */

-byte hpt366_proc = 0;
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-byte hpt363_shared_irq;
-byte hpt363_shared_pin;
-
static unsigned int pci_rev_check_hpt3xx (struct pci_dev *dev)
{
unsigned int class_rev;
@@ -282,16 +473,16 @@
return 0;
}

-static unsigned int pci_bus_clock_list (byte speed, int direction, struct chipset_bus_clock_list_entry * chipset_table)
+static unsigned int pci_bus_clock_list (byte speed, struct chipset_bus_clock_list_entry * chipset_table)
{
for ( ; chipset_table->xfer_speed ; chipset_table++)
if (chipset_table->xfer_speed == speed) {
- return (direction) ? chipset_table->chipset_settings_write : chipset_table->chipset_settings_read;
+ return chipset_table->chipset_settings;
}
- return (direction) ? chipset_table->chipset_settings_write : chipset_table->chipset_settings_read;
+ return chipset_table->chipset_settings;
}

-static void hpt366_tune_chipset (ide_drive_t *drive, byte speed, int direction)
+static void hpt366_tune_chipset (ide_drive_t *drive, byte speed)
{
byte regtime = (drive->select.b.unit & 0x01) ? 0x44 : 0x40;
byte regfast = (HWIF(drive)->channel) ? 0x55 : 0x51;
@@ -304,36 +495,24 @@
byte drive_fast = 0;

/*
- * Disable the "fast interrupt" prediction.
+ * Disable the "fast interrupt" prediction.
*/
pci_read_config_byte(HWIF(drive)->pci_dev, regfast, &drive_fast);
-
- /*
- * FIXME kludge to correct a detection problem or driver design flaw.
- */
- if (pci_rev_check_hpt3xx(HWIF(drive)->pci_dev)) {
- if (drive_fast & 0x80)
- pci_write_config_byte(HWIF(drive)->pci_dev, regfast, drive_fast & ~0x80);
- } else {
- if (drive_fast & 0x02)
- pci_write_config_byte(HWIF(drive)->pci_dev, regfast, drive_fast& ~0x20);
- }
- /*
- * FIXME kludge end of fsckup
- */
+ if (drive_fast & 0x80)
+ pci_write_config_byte(HWIF(drive)->pci_dev, regfast, drive_fast & ~0x80);

pci_read_config_dword(HWIF(drive)->pci_dev, regtime, &reg1);
/* detect bus speed by looking at control reg timing: */
switch((reg1 >> 8) & 15) {
case 5:
- reg2 = pci_bus_clock_list(speed, direction, forty_base);
+ reg2 = pci_bus_clock_list(speed, forty_base);
break;
case 9:
- reg2 = pci_bus_clock_list(speed, direction, twenty_five_base);
+ reg2 = pci_bus_clock_list(speed, twenty_five_base);
break;
default:
case 7:
- reg2 = pci_bus_clock_list(speed, direction, thirty_three_base);
+ reg2 = pci_bus_clock_list(speed, thirty_three_base);
break;
}
/*
@@ -349,40 +528,47 @@
pci_write_config_dword(HWIF(drive)->pci_dev, regtime, reg2);
}

-static void hpt370_tune_chipset (ide_drive_t *drive, byte speed, int direction)
+static void hpt370_tune_chipset (ide_drive_t *drive, byte speed)
{
byte regfast = (HWIF(drive)->channel) ? 0x55 : 0x51;
- byte reg5bh = (speed != XFER_UDMA_5) ? 0x22 : (direction) ? 0x20 : 0x22;
- unsigned int list_conf = pci_bus_clock_list(speed, direction, thirty_three_base_hpt370);
+ unsigned int list_conf = 0;
unsigned int drive_conf = 0;
unsigned int conf_mask = (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
- byte drive_pci = 0;
- byte drive_fast = 0;
+ byte drive_pci = 0x40 + (drive->dn * 4);
+ byte new_fast, drive_fast = 0;
+ struct pci_dev *dev = HWIF(drive)->pci_dev;

- switch (drive->dn) {
- case 0: drive_pci = 0x40; break;
- case 1: drive_pci = 0x44; break;
- case 2: drive_pci = 0x48; break;
- case 3: drive_pci = 0x4c; break;
- default: return;
- }
/*
* Disable the "fast interrupt" prediction.
+ * don't holdoff on interrupts. (== 0x01 despite what the docs say)
*/
- pci_read_config_byte(HWIF(drive)->pci_dev, regfast, &drive_fast);
- if (drive_fast & 0x80)
- pci_write_config_byte(HWIF(drive)->pci_dev, regfast, drive_fast & ~0x80);
+ pci_read_config_byte(dev, regfast, &drive_fast);
+ new_fast = drive_fast;
+ if (new_fast & 0x02)
+ new_fast &= ~0x02;
+
+#ifdef HPT_DELAY_INTERRUPT
+ if (new_fast & 0x01)
+ new_fast &= ~0x01;
+#else
+ if ((new_fast & 0x01) == 0)
+ new_fast |= 0x01;
+#endif
+ if (new_fast != drive_fast)
+ pci_write_config_byte(HWIF(drive)->pci_dev, regfast, new_fast);

- pci_read_config_dword(HWIF(drive)->pci_dev, drive_pci, &drive_conf);
- pci_write_config_byte(HWIF(drive)->pci_dev, 0x5b, reg5bh);
+ list_conf = pci_bus_clock_list(speed,
+ (struct chipset_bus_clock_list_entry *)
+ dev->sysdata);

+ pci_read_config_dword(dev, drive_pci, &drive_conf);
list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
- /*
- * Disable on-chip PIO FIFO/buffer (to avoid problems handling I/O errors later)
- */
- list_conf &= ~0x80000000;
+
+ if (speed < XFER_MW_DMA_0) {
+ list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
+ }

- pci_write_config_dword(HWIF(drive)->pci_dev, drive_pci, list_conf);
+ pci_write_config_dword(dev, drive_pci, list_conf);
}

static int hpt3xx_tune_chipset (ide_drive_t *drive, byte speed)
@@ -394,9 +580,9 @@
drive->init_speed = speed;

if (pci_rev_check_hpt3xx(HWIF(drive)->pci_dev)) {
- hpt370_tune_chipset(drive, speed, 0);
+ hpt370_tune_chipset(drive, speed);
} else {
- hpt366_tune_chipset(drive, speed, 0);
+ hpt366_tune_chipset(drive, speed);
}
drive->current_speed = speed;
return ((int) ide_config_drive_speed(drive, speed));
@@ -525,9 +711,8 @@

void hpt3xx_intrproc (ide_drive_t *drive)
{
- if (drive->quirk_list) {
+ if (!drive->quirk_list) {
/* drives in the quirk_list may not like intr setups/cleanups */
- } else {
OUT_BYTE((drive)->ctl|2, HWIF(drive)->io_ports[IDE_CONTROL_OFFSET]);
}
}
@@ -553,13 +738,6 @@
}
}

-void hpt370_rw_proc (ide_drive_t *drive, ide_dma_action_t func)
-{
- if ((func != ide_dma_write) || (func != ide_dma_read))
- return;
- hpt370_tune_chipset(drive, drive->current_speed, (func == ide_dma_write));
-}
-
static int config_drive_xfer_rate (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
@@ -573,7 +751,7 @@
}
dma_func = ide_dma_off_quietly;
if (id->field_valid & 4) {
- if (id->dma_ultra & 0x003F) {
+ if (id->dma_ultra & 0x002F) {
/* Force if Capable UltraDMA */
dma_func = config_chipset_for_dma(drive);
if ((id->field_valid & 2) &&
@@ -636,17 +814,13 @@
reg50h, reg52h, reg5ah);
if (reg5ah & 0x10)
pci_write_config_byte(HWIF(drive)->pci_dev, 0x5a, reg5ah & ~0x10);
- /* how about we flush and reset, mmmkay? */
- pci_write_config_byte(HWIF(drive)->pci_dev, 0x51, 0x1F);
+ /* fall through to a reset */

- break;
-#if 0
case ide_dma_begin:
case ide_dma_end:
/* reset the chips state over and over.. */
pci_write_config_byte(HWIF(drive)->pci_dev, 0x51, 0x13);
break;
-#endif
case ide_dma_timeout:
default:
break;
@@ -656,8 +830,11 @@

int hpt370_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
{
- byte dma_stat = 0;
- unsigned long dma_base = HWIF(drive)->dma_base;
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned long dma_base = hwif->dma_base;
+ byte regstate = hwif->channel ? 0x54 : 0x50;
+ byte reginfo = hwif->channel ? 0x56 : 0x52;
+ byte dma_stat;

switch (func) {
case ide_dma_check:
@@ -665,15 +842,40 @@
case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */
dma_stat = inb(dma_base+2);
return (dma_stat & 4) == 4; /* return 1 if INTR asserted */
- case ide_dma_lostirq:
- /* how about we flush and reset, mmmkay? */
- pci_write_config_byte(HWIF(drive)->pci_dev, 0x51, 0x1F);
- break;
- case ide_dma_begin:
+
case ide_dma_end:
- /* reset the chips state over and over.. */
- pci_write_config_byte(HWIF(drive)->pci_dev, 0x51, 0x13);
+ dma_stat = inb(dma_base + 2);
+ if (dma_stat & 0x01) {
+ udelay(20); /* wait a little */
+ dma_stat = inb(dma_base + 2);
+ }
+ if ((dma_stat & 0x01) == 0)
+ break;
+
+ func = ide_dma_timeout;
+ /* fallthrough */
+
+ case ide_dma_timeout:
+ case ide_dma_lostirq:
+ pci_read_config_byte(hwif->pci_dev, reginfo,
+ &dma_stat);
+ printk("%s: %d bytes in FIFO\n", drive->name,
+ dma_stat);
+ pci_write_config_byte(hwif->pci_dev, regstate, 0x37);
+ udelay(10);
+ dma_stat = inb(dma_base);
+ outb(dma_stat & ~0x1, dma_base); /* stop dma */
+ dma_stat = inb(dma_base + 2);
+ outb(dma_stat | 0x6, dma_base+2); /* clear errors */
+ /* fallthrough */
+
+#ifdef HPT_RESET_STATE_ENGINE
+ case ide_dma_begin:
+#endif
+ pci_write_config_byte(hwif->pci_dev, regstate, 0x37);
+ udelay(10);
break;
+
default:
break;
}
@@ -681,6 +883,87 @@
}
#endif /* CONFIG_BLK_DEV_IDEDMA */

+static void __init init_hpt370(struct pci_dev *dev)
+{
+ int adjust, i;
+ u16 freq;
+ u32 pll;
+ byte reg5bh;
+
+ /* default to pci clock. make sure MA15/16 are set to output
+ * to prevent drives having problems with 40-pin cables. */
+ pci_write_config_byte(dev, 0x5b, 0x23);
+
+ /* set up the PLL. we need to adjust it so that it's stable.
+ * freq = Tpll * 192 / Tpci */
+ pci_read_config_word(dev, 0x78, &freq);
+ freq &= 0x1FF;
+ if (freq < 0x9c) {
+ pll = F_LOW_PCI_33;
+ dev->sysdata = (void *) thirty_three_base_hpt370;
+ printk("HPT370: using 33MHz PCI clock\n");
+ } else if (freq < 0xb0)
+ pll = F_LOW_PCI_40;
+ else if (freq < 0xc8) {
+ pll = F_LOW_PCI_50;
+ dev->sysdata = (void *) fifty_base_hpt370;
+ printk("HPT370: using 50MHz PCI clock\n");
+ } else {
+ pll = F_LOW_PCI_66;
+ dev->sysdata = (void *) sixty_six_base_hpt370;
+ printk("HPT370: using 66MHz PCI clock\n");
+ }
+
+ /* only try the pll if we don't have a table for the clock
+ * speed that we're running at. NOTE: the internal PLL will
+ * result in slow reads when using a 33MHz PCI clock. we also
+ * don't like to use the PLL because it will cause glitches
+ * on PRST/SRST when the HPT state engine gets reset. */
+ if (dev->sysdata)
+ goto init_hpt370_done;
+
+ /* adjust PLL based upon PCI clock, enable it, and wait for
+ stabilization. */
+ adjust = 0;
+ freq = (pll < F_LOW_PCI_50) ? 2 : 4;
+ while (adjust++ < 6) {
+ pci_write_config_dword(dev, 0x5c, (freq + pll) << 16 |
+ pll | 0x100);
+
+ /* wait for clock stabilization */
+ for (i = 0; i < 0x50000; i++) {
+ pci_read_config_byte(dev, 0x5b, &reg5bh);
+ if (reg5bh & 0x80) {
+ /* spin looking for the clock to destabilize */
+ for (i = 0; i < 0x1000; ++i) {
+ pci_read_config_byte(dev, 0x5b,
+ &reg5bh);
+ if ((reg5bh & 0x80) == 0)
+ goto pll_recal;
+ }
+ pci_read_config_dword(dev, 0x5c, &pll);
+ pci_write_config_dword(dev, 0x5c,
+ pll & ~0x100);
+ pci_write_config_byte(dev, 0x5b, 0x21);
+ dev->sysdata = (void *) fifty_base_hpt370;
+ printk("HPT370: using 50MHz internal PLL\n");
+ goto init_hpt370_done;
+ }
+ }
+pll_recal:
+ if (adjust & 1)
+ pll -= (adjust >> 1);
+ else
+ pll += (adjust >> 1);
+ }
+
+init_hpt370_done:
+ /* reset state engine */
+ pci_write_config_byte(dev, 0x50, 0x37);
+ pci_write_config_byte(dev, 0x54, 0x37);
+ udelay(100);
+}
+
unsigned int __init pci_init_hpt366 (struct pci_dev *dev, const char *name)
{
byte test = 0;
@@ -689,14 +972,8 @@
pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);

pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &test);
-
-#if 0
- if (test != 0x08)
- pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x08);
-#else
if (test != (L1_CACHE_BYTES / 4))
pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
-#endif

pci_read_config_byte(dev, PCI_LATENCY_TIMER, &test);
if (test != 0x78)
@@ -710,17 +987,15 @@
if (test != 0x08)
pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);

+ if (pci_rev_check_hpt3xx(dev))
+ init_hpt370(dev);
+
+ hpt_devs[n_hpt_devs++] = dev;
#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
if (!hpt366_proc) {
hpt366_proc = 1;
- bmide_dev = dev;
- if (pci_rev_check_hpt3xx(dev))
- bmide2_dev = dev;
hpt366_display_info = &hpt366_get_info;
}
- if ((hpt366_proc) && ((dev->devfn - bmide_dev->devfn) == 1)) {
- bmide2_dev = dev;
- }
#endif /* DISPLAY_HPT366_TIMINGS && CONFIG_PROC_FS */

return dev->irq;
@@ -729,37 +1004,121 @@
unsigned int __init ata66_hpt366 (ide_hwif_t *hwif)
{
byte ata66 = 0;
+ int is33 = 0;

pci_read_config_byte(hwif->pci_dev, 0x5a, &ata66);
+ if (hwif->channel) {
+ is33 = ata66 & 1;
+ } else {
+ is33 = ata66 & 2;
+ }
+
#ifdef DEBUG
printk("HPT366: reg5ah=0x%02x ATA-%s Cable Port%d\n",
- ata66, (ata66 & 0x02) ? "33" : "66",
+ ata66, is33 ? "33" : "66",
PCI_FUNC(hwif->pci_dev->devfn));
#endif /* DEBUG */
- return ((ata66 & 0x02) ? 0 : 1);
+ return (!is33);
+}
+
+/*
+ * set/get power state for a drive.
+ * turning the power off does the following things:
+ * 1) soft-reset the drive
+ * 2) tri-states the ide bus
+ *
+ * when we turn things back on, we need to re-initialize things.
+ */
+#define TRISTATE_BIT 0x8000
+static int hpt3xx_busproc(ide_hwif_t *hwif, int state)
+{
+ byte tristate, resetmask, bus_reg;
+ u16 tri_reg;
+
+ if (!hwif)
+ return -EINVAL;
+
+ hwif->bus_state = state;
+
+ if (hwif->channel) {
+ /* secondary channel */
+ tristate = 0x56;
+ resetmask = 0x80;
+ } else {
+ /* primary channel */
+ tristate = 0x52;
+ resetmask = 0x40;
+ }
+
+ /* grab status */
+ pci_read_config_word(hwif->pci_dev, tristate, &tri_reg);
+ pci_read_config_byte(hwif->pci_dev, 0x59, &bus_reg);
+
+ /* set the state. we don't set it if we don't need to do so.
+ * make sure that the drive knows that it has failed if it's off */
+ switch (state) {
+ case BUSSTATE_ON:
+ hwif->drives[0].failures = 0;
+ hwif->drives[1].failures = 0;
+ if ((bus_reg & resetmask) == 0)
+ return 0;
+ tri_reg &= ~TRISTATE_BIT;
+ bus_reg &= ~resetmask;
+ break;
+ case BUSSTATE_OFF:
+ hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+ hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+ if ((tri_reg & TRISTATE_BIT) == 0 && (bus_reg & resetmask))
+ return 0;
+ tri_reg &= ~TRISTATE_BIT;
+ bus_reg |= resetmask;
+ break;
+ case BUSSTATE_TRISTATE:
+ hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+ hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+ if ((tri_reg & TRISTATE_BIT) && (bus_reg & resetmask))
+ return 0;
+ tri_reg |= TRISTATE_BIT;
+ bus_reg |= resetmask;
+ break;
+ }
+ pci_write_config_byte(hwif->pci_dev, 0x59, bus_reg);
+ pci_write_config_word(hwif->pci_dev, tristate, tri_reg);
+
+ return 0;
}

void __init ide_init_hpt366 (ide_hwif_t *hwif)
{
+ int hpt_rev;
+
hwif->tuneproc = &hpt3xx_tune_drive;
hwif->speedproc = &hpt3xx_tune_chipset;
hwif->quirkproc = &hpt3xx_quirkproc;
hwif->intrproc = &hpt3xx_intrproc;
hwif->maskproc = &hpt3xx_maskproc;

- if (pci_rev2_check_hpt3xx(hwif->pci_dev)) {
- /* do nothing now but will split device types */
+#ifdef HPT_SERIALIZE_IO
+ /* serialize access to this device */
+ if (hwif->mate)
+ hwif->serialized = hwif->mate->serialized = 1;
+#endif
+
+ hpt_rev = pci_rev_check_hpt3xx(hwif->pci_dev);
+ if (hpt_rev) {
+ /* set up ioctl for power status. note: power affects both
+ * drives on each channel */
+ hwif->busproc = &hpt3xx_busproc;
}

#ifdef CONFIG_BLK_DEV_IDEDMA
if (hwif->dma_base) {
- if (pci_rev_check_hpt3xx(hwif->pci_dev)) {
+ if (hpt_rev) {
byte reg5ah = 0;
pci_read_config_byte(hwif->pci_dev, 0x5a, &reg5ah);
if (reg5ah & 0x10) /* interrupt force enable */
pci_write_config_byte(hwif->pci_dev, 0x5a, reg5ah & ~0x10);
hwif->dmaproc = &hpt370_dmaproc;
- hwif->rwproc = &hpt370_rw_proc;
} else {
hwif->dmaproc = &hpt366_dmaproc;
}diff -ruN dist-2.4.13+patches/drivers/ide/serverworks.c linux-2.4/drivers/ide/serverworks.c
--- dist-2.4.13+patches/drivers/ide/serverworks.c Mon Oct 1 16:43:56 2001
+++ linux-2.4/drivers/ide/serverworks.c Fri Oct 26 19:39:02 2001
@@ -1,16 +1,26 @@
/*
- * linux/drivers/ide/serverworks.c Version 0.2 17 Oct 2000
+ * linux/drivers/ide/serverworks.c Version 0.3 26 Oct 2001
*
- * Copyright (C) 2000 Cobalt Networks, Inc. <asun@cobalt.com>
- * May be copied or modified under the terms of the GNU General Public License
+ * May be copied or modified under the terms of the GNU General Public License
*
- * interface borrowed from alim15x3.c:
- * Copyright (C) 1998-2000 Michel Aubry, Maintainer
- * Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer
+ * Copyright (C) 1998-2000 Michel Aubry
+ * Copyright (C) 1998-2000 Andrzej Krzysztofowicz
+ * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
+ * Portions copyright (c) 2001 Sun Microsystems
*
- * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
*
- * IDE support for the ServerWorks OSB4 IDE chipset
+ * RCC/ServerWorks IDE driver for Linux
+ *
+ * OSB4: `Open South Bridge' IDE Interface (fn 1)
+ * supports UDMA mode 2 (33 MB/s)
+ *
+ * CSB5: `Champion South Bridge' IDE Interface (fn 1)
+ * all revisions support UDMA mode 4 (66 MB/s)
+ * revision A2.0 and up support UDMA mode 5 (100 MB/s)
+ *
+ * *** The CSB5 does not provide ANY register ***
+ * *** to detect 80-conductor cable presence. ***
+ *
*
* here's the default lspci:
*
@@ -83,15 +93,15 @@

#include "ide_modes.h"

-#define SVWKS_DEBUG_DRIVE_INFO 0
-
-#define DISPLAY_SVWKS_TIMINGS
+#define DISPLAY_SVWKS_TIMINGS 1
+#undef SVWKS_DEBUG_DRIVE_INFO

#if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS)
#include <linux/stat.h>
#include <linux/proc_fs.h>

static struct pci_dev *bmide_dev;
+static byte svwks_revision = 0;

static int svwks_get_info(char *, char **, off_t, int);
extern int (*svwks_display_info)(char *, char **, off_t, int); /* ide-proc.c */
@@ -103,7 +113,7 @@
u32 bibma = pci_resource_start(bmide_dev, 4);
u32 reg40, reg44;
u16 reg48, reg56;
- u8 c0 = 0, c1 = 0, reg54;
+ u8 reg54, c0=0, c1=0;

pci_read_config_dword(bmide_dev, 0x40, &reg40);
pci_read_config_dword(bmide_dev, 0x44, &reg44);
@@ -120,20 +130,23 @@

switch(bmide_dev->device) {
case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
- p += sprintf(p, "\n ServerWorks CSB5 Chipset.\n");
+ p += sprintf(p, "\n "
+ "ServerWorks CSB5 Chipset (rev %02x)\n",
+ svwks_revision);
break;
- case PCI_DEVICE_ID_SERVERWORKS_OSB4:
- p += sprintf(p, "\n ServerWorks OSB4 Chipset.\n");
+ case PCI_DEVICE_ID_SERVERWORKS_OSB4IDE:
+ p += sprintf(p, "\n "
+ "ServerWorks OSB4 Chipset (rev %02x)\n",
+ svwks_revision);
break;
default:
- p += sprintf(p, "\n ServerWorks 0x%04x Chipset.\n", bmide_dev->device);
+ p += sprintf(p, "\n "
+ "ServerWorks %04x Chipset (rev %02x)\n",
+ bmide_dev->device, svwks_revision);
break;
}

p += sprintf(p, "------------------------------- General Status ---------------------------------\n");
-#if 0
- p += sprintf(p, " : %s\n", "str");
-#endif
p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
p += sprintf(p, " %sabled %sabled\n",
(c0&0x80) ? "dis" : " en",
@@ -191,11 +204,7 @@
((reg44&0x00210000)==0x00210000)?"1":
((reg44&0x00770000)==0x00770000)?"0":
((reg44&0x00FF0000)==0x00FF0000)?"X":"?");
-#if 0
- if (bmide_dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
- p += sprintf(p, "PIO enabled: %s %s %s %s\n",
- if (bmide_dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4)
-#endif
+
p += sprintf(p, "PIO enabled: %s %s %s %s\n",
((reg40&0x00002000)==0x00002000)?"4":
((reg40&0x00002200)==0x00002200)?"3":
@@ -221,7 +230,7 @@
}
#endif /* defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS) */

-static byte svwks_revision = 0;
+#define SVWKS_CSB5_REVISION_NEW 0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */

byte svwks_proc = 0;

@@ -292,6 +301,7 @@
pio_timing |= pio_modes[speed - XFER_PIO_0];
csb5_pio |= ((speed - XFER_PIO_0) << (4*drive->dn));
break;
+
#ifdef CONFIG_BLK_DEV_IDEDMA
case XFER_MW_DMA_2:
case XFER_MW_DMA_1:
@@ -307,9 +317,9 @@
case XFER_UDMA_2:
case XFER_UDMA_1:
case XFER_UDMA_0:
- pio_timing |= pio_modes[pio];
- csb5_pio |= (pio << (4*drive->dn));
- dma_timing |= dma_modes[2];
+ 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);
#endif
@@ -322,9 +332,9 @@
drive->name, ultra_timing, dma_timing, pio_timing);
#endif

-#if OSB4_DEBUG_DRIVE_INFO
+#if SVWKS_DEBUG_DRIVE_INFO
printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive->dn);
-#endif /* OSB4_DEBUG_DRIVE_INFO */
+#endif /* SVWKS_DEBUG_DRIVE_INFO */

if (!drive->init_speed)
drive->init_speed = speed;
@@ -338,11 +348,10 @@
pci_write_config_byte(dev, drive_pci3, ultra_timing);
pci_write_config_byte(dev, 0x54, ultra_enable);

- if (speed > XFER_PIO_4) {
+ if (speed > XFER_PIO_4)
outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
- } else {
+ else
outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
- }
#endif /* CONFIG_BLK_DEV_IDEDMA */

err = ide_config_drive_speed(drive, speed);
@@ -354,25 +363,24 @@
{
unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
unsigned short xfer_pio = drive->id->eide_pio_modes;
- byte timing, speed, pio;
+ byte timing, speed, pio;

pio = ide_get_best_pio_mode(drive, 255, 5, NULL);

if (xfer_pio> 4)
xfer_pio = 0;

- if (drive->id->eide_pio_iordy > 0) {
+ 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--);
- } else {
+ else
xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
(drive->id->eide_pio_modes & 2) ? 0x04 :
(drive->id->eide_pio_modes & 1) ? 0x03 :
(drive->id->tPIO & 2) ? 0x02 :
(drive->id->tPIO & 1) ? 0x01 : xfer_pio;
- }

timing = (xfer_pio >= pio) ? xfer_pio : pio;

@@ -407,12 +415,10 @@
{
struct hd_driveid *id = drive->id;
struct pci_dev *dev = HWIF(drive)->pci_dev;
- byte udma_66 = eighty_ninty_three(drive);
- byte speed;
-
- int ultra66 = (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ? 1 : 0;
- /* need specs to figure out if osb4 is capable of ata/66/100 */
- int ultra100 = (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ? 1 : 0;
+ byte udma_66 = eighty_ninty_three(drive);
+ int ultra66 = (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ? 1 : 0;
+ int ultra100 = (ultra66 && svwks_revision >= SVWKS_CSB5_REVISION_NEW) ? 1 : 0;
+ byte speed;

if ((id->dma_ultra & 0x0020) && (udma_66) && (ultra100)) {
speed = XFER_UDMA_5;
@@ -499,7 +505,7 @@
switch (func) {
case ide_dma_check:
return config_drive_xfer_rate(drive);
- default :
+ default:
break;
}
/* Other cases are done by generic IDE-DMA code. */
@@ -509,30 +515,43 @@

unsigned int __init pci_init_svwks (struct pci_dev *dev, const char *name)
{
- unsigned int reg64;
+ unsigned int reg;
+ byte btr;

+ /* save revision id to determine DMA capability */
pci_read_config_byte(dev, PCI_REVISION_ID, &svwks_revision);

- if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
- isa_dev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL);
+ /* force Master Latency Timer value to 64 PCICLKs */
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40);

- pci_read_config_dword(isa_dev, 0x64, &reg64);
-#ifdef DEBUG
- printk("%s: reg64 == 0x%08x\n", name, reg64);
-#endif
+ /* OSB4 : South Bridge and IDE */
+ if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
+ isa_dev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS,
+ PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL);
+ if (isa_dev) {
+ pci_read_config_dword(isa_dev, 0x64, &reg);
+ reg &= ~0x00002000; /* disable 600ns interrupt mask */
+ reg |= 0x00004000; /* enable UDMA/33 support */
+ pci_write_config_dword(isa_dev, 0x64, reg);
+ }
+ }

-// reg64 &= ~0x0000A000;
-//#ifdef CONFIG_SMP
-// reg64 |= 0x00008000;
-//#endif
- /* Assume the APIC was set up properly by the BIOS for now . If it
- wasnt we need to do a fix up _way_ earlier. Bits 15,10,3 control
- APIC enable, routing and decode */
-
- reg64 &= ~0x00002000;
- pci_write_config_dword(isa_dev, 0x64, reg64);
+ /* setup CSB5 : South Bridge and IDE */
+ else if (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) {
+ /* setup the UDMA Control register
+ *
+ * 1. clear bit 6 to enable DMA
+ * 2. enable DMA modes with bits 0-1
+ * 00 : legacy
+ * 01 : udma2
+ * 10 : udma2/udma4
+ * 11 : udma2/udma4/udma5
+ */
+ pci_read_config_byte(dev, 0x5A, &btr);
+ btr &= ~0x40;
+ btr |= (svwks_revision >= SVWKS_CSB5_REVISION_NEW) ? 0x3 : 0x2;
+ pci_write_config_byte(dev, 0x5A, btr);
}
- pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40);

#if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS)
if (!svwks_proc) {
@@ -551,26 +570,46 @@
* Bit 14 clear = primary IDE channel does not have 80-pin cable.
* Bit 14 set = primary IDE channel has 80-pin cable.
*/
-
static unsigned int __init ata66_svwks_dell (ide_hwif_t *hwif)
{
- struct pci_dev *dev = hwif->pci_dev;
- if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL &&
- dev->vendor == PCI_VENDOR_ID_SERVERWORKS &&
- dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
+ struct pci_dev *dev = hwif->pci_dev;
+ if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL &&
+ dev->vendor == PCI_VENDOR_ID_SERVERWORKS &&
+ dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
return ((1 << (hwif->channel + 14)) &
dev->subsystem_device) ? 1 : 0;
-
return 0;
+}

+/* Sun Cobalt Alpine hardware avoids the 80-pin cable
+ * detect issue by attaching the drives directly to the board.
+ * This check follows the Dell precedent (how scary is that?!)
+ *
+ * WARNING: this only works on Alpine hardware!
+ */
+static unsigned int __init ata66_svwks_cobalt (ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = hwif->pci_dev;
+ if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN &&
+ dev->vendor == PCI_VENDOR_ID_SERVERWORKS &&
+ dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
+ return ((1 << (hwif->channel + 14)) &
+ dev->subsystem_device) ? 1 : 0;
+ return 0;
}

unsigned int __init ata66_svwks (ide_hwif_t *hwif)
{
- struct pci_dev *dev = hwif->pci_dev;
+ struct pci_dev *dev = hwif->pci_dev;
+
+ /* Dell PowerEdge */
if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL)
return ata66_svwks_dell (hwif);
-
+
+ /* Cobalt Alpine */
+ if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN)
+ return ata66_svwks_cobalt (hwif);
+
return 0;
}

@@ -586,9 +625,7 @@
hwif->drives[0].autotune = 1;
hwif->drives[1].autotune = 1;
hwif->autodma = 0;
- return;
#else /* CONFIG_BLK_DEV_IDEDMA */
-
if (hwif->dma_base) {
if (!noautodma)
hwif->autodma = 1;
\
 
 \ /
  Last update: 2005-03-22 13:12    [from the cache]
©2003-2011 Jasper Spaans