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

📄 serverworks.c

📁 一个2.4.21版本的嵌入式linux内核
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * linux/drivers/ide/pci/serverworks.c		Version 0.8	 25 Ebr 2003 * * Copyright (C) 1998-2000 Michel Aubry * Copyright (C) 1998-2000 Andrzej Krzysztofowicz * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org> * Portions copyright (c) 2001 Sun Microsystems * * * RCC/ServerWorks IDE driver for Linux * *   OSB4: `Open South Bridge' IDE Interface (fn 1) *         supports UDMA mode 2 (33 MB/s) * *   CSB5: `Champion South Bridge' IDE Interface (fn 1) *         all revisions support UDMA mode 4 (66 MB/s) *         revision A2.0 and up support UDMA mode 5 (100 MB/s) * *         *** The CSB5 does not provide ANY register *** *         *** to detect 80-conductor cable presence. *** * *   CSB6: `Champion South Bridge' IDE Interface (optional: third channel) * * Documentation: *	Available under NDA only. Errata info very hard to get. * */#include <linux/config.h>#include <linux/types.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/ioport.h>#include <linux/pci.h>#include <linux/hdreg.h>#include <linux/ide.h>#include <linux/init.h>#include <linux/delay.h>#include <asm/io.h>#include "ide_modes.h"#include "serverworks.h"static u8 svwks_revision = 0;static struct pci_dev *isa_dev;#if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS)#include <linux/stat.h>#include <linux/proc_fs.h>static u8 svwks_proc = 0;#define SVWKS_MAX_DEVS		2static struct pci_dev *svwks_devs[SVWKS_MAX_DEVS];static int n_svwks_devs;static int svwks_get_info (char *buffer, char **addr, off_t offset, int count){	char *p = buffer;	int i, len;	p += sprintf(p, "\n                             "			"ServerWorks OSB4/CSB5/CSB6\n");	for (i = 0; i < n_svwks_devs; i++) {		struct pci_dev *dev = svwks_devs[i];		unsigned long bibma = pci_resource_start(dev, 4);		u32 reg40, reg44;		u16 reg48, reg56;		u8  reg54, c0=0, c1=0;		pci_read_config_dword(dev, 0x40, &reg40);		pci_read_config_dword(dev, 0x44, &reg44);		pci_read_config_word(dev, 0x48, &reg48);		pci_read_config_byte(dev, 0x54, &reg54);		pci_read_config_word(dev, 0x56, &reg56);		/*		 * at that point bibma+0x2 et bibma+0xa are byte registers		 * to investigate:		 */		c0 = inb_p(bibma + 0x02);		c1 = inb_p(bibma + 0x0a);		p += sprintf(p, "\n                            ServerWorks ");		switch(dev->device) {			case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2:			case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE:				p += sprintf(p, "CSB6 ");				break;			case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:				p += sprintf(p, "CSB5 ");				break;			case PCI_DEVICE_ID_SERVERWORKS_OSB4IDE:				p += sprintf(p, "OSB4 ");				break;			default:				p += sprintf(p, "%04x ", dev->device);				break;		}		p += sprintf(p, "Chipset (rev %02x)\n", svwks_revision);		p += sprintf(p, "------------------------------- "				"General Status "				"---------------------------------\n");		p += sprintf(p, "--------------- Primary Channel "				"---------------- Secondary Channel "				"-------------\n");		p += sprintf(p, "                %sabled"				"                         %sabled\n",				(c0&0x80) ? "dis" : " en",				(c1&0x80) ? "dis" : " en");		p += sprintf(p, "--------------- drive0 --------- drive1 "				"-------- drive0 ---------- drive1 ------\n");		p += sprintf(p, "DMA enabled:    %s              %s"				"             %s               %s\n",			(c0&0x20) ? "yes" : "no ",			(c0&0x40) ? "yes" : "no ",			(c1&0x20) ? "yes" : "no ",			(c1&0x40) ? "yes" : "no " );		p += sprintf(p, "UDMA enabled:   %s              %s"				"             %s               %s\n",			(reg54 & 0x01) ? "yes" : "no ",			(reg54 & 0x02) ? "yes" : "no ",			(reg54 & 0x04) ? "yes" : "no ",			(reg54 & 0x08) ? "yes" : "no " );		p += sprintf(p, "UDMA enabled:   %s                %s"				"               %s                 %s\n",			((reg56&0x0005)==0x0005)?"5":				((reg56&0x0004)==0x0004)?"4":				((reg56&0x0003)==0x0003)?"3":				((reg56&0x0002)==0x0002)?"2":				((reg56&0x0001)==0x0001)?"1":				((reg56&0x000F))?"?":"0",			((reg56&0x0050)==0x0050)?"5":				((reg56&0x0040)==0x0040)?"4":				((reg56&0x0030)==0x0030)?"3":				((reg56&0x0020)==0x0020)?"2":				((reg56&0x0010)==0x0010)?"1":				((reg56&0x00F0))?"?":"0",			((reg56&0x0500)==0x0500)?"5":				((reg56&0x0400)==0x0400)?"4":				((reg56&0x0300)==0x0300)?"3":				((reg56&0x0200)==0x0200)?"2":				((reg56&0x0100)==0x0100)?"1":				((reg56&0x0F00))?"?":"0",			((reg56&0x5000)==0x5000)?"5":				((reg56&0x4000)==0x4000)?"4":				((reg56&0x3000)==0x3000)?"3":				((reg56&0x2000)==0x2000)?"2":				((reg56&0x1000)==0x1000)?"1":				((reg56&0xF000))?"?":"0");		p += sprintf(p, "DMA enabled:    %s                %s"				"               %s                 %s\n",			((reg44&0x00002000)==0x00002000)?"2":				((reg44&0x00002100)==0x00002100)?"1":				((reg44&0x00007700)==0x00007700)?"0":				((reg44&0x0000FF00)==0x0000FF00)?"X":"?",			((reg44&0x00000020)==0x00000020)?"2":				((reg44&0x00000021)==0x00000021)?"1":				((reg44&0x00000077)==0x00000077)?"0":				((reg44&0x000000FF)==0x000000FF)?"X":"?",			((reg44&0x20000000)==0x20000000)?"2":				((reg44&0x21000000)==0x21000000)?"1":				((reg44&0x77000000)==0x77000000)?"0":				((reg44&0xFF000000)==0xFF000000)?"X":"?",			((reg44&0x00200000)==0x00200000)?"2":				((reg44&0x00210000)==0x00210000)?"1":				((reg44&0x00770000)==0x00770000)?"0":				((reg44&0x00FF0000)==0x00FF0000)?"X":"?");		p += sprintf(p, "PIO  enabled:   %s                %s"				"               %s                 %s\n",			((reg40&0x00002000)==0x00002000)?"4":				((reg40&0x00002200)==0x00002200)?"3":				((reg40&0x00003400)==0x00003400)?"2":				((reg40&0x00004700)==0x00004700)?"1":				((reg40&0x00005D00)==0x00005D00)?"0":"?",			((reg40&0x00000020)==0x00000020)?"4":				((reg40&0x00000022)==0x00000022)?"3":				((reg40&0x00000034)==0x00000034)?"2":				((reg40&0x00000047)==0x00000047)?"1":				((reg40&0x0000005D)==0x0000005D)?"0":"?",			((reg40&0x20000000)==0x20000000)?"4":				((reg40&0x22000000)==0x22000000)?"3":				((reg40&0x34000000)==0x34000000)?"2":				((reg40&0x47000000)==0x47000000)?"1":				((reg40&0x5D000000)==0x5D000000)?"0":"?",			((reg40&0x00200000)==0x00200000)?"4":				((reg40&0x00220000)==0x00220000)?"3":				((reg40&0x00340000)==0x00340000)?"2":				((reg40&0x00470000)==0x00470000)?"1":				((reg40&0x005D0000)==0x005D0000)?"0":"?");	}	p += sprintf(p, "\n");	/* p - buffer must be less than 4k! */	len = (p - buffer) - offset;	*addr = buffer + offset;		return len > count ? count : len;}#endif  /* defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS) */static int check_in_drive_lists (ide_drive_t *drive, const char **list){	while (*list)		if (!strcmp(*list++, drive->id->model))			return 1;	return 0;}static u8 svwks_ratemask (ide_drive_t *drive){	struct pci_dev *dev     = HWIF(drive)->pci_dev;	u8 mode;	if (!svwks_revision)		pci_read_config_byte(dev, PCI_REVISION_ID, &svwks_revision);	if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {		u32 reg = 0;		if (isa_dev)			pci_read_config_dword(isa_dev, 0x64, &reg);					/*		 *	Don't enable UDMA on disk devices for the moment		 */		if(drive->media == ide_disk)			return 0;		/* Check the OSB4 DMA33 enable bit */		return ((reg & 0x00004000) == 0x00004000) ? 1 : 0;	} else if (svwks_revision < SVWKS_CSB5_REVISION_NEW) {		return 1;	} else if (svwks_revision >= SVWKS_CSB5_REVISION_NEW) {		u8 btr = 0;		pci_read_config_byte(dev, 0x5A, &btr);		mode = btr & 0x3;		if (!eighty_ninty_three(drive))			mode = min(mode, (u8)1);		/* If someone decides to do UDMA133 on CSB5 the same 		   issue will bite so be inclusive */		if (mode > 2 && check_in_drive_lists(drive, svwks_bad_ata100))			mode = 2;	}	if (((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||	     (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) &&	    (!(PCI_FUNC(dev->devfn) & 1)))		mode = 2;	return mode;}static u8 svwks_csb_check (struct pci_dev *dev){	switch (dev->device) {		case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:		case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE:		case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2:			return 1;		default:			break;	}	return 0;}static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed){	u8 udma_modes[]		= { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };	u8 dma_modes[]		= { 0x77, 0x21, 0x20 };	u8 pio_modes[]		= { 0x5d, 0x47, 0x34, 0x22, 0x20 };	u8 drive_pci[]		= { 0x41, 0x40, 0x43, 0x42 };	u8 drive_pci2[]		= { 0x45, 0x44, 0x47, 0x46 };	ide_hwif_t *hwif	= HWIF(drive);	struct pci_dev *dev	= hwif->pci_dev;	u8 speed		= ide_rate_filter(svwks_ratemask(drive), xferspeed);	u8 pio			= ide_get_best_pio_mode(drive, 255, 5, NULL);	u8 unit			= (drive->select.b.unit & 0x01);	u8 csb5			= svwks_csb_check(dev);	u8 ultra_enable		= 0, ultra_timing = 0;	u8 dma_timing		= 0, pio_timing = 0;	u16 csb5_pio		= 0;	/* If we are about to put a disk into UDMA mode we screwed up.	   Our code assumes we never _ever_ do this on an OSB4 */	   	if(dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4 &&		drive->media == ide_disk && speed >= XFER_UDMA_0)			BUG();				pci_read_config_byte(dev, drive_pci[drive->dn], &pio_timing);	pci_read_config_byte(dev, drive_pci2[drive->dn], &dma_timing);	pci_read_config_byte(dev, (0x56|hwif->channel), &ultra_timing);	pci_read_config_word(dev, 0x4A, &csb5_pio);	pci_read_config_byte(dev, 0x54, &ultra_enable);	/* Per Specified Design by OEM, and ASIC Architect */	if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||	    (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) {		if (!drive->init_speed) {			u8 dma_stat = hwif->INB(hwif->dma_status);dma_pio:			if (((ultra_enable << (7-drive->dn) & 0x80) == 0x80) &&			    ((dma_stat & (1<<(5+unit))) == (1<<(5+unit)))) {				drive->current_speed = drive->init_speed = XFER_UDMA_0 + udma_modes[(ultra_timing >> (4*unit)) & ~(0xF0)];				return 0;			} else if ((dma_timing) &&				   ((dma_stat&(1<<(5+unit)))==(1<<(5+unit)))) {				u8 dmaspeed = dma_timing;				dma_timing &= ~0xFF;				if ((dmaspeed & 0x20) == 0x20)					dmaspeed = XFER_MW_DMA_2;				else if ((dmaspeed & 0x21) == 0x21)					dmaspeed = XFER_MW_DMA_1;				else if ((dmaspeed & 0x77) == 0x77)					dmaspeed = XFER_MW_DMA_0;				else					goto dma_pio;				drive->current_speed = drive->init_speed = dmaspeed;				return 0;			} else if (pio_timing) {				u8 piospeed = pio_timing;				pio_timing &= ~0xFF;				if ((piospeed & 0x20) == 0x20)					piospeed = XFER_PIO_4;				else if ((piospeed & 0x22) == 0x22)					piospeed = XFER_PIO_3;				else if ((piospeed & 0x34) == 0x34)					piospeed = XFER_PIO_2;				else if ((piospeed & 0x47) == 0x47)					piospeed = XFER_PIO_1;				else if ((piospeed & 0x5d) == 0x5d)					piospeed = XFER_PIO_0;				else					goto oem_setup_failed;				drive->current_speed = drive->init_speed = piospeed;				return 0;			}		}	}oem_setup_failed:	pio_timing	&= ~0xFF;	dma_timing	&= ~0xFF;	ultra_timing	&= ~(0x0F << (4*unit));	ultra_enable	&= ~(0x01 << drive->dn);	csb5_pio	&= ~(0x0F << (4*drive->dn));	switch(speed) {		case XFER_PIO_4:		case XFER_PIO_3:		case XFER_PIO_2:		case XFER_PIO_1:		case XFER_PIO_0:			pio_timing |= pio_modes[speed - XFER_PIO_0];			csb5_pio   |= ((speed - XFER_PIO_0) << (4*drive->dn));			break;		case XFER_MW_DMA_2:		case XFER_MW_DMA_1:		case XFER_MW_DMA_0:			pio_timing |= pio_modes[pio];			csb5_pio   |= (pio << (4*drive->dn));			dma_timing |= dma_modes[speed - XFER_MW_DMA_0];			break;		case XFER_UDMA_5:		case XFER_UDMA_4:		case XFER_UDMA_3:		case XFER_UDMA_2:		case XFER_UDMA_1:		case XFER_UDMA_0:			pio_timing   |= pio_modes[pio];			csb5_pio     |= (pio << (4*drive->dn));			dma_timing   |= dma_modes[2];			ultra_timing |= ((udma_modes[speed - XFER_UDMA_0]) << (4*unit));			ultra_enable |= (0x01 << drive->dn);		default:			break;	}	pci_write_config_byte(dev, drive_pci[drive->dn], pio_timing);	if (csb5)		pci_write_config_word(dev, 0x4A, csb5_pio);	pci_write_config_byte(dev, drive_pci2[drive->dn], dma_timing);	pci_write_config_byte(dev, (0x56|hwif->channel), ultra_timing);	pci_write_config_byte(dev, 0x54, ultra_enable);	return (ide_config_drive_speed(drive, speed));}static void config_chipset_for_pio (ide_drive_t *drive){	u16 eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};	u16 xfer_pio = drive->id->eide_pio_modes;	u8 timing, speed, pio;	pio = ide_get_best_pio_mode(drive, 255, 5, NULL);	if (xfer_pio > 4)		xfer_pio = 0;	if (drive->id->eide_pio_iordy > 0)		for (xfer_pio = 5;			xfer_pio>0 &&			drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];			xfer_pio--);	else		xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :			   (drive->id->eide_pio_modes & 2) ? 0x04 :			   (drive->id->eide_pio_modes & 1) ? 0x03 :			   (drive->id->tPIO & 2) ? 0x02 :			   (drive->id->tPIO & 1) ? 0x01 : xfer_pio;

⌨️ 快捷键说明

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