📄 pdc202xx.c
字号:
#ifdef CONFIG_BLK_DEV_IDEDMA if (speed >= XFER_SW_DMA_0) { pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB); pci_write_config_byte(dev, (drive_pci)|0x02, CP|TC); } else {#else {#endif /* CONFIG_BLK_DEV_IDEDMA */ pci_write_config_byte(dev, (drive_pci), AP|TA); pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB); }#if PDC202XX_DECODE_REGISTER_INFO pci_read_config_byte(dev, (drive_pci), &AP); pci_read_config_byte(dev, (drive_pci)|0x01, &BP); pci_read_config_byte(dev, (drive_pci)|0x02, &CP); pci_read_config_byte(dev, (drive_pci)|0x03, &DP); decode_registers(REG_A, AP); decode_registers(REG_B, BP); decode_registers(REG_C, CP); decode_registers(REG_D, DP);#endif /* PDC202XX_DECODE_REGISTER_INFO */skip_register_hell: if (!drive->init_speed) drive->init_speed = speed; err = ide_config_drive_speed(drive, speed); drive->current_speed = speed;#if PDC202XX_DEBUG_DRIVE_INFO printk("%s: %s drive%d 0x%08x ", drive->name, ide_xfer_verbose(speed), drive->dn, drive_conf); pci_read_config_dword(dev, drive_pci, &drive_conf); printk("0x%08x\n", drive_conf);#endif /* PDC202XX_DEBUG_DRIVE_INFO */ return err;}/* 0 1 2 3 4 5 6 7 8 * 960, 480, 390, 300, 240, 180, 120, 90, 60 * 180, 150, 120, 90, 60 * DMA_Speed * 180, 120, 90, 90, 90, 60, 30 * 11, 5, 4, 3, 2, 1, 0 */static int config_chipset_for_pio (ide_drive_t *drive, byte pio){ byte speed = 0x00; pio = (pio == 5) ? 4 : pio; speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, pio, NULL); return ((int) pdc202xx_tune_chipset(drive, speed));}static void pdc202xx_tune_drive (ide_drive_t *drive, byte pio){ (void) config_chipset_for_pio(drive, pio);}#ifdef CONFIG_BLK_DEV_IDEDMAstatic int config_chipset_for_dma (ide_drive_t *drive, byte ultra){ struct hd_driveid *id = drive->id; ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; unsigned long high_16 = pci_resource_start(dev, 4); unsigned long dma_base = hwif->dma_base; byte unit = (drive->select.b.unit & 0x01); unsigned int drive_conf; byte drive_pci; byte test1, test2, speed = -1; byte AP; unsigned short EP; byte CLKSPD = IN_BYTE(high_16 + 0x11); byte udma_33 = ultra ? (inb(high_16 + 0x001f) & 1) : 0; byte udma_66 = ((eighty_ninty_three(drive)) && udma_33) ? 1 : 0; byte udma_100 = (((dev->device == PCI_DEVICE_ID_PROMISE_20265) || (dev->device == PCI_DEVICE_ID_PROMISE_20267) || (dev->device == PCI_DEVICE_ID_PROMISE_20268)) && udma_66) ? 1 : 0; /* * Set the control register to use the 66Mhz system * clock for UDMA 3/4 mode operation. If one drive on * a channel is U66 capable but the other isn't we * fall back to U33 mode. The BIOS INT 13 hooks turn * the clock on then off for each read/write issued. I don't * do that here because it would require modifying the * kernel, seperating the fop routines from the kernel or * somehow hooking the fops calls. It may also be possible to * leave the 66Mhz clock on and readjust the timing * parameters. */ byte mask = hwif->channel ? 0x08 : 0x02; unsigned short c_mask = hwif->channel ? (1<<11) : (1<<10); byte ultra_66 = ((id->dma_ultra & 0x0010) || (id->dma_ultra & 0x0008)) ? 1 : 0; byte ultra_100 = ((id->dma_ultra & 0x0020) || (id->dma_ultra & 0x0010) || (id->dma_ultra & 0x0008)) ? 1 : 0; if (dev->device == PCI_DEVICE_ID_PROMISE_20268) goto jump_pci_mucking; pci_read_config_word(dev, 0x50, &EP); if (((ultra_66) || (ultra_100)) && (EP & c_mask)) {#ifdef DEBUG printk("ULTRA66: %s channel of Ultra 66 requires an 80-pin cable for Ultra66 operation.\n", hwif->channel ? "Secondary" : "Primary"); printk(" Switching to Ultra33 mode.\n");#endif /* DEBUG */ /* Primary : zero out second bit */ /* Secondary : zero out fourth bit */ OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11)); } else { if ((ultra_66) || (ultra_100)) { /* * check to make sure drive on same channel * is u66 capable */ if (hwif->drives[!(drive->dn%2)].id) { if ((hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0020) || (hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0010) || (hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0008)) { OUT_BYTE(CLKSPD | mask, (high_16 + 0x11)); } else { OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11)); } } else { /* udma4 drive by itself */ OUT_BYTE(CLKSPD | mask, (high_16 + 0x11)); } } } switch(drive->dn) { case 0: drive_pci = 0x60; pci_read_config_dword(dev, drive_pci, &drive_conf); if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) goto chipset_is_set; pci_read_config_byte(dev, (drive_pci), &test1); if (!(test1 & SYNC_ERRDY_EN)) pci_write_config_byte(dev, (drive_pci), test1|SYNC_ERRDY_EN); break; case 1: drive_pci = 0x64; pci_read_config_dword(dev, drive_pci, &drive_conf); if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) goto chipset_is_set; pci_read_config_byte(dev, 0x60, &test1); pci_read_config_byte(dev, (drive_pci), &test2); if ((test1 & SYNC_ERRDY_EN) && !(test2 & SYNC_ERRDY_EN)) pci_write_config_byte(dev, (drive_pci), test2|SYNC_ERRDY_EN); break; case 2: drive_pci = 0x68; pci_read_config_dword(dev, drive_pci, &drive_conf); if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) goto chipset_is_set; pci_read_config_byte(dev, (drive_pci), &test1); if (!(test1 & SYNC_ERRDY_EN)) pci_write_config_byte(dev, (drive_pci), test1|SYNC_ERRDY_EN); break; case 3: drive_pci = 0x6c; pci_read_config_dword(dev, drive_pci, &drive_conf); if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) goto chipset_is_set; pci_read_config_byte(dev, 0x68, &test1); pci_read_config_byte(dev, (drive_pci), &test2); if ((test1 & SYNC_ERRDY_EN) && !(test2 & SYNC_ERRDY_EN)) pci_write_config_byte(dev, (drive_pci), test2|SYNC_ERRDY_EN); break; default: return ide_dma_off; }chipset_is_set: if (drive->media != ide_disk) return ide_dma_off_quietly; pci_read_config_byte(dev, (drive_pci), &AP); if (id->capability & 4) /* IORDY_EN */ pci_write_config_byte(dev, (drive_pci), AP|IORDY_EN); pci_read_config_byte(dev, (drive_pci), &AP); if (drive->media == ide_disk) /* PREFETCH_EN */ pci_write_config_byte(dev, (drive_pci), AP|PREFETCH_EN);jump_pci_mucking: if ((id->dma_ultra & 0x0020) && (udma_100)) speed = XFER_UDMA_5; else if ((id->dma_ultra & 0x0010) && (udma_66)) speed = XFER_UDMA_4; else if ((id->dma_ultra & 0x0008) && (udma_66)) speed = XFER_UDMA_3; else if ((id->dma_ultra & 0x0004) && (udma_33)) speed = XFER_UDMA_2; else if ((id->dma_ultra & 0x0002) && (udma_33)) speed = XFER_UDMA_1; else if ((id->dma_ultra & 0x0001) && (udma_33)) speed = XFER_UDMA_0; else if (id->dma_mword & 0x0004) speed = XFER_MW_DMA_2; else if (id->dma_mword & 0x0002) speed = XFER_MW_DMA_1; else if (id->dma_mword & 0x0001) speed = XFER_MW_DMA_0; else if (id->dma_1word & 0x0004) speed = XFER_SW_DMA_2; else if (id->dma_1word & 0x0002) speed = XFER_SW_DMA_1; else if (id->dma_1word & 0x0001) speed = XFER_SW_DMA_0; else { /* restore original pci-config space */ if (dev->device != PCI_DEVICE_ID_PROMISE_20268) pci_write_config_dword(dev, drive_pci, drive_conf); return ide_dma_off_quietly; } outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2); (void) pdc202xx_tune_chipset(drive, speed); return ((int) ((id->dma_ultra >> 11) & 7) ? ide_dma_on : ((id->dma_ultra >> 8) & 7) ? ide_dma_on : ((id->dma_mword >> 8) & 7) ? ide_dma_on : ((id->dma_1word >> 8) & 7) ? ide_dma_on : ide_dma_off_quietly);}static int config_drive_xfer_rate (ide_drive_t *drive){ struct hd_driveid *id = drive->id; ide_hwif_t *hwif = HWIF(drive); ide_dma_action_t dma_func = ide_dma_off_quietly; if (id && (id->capability & 1) && hwif->autodma) { /* Consult the list of known "bad" drives */ if (ide_dmaproc(ide_dma_bad_drive, drive)) { dma_func = ide_dma_off; goto fast_ata_pio; } dma_func = ide_dma_off_quietly; if (id->field_valid & 4) { if (id->dma_ultra & 0x002F) { /* Force if Capable UltraDMA */ dma_func = config_chipset_for_dma(drive, 1); if ((id->field_valid & 2) && (dma_func != ide_dma_on)) goto try_dma_modes; } } else if (id->field_valid & 2) {try_dma_modes: if ((id->dma_mword & 0x0007) || (id->dma_1word & 0x0007)) { /* Force if Capable regular DMA modes */ dma_func = config_chipset_for_dma(drive, 0); if (dma_func != ide_dma_on) goto no_dma_set; } } else if (ide_dmaproc(ide_dma_good_drive, drive)) { if (id->eide_dma_time > 150) { goto no_dma_set; } /* Consult the list of known "good" drives */ dma_func = config_chipset_for_dma(drive, 0); if (dma_func != ide_dma_on) goto no_dma_set; } else { goto fast_ata_pio; } } else if ((id->capability & 8) || (id->field_valid & 2)) {fast_ata_pio: dma_func = ide_dma_off_quietly;no_dma_set: (void) config_chipset_for_pio(drive, 5); } return HWIF(drive)->dmaproc(dma_func, drive);}int pdc202xx_quirkproc (ide_drive_t *drive){ return ((int) check_in_drive_lists(drive, pdc_quirk_drives));}/* * pdc202xx_dmaproc() initiates/aborts (U)DMA read/write operations on a drive. */int pdc202xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive){ byte dma_stat = 0, sc1d = 0; unsigned long high_16 = pci_resource_start(HWIF(drive)->pci_dev, 4); unsigned long dma_base = HWIF(drive)->dma_base; switch (func) { case ide_dma_check: return config_drive_xfer_rate(drive); case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */ dma_stat = inb(dma_base+2); sc1d = inb(high_16 + 0x001d); if (HWIF(drive)->channel) { if ((sc1d & 0x50) == 0x50) goto somebody_else; else if ((sc1d & 0x40) == 0x40) return (dma_stat & 4) == 4; } else { if ((sc1d & 0x05) == 0x05) goto somebody_else; else if ((sc1d & 0x04) == 0x04) return (dma_stat & 4) == 4; }somebody_else: return (dma_stat & 4) == 4; /* return 1 if INTR asserted */ case ide_dma_lostirq: case ide_dma_timeout: if (HWIF(drive)->resetproc != NULL) HWIF(drive)->resetproc(drive); default: break; } return ide_dmaproc(func, drive); /* use standard DMA stuff */}#endif /* CONFIG_BLK_DEV_IDEDMA */void pdc202xx_reset (ide_drive_t *drive){ unsigned long high_16 = pci_resource_start(HWIF(drive)->pci_dev, 4); byte udma_speed_flag = inb(high_16 + 0x001f); OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f); mdelay(100); OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f); mdelay(2000); /* 2 seconds ?! */}unsigned int __init pci_init_pdc202xx (struct pci_dev *dev, const char *name){ unsigned long high_16 = pci_resource_start(dev, 4); byte udma_speed_flag = inb(high_16 + 0x001f); byte primary_mode = inb(high_16 + 0x001a); byte secondary_mode = inb(high_16 + 0x001b); if ((dev->device == PCI_DEVICE_ID_PROMISE_20262) || (dev->device == PCI_DEVICE_ID_PROMISE_20265) || (dev->device == PCI_DEVICE_ID_PROMISE_20267)) { /* * software reset - this is required because the bios * will set UDMA timing on if the hdd supports it. The * user may want to turn udma off. A bug in the pdc20262 * is that it cannot handle a downgrade in timing from UDMA * to DMA. Disk accesses after issuing a set feature command * will result in errors. A software reset leaves the timing * registers intact, but resets the drives. */ OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f); mdelay(100); OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f); mdelay(2000); /* 2 seconds ?! */ } if (dev->resource[PCI_ROM_RESOURCE].start) { pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE); printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start); } if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) { byte irq = 0, irq2 = 0; pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq); pci_read_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, &irq2); /* 0xbc */ if ((irq != irq2) && (dev->device != PCI_DEVICE_ID_PROMISE_20265) && (dev->device != PCI_DEVICE_ID_PROMISE_20267) && (dev->device != PCI_DEVICE_ID_PROMISE_20268)) { pci_write_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, irq); /* 0xbc */ printk("%s: pci-config space interrupt mirror fixed.\n", name); } } printk("%s: (U)DMA Burst Bit %sABLED " \ "Primary %s Mode " \ "Secondary %s Mode.\n", name, (udma_speed_flag & 1) ? "EN" : "DIS", (primary_mode & 1) ? "MASTER" : "PCI", (secondary_mode & 1) ? "MASTER" : "PCI" );#ifdef CONFIG_PDC202XX_BURST if (!(udma_speed_flag & 1)) { printk("%s: FORCING BURST BIT 0x%02x -> 0x%02x ", name, udma_speed_flag, (udma_speed_flag|1)); outb(udma_speed_flag|1, high_16 + 0x001f); printk("%sCTIVE\n", (inb(high_16 + 0x001f) & 1) ? "A" : "INA"); }#endif /* CONFIG_PDC202XX_BURST */#ifdef CONFIG_PDC202XX_MASTER if (!(primary_mode & 1)) { printk("%s: FORCING PRIMARY MODE BIT 0x%02x -> 0x%02x ", name, primary_mode, (primary_mode|1)); outb(primary_mode|1, high_16 + 0x001a); printk("%s\n", (inb(high_16 + 0x001a) & 1) ? "MASTER" : "PCI"); } if (!(secondary_mode & 1)) { printk("%s: FORCING SECONDARY MODE BIT 0x%02x -> 0x%02x ", name, secondary_mode, (secondary_mode|1)); outb(secondary_mode|1, high_16 + 0x001b); printk("%s\n", (inb(high_16 + 0x001b) & 1) ? "MASTER" : "PCI"); }#endif /* CONFIG_PDC202XX_MASTER */#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) if (!pdc202xx_proc) { pdc202xx_proc = 1; bmide_dev = dev; pdc202xx_display_info = &pdc202xx_get_info; }#endif /* DISPLAY_PDC202XX_TIMINGS && CONFIG_PROC_FS */ return dev->irq;}unsigned int __init ata66_pdc202xx (ide_hwif_t *hwif){ unsigned short mask = (hwif->channel) ? (1<<11) : (1<<10); unsigned short CIS; pci_read_config_word(hwif->pci_dev, 0x50, &CIS); return ((CIS & mask) ? 0 : 1);}void __init ide_init_pdc202xx (ide_hwif_t *hwif){ hwif->tuneproc = &pdc202xx_tune_drive; hwif->speedproc = &pdc202xx_tune_chipset; hwif->quirkproc = &pdc202xx_quirkproc; if ((hwif->pci_dev->device == PCI_DEVICE_ID_PROMISE_20262) || (hwif->pci_dev->device == PCI_DEVICE_ID_PROMISE_20265) || (hwif->pci_dev->device == PCI_DEVICE_ID_PROMISE_20267)) { hwif->resetproc = &pdc202xx_reset; }#undef CONFIG_PDC202XX_32_UNMASK#ifdef CONFIG_PDC202XX_32_UNMASK hwif->drives[0].io_32bit = 1; hwif->drives[1].io_32bit = 1; hwif->drives[0].unmask = 1; hwif->drives[1].unmask = 1;#endif /* CONFIG_PDC202XX_32_UNMASK */#ifdef CONFIG_BLK_DEV_IDEDMA if (hwif->dma_base) { hwif->dmaproc = &pdc202xx_dmaproc; if (!noautodma) hwif->autodma = 1; } else { hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; hwif->autodma = 0; }#else /* !CONFIG_BLK_DEV_IDEDMA */ hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; hwif->autodma = 0;#endif /* CONFIG_BLK_DEV_IDEDMA */}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -