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

📄 ide-pmac.c

📁 at91rm9200处理器ide接口驱动程序源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
		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 + -