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

📄 ide-pmac.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 2 页
字号:
			size = bh->b_size;			while ((bh = bh->b_reqnext) != NULL) {				if ((addr + size) != virt_to_bus(bh->b_data))					break;				size += bh->b_size;			}		}		/*		 * Fill in the next DBDMA command block.		 * Note that one DBDMA command can transfer		 * at most 65535 bytes.		 */		while (size) {			unsigned int tc = (size < 0xfe00)? size: 0xfe00;			if (++count >= MAX_DCMDS) {				printk("%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, addr);			table->cmd_dep = 0;			table->xfer_status = 0;			table->res_count = 0;			addr += tc;			size -= tc;			++table;		}	} while (bh != NULL);	/* 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, virt_to_bus(tstart));	return 1;}/* This is fun.  -DaveM */#define IDE_SETXFER		0x03#define IDE_SETFEATURE		0xef#define IDE_DMA2_ENABLE		0x22#define IDE_DMA1_ENABLE		0x21#define IDE_DMA0_ENABLE		0x20#define IDE_UDMA4_ENABLE	0x44#define IDE_UDMA3_ENABLE	0x43#define IDE_UDMA2_ENABLE	0x42#define IDE_UDMA1_ENABLE	0x41#define IDE_UDMA0_ENABLE	0x40static __inline__ unsigned chardma_bits_to_command(unsigned char bits){	if(bits & 0x04)		return IDE_DMA2_ENABLE;	if(bits & 0x02)		return IDE_DMA1_ENABLE;	return IDE_DMA0_ENABLE;}static __inline__ unsigned charudma_bits_to_command(unsigned char bits){	if(bits & 0x10)		return IDE_UDMA4_ENABLE;	if(bits & 0x08)		return IDE_UDMA3_ENABLE;	if(bits & 0x04)		return IDE_UDMA2_ENABLE;	if(bits & 0x02)		return IDE_UDMA1_ENABLE;	if(bits & 0x01)		return IDE_UDMA0_ENABLE;	return 0;}static __inline__ intwait_for_ready(ide_drive_t *drive){	/* Timeout bumped for some powerbooks */	int timeout = 2000;	byte stat;	while(--timeout) {		stat = GET_STAT();		if(!(stat & BUSY_STAT)) {			if (drive->ready_stat == 0)				break;			else if((stat & drive->ready_stat) || (stat & ERR_STAT))				break;		}		mdelay(1);	}	if((stat & ERR_STAT) || timeout <= 0) {		if (stat & ERR_STAT) {			printk("ide_pmace: wait_for_ready, error status: %x\n", stat);		}		return 1;	}	return 0;}static intpmac_ide_do_setfeature(ide_drive_t *drive, byte command){	unsigned long flags;	byte old_select;	int result = 1;	save_flags(flags);	cli();	old_select = IN_BYTE(IDE_SELECT_REG);	OUT_BYTE(drive->select.all, IDE_SELECT_REG);	udelay(10);	OUT_BYTE(IDE_SETXFER, IDE_FEATURE_REG);	OUT_BYTE(command, IDE_NSECTOR_REG);	if(wait_for_ready(drive)) {		printk("pmac_ide_do_setfeature disk not ready before SET_FEATURE!\n");		goto out;	}	OUT_BYTE(IDE_SETFEATURE, IDE_COMMAND_REG);	result = wait_for_ready(drive);	if (result)		printk("pmac_ide_do_setfeature disk not ready after SET_FEATURE !\n");out:	OUT_BYTE(old_select, IDE_SELECT_REG);	restore_flags(flags);		return result;}/* Calculate MultiWord DMA timings */static intpmac_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 cycleTime, accessTime;	int accessTicks, recTicks;	struct hd_driveid *id = drive->id;		/* Set feature on drive */    	printk("%s: Enabling MultiWord DMA %d\n", drive->name, feature & 0xf);	if (pmac_ide_do_setfeature(drive, feature)) {	    	printk("%s: Failed !\n", drive->name);	    	return 0;	}	if (!drive->init_speed)		drive->init_speed = feature;		/* which drive is it ? */	if (drive->select.all & 0x10)		timings = &pmac_ide[idx].timings[1];	else		timings = &pmac_ide[idx].timings[0];	/* Calculate accesstime and cycle time */	cycleTime = mdma_timings[feature & 0xf].cycleTime;	accessTime = mdma_timings[feature & 0xf].accessTime;	if ((id->field_valid & 2) && (id->eide_dma_time))		cycleTime = id->eide_dma_time;	if ((pmac_ide[idx].kind == controller_ohare) && (cycleTime < 150))		cycleTime = 150;	/* For ata-4 controller, we don't know the calculation */	if (pmac_ide[idx].kind == controller_kl_ata4) {		accessTicks = SYSCLK_TICKS_UDMA(accessTime * 1000);		recTicks = SYSCLK_TICKS_UDMA(cycleTime * 1000) - accessTicks;		*timings = ((*timings) & 0xffe003ff) |			(accessTicks | (recTicks << 5)) << 10;	} else {		int halfTick = 0;		int origAccessTime = accessTime;		int origCycleTime = cycleTime;				accessTicks = SYSCLK_TICKS(accessTime);		if (accessTicks < 1)			accessTicks = 1;		accessTime = accessTicks * IDE_SYSCLK_NS;		recTicks = SYSCLK_TICKS(cycleTime - accessTime) - 1;		if (recTicks < 1)			recTicks = 1;		cycleTime = (recTicks + 1 + accessTicks) * IDE_SYSCLK_NS;		/* KeyLargo ata-3 don't support the half-tick stuff */		if ((pmac_ide[idx].kind != controller_kl_ata3) &&			(accessTicks > 1) &&			((accessTime - IDE_SYSCLK_NS/2) >= origAccessTime) &&			((cycleTime - IDE_SYSCLK_NS) >= origCycleTime)) {            			halfTick    = 1;				accessTicks--;		}		*timings = ((*timings) & 0x7FF) |			(accessTicks | (recTicks << 5) | (halfTick << 10)) << 11;	}#ifdef IDE_PMAC_DEBUG	printk("ide_pmac: Set MDMA timing for mode %d, reg: 0x%08x\n",		feature & 0xf, *timings);#endif	drive->current_speed = feature;		return 1;}/* Calculate Ultra DMA timings */static intpmac_ide_udma_enable(ide_drive_t *drive, int idx){	byte bits = drive->id->dma_ultra & 0x1f;	byte feature = udma_bits_to_command(bits);	int cycleTime, accessTime;	int rdyToPauseTicks, cycleTicks;	u32 *timings;		/* Set feature on drive */    	printk("%s: Enabling Ultra DMA %d\n", drive->name, feature & 0xf);	if (pmac_ide_do_setfeature(drive, feature)) {		printk("%s: Failed !\n", drive->name);		return 0;	}	if (!drive->init_speed)		drive->init_speed = feature;	/* which drive is it ? */	if (drive->select.all & 0x10)		timings = &pmac_ide[idx].timings[1];	else		timings = &pmac_ide[idx].timings[0];	cycleTime = udma_timings[feature & 0xf].cycleTime;	accessTime = udma_timings[feature & 0xf].accessTime;	rdyToPauseTicks = SYSCLK_TICKS_UDMA(accessTime * 1000);	cycleTicks = SYSCLK_TICKS_UDMA(cycleTime * 1000);	*timings = ((*timings) & 0xe00fffff) |			((cycleTicks << 1) | (rdyToPauseTicks << 5) | 1) << 20;	drive->current_speed = feature;		return 1;}static intpmac_ide_dma_onoff(ide_drive_t *drive, int enable){	int ata4, udma, idx;	struct hd_driveid *id = drive->id;	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);				if(enable) {		if (ata4 && (drive->media == ide_disk) &&		    (id->field_valid & 0x0004) && (id->dma_ultra & 0x17)) {			/* UltraDMA modes. */			drive->using_dma = pmac_ide_udma_enable(drive, idx);		}		if (!drive->using_dma && (id->dma_mword & 0x0007)) {			/* Normal MultiWord DMA modes. */			drive->using_dma = pmac_ide_mdma_enable(drive, idx);		}		/* Without this, strange things will happen on Keylargo-based		 * machines		 */		OUT_BYTE(0, IDE_CONTROL_REG);		if (drive->select.all == IN_BYTE(IDE_SELECT_REG))			pmac_ide_selectproc(drive);	}	return 0;}int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive){	ide_hwif_t *hwif = HWIF(drive);	int ix, dstat;	volatile struct dbdma_regs *dma;	/* Can we stuff a pointer to our intf structure in config_data	 * or select_data in hwif ?	 */	ix = pmac_ide_find(drive);	if (ix < 0)		return 0;			dma = pmac_ide[ix].dma_regs;	switch (func) {	case ide_dma_on:	case ide_dma_off:	case ide_dma_off_quietly:		pmac_ide_dma_onoff(drive, (func == ide_dma_on));		break;	case ide_dma_check:		printk("IDE-DMA check !\n");		if (hwif->autodma)			pmac_ide_dma_onoff(drive, 1);		break;	case ide_dma_read:	case ide_dma_write:		if (!pmac_ide_build_dmatable(drive, ix, func==ide_dma_write))			return 1;		drive->waiting_for_dma = 1;		if (drive->media != ide_disk)			return 0;		ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);		OUT_BYTE(func==ide_dma_write? WIN_WRITEDMA: WIN_READDMA,			 IDE_COMMAND_REG);	case ide_dma_begin:		out_le32(&dma->control, (RUN << 16) | RUN);		break;	case ide_dma_end:		drive->waiting_for_dma = 0;		dstat = in_le32(&dma->status);		out_le32(&dma->control, ((RUN|WAKE|DEAD) << 16));		/* verify good dma status */		return (dstat & (RUN|DEAD|ACTIVE)) != RUN;	case ide_dma_test_irq:		return (in_le32(&dma->status) & (RUN|ACTIVE)) == RUN;		/* Let's implement tose just in case someone wants them */	case ide_dma_bad_drive:	case ide_dma_good_drive:		return check_drive_lists(drive, (func == ide_dma_good_drive));	case ide_dma_verbose:		return report_drive_dmaing(drive);	case ide_dma_retune:	case ide_dma_lostirq:	case ide_dma_timeout:		printk("ide_pmac_dmaproc: chipset supported %s func only: %d\n", ide_dmafunc_verbose(func),  func);		return 1;	default:		printk("ide_pmac_dmaproc: unsupported %s func: %d\n", ide_dmafunc_verbose(func), func);		return 1;	}	return 0;}#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */#ifdef CONFIG_PMAC_PBOOKstatic void idepmac_sleep_disk(int i, unsigned long base){	struct device_node* np = pmac_ide[i].node;	int j;	/* FIXME: We only handle the master IDE */	if (ide_hwifs[i].drives[0].media == ide_disk) {		/* Spin down the drive */		outb(0xa0, base+0x60);		outb(0x0, base+0x30);		outb(0x0, base+0x20);		outb(0x0, base+0x40);		outb(0x0, base+0x50);		outb(0xe0, base+0x70);		outb(0x2, base+0x160);   		for (j = 0; j < 10; j++) {			int status;			mdelay(100);			status = inb(base+0x70);			if (!(status & BUSY_STAT) && (status & DRQ_STAT))				break;		}	}	feature_set(np, FEATURE_IDE0_reset);	feature_clear(np, FEATURE_IDE0_enable);	switch(pmac_ide[i].aapl_bus_id) {	    case 0:		feature_set(np, FEATURE_IDE0_reset);		feature_clear(np, FEATURE_IDE0_enable);		break;	    case 1:		feature_set(np, FEATURE_IDE1_reset);		feature_clear(np, FEATURE_IDE1_enable);		break;	    case 2:		feature_set(np, FEATURE_IDE2_reset);		break;	}	pmac_ide[i].timings[0] = 0;	pmac_ide[i].timings[1] = 0;}static void idepmac_wake_disk(int i, unsigned long base){	struct device_node* np = pmac_ide[i].node;	int j;	/* Revive IDE disk and controller */	switch(pmac_ide[i].aapl_bus_id) {	    case 0:		feature_set(np, FEATURE_IDE0_reset);		mdelay(10); 		feature_set(np, FEATURE_IDE0_enable);		mdelay(10);		feature_clear(np, FEATURE_IDE0_reset);		break;	    case 1:		feature_set(np, FEATURE_IDE1_reset);		mdelay(10); 		feature_set(np, FEATURE_IDE1_enable);		mdelay(10);		feature_clear(np, FEATURE_IDE1_reset);		break;	    case 2:	    	/* This one exists only for KL, I don't know		   about any enable bit */		feature_set(np, FEATURE_IDE2_reset);		mdelay(10);		feature_clear(np, FEATURE_IDE2_reset);		break;	}	mdelay(IDE_WAKEUP_DELAY_MS);	/* Reset timings */	pmac_ide_selectproc(&ide_hwifs[i].drives[0]);	mdelay(10);	/* Wait up to 10 seconds (enough for recent drives) */	for (j = 0; j < 100; j++) {		int status;		mdelay(100);		status = inb(base + 0x70);		if (!(status & BUSY_STAT))			break;	}}/* Here we handle media bay devices */static voididepmac_wake_bay(int i, unsigned long base){	int timeout;	/* Reset timings */	pmac_ide_selectproc(&ide_hwifs[i].drives[0]);	mdelay(10);	timeout = 10000;	while ((inb(base + 0x70) & BUSY_STAT) && timeout) {		mdelay(1);		--timeout;	}}/* Note: We support only master drives for now. This will have to be * improved if we want to handle sleep on the iMacDV where the CD-ROM * is a slave */static int idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when){	int i, ret;	unsigned long base;	switch (when) {	case PBOOK_SLEEP_REQUEST:		break;	case PBOOK_SLEEP_REJECT:		break;	case PBOOK_SLEEP_NOW:		for (i = 0; i < pmac_ide_count; ++i) {			if ((base = pmac_ide[i].regbase) == 0)				continue;			/* Disable irq during sleep */			disable_irq(pmac_ide[i].irq);			ret = check_media_bay_by_base(base, MB_CD);			if ((ret == -ENODEV) && ide_hwifs[i].drives[0].present)				/* not media bay - put the disk to sleep */				idepmac_sleep_disk(i, base);		}		break;	case PBOOK_WAKE:		for (i = 0; i < pmac_ide_count; ++i) {			ide_hwif_t *hwif;			if ((base = pmac_ide[i].regbase) == 0)				continue;			hwif = &ide_hwifs[i];		        /* We don't handle media bay devices this way */			ret = check_media_bay_by_base(base, MB_CD);			if ((ret == -ENODEV) && ide_hwifs[i].drives[0].present)				idepmac_wake_disk(i, base);			else if (ret == 0)				idepmac_wake_bay(i, base);			enable_irq(pmac_ide[i].irq);#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC			if (hwif->drives[0].present && hwif->drives[0].using_dma)				pmac_ide_dma_onoff(&hwif->drives[0], 1);#endif						}		break;	}	return PBOOK_SLEEP_OK;}#endif /* CONFIG_PMAC_PBOOK */

⌨️ 快捷键说明

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