⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pmac.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
		/* The inteface is released to the common IDE layer */		pci_set_drvdata(pdev, NULL);		iounmap(base);		memset(pmif, 0, sizeof(*pmif));		pci_release_regions(pdev);	}	return rc;}static intpmac_ide_pci_suspend(struct pci_dev *pdev, pm_message_t mesg){	ide_hwif_t	*hwif = (ide_hwif_t *)pci_get_drvdata(pdev);	int		rc = 0;		if (mesg.event != pdev->dev.power.power_state.event			&& mesg.event == PM_EVENT_SUSPEND) {		rc = pmac_ide_do_suspend(hwif);		if (rc == 0)			pdev->dev.power.power_state = mesg;	}	return rc;}static intpmac_ide_pci_resume(struct pci_dev *pdev){	ide_hwif_t	*hwif = (ide_hwif_t *)pci_get_drvdata(pdev);	int		rc = 0;		if (pdev->dev.power.power_state.event != PM_EVENT_ON) {		rc = pmac_ide_do_resume(hwif);		if (rc == 0)			pdev->dev.power.power_state = PMSG_ON;	}	return rc;}static struct of_device_id pmac_ide_macio_match[] = {	{	.name 		= "IDE",	},	{	.name 		= "ATA",	},	{	.type		= "ide",	},	{	.type		= "ata",	},	{},};static struct macio_driver pmac_ide_macio_driver = {	.name 		= "ide-pmac",	.match_table	= pmac_ide_macio_match,	.probe		= pmac_ide_macio_attach,	.suspend	= pmac_ide_macio_suspend,	.resume		= pmac_ide_macio_resume,};static const struct pci_device_id pmac_ide_pci_match[] = {	{ PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_UNI_N_ATA),	0 },	{ PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_IPID_ATA100),	0 },	{ PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_K2_ATA100),	0 },	{ PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_SH_ATA),	0 },	{ PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_IPID2_ATA),	0 },	{},};static struct pci_driver pmac_ide_pci_driver = {	.name		= "ide-pmac",	.id_table	= pmac_ide_pci_match,	.probe		= pmac_ide_pci_attach,	.suspend	= pmac_ide_pci_suspend,	.resume		= pmac_ide_pci_resume,};MODULE_DEVICE_TABLE(pci, pmac_ide_pci_match);int __init pmac_ide_probe(void){	int error;	if (!machine_is(powermac))		return -ENODEV;#ifdef CONFIG_BLK_DEV_IDE_PMAC_ATA100FIRST	error = pci_register_driver(&pmac_ide_pci_driver);	if (error)		goto out;	error = macio_register_driver(&pmac_ide_macio_driver);	if (error) {		pci_unregister_driver(&pmac_ide_pci_driver);		goto out;	}#else	error = macio_register_driver(&pmac_ide_macio_driver);	if (error)		goto out;	error = pci_register_driver(&pmac_ide_pci_driver);	if (error) {		macio_unregister_driver(&pmac_ide_macio_driver);		goto out;	}#endifout:	return error;}#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC/* * 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, struct request *rq){	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 __iomem *dma = pmif->dma_regs;	struct scatterlist *sg;	int wr = (rq_data_dir(rq) == WRITE);	/* 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);	hwif->sg_nents = i = ide_build_sglist(drive, rq);	if (!i)		return 0;	/* Build DBDMA commands list */	sg = hwif->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);		if (pmif->broken_dma && cur_addr & (L1_CACHE_BYTES - 1)) {			if (pmif->broken_dma_warn == 0) {				printk(KERN_WARNING "%s: DMA on non aligned address, "				       "switching to PIO on Ohare chipset\n", drive->name);				pmif->broken_dma_warn = 1;			}			goto use_pio_instead;		}		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, 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 = sg_next(sg);		i--;	}	/* convert the last command to an input/output last command */	if (count) {		st_le16(&table[-1].command, wr? 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(hwif->dmatable_dma, &dma->cmdptr);		return 1;	}	printk(KERN_DEBUG "%s: empty DMA table?\n", drive->name); use_pio_instead:	pci_unmap_sg(hwif->pci_dev,		     hwif->sg_table,		     hwif->sg_nents,		     hwif->sg_dma_direction);	return 0; /* revert to PIO for this request */}/* Teardown mappings after DMA has completed.  */static voidpmac_ide_destroy_dmatable (ide_drive_t *drive){	ide_hwif_t *hwif = drive->hwif;	struct pci_dev *dev = HWIF(drive)->pci_dev;	struct scatterlist *sg = hwif->sg_table;	int nents = hwif->sg_nents;	if (nents) {		pci_unmap_sg(dev, sg, nents, hwif->sg_dma_direction);		hwif->sg_nents = 0;	}}/* * Prepare a DMA transfer. We build the DMA table, adjust the timings for * a read on KeyLargo ATA/66 and mark us as waiting for DMA completion */static intpmac_ide_dma_setup(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;	u8 unit = (drive->select.b.unit & 0x01);	u8 ata4;	if (pmif == NULL)		return 1;	ata4 = (pmif->kind == controller_kl_ata4);		if (!pmac_ide_build_dmatable(drive, rq)) {		ide_map_sg(drive, rq);		return 1;	}	/* Apple adds 60ns to wrDataSetup on reads */	if (ata4 && (pmif->timings[unit] & TR_66_UDMA_EN)) {		writel(pmif->timings[unit] + (!rq_data_dir(rq) ? 0x00800000UL : 0),			PMAC_IDE_REG(IDE_TIMING_CONFIG));		(void)readl(PMAC_IDE_REG(IDE_TIMING_CONFIG));	}	drive->waiting_for_dma = 1;	return 0;}static voidpmac_ide_dma_exec_cmd(ide_drive_t *drive, u8 command){	/* issue cmd to drive */	ide_execute_command(drive, command, &ide_dma_intr, 2*WAIT_CMD, NULL);}/* * Kick the DMA controller into life after the DMA command has been issued * to the drive. */static voidpmac_ide_dma_start(ide_drive_t *drive){	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;	volatile struct dbdma_regs __iomem *dma;	dma = pmif->dma_regs;	writel((RUN << 16) | RUN, &dma->control);	/* Make sure it gets to the controller right now */	(void)readl(&dma->control);}/* * After a DMA transfer, make sure the controller is stopped */static intpmac_ide_dma_end (ide_drive_t *drive){	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;	volatile struct dbdma_regs __iomem *dma;	u32 dstat;		if (pmif == NULL)		return 0;	dma = pmif->dma_regs;	drive->waiting_for_dma = 0;	dstat = readl(&dma->status);	writel(((RUN|WAKE|DEAD) << 16), &dma->control);	pmac_ide_destroy_dmatable(drive);	/* verify good dma status. we don't check for ACTIVE beeing 0. We should...	 * in theory, but with ATAPI decices doing buffer underruns, that would	 * cause us to disable DMA, which isn't what we want	 */	return (dstat & (RUN|DEAD)) != RUN;}/* * Check out that the interrupt we got was for us. We can't always know this * for sure with those Apple interfaces (well, we could on the recent ones but * that's not implemented yet), on the other hand, we don't have shared interrupts * so it's not really a problem */static intpmac_ide_dma_test_irq (ide_drive_t *drive){	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;	volatile struct dbdma_regs __iomem *dma;	unsigned long status, timeout;	if (pmif == NULL)		return 0;	dma = pmif->dma_regs;	/* We have to things to deal with here:	 * 	 * - The dbdma won't stop if the command was started	 * but completed with an error without transferring all	 * datas. This happens when bad blocks are met during	 * a multi-block transfer.	 * 	 * - The dbdma fifo hasn't yet finished flushing to	 * to system memory when the disk interrupt occurs.	 * 	 */	/* If ACTIVE is cleared, the STOP command have passed and	 * transfer is complete.	 */	status = readl(&dma->status);	if (!(status & ACTIVE))		return 1;	if (!drive->waiting_for_dma)		printk(KERN_WARNING "ide%d, ide_dma_test_irq \			called while not waiting\n", HWIF(drive)->index);	/* If dbdma didn't execute the STOP command yet, the	 * active bit is still set. We consider that we aren't	 * sharing interrupts (which is hopefully the case with	 * those controllers) and so we just try to flush the	 * channel for pending data in the fifo	 */	udelay(1);	writel((FLUSH << 16) | FLUSH, &dma->control);	timeout = 0;	for (;;) {		udelay(1);		status = readl(&dma->status);		if ((status & FLUSH) == 0)			break;		if (++timeout > 100) {			printk(KERN_WARNING "ide%d, ide_dma_test_irq \			timeout flushing channel\n", HWIF(drive)->index);			break;		}	}		return 1;}static void pmac_ide_dma_host_off(ide_drive_t *drive){}static void pmac_ide_dma_host_on(ide_drive_t *drive){}static voidpmac_ide_dma_lost_irq (ide_drive_t *drive){	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;	volatile struct dbdma_regs __iomem *dma;	unsigned long status;	if (pmif == NULL)		return;	dma = pmif->dma_regs;	status = readl(&dma->status);	printk(KERN_ERR "ide-pmac lost interrupt, dma status: %lx\n", status);}/* * Allocate the data structures needed for using DMA with an interface * and fill the proper list of functions pointers */static void __init pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif){	/* We won't need pci_dev if we switch to generic consistent	 * DMA routines ...	 */	if (hwif->pci_dev == NULL)		return;	/*	 * 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(		hwif->pci_dev,		(MAX_DCMDS + 2) * sizeof(struct dbdma_cmd),		&hwif->dmatable_dma);	if (pmif->dma_table_cpu == NULL) {		printk(KERN_ERR "%s: unable to allocate DMA command list\n",		       hwif->name);		return;	}	hwif->dma_off_quietly = &ide_dma_off_quietly;	hwif->ide_dma_on = &__ide_dma_on;	hwif->dma_setup = &pmac_ide_dma_setup;	hwif->dma_exec_cmd = &pmac_ide_dma_exec_cmd;	hwif->dma_start = &pmac_ide_dma_start;	hwif->ide_dma_end = &pmac_ide_dma_end;	hwif->ide_dma_test_irq = &pmac_ide_dma_test_irq;	hwif->dma_host_off = &pmac_ide_dma_host_off;	hwif->dma_host_on = &pmac_ide_dma_host_on;	hwif->dma_timeout = &ide_dma_timeout;	hwif->dma_lost_irq = &pmac_ide_dma_lost_irq;	switch(pmif->kind) {		case controller_sh_ata6:			hwif->ultra_mask = pmif->cable_80 ? 0x7f : 0x07;			hwif->mwdma_mask = 0x07;			hwif->swdma_mask = 0x00;			break;		case controller_un_ata6:		case controller_k2_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 */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -