📄 ide-pmac.c
字号:
if (np->addrs[0].size > 0x1000) np->addrs[0].size = 0x1000; if (np->n_addrs > 1 && np->addrs[1].size > 0x100) np->addrs[1].size = 0x100; if (request_OF_resource(np, 0, " (mac-io IDE IO)") == NULL) { printk(KERN_ERR "ide-pmac(%s): can't request IO resource !\n", np->name); continue; } base = (unsigned long) ioremap(np->addrs[0].address, 0x400) - _IO_BASE; /* XXX This is bogus. Should be fixed in the registry by checking the kind of host interrupt controller, a bit like gatwick fixes in irq.c */ if (np->n_intrs == 0) { printk(KERN_WARNING "ide: no intrs for device %s, using 13\n", np->full_name); irq = 13; } else { irq = np->intrs[0].line; } pmhw->regbase = base; pmhw->irq = irq; pmhw->node = np; if (device_is_compatible(np, "keylargo-ata")) { if (strcmp(np->name, "ata-4") == 0) pmhw->kind = controller_kl_ata4; else pmhw->kind = controller_kl_ata3; } else if (device_is_compatible(np, "heathrow-ata")) pmhw->kind = controller_heathrow; else pmhw->kind = controller_ohare; bidp = (int *)get_property(np, "AAPL,bus-id", NULL); pmhw->aapl_bus_id = bidp ? *bidp : 0; if (pmhw->kind == controller_kl_ata4) { char* cable = get_property(np, "cable-type", NULL); if (cable && !strncmp(cable, "80-", 3)) pmhw->kind = controller_kl_ata4_80; } /* Make sure we have sane timings */ sanitize_timings(i); if (np->parent && np->parent->name && strcasecmp(np->parent->name, "media-bay") == 0) {#ifdef CONFIG_PMAC_PBOOK media_bay_set_ide_infos(np->parent,base,irq,i);#endif /* CONFIG_PMAC_PBOOK */ in_bay = 1; if (!bidp) pmhw->aapl_bus_id = 1; } else if (pmhw->kind == controller_ohare) { /* The code below is having trouble on some ohare machines * (timing related ?). Until I can put my hand on one of these * units, I keep the old way */ ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, 0, 1); } else { /* This is necessary to enable IDE when net-booting */ printk(KERN_INFO "pmac_ide: enabling IDE bus ID %d\n", pmhw->aapl_bus_id); ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmhw->aapl_bus_id, 1); ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmhw->aapl_bus_id, 1); mdelay(10); ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmhw->aapl_bus_id, 0); big_delay = 1; } hwif = &ide_hwifs[i]; pmac_ide_init_hwif_ports(&hwif->hw, base, 0, &hwif->irq); memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports)); hwif->chipset = ide_pmac; hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET] || in_bay; hwif->udma_four = (pmhw->kind == controller_kl_ata4_80); hwif->pci_dev = pdev;#ifdef CONFIG_PMAC_PBOOK if (in_bay && check_media_bay_by_base(base, MB_CD) == 0) hwif->noprobe = 0;#endif /* CONFIG_PMAC_PBOOK */#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC if (np->n_addrs >= 2) { /* has a DBDMA controller channel */ pmac_ide_setup_dma(np, i); }#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ ++i; } pmac_ide_count = i; if (big_delay) mdelay(IDE_WAKEUP_DELAY_MS);#ifdef CONFIG_PMAC_PBOOK pmu_register_sleep_notifier(&idepmac_sleep_notifier);#endif /* CONFIG_PMAC_PBOOK */ register_reboot_notifier(&pmac_ide_reboot_notifier);}#ifdef CONFIG_BLK_DEV_IDEDMA_PMACstatic void __init pmac_ide_setup_dma(struct device_node *np, int ix){ struct pmac_ide_hwif *pmif = &pmac_ide[ix]; if (request_OF_resource(np, 1, " (mac-io IDE DMA)") == NULL) { printk(KERN_ERR "ide-pmac(%s): can't request DMA resource !\n", np->name); return; } pmif->dma_regs = (volatile struct dbdma_regs*)ioremap(np->addrs[1].address, 0x200); /* * Allocate space for the DBDMA commands. * The +2 is +1 for the stop command and +1 to allow for * aligning the start address to a multiple of 16 bytes. */ pmif->dma_table_cpu = (struct dbdma_cmd*)pci_alloc_consistent( ide_hwifs[ix].pci_dev, (MAX_DCMDS + 2) * sizeof(struct dbdma_cmd), &pmif->dma_table_dma); if (pmif->dma_table_cpu == NULL) { printk(KERN_ERR "%s: unable to allocate DMA command list\n", ide_hwifs[ix].name); return; } pmif->sg_table = kmalloc(sizeof(struct scatterlist) * MAX_DCMDS, GFP_KERNEL); if (pmif->sg_table == NULL) { pci_free_consistent( ide_hwifs[ix].pci_dev, (MAX_DCMDS + 2) * sizeof(struct dbdma_cmd), pmif->dma_table_cpu, pmif->dma_table_dma); return; } ide_hwifs[ix].dmaproc = &pmac_ide_dmaproc;#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO if (!noautodma) ide_hwifs[ix].autodma = 1;#endif}static intpmac_ide_build_sglist (int ix, struct request *rq){ ide_hwif_t *hwif = &ide_hwifs[ix]; struct pmac_ide_hwif *pmif = &pmac_ide[ix]; struct buffer_head *bh; struct scatterlist *sg = pmif->sg_table; int nents = 0; if (hwif->sg_dma_active) BUG(); if (rq->cmd == READ) pmif->sg_dma_direction = PCI_DMA_FROMDEVICE; else pmif->sg_dma_direction = PCI_DMA_TODEVICE; bh = rq->bh; do { unsigned char *virt_addr = bh->b_data; unsigned int size = bh->b_size; if (nents >= MAX_DCMDS) return 0; while ((bh = bh->b_reqnext) != NULL) { if ((virt_addr + size) != (unsigned char *) bh->b_data) break; size += bh->b_size; } memset(&sg[nents], 0, sizeof(*sg)); sg[nents].address = virt_addr; sg[nents].length = size; nents++; } while (bh != NULL); return pci_map_sg(hwif->pci_dev, sg, nents, pmif->sg_dma_direction);}static intpmac_ide_raw_build_sglist (int ix, struct request *rq){ ide_hwif_t *hwif = &ide_hwifs[ix]; struct pmac_ide_hwif *pmif = &pmac_ide[ix]; struct scatterlist *sg = hwif->sg_table; int nents = 0; ide_task_t *args = rq->special; unsigned char *virt_addr = rq->buffer; int sector_count = rq->nr_sectors;// if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_WRITEDMA) ||// (args->tfRegister[IDE_COMMAND_OFFSET] == WIN_WRITEDMA_EXT)) if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE) pmif->sg_dma_direction = PCI_DMA_TODEVICE; else pmif->sg_dma_direction = PCI_DMA_FROMDEVICE; if (sector_count > 128) { memset(&sg[nents], 0, sizeof(*sg)); sg[nents].address = virt_addr; sg[nents].length = 128 * SECTOR_SIZE; nents++; virt_addr = virt_addr + (128 * SECTOR_SIZE); sector_count -= 128; } memset(&sg[nents], 0, sizeof(*sg)); sg[nents].address = virt_addr; sg[nents].length = sector_count * SECTOR_SIZE; nents++; return pci_map_sg(hwif->pci_dev, sg, nents, pmif->sg_dma_direction);}/* * pmac_ide_build_dmatable builds the DBDMA command list * for a transfer and sets the DBDMA channel to point to it. */static intpmac_ide_build_dmatable(ide_drive_t *drive, int ix, int wr){ struct dbdma_cmd *table; int i, count = 0; struct request *rq = HWGROUP(drive)->rq; volatile struct dbdma_regs *dma = pmac_ide[ix].dma_regs; struct scatterlist *sg; /* DMA table is already aligned */ table = (struct dbdma_cmd *) pmac_ide[ix].dma_table_cpu; /* Make sure DMA controller is stopped (necessary ?) */ out_le32(&dma->control, (RUN|PAUSE|FLUSH|WAKE|DEAD) << 16); while (in_le32(&dma->status) & RUN) udelay(1); /* Build sglist */ if (HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE) pmac_ide[ix].sg_nents = i = pmac_ide_raw_build_sglist(ix, rq); else pmac_ide[ix].sg_nents = i = pmac_ide_build_sglist(ix, rq); if (!i) return 0; /* Build DBDMA commands list */ sg = pmac_ide[ix].sg_table; while (i) { u32 cur_addr; u32 cur_len; cur_addr = sg_dma_address(sg); cur_len = sg_dma_len(sg); while (cur_len) { unsigned int tc = (cur_len < 0xfe00)? cur_len: 0xfe00; if (++count >= MAX_DCMDS) { printk(KERN_WARNING "%s: DMA table too small\n", drive->name); return 0; /* revert to PIO for this request */ } st_le16(&table->command, wr? OUTPUT_MORE: INPUT_MORE); st_le16(&table->req_count, tc); st_le32(&table->phy_addr, cur_addr); table->cmd_dep = 0; table->xfer_status = 0; table->res_count = 0; cur_addr += tc; cur_len -= tc; ++table; } sg++; i--; } /* convert the last command to an input/output last command */ if (count) st_le16(&table[-1].command, wr? OUTPUT_LAST: INPUT_LAST); else printk(KERN_DEBUG "%s: empty DMA table?\n", drive->name); /* add the stop command to the end of the list */ memset(table, 0, sizeof(struct dbdma_cmd)); out_le16(&table->command, DBDMA_STOP); out_le32(&dma->cmdptr, pmac_ide[ix].dma_table_dma); return 1;}/* Teardown mappings after DMA has completed. */static voidpmac_ide_destroy_dmatable (ide_drive_t *drive, int ix){ struct pci_dev *dev = HWIF(drive)->pci_dev; struct scatterlist *sg = pmac_ide[ix].sg_table; int nents = pmac_ide[ix].sg_nents; if (nents) { pci_unmap_sg(dev, sg, nents, pmac_ide[ix].sg_dma_direction); pmac_ide[ix].sg_nents = 0; }}static __inline__ unsigned chardma_bits_to_command(unsigned char bits){ if(bits & 0x04) return XFER_MW_DMA_2; if(bits & 0x02) return XFER_MW_DMA_1; if(bits & 0x01) return XFER_MW_DMA_0; return 0;}static __inline__ unsigned charudma_bits_to_command(unsigned char bits, int high_speed){ if (high_speed) { if(bits & 0x10) return XFER_UDMA_4; if(bits & 0x08) return XFER_UDMA_3; } if(bits & 0x04) return XFER_UDMA_2; if(bits & 0x02) return XFER_UDMA_1; if(bits & 0x01) return XFER_UDMA_0; return 0;}/* Calculate MultiWord DMA timings */static int __pmacpmac_ide_mdma_enable(ide_drive_t *drive, int idx){ byte bits = drive->id->dma_mword & 0x07; byte feature = dma_bits_to_command(bits); u32 *timings; int drive_cycle_time; struct hd_driveid *id = drive->id; int ret; /* Set feature on drive */ printk(KERN_INFO "%s: Enabling MultiWord DMA %d\n", drive->name, feature & 0xf); ret = pmac_ide_do_setfeature(drive, feature); if (ret) { printk(KERN_WARNING "%s: Failed !\n", drive->name); return 0; } if (!drive->init_speed) drive->init_speed = feature; /* which drive is it ? */ if (drive->select.b.unit & 0x01) timings = &pmac_ide[idx].timings[1]; else timings = &pmac_ide[idx].timings[0]; /* Check if drive provide explicit cycle time */ if ((id->field_valid & 2) && (id->eide_dma_time)) drive_cycle_time = id->eide_dma_time; else drive_cycle_time = 0; /* Calculate controller timings */ set_timings_mdma(pmac_ide[idx].kind, timings, feature, drive_cycle_time); drive->current_speed = feature; return 1;}/* Calculate Ultra DMA timings */static int __pmacpmac_ide_udma_enable(ide_drive_t *drive, int idx, int high_speed){ byte bits = drive->id->dma_ultra & 0x1f; byte feature = udma_bits_to_command(bits, high_speed); u32 *timings; int ret; /* Set feature on drive */ printk(KERN_INFO "%s: Enabling Ultra DMA %d\n", drive->name, feature & 0xf); ret = pmac_ide_do_setfeature(drive, feature); if (ret) { printk(KERN_WARNING "%s: Failed !\n", drive->name); return 0; } if (!drive->init_speed) drive->init_speed = feature; /* which drive is it ? */ if (drive->select.b.unit & 0x01) timings = &pmac_ide[idx].timings[1]; else timings = &pmac_ide[idx].timings[0]; set_timings_udma(timings, feature); drive->current_speed = feature; return 1;}static int __pmacpmac_ide_check_dma(ide_drive_t *drive){ int ata4, udma, idx; struct hd_driveid *id = drive->id; int enable = 1; drive->using_dma = 0; idx = pmac_ide_find(drive); if (idx < 0) return 0; if (drive->media == ide_floppy) enable = 0; if (((id->capability & 1) == 0) && !check_drive_lists(drive, GOOD_DMA_DRIVE)) enable = 0; if (check_drive_lists(drive, BAD_DMA_DRIVE)) enable = 0; udma = 0; ata4 = (pmac_ide[idx].kind == controller_kl_ata4 || pmac_ide[idx].kind == controller_kl_ata4_80); if(enable) { if (ata4 && (drive->media == ide_disk) && (id->field_valid & 0x0004) && (id->dma_ultra & 0x1f)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -