hpt366.c

来自「linux 内核源代码」· C语言 代码 · 共 1,677 行 · 第 1/4 页

C
1,677
字号
{#ifdef HPT_RESET_STATE_ENGINE	hpt370_clear_engine(drive);#endif	ide_dma_start(drive);}static int hpt370_ide_dma_end(ide_drive_t *drive){	ide_hwif_t *hwif	= HWIF(drive);	u8  dma_stat		= inb(hwif->dma_status);	if (dma_stat & 0x01) {		/* wait a little */		udelay(20);		dma_stat = inb(hwif->dma_status);		if (dma_stat & 0x01)			hpt370_irq_timeout(drive);	}	return __ide_dma_end(drive);}static void hpt370_dma_timeout(ide_drive_t *drive){	hpt370_irq_timeout(drive);	ide_dma_timeout(drive);}/* returns 1 if DMA IRQ issued, 0 otherwise */static int hpt374_ide_dma_test_irq(ide_drive_t *drive){	ide_hwif_t *hwif	= HWIF(drive);	u16 bfifo		= 0;	u8  dma_stat;	pci_read_config_word(hwif->pci_dev, hwif->select_data + 2, &bfifo);	if (bfifo & 0x1FF) {//		printk("%s: %d bytes in FIFO\n", drive->name, bfifo);		return 0;	}	dma_stat = inb(hwif->dma_status);	/* return 1 if INTR asserted */	if (dma_stat & 4)		return 1;	if (!drive->waiting_for_dma)		printk(KERN_WARNING "%s: (%s) called while not waiting\n",				drive->name, __FUNCTION__);	return 0;}static int hpt374_ide_dma_end(ide_drive_t *drive){	ide_hwif_t *hwif	= HWIF(drive);	struct pci_dev	*dev	= hwif->pci_dev;	u8 mcr	= 0, mcr_addr	= hwif->select_data;	u8 bwsr = 0, mask	= hwif->channel ? 0x02 : 0x01;	pci_read_config_byte(dev, 0x6a, &bwsr);	pci_read_config_byte(dev, mcr_addr, &mcr);	if (bwsr & mask)		pci_write_config_byte(dev, mcr_addr, mcr | 0x30);	return __ide_dma_end(drive);}/** *	hpt3xxn_set_clock	-	perform clock switching dance *	@hwif: hwif to switch *	@mode: clocking mode (0x21 for write, 0x23 otherwise) * *	Switch the DPLL clock on the HPT3xxN devices. This is a	right mess. */static void hpt3xxn_set_clock(ide_hwif_t *hwif, u8 mode){	u8 scr2 = inb(hwif->dma_master + 0x7b);	if ((scr2 & 0x7f) == mode)		return;	/* Tristate the bus */	outb(0x80, hwif->dma_master + 0x73);	outb(0x80, hwif->dma_master + 0x77);	/* Switch clock and reset channels */	outb(mode, hwif->dma_master + 0x7b);	outb(0xc0, hwif->dma_master + 0x79);	/*	 * Reset the state machines.	 * NOTE: avoid accidentally enabling the disabled channels.	 */	outb(inb(hwif->dma_master + 0x70) | 0x32, hwif->dma_master + 0x70);	outb(inb(hwif->dma_master + 0x74) | 0x32, hwif->dma_master + 0x74);	/* Complete reset */	outb(0x00, hwif->dma_master + 0x79);	/* Reconnect channels to bus */	outb(0x00, hwif->dma_master + 0x73);	outb(0x00, hwif->dma_master + 0x77);}/** *	hpt3xxn_rw_disk		-	prepare for I/O *	@drive: drive for command *	@rq: block request structure * *	This is called when a disk I/O is issued to HPT3xxN. *	We need it because of the clock switching. */static void hpt3xxn_rw_disk(ide_drive_t *drive, struct request *rq){	hpt3xxn_set_clock(HWIF(drive), rq_data_dir(rq) ? 0x23 : 0x21);}/*  * Set/get power state for a drive. * NOTE: affects both drives on each channel. * * When we turn the power back on, we need to re-initialize things. */#define TRISTATE_BIT  0x8000static int hpt3xx_busproc(ide_drive_t *drive, int state){	ide_hwif_t *hwif	= HWIF(drive);	struct pci_dev *dev	= hwif->pci_dev;	u8  mcr_addr		= hwif->select_data + 2;	u8  resetmask		= hwif->channel ? 0x80 : 0x40;	u8  bsr2		= 0;	u16 mcr			= 0;	hwif->bus_state = state;	/* Grab the status. */	pci_read_config_word(dev, mcr_addr, &mcr);	pci_read_config_byte(dev, 0x59, &bsr2);	/*	 * Set the state. We don't set it if we don't need to do so.	 * Make sure that the drive knows that it has failed if it's off.	 */	switch (state) {	case BUSSTATE_ON:		if (!(bsr2 & resetmask))			return 0;		hwif->drives[0].failures = hwif->drives[1].failures = 0;		pci_write_config_byte(dev, 0x59, bsr2 & ~resetmask);		pci_write_config_word(dev, mcr_addr, mcr & ~TRISTATE_BIT);		return 0;	case BUSSTATE_OFF:		if ((bsr2 & resetmask) && !(mcr & TRISTATE_BIT))			return 0;		mcr &= ~TRISTATE_BIT;		break;	case BUSSTATE_TRISTATE:		if ((bsr2 & resetmask) &&  (mcr & TRISTATE_BIT))			return 0;		mcr |= TRISTATE_BIT;		break;	default:		return -EINVAL;	}	hwif->drives[0].failures = hwif->drives[0].max_failures + 1;	hwif->drives[1].failures = hwif->drives[1].max_failures + 1;	pci_write_config_word(dev, mcr_addr, mcr);	pci_write_config_byte(dev, 0x59, bsr2 | resetmask);	return 0;}/** *	hpt37x_calibrate_dpll	-	calibrate the DPLL *	@dev: PCI device * *	Perform a calibration cycle on the DPLL. *	Returns 1 if this succeeds */static int __devinit hpt37x_calibrate_dpll(struct pci_dev *dev, u16 f_low, u16 f_high){	u32 dpll = (f_high << 16) | f_low | 0x100;	u8  scr2;	int i;	pci_write_config_dword(dev, 0x5c, dpll);	/* Wait for oscillator ready */	for(i = 0; i < 0x5000; ++i) {		udelay(50);		pci_read_config_byte(dev, 0x5b, &scr2);		if (scr2 & 0x80)			break;	}	/* See if it stays ready (we'll just bail out if it's not yet) */	for(i = 0; i < 0x1000; ++i) {		pci_read_config_byte(dev, 0x5b, &scr2);		/* DPLL destabilized? */		if(!(scr2 & 0x80))			return 0;	}	/* Turn off tuning, we have the DPLL set */	pci_read_config_dword (dev, 0x5c, &dpll);	pci_write_config_dword(dev, 0x5c, (dpll & ~0x100));	return 1;}static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const char *name){	struct hpt_info *info	= kmalloc(sizeof(struct hpt_info), GFP_KERNEL);	unsigned long io_base	= pci_resource_start(dev, 4);	u8 pci_clk,  dpll_clk	= 0;	/* PCI and DPLL clock in MHz */	u8 chip_type;	enum ata_clock	clock;	if (info == NULL) {		printk(KERN_ERR "%s: out of memory!\n", name);		return -ENOMEM;	}	/*	 * Copy everything from a static "template" structure	 * to just allocated per-chip hpt_info structure.	 */	memcpy(info, pci_get_drvdata(dev), sizeof(struct hpt_info));	chip_type = info->chip_type;	pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));	pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);	pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);	pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);	/*	 * First, try to estimate the PCI clock frequency...	 */	if (chip_type >= HPT370) {		u8  scr1  = 0;		u16 f_cnt = 0;		u32 temp  = 0;		/* Interrupt force enable. */		pci_read_config_byte(dev, 0x5a, &scr1);		if (scr1 & 0x10)			pci_write_config_byte(dev, 0x5a, scr1 & ~0x10);		/*		 * HighPoint does this for HPT372A.		 * NOTE: This register is only writeable via I/O space.		 */		if (chip_type == HPT372A)			outb(0x0e, io_base + 0x9c);		/*		 * Default to PCI clock. Make sure MA15/16 are set to output		 * to prevent drives having problems with 40-pin cables.		 */		pci_write_config_byte(dev, 0x5b, 0x23);		/*		 * We'll have to read f_CNT value in order to determine		 * the PCI clock frequency according to the following ratio:		 *		 * f_CNT = Fpci * 192 / Fdpll		 *		 * First try reading the register in which the HighPoint BIOS		 * saves f_CNT value before  reprogramming the DPLL from its		 * default setting (which differs for the various chips).		 *		 * NOTE: This register is only accessible via I/O space;		 * HPT374 BIOS only saves it for the function 0, so we have to		 * always read it from there -- no need to check the result of		 * pci_get_slot() for the function 0 as the whole device has		 * been already "pinned" (via function 1) in init_setup_hpt374()		 */		if (chip_type == HPT374 && (PCI_FUNC(dev->devfn) & 1)) {			struct pci_dev	*dev1 = pci_get_slot(dev->bus,							     dev->devfn - 1);			unsigned long io_base = pci_resource_start(dev1, 4);			temp =	inl(io_base + 0x90);			pci_dev_put(dev1);		} else			temp =	inl(io_base + 0x90);		/*		 * In case the signature check fails, we'll have to		 * resort to reading the f_CNT register itself in hopes		 * that nobody has touched the DPLL yet...		 */		if ((temp & 0xFFFFF000) != 0xABCDE000) {			int i;			printk(KERN_WARNING "%s: no clock data saved by BIOS\n",			       name);			/* Calculate the average value of f_CNT. */			for (temp = i = 0; i < 128; i++) {				pci_read_config_word(dev, 0x78, &f_cnt);				temp += f_cnt & 0x1ff;				mdelay(1);			}			f_cnt = temp / 128;		} else			f_cnt = temp & 0x1ff;		dpll_clk = info->dpll_clk;		pci_clk  = (f_cnt * dpll_clk) / 192;		/* Clamp PCI clock to bands. */		if (pci_clk < 40)			pci_clk = 33;		else if(pci_clk < 45)			pci_clk = 40;		else if(pci_clk < 55)			pci_clk = 50;		else			pci_clk = 66;		printk(KERN_INFO "%s: DPLL base: %d MHz, f_CNT: %d, "		       "assuming %d MHz PCI\n", name, dpll_clk, f_cnt, pci_clk);	} else {		u32 itr1 = 0;		pci_read_config_dword(dev, 0x40, &itr1);		/* Detect PCI clock by looking at cmd_high_time. */		switch((itr1 >> 8) & 0x07) {			case 0x09:				pci_clk = 40;				break;			case 0x05:				pci_clk = 25;				break;			case 0x07:			default:				pci_clk = 33;				break;		}	}	/* Let's assume we'll use PCI clock for the ATA clock... */	switch (pci_clk) {		case 25:			clock = ATA_CLOCK_25MHZ;			break;		case 33:		default:			clock = ATA_CLOCK_33MHZ;			break;		case 40:			clock = ATA_CLOCK_40MHZ;			break;		case 50:			clock = ATA_CLOCK_50MHZ;			break;		case 66:			clock = ATA_CLOCK_66MHZ;			break;	}	/*	 * Only try the DPLL if we don't have a table for the PCI clock that	 * we are running at for HPT370/A, always use it  for anything newer...	 *	 * NOTE: Using the internal DPLL results in slow reads on 33 MHz PCI.	 * We also  don't like using  the DPLL because this causes glitches	 * on PRST-/SRST- when the state engine gets reset...	 */	if (chip_type >= HPT374 || info->settings[clock] == NULL) {		u16 f_low, delta = pci_clk < 50 ? 2 : 4;		int adjust;		 /*		  * Select 66 MHz DPLL clock only if UltraATA/133 mode is		  * supported/enabled, use 50 MHz DPLL clock otherwise...		  */		if (info->udma_mask == ATA_UDMA6) {			dpll_clk = 66;			clock = ATA_CLOCK_66MHZ;		} else if (dpll_clk) {	/* HPT36x chips don't have DPLL */			dpll_clk = 50;			clock = ATA_CLOCK_50MHZ;		}		if (info->settings[clock] == NULL) {			printk(KERN_ERR "%s: unknown bus timing!\n", name);			kfree(info);			return -EIO;		}		/* Select the DPLL clock. */		pci_write_config_byte(dev, 0x5b, 0x21);		/*		 * Adjust the DPLL based upon PCI clock, enable it,		 * and wait for stabilization...		 */		f_low = (pci_clk * 48) / dpll_clk;		for (adjust = 0; adjust < 8; adjust++) {			if(hpt37x_calibrate_dpll(dev, f_low, f_low + delta))				break;			/*			 * See if it'll settle at a fractionally different clock			 */			if (adjust & 1)				f_low -= adjust >> 1;			else				f_low += adjust >> 1;		}		if (adjust == 8) {			printk(KERN_ERR "%s: DPLL did not stabilize!\n", name);			kfree(info);			return -EIO;		}

⌨️ 快捷键说明

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