siimage.c

来自「linux-2.4.29操作系统的源码」· C语言 代码 · 共 1,228 行 · 第 1/3 页

C
1,228
字号
/* * linux/drivers/ide/pci/siimage.c		Version 1.06	June 11, 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>#include "ide_modes.h"#include "siimage.h"#if defined(DISPLAY_SIIMAGE_TIMINGS) && defined(CONFIG_PROC_FS)#include <linux/stat.h>#include <linux/proc_fs.h>static u8 siimage_proc = 0;#define SIIMAGE_MAX_DEVS		16static struct pci_dev *siimage_devs[SIIMAGE_MAX_DEVS];static int n_siimage_devs;/** *	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;}	/** *	print_siimage_get_info	-	print minimal proc information *	@buf: buffer to write into (kernel space) *	@dev: PCI device we are describing *	@index: Controller number * *	Print the basic information for the state of the CMD680/SI3112 *	channel. We don't actually dump a lot of information out for *	this controller although we could expand it if we needed. */ static char *print_siimage_get_info (char *buf, struct pci_dev *dev, int index){	char *p		= buf;	u8 mmio		= (pci_get_drvdata(dev) != NULL) ? 1 : 0;	unsigned long bmdma = pci_resource_start(dev, 4);		if(mmio)		bmdma = pci_resource_start(dev, 5);	p += sprintf(p, "\nController: %d\n", index);	p += sprintf(p, "SiI%x Chipset.\n", dev->device);	if (mmio)		p += sprintf(p, "MMIO Base 0x%lx\n", bmdma);	p += sprintf(p, "%s-DMA Base 0x%lx\n", (mmio)?"MMIO":"BM", bmdma);	p += sprintf(p, "%s-DMA Base 0x%lx\n", (mmio)?"MMIO":"BM", bmdma+8);	return (char *)p;}/** *	siimage_get_info	-	proc callback *	@buffer: kernel buffer to complete *	@addr: written with base of data to return *	offset: seek offset *	count: bytes to fill in  * *	Called when the user reads data from the virtual file for this *	controller from /proc */ static int siimage_get_info (char *buffer, char **addr, off_t offset, int count){	char *p = buffer;	int len;	u16 i;	p += sprintf(p, "\n");	for (i = 0; i < n_siimage_devs; i++) {		struct pci_dev *dev	= siimage_devs[i];		p = print_siimage_get_info(p, dev, i);	}	/* p - buffer must be less than 4k! */	len = (p - buffer) - offset;	*addr = buffer + offset;		return len > count ? count : len;}#endif	/* defined(DISPLAY_SIIMAGE_TIMINGS) && defined(CONFIG_PROC_FS) *//** *	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));

⌨️ 快捷键说明

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