📄 hpt366.c
字号:
/* * linux/drivers/ide/pci/hpt366.c Version 0.34 Sept 17, 2002 * * Copyright (C) 1999-2002 Andre Hedrick <andre@linux-ide.org> * Portions Copyright (C) 2001 Sun Microsystems, Inc. * * Thanks to HighPoint Technologies for their assistance, and hardware. * Special Thanks to Jon Burchmore in SanDiego for the deep pockets, his * donation of an ABit BP6 mainboard, processor, and memory acellerated * development and support. * * 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>#include <linux/types.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/delay.h>#include <linux/timer.h>#include <linux/mm.h>#include <linux/ioport.h>#include <linux/blkdev.h>#include <linux/hdreg.h>#include <linux/interrupt.h>#include <linux/pci.h>#include <linux/init.h>#include <linux/ide.h>#include <asm/uaccess.h>#include <asm/io.h>#include <asm/irq.h>#include "ide_modes.h"#include "hpt366.h"#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)#include <linux/stat.h>#include <linux/proc_fs.h>#endif /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */static unsigned int hpt_revision(struct pci_dev *dev);static unsigned int hpt_minimum_revision(struct pci_dev *dev, int revision);#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)static u8 hpt366_proc = 0;static struct pci_dev *hpt_devs[HPT366_MAX_DEVS];static int n_hpt_devs;static int hpt366_get_info (char *buffer, char **addr, off_t offset, int count){ char *p = buffer; char *chipset_nums[] = {"366", "366", "368", "370", "370A", "372", "302", "371", "374" }; int i; p += sprintf(p, "\n " "HighPoint HPT366/368/370/372/374\n"); for (i = 0; i < n_hpt_devs; i++) { struct pci_dev *dev = hpt_devs[i]; unsigned long iobase = dev->resource[4].start; u32 class_rev = hpt_revision(dev); u8 c0, c1; 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(iobase + 0x2); c1 = inb(iobase + 0xa); p += sprintf(p, "Enabled: %s" " %s\n", (c0 & 0x80) ? "no" : "yes", (c1 & 0x80) ? "no" : "yes"); if (hpt_minimum_revision(dev, 3)) { u8 cbl; cbl = inb(iobase + 0x7b); outb(cbl | 1, iobase + 0x7b); outb(cbl & ~1, iobase + 0x7b); cbl = inb(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) */static u32 hpt_revision (struct pci_dev *dev){ u32 class_rev; pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); class_rev &= 0xff; switch(dev->device) { case PCI_DEVICE_ID_TTI_HPT374: class_rev = PCI_DEVICE_ID_TTI_HPT374; break; case PCI_DEVICE_ID_TTI_HPT371: class_rev = PCI_DEVICE_ID_TTI_HPT371; break; case PCI_DEVICE_ID_TTI_HPT302: class_rev = PCI_DEVICE_ID_TTI_HPT302; break; case PCI_DEVICE_ID_TTI_HPT372: class_rev = PCI_DEVICE_ID_TTI_HPT372; break; default: break; } return class_rev;}static u32 hpt_minimum_revision (struct pci_dev *dev, int revision){ unsigned int class_rev = hpt_revision(dev); revision--; return ((int) (class_rev > revision) ? 1 : 0);}static int check_in_drive_lists(ide_drive_t *drive, const char **list);static u8 hpt3xx_ratemask (ide_drive_t *drive){ struct pci_dev *dev = HWIF(drive)->pci_dev; u8 mode = 0; if (hpt_minimum_revision(dev, 8)) { /* HPT374 */ mode = (HPT374_ALLOW_ATA133_6) ? 4 : 3; } else if (hpt_minimum_revision(dev, 7)) { /* HPT371 */ mode = (HPT371_ALLOW_ATA133_6) ? 4 : 3; } else if (hpt_minimum_revision(dev, 6)) { /* HPT302 */ mode = (HPT302_ALLOW_ATA133_6) ? 4 : 3; } else if (hpt_minimum_revision(dev, 5)) { /* HPT372 */ mode = (HPT372_ALLOW_ATA133_6) ? 4 : 3; } else if (hpt_minimum_revision(dev, 4)) { /* HPT370A */ mode = (HPT370_ALLOW_ATA100_5) ? 3 : 2; } else if (hpt_minimum_revision(dev, 3)) { /* HPT370 */ mode = (HPT370_ALLOW_ATA100_5) ? 3 : 2; mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : mode; } else { /* HPT366 and HPT368 */ mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : 2; } if (!eighty_ninty_three(drive) && (mode)) mode = min(mode, (u8)1); return mode;}static u8 hpt3xx_ratefilter (ide_drive_t *drive, u8 speed){ struct pci_dev *dev = HWIF(drive)->pci_dev; u8 mode = hpt3xx_ratemask(drive); if (drive->media != ide_disk) return min(speed, (u8)XFER_PIO_4); switch(mode) { case 0x04: speed = min(speed, (u8)XFER_UDMA_6); break; case 0x03: speed = min(speed, (u8)XFER_UDMA_5); if (hpt_minimum_revision(dev, 5)) break; if (check_in_drive_lists(drive, bad_ata100_5)) speed = min(speed, (u8)XFER_UDMA_4); break; case 0x02: speed = min(speed, (u8)XFER_UDMA_4); /* * CHECK ME, Does this need to be set to 5 ?? */ if (hpt_minimum_revision(dev, 3)) break; if ((check_in_drive_lists(drive, bad_ata66_4)) || (!(HPT366_ALLOW_ATA66_4))) speed = min(speed, (u8)XFER_UDMA_3); if ((check_in_drive_lists(drive, bad_ata66_3)) || (!(HPT366_ALLOW_ATA66_3))) speed = min(speed, (u8)XFER_UDMA_2); break; case 0x01: speed = min(speed, (u8)XFER_UDMA_2); /* * CHECK ME, Does this need to be set to 5 ?? */ if (hpt_minimum_revision(dev, 3)) break; if (check_in_drive_lists(drive, bad_ata33)) speed = min(speed, (u8)XFER_MW_DMA_2); break; case 0x00: default: speed = min(speed, (u8)XFER_MW_DMA_2); break; } return speed;}static int check_in_drive_lists (ide_drive_t *drive, const char **list){ struct hd_driveid *id = drive->id; if (quirk_drives == list) { while (*list) if (strstr(id->model, *list++)) return 1; } else { while (*list) if (!strcmp(*list++,id->model)) return 1; } return 0;}static unsigned int pci_bus_clock_list (u8 speed, struct chipset_bus_clock_list_entry * chipset_table){ for ( ; chipset_table->xfer_speed ; chipset_table++) if (chipset_table->xfer_speed == speed) return chipset_table->chipset_settings; return chipset_table->chipset_settings;}static void hpt366_tune_chipset (ide_drive_t *drive, u8 xferspeed){ struct pci_dev *dev = HWIF(drive)->pci_dev; u8 speed = hpt3xx_ratefilter(drive, xferspeed);// u8 speed = ide_rate_filter(hpt3xx_ratemask(drive), xferspeed); u8 regtime = (drive->select.b.unit & 0x01) ? 0x44 : 0x40; u8 regfast = (HWIF(drive)->channel) ? 0x55 : 0x51; u8 drive_fast = 0; u32 reg1 = 0, reg2 = 0; /* * Disable the "fast interrupt" prediction. */ pci_read_config_byte(dev, regfast, &drive_fast);#if 0 if (drive_fast & 0x02) pci_write_config_byte(dev, regfast, drive_fast & ~0x20);#else if (drive_fast & 0x80) pci_write_config_byte(dev, regfast, drive_fast & ~0x80);#endif reg2 = pci_bus_clock_list(speed, (struct chipset_bus_clock_list_entry *) pci_get_drvdata(dev)); /* * Disable on-chip PIO FIFO/buffer * (to avoid problems handling I/O errors later) */ pci_read_config_dword(dev, regtime, ®1); if (speed >= XFER_MW_DMA_0) { reg2 = (reg2 & ~0xc0000000) | (reg1 & 0xc0000000); } else { reg2 = (reg2 & ~0x30070000) | (reg1 & 0x30070000); } reg2 &= ~0x80000000; pci_write_config_dword(dev, regtime, reg2);}static void hpt368_tune_chipset (ide_drive_t *drive, u8 speed){ hpt366_tune_chipset(drive, speed);}static void hpt370_tune_chipset (ide_drive_t *drive, u8 xferspeed){ struct pci_dev *dev = HWIF(drive)->pci_dev; u8 speed = hpt3xx_ratefilter(drive, xferspeed);// u8 speed = ide_rate_filter(hpt3xx_ratemask(drive), xferspeed); u8 regfast = (HWIF(drive)->channel) ? 0x55 : 0x51; u8 drive_pci = 0x40 + (drive->dn * 4); u8 new_fast = 0, drive_fast = 0; u32 list_conf = 0, drive_conf = 0; u32 conf_mask = (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000; /* * Disable the "fast interrupt" prediction. * don't holdoff on interrupts. (== 0x01 despite what the docs say) */ 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(dev, regfast, new_fast); list_conf = pci_bus_clock_list(speed, (struct chipset_bus_clock_list_entry *) pci_get_drvdata(dev)); pci_read_config_dword(dev, drive_pci, &drive_conf); list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask); if (speed < XFER_MW_DMA_0) { list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */ } pci_write_config_dword(dev, drive_pci, list_conf);}static void hpt372_tune_chipset (ide_drive_t *drive, u8 xferspeed){ struct pci_dev *dev = HWIF(drive)->pci_dev; u8 speed = hpt3xx_ratefilter(drive, xferspeed);// u8 speed = ide_rate_filter(hpt3xx_ratemask(drive), xferspeed); u8 regfast = (HWIF(drive)->channel) ? 0x55 : 0x51; u8 drive_fast = 0, drive_pci = 0x40 + (drive->dn * 4); u32 list_conf = 0, drive_conf = 0; u32 conf_mask = (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000; /* * Disable the "fast interrupt" prediction. * don't holdoff on interrupts. (== 0x01 despite what the docs say) */ pci_read_config_byte(dev, regfast, &drive_fast); drive_fast &= ~0x07; pci_write_config_byte(dev, regfast, drive_fast); list_conf = pci_bus_clock_list(speed, (struct chipset_bus_clock_list_entry *) pci_get_drvdata(dev)); pci_read_config_dword(dev, drive_pci, &drive_conf); list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask); if (speed < XFER_MW_DMA_0) list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */ pci_write_config_dword(dev, drive_pci, list_conf);}static void hpt374_tune_chipset (ide_drive_t *drive, u8 speed){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -