📄 sis5513.c
字号:
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 if (chipset_family < ATA_133) { 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); } else { /* ATA_133 */ u32 test3; pci_read_config_dword(dev, drive_pci, &test3); test3 &= 0xc0c00fff; if (test3 & 0x08) { test3 |= (unsigned long)ini_time_value[ATA_133][timing] << 12; test3 |= (unsigned long)act_time_value[ATA_133][timing] << 16; test3 |= (unsigned long)rco_time_value[ATA_133][timing] << 24; } else { test3 |= (unsigned long)ini_time_value[ATA_100][timing] << 12; test3 |= (unsigned long)act_time_value[ATA_100][timing] << 16; test3 |= (unsigned long)rco_time_value[ATA_100][timing] << 24; } pci_write_config_dword(dev, drive_pci, test3); }}static int config_chipset_for_pio (ide_drive_t *drive, u8 pio){ if (pio == 255) pio = ide_find_best_mode(drive, XFER_PIO | XFER_EPIO) - XFER_PIO_0; config_art_rwp_pio(drive, pio); return ide_config_drive_speed(drive, XFER_PIO_0 + min_t(u8, pio, 4));}static int sis5513_tune_chipset (ide_drive_t *drive, u8 xferspeed){ ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; u8 drive_pci, reg, speed; u32 regdw; speed = ide_rate_filter(sis5513_ratemask(drive), xferspeed); /* See config_art_rwp_pio for drive pci config registers */ drive_pci = 0x40; if (chipset_family >= ATA_133) { u32 reg54h; pci_read_config_dword(dev, 0x54, ®54h); if (reg54h & 0x40000000) drive_pci = 0x70; drive_pci += ((drive->dn)*0x4); pci_read_config_dword(dev, (unsigned long)drive_pci, ®dw); /* Disable UDMA bit for non UDMA modes on UDMA chips */ if (speed < XFER_UDMA_0) { regdw &= 0xfffffffb; pci_write_config_dword(dev, (unsigned long)drive_pci, regdw); } } else { drive_pci += ((drive->dn)*0x2); pci_read_config_byte(dev, drive_pci+1, ®); /* 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) { case XFER_UDMA_6: case XFER_UDMA_5: case XFER_UDMA_4: case XFER_UDMA_3: case XFER_UDMA_2: case XFER_UDMA_1: case XFER_UDMA_0: if (chipset_family >= ATA_133) { regdw |= 0x04; regdw &= 0xfffff00f; /* check if ATA133 enable */ if (regdw & 0x08) { regdw |= (unsigned long)cycle_time_value[ATA_133][speed-XFER_UDMA_0] << 4; regdw |= (unsigned long)cvs_time_value[ATA_133][speed-XFER_UDMA_0] << 8; } else { /* if ATA133 disable, we should not set speed above UDMA5 */ if (speed > XFER_UDMA_5) speed = XFER_UDMA_5; regdw |= (unsigned long)cycle_time_value[ATA_100][speed-XFER_UDMA_0] << 4; regdw |= (unsigned long)cvs_time_value[ATA_100][speed-XFER_UDMA_0] << 8; } pci_write_config_dword(dev, (unsigned long)drive_pci, regdw); } else { /* 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][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_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)); } return ((int) ide_config_drive_speed(drive, speed));}static void sis5513_tune_drive (ide_drive_t *drive, u8 pio){ (void) config_chipset_for_pio(drive, pio);}/* * ((id->hw_config & 0x4000|0x2000) && (HWIF(drive)->udma_four)) */static int config_chipset_for_dma (ide_drive_t *drive){ u8 speed = ide_dma_speed(drive, sis5513_ratemask(drive));#ifdef DEBUG printk("SIS5513: config_chipset_for_dma, drive %d, ultra %x\n", drive->dn, drive->id->dma_ultra);#endif if (!(speed)) return 0; sis5513_tune_chipset(drive, speed); return ide_dma_enable(drive);}static int sis5513_config_drive_xfer_rate (ide_drive_t *drive){ ide_hwif_t *hwif = HWIF(drive); struct hd_driveid *id = drive->id; drive->init_speed = 0; if ((id->capability & 1) && drive->autodma) { /* Consult the list of known "bad" drives */ if (hwif->ide_dma_bad_drive(drive)) goto fast_ata_pio; if (id->field_valid & 4) { if (id->dma_ultra & hwif->ultra_mask) { /* Force if Capable UltraDMA */ int dma = config_chipset_for_dma(drive); if ((id->field_valid & 2) && !dma) goto try_dma_modes; } } else if (id->field_valid & 2) {try_dma_modes: if ((id->dma_mword & hwif->mwdma_mask) || (id->dma_1word & hwif->swdma_mask)) { /* Force if Capable regular DMA modes */ if (!config_chipset_for_dma(drive)) goto no_dma_set; } } else if (hwif->ide_dma_good_drive(drive) && (id->eide_dma_time < 150)) { /* Consult the list of known "good" drives */ if (!config_chipset_for_dma(drive)) goto no_dma_set; } else { goto fast_ata_pio; } return hwif->ide_dma_on(drive); } else if ((id->capability & 8) || (id->field_valid & 2)) {fast_ata_pio:no_dma_set: sis5513_tune_drive(drive, 5); return hwif->ide_dma_off_quietly(drive); } /* IORDY not supported */ return 0;}/* initiates/aborts (U)DMA read/write operations on a drive. */static int sis5513_config_xfer_rate (ide_drive_t *drive){ config_drive_art_rwp(drive); config_art_rwp_pio(drive, 5); return sis5513_config_drive_xfer_rate(drive);}/* Future simpler config_xfer_rate : When ide_find_best_mode is made bad-drive aware - remove config_drive_xfer_rate and config_chipset_for_dma, - replace config_xfer_rate with the followingstatic int sis5513_config_xfer_rate (ide_drive_t *drive){ u16 w80 = HWIF(drive)->udma_four; u16 speed; config_drive_art_rwp(drive); config_art_rwp_pio(drive, 5); speed = ide_find_best_mode(drive, XFER_PIO | XFER_EPIO | XFER_SWDMA | XFER_MWDMA | (chipset_family >= ATA_33 ? XFER_UDMA : 0) | (w80 && chipset_family >= ATA_66 ? XFER_UDMA_66 : 0) | (w80 && chipset_family >= ATA_100a ? XFER_UDMA_100 : 0) | (w80 && chipset_family >= ATA_133a ? XFER_UDMA_133 : 0)); sis5513_tune_chipset(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);}*//* Chip detection and general config */static unsigned int __init init_chipset_sis5513 (struct pci_dev *dev, const char *name){ struct pci_dev *host; int i = 0; chipset_family = 0; for (i = 0; i < ARRAY_SIZE(SiSHostChipInfo) && !chipset_family; i++) { host = pci_find_device(PCI_VENDOR_ID_SI, SiSHostChipInfo[i].host_id, NULL); if (!host) continue; chipset_family = SiSHostChipInfo[i].chipset_family; /* Special case for SiS630 : 630S/ET is ATA_100a */ if (SiSHostChipInfo[i].host_id == PCI_DEVICE_ID_SI_630) { u8 hostrev; pci_read_config_byte(host, PCI_REVISION_ID, &hostrev); if (hostrev >= 0x30) chipset_family = ATA_100a; } printk(KERN_INFO "SIS5513: %s %s controller\n", SiSHostChipInfo[i].name, chipset_capability[chipset_family]); } if (!chipset_family) { /* Belongs to pci-quirks */ u32 idemisc; u16 trueid; /* Disable ID masking and register remapping */ pci_read_config_dword(dev, 0x54, &idemisc); pci_write_config_dword(dev, 0x54, (idemisc & 0x7fffffff)); pci_read_config_word(dev, PCI_DEVICE_ID, &trueid); pci_write_config_dword(dev, 0x54, idemisc); if (trueid == 0x5518) { printk(KERN_INFO "SIS5513: SiS 962/963 MuTIOL IDE UDMA133 controller\n"); chipset_family = ATA_133; } } if (!chipset_family) { /* Belongs to pci-quirks */ struct pci_dev *lpc_bridge; u16 trueid; u8 prefctl; u8 idecfg; u8 sbrev; pci_read_config_byte(dev, 0x4a, &idecfg); pci_write_config_byte(dev, 0x4a, idecfg | 0x10); pci_read_config_word(dev, PCI_DEVICE_ID, &trueid); pci_write_config_byte(dev, 0x4a, idecfg); if (trueid == 0x5517) { /* SiS 961/961B */ lpc_bridge = pci_find_slot(0x00, 0x10); /* Bus 0, Dev 2, Fn 0 */ pci_read_config_byte(lpc_bridge, PCI_REVISION_ID, &sbrev); pci_read_config_byte(dev, 0x49, &prefctl); if (sbrev == 0x10 && (prefctl & 0x80)) { printk(KERN_INFO "SIS5513: SiS 961B MuTIOL IDE UDMA133 controller\n"); chipset_family = ATA_133a; } else { printk(KERN_INFO "SIS5513: SiS 961 MuTIOL IDE UDMA100 controller\n"); chipset_family = ATA_100; } } } if (!chipset_family) return -1; /* Make general config ops here 1/ tell IDE channels to operate in Compatibility mode only 2/ tell old chips to allow per drive IDE timings */ { u8 reg; u16 regw; switch(chipset_family) { case ATA_133: /* SiS962 operation mode */ pci_read_config_word(dev, 0x50, ®w); if (regw & 0x08) pci_write_config_word(dev, 0x50, regw&0xfff7); pci_read_config_word(dev, 0x52, ®w); if (regw & 0x08) pci_write_config_word(dev, 0x52, regw&0xfff7); break; case ATA_133a: case ATA_100: /* Fixup latency */ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x80); /* Set compatibility bit */ pci_read_config_byte(dev, 0x49, ®); if (!(reg & 0x01)) { pci_write_config_byte(dev, 0x49, reg|0x01); } break; case ATA_100a: case ATA_66: /* Fixup latency */ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x10); /* On ATA_66 chips the bit was elsewhere */ pci_read_config_byte(dev, 0x52, ®); 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, ®); 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, ®); if (!(reg & 0x08)) { pci_write_config_byte(dev, 0x52, reg|0x08); } break; }#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) if (!sis_proc) { sis_proc = 1; bmide_dev = dev; ide_pci_register_host_proc(&sis_procs[0]); }#endif } return 0;}static unsigned int __init ata66_sis5513 (ide_hwif_t *hwif){ u8 ata66 = 0; if (chipset_family >= ATA_133) { u16 regw = 0; u16 reg_addr = hwif->channel ? 0x52: 0x50; pci_read_config_word(hwif->pci_dev, reg_addr, ®w); ata66 = (regw & 0x8000) ? 0 : 1; } else if (chipset_family >= ATA_66) { u8 reg48h = 0; u8 mask = hwif->channel ? 0x20 : 0x10; pci_read_config_byte(hwif->pci_dev, 0x48, ®48h); ata66 = (reg48h & mask) ? 0 : 1; } return ata66;}static void __init init_hwif_sis5513 (ide_hwif_t *hwif){ hwif->autodma = 0; if (!hwif->irq) hwif->irq = hwif->channel ? 15 : 14; hwif->tuneproc = &sis5513_tune_drive; hwif->speedproc = &sis5513_tune_chipset; if (!(hwif->dma_base)) { hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; return; } hwif->atapi_dma = 1; hwif->ultra_mask = 0x7f; hwif->mwdma_mask = 0x07; hwif->swdma_mask = 0x07; if (!chipset_family) return; if (!(hwif->udma_four)) hwif->udma_four = ata66_sis5513(hwif); if (chipset_family > ATA_16) { hwif->ide_dma_check = &sis5513_config_xfer_rate; if (!noautodma) hwif->autodma = 1; } hwif->drives[0].autodma = hwif->autodma; hwif->drives[1].autodma = hwif->autodma; return;}static void __init init_dma_sis5513 (ide_hwif_t *hwif, unsigned long dmabase){ ide_setup_dma(hwif, dmabase, 8);}extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);static int __devinit sis5513_init_one(struct pci_dev *dev, const struct pci_device_id *id){ ide_pci_device_t *d = &sis5513_chipsets[id->driver_data]; if (dev->device != d->device) BUG(); ide_setup_pci_device(dev, d); MOD_INC_USE_COUNT; return 0;}static struct pci_device_id sis5513_pci_tbl[] __devinitdata = { { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5513, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { 0, },};static struct pci_driver driver = { .name = "SIS IDE", .id_table = sis5513_pci_tbl, .probe = sis5513_init_one,};static int sis5513_ide_init(void){ return ide_pci_register_driver(&driver);}static void sis5513_ide_exit(void){ ide_pci_unregister_driver(&driver);}module_init(sis5513_ide_init);module_exit(sis5513_ide_exit);MODULE_AUTHOR("Lionel Bouton, L C Chang, Andre Hedrick, Vojtech Pavlik");MODULE_DESCRIPTION("PCI driver module for SIS IDE");MODULE_LICENSE("GPL");EXPORT_NO_SYMBOLS;/* * TODO: * - CLEANUP * - Use drivers/ide/ide-timing.h ! * - 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 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -