📄 piix.c
字号:
/** * piix_tune_chipset - tune a PIIX interface * @drive: IDE drive to tune * @xferspeed: speed to configure * * Set a PIIX interface channel to the desired speeds. This involves * requires the right timing data into the PIIX configuration space * then setting the drive parameters appropriately */ static int piix_tune_chipset (ide_drive_t *drive, u8 xferspeed){ ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; u8 maslave = hwif->channel ? 0x42 : 0x40; u8 speed = ide_rate_filter(piix_ratemask(drive), xferspeed); int a_speed = 3 << (drive->dn * 4); int u_flag = 1 << drive->dn; int v_flag = 0x01 << drive->dn; int w_flag = 0x10 << drive->dn; int u_speed = 0; int sitre; u16 reg4042, reg4a; u8 reg48, reg54, reg55; pci_read_config_word(dev, maslave, ®4042); sitre = (reg4042 & 0x4000) ? 1 : 0; pci_read_config_byte(dev, 0x48, ®48); pci_read_config_word(dev, 0x4a, ®4a); pci_read_config_byte(dev, 0x54, ®54); pci_read_config_byte(dev, 0x55, ®55); switch(speed) { case XFER_UDMA_4: case XFER_UDMA_2: u_speed = 2 << (drive->dn * 4); break; case XFER_UDMA_5: case XFER_UDMA_3: case XFER_UDMA_1: u_speed = 1 << (drive->dn * 4); break; case XFER_UDMA_0: u_speed = 0 << (drive->dn * 4); break; case XFER_MW_DMA_2: case XFER_MW_DMA_1: case XFER_SW_DMA_2: break; case XFER_PIO_4: case XFER_PIO_3: case XFER_PIO_2: case XFER_PIO_0: break; default: return -1; } if (speed >= XFER_UDMA_0) { if (!(reg48 & u_flag)) pci_write_config_byte(dev, 0x48, reg48 | u_flag); if (speed == XFER_UDMA_5) { pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag); } else { pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); } if ((reg4a & a_speed) != u_speed) pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed); if (speed > XFER_UDMA_2) { if (!(reg54 & v_flag)) pci_write_config_byte(dev, 0x54, reg54 | v_flag); } else pci_write_config_byte(dev, 0x54, reg54 & ~v_flag); } else { if (reg48 & u_flag) pci_write_config_byte(dev, 0x48, reg48 & ~u_flag); if (reg4a & a_speed) pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); if (reg54 & v_flag) pci_write_config_byte(dev, 0x54, reg54 & ~v_flag); if (reg55 & w_flag) pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); } piix_tune_drive(drive, piix_dma_2_pio(speed)); return (ide_config_drive_speed(drive, speed));}/** * piix_faulty_dma0 - check for DMA0 errata * @hwif: IDE interface to check * * If an ICH/ICH0/ICH2 interface is is operating in multi-word * DMA mode with 600nS cycle time the IDE PIO prefetch buffer will * inadvertently provide an extra piece of secondary data to the primary * device resulting in data corruption. * * With such a device this test function returns true. This allows * our tuning code to follow Intel recommendations and use PIO on * such devices. */ static int piix_faulty_dma0(ide_hwif_t *hwif){ switch(hwif->pci_dev->device) { case PCI_DEVICE_ID_INTEL_82801AA_1: /* ICH */ case PCI_DEVICE_ID_INTEL_82801AB_1: /* ICH0 */ case PCI_DEVICE_ID_INTEL_82801BA_8: /* ICH2 */ case PCI_DEVICE_ID_INTEL_82801BA_9: /* ICH2 */ return 1; } return 0;}/** * piix_config_drive_for_dma - configure drive for DMA * @drive: IDE drive to configure * * Set up a PIIX interface channel for the best available speed. * We prefer UDMA if it is available and then MWDMA. If DMA is * not available we switch to PIO and return 0. */ static int piix_config_drive_for_dma (ide_drive_t *drive){ u8 speed = ide_dma_speed(drive, piix_ratemask(drive)); /* Some ICH devices cannot support DMA mode 0 */ if(speed == XFER_MW_DMA_0 && piix_faulty_dma0(HWIF(drive))) speed = 0; /* If no DMA speed was available or the chipset has DMA bugs then disable DMA and use PIO */ if (!speed || no_piix_dma) { u8 tspeed = ide_get_best_pio_mode(drive, 255, 5, NULL); speed = piix_dma_2_pio(XFER_PIO_0 + tspeed); } (void) piix_tune_chipset(drive, speed); return ide_dma_enable(drive);}/** * piix_config_drive_xfer_rate - set up an IDE device * @drive: IDE drive to configure * * Set up the PIIX interface for the best available speed on this * interface, preferring DMA to PIO. */ static int piix_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 (__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 */ if ((id->field_valid & 2) && (!piix_config_drive_for_dma(drive))) 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 (!piix_config_drive_for_dma(drive)) goto no_dma_set; } } else if (__ide_dma_good_drive(drive) && (id->eide_dma_time < 150)) { /* Consult the list of known "good" drives */ if (!piix_config_drive_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: hwif->tuneproc(drive, 255); return hwif->ide_dma_off_quietly(drive); } /* IORDY not supported */ return 0;}/** * init_chipset_piix - set up the PIIX chipset * @dev: PCI device to set up * @name: Name of the device * * Initialize the PCI device as required. For the PIIX this turns * out to be nice and simple */ static unsigned int __devinit init_chipset_piix (struct pci_dev *dev, const char *name){ switch(dev->device) { case PCI_DEVICE_ID_INTEL_82801EB_1: case PCI_DEVICE_ID_INTEL_82801AA_1: case PCI_DEVICE_ID_INTEL_82801AB_1: case PCI_DEVICE_ID_INTEL_82801BA_8: case PCI_DEVICE_ID_INTEL_82801BA_9: case PCI_DEVICE_ID_INTEL_82801CA_10: case PCI_DEVICE_ID_INTEL_82801CA_11: case PCI_DEVICE_ID_INTEL_82801DB_10: case PCI_DEVICE_ID_INTEL_82801DB_11: case PCI_DEVICE_ID_INTEL_82801EB_11: case PCI_DEVICE_ID_INTEL_82801E_11: case PCI_DEVICE_ID_INTEL_ESB_2: case PCI_DEVICE_ID_INTEL_ICH6_19: { unsigned int extra = 0; pci_read_config_dword(dev, 0x54, &extra); pci_write_config_dword(dev, 0x54, extra|0x400); } default: break; }#if defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS) piix_devs[n_piix_devs++] = dev; if (!piix_proc) { piix_proc = 1; ide_pci_create_host_proc("piix", piix_get_info); }#endif /* DISPLAY_PIIX_TIMINGS && CONFIG_PROC_FS */ return 0;}/** * init_hwif_piix - fill in the hwif for the PIIX * @hwif: IDE interface * * Set up the ide_hwif_t for the PIIX interface according to the * capabilities of the hardware. */static void __devinit init_hwif_piix(ide_hwif_t *hwif){ u8 reg54h = 0, reg55h = 0, ata66 = 0; u8 mask = hwif->channel ? 0xc0 : 0x30;#ifndef CONFIG_IA64 if (!hwif->irq) hwif->irq = hwif->channel ? 15 : 14;#endif /* CONFIG_IA64 */ if (hwif->pci_dev->device == PCI_DEVICE_ID_INTEL_82371MX) { /* This is a painful system best to let it self tune for now */ return; } hwif->autodma = 0; hwif->tuneproc = &piix_tune_drive; hwif->speedproc = &piix_tune_chipset; hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; if (!hwif->dma_base) return; hwif->atapi_dma = 1; hwif->ultra_mask = 0x3f; hwif->mwdma_mask = 0x06; hwif->swdma_mask = 0x04; switch(hwif->pci_dev->device) { case PCI_DEVICE_ID_INTEL_82371MX: hwif->mwdma_mask = 0x80; hwif->swdma_mask = 0x80; case PCI_DEVICE_ID_INTEL_82371FB_0: case PCI_DEVICE_ID_INTEL_82371FB_1: case PCI_DEVICE_ID_INTEL_82371SB_1: hwif->ultra_mask = 0x80; break; case PCI_DEVICE_ID_INTEL_82371AB: case PCI_DEVICE_ID_INTEL_82443MX_1: case PCI_DEVICE_ID_INTEL_82451NX: case PCI_DEVICE_ID_INTEL_82801AB_1: hwif->ultra_mask = 0x07; break; default: pci_read_config_byte(hwif->pci_dev, 0x54, ®54h); pci_read_config_byte(hwif->pci_dev, 0x55, ®55h); ata66 = (reg54h & mask) ? 1 : 0; break; } if (!(hwif->udma_four)) hwif->udma_four = ata66; hwif->ide_dma_check = &piix_config_drive_xfer_rate; if (!noautodma) hwif->autodma = 1; hwif->drives[1].autodma = hwif->autodma; hwif->drives[0].autodma = hwif->autodma;}/** * init_setup_piix - callback for IDE initialize * @dev: PIIX PCI device * @d: IDE pci info * * Enable the xp fixup for the PIIX controller and then perform * a standard ide PCI setup */static void __devinit init_setup_piix(struct pci_dev *dev, ide_pci_device_t *d){ ide_setup_pci_device(dev, d);}/** * piix_init_one - called when a PIIX is found * @dev: the piix device * @id: the matching pci id * * Called when the PCI registration layer (or the IDE initialization) * finds a device matching our IDE device tables. */ static int __devinit piix_init_one(struct pci_dev *dev, const struct pci_device_id *id){ ide_pci_device_t *d = &piix_pci_info[id->driver_data]; d->init_setup(dev, d); return 0;}/** * piix_check_450nx - Check for problem 450NX setup * * Check for the present of 450NX errata #19 and errata #25. If * they are found, disable use of DMA IDE */static void __devinit piix_check_450nx(void){ struct pci_dev *pdev = NULL; u16 cfg; u8 rev; while((pdev=pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, pdev))!=NULL) { /* Look for 450NX PXB. Check for problem configurations A PCI quirk checks bit 6 already */ pci_read_config_byte(pdev, PCI_REVISION_ID, &rev); pci_read_config_word(pdev, 0x41, &cfg); /* Only on the original revision: IDE DMA can hang */ if(rev == 0x00) no_piix_dma = 1; /* On all revisions below 5 PXB bus lock must be disabled for IDE */ else if(cfg & (1<<14) && rev < 5) no_piix_dma = 2; } if(no_piix_dma) printk(KERN_WARNING "piix: 450NX errata present, disabling IDE DMA.\n"); if(no_piix_dma == 2) printk(KERN_WARNING "piix: A BIOS update may resolve this.\n");} static struct pci_device_id piix_pci_tbl[] = { { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371MX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3}, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4}, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5}, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6}, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7}, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82372FB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8}, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9}, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10}, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11}, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_10,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12}, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_11,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13}, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_11,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14}, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_11,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15}, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_11, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 16}, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_10,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 17},#ifdef CONFIG_BLK_DEV_IDE_SATA { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 18},#endif { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 19}, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_19, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 20}, { 0, },};MODULE_DEVICE_TABLE(pci, piix_pci_tbl);static struct pci_driver driver = { .name = "PIIX IDE", .id_table = piix_pci_tbl, .probe = piix_init_one,};static int __init piix_ide_init(void){ piix_check_450nx(); return ide_pci_register_driver(&driver);}module_init(piix_ide_init);MODULE_AUTHOR("Andre Hedrick, Andrzej Krzysztofowicz");MODULE_DESCRIPTION("PCI driver module for Intel PIIX IDE");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -