📄 pmac.c
字号:
continue; } pci_set_master(pdev); if (pci_request_regions(pdev, "U2 IDE")) { printk(KERN_ERR "ide-pmac: Cannot obtain PCI resources\n"); continue; } rbase = pci_resource_start(pdev, 0); rlen = pci_resource_len(pdev, 0); base = (unsigned long) ioremap(rbase, rlen); regbase = base + 0x2000; irq = pdev->irq; } /* * If this slot is taken (e.g. by ide-pci.c) try the next one. */ while (i < MAX_HWIFS && ide_hwifs[i].io_ports[IDE_DATA_OFFSET] != 0) ++i; if (i >= MAX_HWIFS) break; pmif = &pmac_ide[i]; pmif->mapbase = base; pmif->regbase = regbase; pmif->irq = irq; pmif->node = np; pmif->cable_80 = 0; if (device_is_compatible(np, "kauai-ata")) { pmif->kind = controller_un_ata6; pci_set_drvdata(pdev, pmif); } else if (device_is_compatible(np, "keylargo-ata")) { if (strcmp(np->name, "ata-4") == 0) pmif->kind = controller_kl_ata4; else pmif->kind = controller_kl_ata3; } else if (device_is_compatible(np, "heathrow-ata")) pmif->kind = controller_heathrow; else pmif->kind = controller_ohare; bidp = (int *)get_property(np, "AAPL,bus-id", NULL); pmif->aapl_bus_id = bidp ? *bidp : 0; /* Get cable type from device-tree */ if (pmif->kind == controller_kl_ata4 || pmif->kind == controller_un_ata6) { char* cable = get_property(np, "cable-type", NULL); if (cable && !strncmp(cable, "80-", 3)) pmif->cable_80 = 1; } /* Make sure we have sane timings */ sanitize_timings(pmif); if (np->parent && np->parent->name && strcasecmp(np->parent->name, "media-bay") == 0) {#ifdef CONFIG_PMAC_PBOOK media_bay_set_ide_infos(np->parent,regbase,irq,i);#endif /* CONFIG_PMAC_PBOOK */ in_bay = 1; if (!bidp) pmif->aapl_bus_id = 1; } else if (pmif->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 */ ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 1); ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmif->aapl_bus_id, 1); mdelay(10); ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 0); big_delay = 1; } hwif = &ide_hwifs[i]; /* Setup MMIO ops */ default_hwif_mmiops(hwif); hwif->OUTBSYNC = pmac_outbsync; /* Tell common code _not_ to mess with resources */ hwif->mmio = 2; hwif->hwif_data = pmif; 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 = pmif->cable_80; hwif->pci_dev = pdev; hwif->drives[0].unmask = 1; hwif->drives[1].unmask = 1; hwif->tuneproc = pmac_ide_tuneproc; if (pmif->kind == controller_un_ata6) hwif->selectproc = pmac_ide_kauai_selectproc; else hwif->selectproc = pmac_ide_selectproc; hwif->speedproc = pmac_ide_tune_chipset; printk(KERN_INFO "ide%d: Found Apple %s controller, bus ID %d%s\n", i, model_name[pmif->kind], pmif->aapl_bus_id, in_bay ? " (mediabay)" : ""); #ifdef CONFIG_PMAC_PBOOK if (in_bay && check_media_bay_by_base(regbase, MB_CD) == 0) hwif->noprobe = 0;#endif /* CONFIG_PMAC_PBOOK */#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC if (np->n_addrs >= 2 || pmif->kind == controller_un_ata6) { /* has a DBDMA controller channel */ pmac_ide_setup_dma(np, i); } hwif->atapi_dma = 1; switch(pmif->kind) { case controller_un_ata6: hwif->ultra_mask = pmif->cable_80 ? 0x3f : 0x07; hwif->mwdma_mask = 0x07; hwif->swdma_mask = 0x00; break; case controller_kl_ata4: hwif->ultra_mask = pmif->cable_80 ? 0x1f : 0x07; hwif->mwdma_mask = 0x07; hwif->swdma_mask = 0x00; break; default: hwif->ultra_mask = 0x00; hwif->mwdma_mask = 0x07; hwif->swdma_mask = 0x00; break; } #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ ++i; } pmac_ide_count = i; if (pmac_ide_count == 0) return; if (big_delay) mdelay(IDE_WAKEUP_DELAY_MS);#ifdef CONFIG_PMAC_PBOOK pmu_register_sleep_notifier(&idepmac_sleep_notifier);#endif /* CONFIG_PMAC_PBOOK */}#ifdef CONFIG_BLK_DEV_IDEDMA_PMACstatic int __pmacpmac_ide_build_sglist(ide_hwif_t *hwif, struct request *rq, int data_dir){ pmac_ide_hwif_t *pmif = (pmac_ide_hwif_t *)hwif->hwif_data; struct buffer_head *bh; struct scatterlist *sg = pmif->sg_table; unsigned long lastdataend = ~0UL; int nents = 0; if (hwif->sg_dma_active) BUG(); pmif->sg_dma_direction = data_dir; bh = rq->bh; do { int contig = 0; if (bh->b_page) { if (bh_phys(bh) == lastdataend) contig = 1; } else { if ((unsigned long) bh->b_data == lastdataend) contig = 1; } if (contig) { sg[nents - 1].length += bh->b_size; lastdataend += bh->b_size; continue; } if (nents >= MAX_DCMDS) return 0; memset(&sg[nents], 0, sizeof(*sg)); if (bh->b_page) { sg[nents].page = bh->b_page; sg[nents].offset = bh_offset(bh); lastdataend = bh_phys(bh) + bh->b_size; } else { if ((unsigned long) bh->b_data < PAGE_SIZE) BUG(); sg[nents].address = bh->b_data; lastdataend = (unsigned long) bh->b_data + bh->b_size; } sg[nents].length = bh->b_size; nents++; } while ((bh = bh->b_reqnext) != NULL); if(nents == 0) BUG(); return pci_map_sg(hwif->pci_dev, sg, nents, data_dir);}static int __pmacpmac_ide_raw_build_sglist(ide_hwif_t *hwif, struct request *rq){ pmac_ide_hwif_t *pmif = (pmac_ide_hwif_t *)hwif->hwif_data; 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->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 int __pmacpmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq, int ddir){ struct dbdma_cmd *table; int i, count = 0; ide_hwif_t *hwif = HWIF(drive); pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data; volatile struct dbdma_regs *dma = pmif->dma_regs; struct scatterlist *sg; /* DMA table is already aligned */ table = (struct dbdma_cmd *) pmif->dma_table_cpu; /* Make sure DMA controller is stopped (necessary ?) */ writel((RUN|PAUSE|FLUSH|WAKE|DEAD) << 16, &dma->control); while (readl(&dma->status) & RUN) udelay(1); /* Build sglist */ if (rq->cmd == IDE_DRIVE_TASKFILE) pmif->sg_nents = i = pmac_ide_raw_build_sglist(hwif, rq); else pmif->sg_nents = i = pmac_ide_build_sglist(hwif, rq, ddir); if (!i) return 0; /* Build DBDMA commands list */ sg = pmif->sg_table; while (i && sg_dma_len(sg)) { 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); goto use_pio_instead; } st_le16(&table->command, (ddir == PCI_DMA_TODEVICE) ? 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, (ddir == PCI_DMA_TODEVICE) ? OUTPUT_LAST: INPUT_LAST); /* add the stop command to the end of the list */ memset(table, 0, sizeof(struct dbdma_cmd)); st_le16(&table->command, DBDMA_STOP); mb(); writel(pmif->dma_table_dma, &dma->cmdptr); return 1; } printk(KERN_DEBUG "%s: empty DMA table?\n", drive->name); use_pio_instead: pci_unmap_sg(hwif->pci_dev, pmif->sg_table, pmif->sg_nents, pmif->sg_dma_direction); hwif->sg_dma_active = 0; return 0; /* revert to PIO for this request */}/* Teardown mappings after DMA has completed. */static void __pmacpmac_ide_destroy_dmatable (ide_drive_t *drive){ struct pci_dev *dev = HWIF(drive)->pci_dev; pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; struct scatterlist *sg = pmif->sg_table; int nents = pmif->sg_nents; if (nents) { pci_unmap_sg(dev, sg, nents, pmif->sg_dma_direction); pmif->sg_nents = 0; HWIF(drive)->sg_dma_active = 0; }}/* Calculate MultiWord DMA timings */static int __pmacpmac_ide_mdma_enable(ide_drive_t *drive, u16 mode){ ide_hwif_t *hwif = HWIF(drive); pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data; int drive_cycle_time; struct hd_driveid *id = drive->id; u32 *timings, *timings2; u32 timing_local[2]; int ret; /* which drive is it ? */ timings = &pmif->timings[drive->select.b.unit & 0x01]; timings2 = &pmif->timings[(drive->select.b.unit & 0x01) + 2]; /* 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; /* Copy timings to local image */ timing_local[0] = *timings; timing_local[1] = *timings2; /* Calculate controller timings */ ret = set_timings_mdma( pmif->kind, &timing_local[0], &timing_local[1], mode, drive_cycle_time); if (ret) return 0; /* Set feature on drive */ printk(KERN_INFO "%s: Enabling MultiWord DMA %d\n", drive->name, mode & 0xf); ret = pmac_ide_do_setfeature(drive, mode); if (ret) { printk(KERN_WARNING "%s: Failed !\n", drive->name); return 0; } /* Apply timings to controller */ *timings = timing_local[0]; *timings2 = timing_local[1]; /* Set speed info in drive */ drive->current_speed = mode; if (!drive->init_speed) drive->init_speed = mode; return 1;}/* Calculate Ultra DMA timings */static int __pmacpmac_ide_udma_enable(ide_drive_t *drive, u16 mode){ ide_hwif_t *hwif = HWIF(drive); pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data; u32 *timings, *timings2; u32 timing_local[2]; int ret; /* which drive is it ? */ timings = &pmif->timings[drive->select.b.unit & 0x01]; timings2 = &pmif->timings[(drive->select.b.unit & 0x01) + 2]; /* Copy timings to local image */ timing_local[0] = *timings; timing_local[1] = *timings2; /* Calculate timings for interface */ if (pmif->kind == controller_un_ata6) ret = set_timings_udma_ata6( &timing_local[0], &timing_local[1], mode); else ret = set_timings_udma_ata4(&timing_local[0], mode); if (ret) return 0; /* Set feature on drive */ printk(KERN_INFO "%s: Enabling Ultra DMA %d\n", drive->name, mode & 0x0f); ret = pmac_ide_do_setfeature(drive, mode); if (ret) { printk(KERN_WARNING "%s: Failed !\n", drive->name); return 0; } /* Apply timings to controller */ *timings = timing_local[0]; *timings2 = timing_local[1]; /* Set speed info in drive */ drive->current_speed = mode; if (!drive->init_speed) drive->init_speed = mode; return 1;}static __pmacint pmac_ide_dma_check(ide_drive_t *drive){ struct hd_driveid *id = drive->id; ide_hwif_t *hwif = HWIF(drive); pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data; int enable = 1; int map; drive->using_dma = 0; if (pmif == NULL) return 0; if (drive->media == ide_floppy) enable = 0; if (((id->capability & 1) == 0) && !HWIF(drive)->ide_dma_good_drive(drive)) enable = 0; if (HWIF(drive)->ide_dma_bad_drive(drive)) enable = 0; if (enable) { short mode; map = XFER_MWDMA; if (pmif->kind == controller_kl_ata4 || pmif->kind == controller_un_ata6) { map |= XFER_UDMA; if (pmif->cable_80) { map |= XFER_UDMA_66; if (pmif->kind == controller_un_ata6) map |= XFER_UDMA_100; } } mode = ide_find_best_mode(drive, map); if (mode & XFER_UDMA) drive->using_dma = pmac_ide_udma_enable(drive, mode); else if (mode & XFER_MWDMA) drive->using_dma = pmac_ide_mdma_enable(drive, mode); hwif->OUTB(0, IDE_CONTROL_REG); /* Apply settings to controller */ pmac_ide_do_update_timings(drive); } return 0;}static int __pmacpmac_ide_dma_read (ide_drive_t *drive){ ide_hwif_t *hwif = HWIF(drive); pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data; struct request *rq = HWGROUP(drive)->rq;// ide_task_t *args = rq->special; u8 unit = (drive->select.b.unit & 0x01); u8 ata4; u8 lba48 = (drive->addressing == 1) ? 1 : 0; task_ioreg_t command = WIN_NOP; if (pmif == NULL) return 1; ata4 = (pmif->kind == controller_kl_ata4); if (!pmac_ide_build_dmatable(drive, rq, PCI_DMA_FROMDEVICE)) /* try PIO instead of DMA */ return 1; /* Apple adds 60ns to wrDataSetup on reads */ if (ata4 && (pmif->timings[unit] & TR_66_UDMA_EN)) { writel(pmif->timings[unit]+0x00800000UL, (unsigned *)(IDE_DATA_REG+IDE_TIMING_CONFIG)); io_flush(readl((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG))); } drive->waiting_for_dma = 1; if (drive->media != ide_disk) return 0; /* paranoia check */ if (HWGROUP(drive)->handler != NULL) /* paranoia check */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -