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

📄 siimage.c

📁 优龙2410linux2.6.8内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * linux/drivers/ide/pci/siimage.c		Version 1.07	Nov 30, 2003 * * Copyright (C) 2001-2002	Andre Hedrick <andre@linux-ide.org> * Copyright (C) 2003		Red Hat <alan@redhat.com> * *  May be copied or modified under the terms of the GNU General Public License * *  Documentation available under NDA only * * *  FAQ Items: *	If you are using Marvell SATA-IDE adapters with Maxtor drives *	ensure the system is set up for ATA100/UDMA5 not UDMA6. * *	If you are using WD drives with SATA bridges you must set the *	drive to "Single". "Master" will hang * *	If you have strange problems with nVidia chipset systems please *	see the SI support documentation and update your system BIOS *	if neccessary */#include <linux/config.h>#include <linux/types.h>#include <linux/module.h>#include <linux/pci.h>#include <linux/delay.h>#include <linux/hdreg.h>#include <linux/ide.h>#include <linux/init.h>#include <asm/io.h>#undef SIIMAGE_VIRTUAL_DMAPIO#undef SIIMAGE_LARGE_DMA/** *	pdev_is_sata		-	check if device is SATA *	@pdev:	PCI device to check *	 *	Returns true if this is a SATA controller */ static int pdev_is_sata(struct pci_dev *pdev){	switch(pdev->device)	{		case PCI_DEVICE_ID_SII_3112:		case PCI_DEVICE_ID_SII_1210SA:			return 1;		case PCI_DEVICE_ID_SII_680:			return 0;	}	BUG();	return 0;} /** *	is_sata			-	check if hwif is SATA *	@hwif:	interface to check *	 *	Returns true if this is a SATA controller */ static inline int is_sata(ide_hwif_t *hwif){	return pdev_is_sata(hwif->pci_dev);}/** *	siimage_selreg		-	return register base *	@hwif: interface *	@r: config offset * *	Turn a config register offset into the right address in either *	PCI space or MMIO space to access the control register in question *	Thankfully this is a configuration operation so isnt performance *	criticial.  */ static unsigned long siimage_selreg(ide_hwif_t *hwif, int r){	unsigned long base = (unsigned long)hwif->hwif_data;	base += 0xA0 + r;	if(hwif->mmio)		base += (hwif->channel << 6);	else		base += (hwif->channel << 4);	return base;}	/** *	siimage_seldev		-	return register base *	@hwif: interface *	@r: config offset * *	Turn a config register offset into the right address in either *	PCI space or MMIO space to access the control register in question *	including accounting for the unit shift. */ static inline unsigned long siimage_seldev(ide_drive_t *drive, int r){	ide_hwif_t *hwif	= HWIF(drive);	unsigned long base = (unsigned long)hwif->hwif_data;	base += 0xA0 + r;	if(hwif->mmio)		base += (hwif->channel << 6);	else		base += (hwif->channel << 4);	base |= drive->select.b.unit << drive->select.b.unit;	return base;}/** *	siimage_ratemask	-	Compute available modes *	@drive: IDE drive * *	Compute the available speeds for the devices on the interface. *	For the CMD680 this depends on the clocking mode (scsc), for the *	SI3312 SATA controller life is a bit simpler. Enforce UDMA33 *	as a limit if there is no 80pin cable present. */ static byte siimage_ratemask (ide_drive_t *drive){	ide_hwif_t *hwif	= HWIF(drive);	u8 mode	= 0, scsc = 0;	unsigned long base = (unsigned long) hwif->hwif_data;	if (hwif->mmio)		scsc = hwif->INB(base + 0x4A);	else		pci_read_config_byte(hwif->pci_dev, 0x8A, &scsc);	if(is_sata(hwif))	{		if(strstr(drive->id->model, "Maxtor"))			return 3;		return 4;	}		if ((scsc & 0x30) == 0x10)	/* 133 */		mode = 4;	else if ((scsc & 0x30) == 0x20)	/* 2xPCI */		mode = 4;	else if ((scsc & 0x30) == 0x00)	/* 100 */		mode = 3;	else 	/* Disabled ? */		BUG();	if (!eighty_ninty_three(drive))		mode = min(mode, (u8)1);	return mode;}/** *	siimage_taskfile_timing	-	turn timing data to a mode *	@hwif: interface to query * *	Read the timing data for the interface and return the  *	mode that is being used. */ static byte siimage_taskfile_timing (ide_hwif_t *hwif){	u16 timing	= 0x328a;	unsigned long addr = siimage_selreg(hwif, 2);	if (hwif->mmio)		timing = hwif->INW(addr);	else		pci_read_config_word(hwif->pci_dev, addr, &timing);	switch (timing) {		case 0x10c1:	return 4;		case 0x10c3:	return 3;		case 0x1104:		case 0x1281:	return 2;		case 0x2283:	return 1;		case 0x328a:		default:	return 0;	}}/** *	simmage_tuneproc	-	tune a drive *	@drive: drive to tune *	@mode_wanted: the target operating mode * *	Load the timing settings for this device mode into the *	controller. If we are in PIO mode 3 or 4 turn on IORDY *	monitoring (bit 9). The TF timing is bits 31:16 */ static void siimage_tuneproc (ide_drive_t *drive, byte mode_wanted){	ide_hwif_t *hwif	= HWIF(drive);	u32 speedt		= 0;	u16 speedp		= 0;	unsigned long addr	= siimage_seldev(drive, 0x04);	unsigned long tfaddr	= siimage_selreg(hwif, 0x02);		/* cheat for now and use the docs */	switch(mode_wanted) {		case 4:				speedp = 0x10c1; 			speedt = 0x10c1;			break;		case 3:				speedp = 0x10C3; 			speedt = 0x10C3;			break;		case 2:				speedp = 0x1104; 			speedt = 0x1281;			break;		case 1:					speedp = 0x2283; 			speedt = 0x1281;			break;		case 0:		default:			speedp = 0x328A; 			speedt = 0x328A;			break;	}	if (hwif->mmio)	{		hwif->OUTW(speedt, addr);		hwif->OUTW(speedp, tfaddr);		/* Now set up IORDY */		if(mode_wanted == 3 || mode_wanted == 4)			hwif->OUTW(hwif->INW(tfaddr-2)|0x200, tfaddr-2);		else			hwif->OUTW(hwif->INW(tfaddr-2)&~0x200, tfaddr-2);	}	else	{		pci_write_config_word(hwif->pci_dev, addr, speedp);		pci_write_config_word(hwif->pci_dev, tfaddr, speedt);		pci_read_config_word(hwif->pci_dev, tfaddr-2, &speedp);		speedp &= ~0x200;		/* Set IORDY for mode 3 or 4 */		if(mode_wanted == 3 || mode_wanted == 4)			speedp |= 0x200;		pci_write_config_word(hwif->pci_dev, tfaddr-2, speedp);	}}/** *	config_siimage_chipset_for_pio	-	set drive timings *	@drive: drive to tune *	@speed we want * *	Compute the best pio mode we can for a given device. Also honour *	the timings for the driver when dealing with mixed devices. Some *	of this is ugly but its all wrapped up here * *	The SI680 can also do VDMA - we need to start using that * *	FIXME: we use the BIOS channel timings to avoid driving the task *	files too fast at the disk. We need to compute the master/slave *	drive PIO mode properly so that we can up the speed on a hotplug *	system. */ static void config_siimage_chipset_for_pio (ide_drive_t *drive, byte set_speed){	u8 channel_timings	= siimage_taskfile_timing(HWIF(drive));	u8 speed = 0, set_pio	= ide_get_best_pio_mode(drive, 4, 5, NULL);	/* WARNING PIO timing mess is going to happen b/w devices, argh */	if ((channel_timings != set_pio) && (set_pio > channel_timings))		set_pio = channel_timings;	siimage_tuneproc(drive, set_pio);	speed = XFER_PIO_0 + set_pio;	if (set_speed)		(void) ide_config_drive_speed(drive, speed);}static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed){	config_siimage_chipset_for_pio(drive, set_speed);}/** *	siimage_tune_chipset	-	set controller timings *	@drive: Drive to set up *	@xferspeed: speed we want to achieve * *	Tune the SII chipset for the desired mode. If we can't achieve *	the desired mode then tune for a lower one, but ultimately *	make the thing work. */ static int siimage_tune_chipset (ide_drive_t *drive, byte xferspeed){	u8 ultra6[]		= { 0x0F, 0x0B, 0x07, 0x05, 0x03, 0x02, 0x01 };	u8 ultra5[]		= { 0x0C, 0x07, 0x05, 0x04, 0x02, 0x01 };	u16 dma[]		= { 0x2208, 0x10C2, 0x10C1 };	ide_hwif_t *hwif	= HWIF(drive);	u16 ultra = 0, multi	= 0;	u8 mode = 0, unit	= drive->select.b.unit;	u8 speed		= ide_rate_filter(siimage_ratemask(drive), xferspeed);	unsigned long base	= (unsigned long)hwif->hwif_data;	u8 scsc = 0, addr_mask	= ((hwif->channel) ?				    ((hwif->mmio) ? 0xF4 : 0x84) :				    ((hwif->mmio) ? 0xB4 : 0x80));				    	unsigned long ma	= siimage_seldev(drive, 0x08);	unsigned long ua	= siimage_seldev(drive, 0x0C);	if (hwif->mmio) {		scsc = hwif->INB(base + 0x4A);		mode = hwif->INB(base + addr_mask);		multi = hwif->INW(ma);		ultra = hwif->INW(ua);	} else {		pci_read_config_byte(hwif->pci_dev, 0x8A, &scsc);		pci_read_config_byte(hwif->pci_dev, addr_mask, &mode);		pci_read_config_word(hwif->pci_dev, ma, &multi);		pci_read_config_word(hwif->pci_dev, ua, &ultra);	}	mode &= ~((unit) ? 0x30 : 0x03);	ultra &= ~0x3F;	scsc = ((scsc & 0x30) == 0x00) ? 0 : 1;	scsc = is_sata(hwif) ? 1 : scsc;	switch(speed) {		case XFER_PIO_4:		case XFER_PIO_3:		case XFER_PIO_2:		case XFER_PIO_1:		case XFER_PIO_0:			siimage_tuneproc(drive, (speed - XFER_PIO_0));			mode |= ((unit) ? 0x10 : 0x01);			break;		case XFER_MW_DMA_2:		case XFER_MW_DMA_1:		case XFER_MW_DMA_0:			multi = dma[speed - XFER_MW_DMA_0];			mode |= ((unit) ? 0x20 : 0x02);			config_siimage_chipset_for_pio(drive, 0);			break;		case XFER_UDMA_6:		case XFER_UDMA_5:		case XFER_UDMA_4:		case XFER_UDMA_3:		case XFER_UDMA_2:		case XFER_UDMA_1:		case XFER_UDMA_0:			multi = dma[2];			ultra |= ((scsc) ? (ultra6[speed - XFER_UDMA_0]) :					   (ultra5[speed - XFER_UDMA_0]));			mode |= ((unit) ? 0x30 : 0x03);			config_siimage_chipset_for_pio(drive, 0);			break;		default:			return 1;	}	if (hwif->mmio) {		hwif->OUTB(mode, base + addr_mask);		hwif->OUTW(multi, ma);		hwif->OUTW(ultra, ua);	} else {		pci_write_config_byte(hwif->pci_dev, addr_mask, mode);		pci_write_config_word(hwif->pci_dev, ma, multi);		pci_write_config_word(hwif->pci_dev, ua, ultra);	}	return (ide_config_drive_speed(drive, speed));}/** *	config_chipset_for_dma	-	configure for DMA *	@drive: drive to configure * *	Called by the IDE layer when it wants the timings set up. *	For the CMD680 we also need to set up the PIO timings and *	enable DMA. */ static int config_chipset_for_dma (ide_drive_t *drive){	u8 speed	= ide_dma_speed(drive, siimage_ratemask(drive));	config_chipset_for_pio(drive, !speed);	if (!speed)		return 0;	if (ide_set_xfer_rate(drive, speed))		return 0;	if (!drive->init_speed)		drive->init_speed = speed;	return ide_dma_enable(drive);}/** *	siimage_configure_drive_for_dma	-	set up for DMA transfers *	@drive: drive we are going to set up * *	Set up the drive for DMA, tune the controller and drive as  *	required. If the drive isn't suitable for DMA or we hit *	other problems then we will drop down to PIO and set up *	PIO appropriately */ static int siimage_config_drive_for_dma (ide_drive_t *drive){	ide_hwif_t *hwif	= HWIF(drive);	struct hd_driveid *id	= drive->id;	if ((id->capability & 1) != 0 && drive->autodma) {		/* Consult the list of known "bad" drives */		if (__ide_dma_bad_drive(drive))			goto fast_ata_pio;		if ((id->field_valid & 4) && siimage_ratemask(drive)) {			if (id->dma_ultra & hwif->ultra_mask) {				/* Force if Capable UltraDMA */				int dma = config_chipset_for_dma(drive);				if ((id->field_valid & 2) && !dma)					goto try_dma_modes;			}		} else if (id->field_valid & 2) {try_dma_modes:			if ((id->dma_mword & hwif->mwdma_mask) ||			    (id->dma_1word & hwif->swdma_mask)) {				/* Force if Capable regular DMA modes */				if (!config_chipset_for_dma(drive))					goto no_dma_set;			}		} else if (__ide_dma_good_drive(drive) &&			   (id->eide_dma_time < 150)) {			/* Consult the list of known "good" drives */			if (!config_chipset_for_dma(drive))				goto no_dma_set;		} else {			goto fast_ata_pio;		}		return hwif->ide_dma_on(drive);	} else if ((id->capability & 8) || (id->field_valid & 2)) {fast_ata_pio:no_dma_set:		config_chipset_for_pio(drive, 1);		return hwif->ide_dma_off_quietly(drive);	}	/* IORDY not supported */	return 0;}/* returns 1 if dma irq issued, 0 otherwise */static int siimage_io_ide_dma_test_irq (ide_drive_t *drive){	ide_hwif_t *hwif	= HWIF(drive);	u8 dma_altstat		= 0;	unsigned long addr	= siimage_selreg(hwif, 1);	/* return 1 if INTR asserted */	if ((hwif->INB(hwif->dma_status) & 4) == 4)		return 1;	/* return 1 if Device INTR asserted */	pci_read_config_byte(hwif->pci_dev, addr, &dma_altstat);	if (dma_altstat & 8)		return 0;	//return 1;	return 0;}#if 0/** *	siimage_mmio_ide_dma_count	-	DMA bytes done *	@drive * *	If we are doing VDMA the CMD680 requires a little bit *	of more careful handling and we have to read the counts *	off ourselves. For non VDMA life is normal. */ static int siimage_mmio_ide_dma_count (ide_drive_t *drive){#ifdef SIIMAGE_VIRTUAL_DMAPIO	struct request *rq	= HWGROUP(drive)->rq;	ide_hwif_t *hwif	= HWIF(drive);	u32 count		= (rq->nr_sectors * SECTOR_SIZE);	u32 rcount		= 0;	unsigned long addr	= siimage_selreg(hwif, 0x1C);	hwif->OUTL(count, addr);	rcount = hwif->INL(addr);	printk("\n%s: count = %d, rcount = %d, nr_sectors = %lu\n",		drive->name, count, rcount, rq->nr_sectors);#endif /* SIIMAGE_VIRTUAL_DMAPIO */	return __ide_dma_count(drive);}#endif/** *	siimage_mmio_ide_dma_test_irq	-	check we caused an IRQ *	@drive: drive we are testing * *	Check if we caused an IDE DMA interrupt. We may also have caused *	SATA status interrupts, if so we clean them up and continue. */ static int siimage_mmio_ide_dma_test_irq (ide_drive_t *drive){	ide_hwif_t *hwif	= HWIF(drive);	unsigned long base	= (unsigned long)hwif->hwif_data;	unsigned long addr	= siimage_selreg(hwif, 0x1);	if (SATA_ERROR_REG) {		u32 ext_stat = hwif->INL(base + 0x10);		u8 watchdog = 0;		if (ext_stat & ((hwif->channel) ? 0x40 : 0x10)) {			u32 sata_error = hwif->INL(SATA_ERROR_REG);			hwif->OUTL(sata_error, SATA_ERROR_REG);			watchdog = (sata_error & 0x00680000) ? 1 : 0;#if 1			printk(KERN_WARNING "%s: sata_error = 0x%08x, "				"watchdog = %d, %s\n",				drive->name, sata_error, watchdog,				__FUNCTION__);#endif		} else {			watchdog = (ext_stat & 0x8000) ? 1 : 0;		}		ext_stat >>= 16;		if (!(ext_stat & 0x0404) && !watchdog)			return 0;	}	/* return 1 if INTR asserted */	if ((hwif->INB(hwif->dma_status) & 0x04) == 0x04)		return 1;	/* return 1 if Device INTR asserted */	if ((hwif->INB(addr) & 8) == 8)		return 0;	//return 1;	return 0;}static int siimage_mmio_ide_dma_verbose (ide_drive_t *drive){	int temp = __ide_dma_verbose(drive);	return temp;}/** *	siimage_busproc		-	bus isolation ioctl *	@drive: drive to isolate/restore *	@state: bus state to set * *	Used by the SII3112 to handle bus isolation. As this is a  *	SATA controller the work required is quite limited, we  *	just have to clean up the statistics */ static int siimage_busproc (ide_drive_t * drive, int state){	ide_hwif_t *hwif	= HWIF(drive);	u32 stat_config		= 0;	unsigned long addr	= siimage_selreg(hwif, 0);

⌨️ 快捷键说明

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