ide_pci.c

来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 1,713 行 · 第 1/3 页

C
1,713
字号
 * XXX timing values set here are only good for 30/33MHz buses; should deal * with slower ones too (BTW: you overclock-- you lose) */static intcyrix_5530_dmainit(struct ide_pci_cookie *cookie, 		struct wdparams *wp, 		int(*wdcmd)(int, void *),		void *wdinfo){	int r;	u_long	pci_revision;	int	unitno;	int	iobase_bm;	int	unit;	/*cookie->unit = 0; */	/* XXX */	unit = cookie->unit;	pci_revision = pci_conf_read(cookie->tag, PCI_CLASS_REG) & 		PCI_REVISION_MASK;	unitno = cookie->ctlr * 2 + unit;	iobase_bm = cookie->iobase_bm;	printf("Setting using 0x%x\n", iobase_bm);	if ((cookie->ctlr == 0) && (unit == 0))	/* XXX */		outb(iobase_bm + (unit * 0x10) + BMISTA_PORT, 0xe6);	outl(iobase_bm + (unit * 0x10) + 0x20, 0x00040010);	outl(iobase_bm + (unit * 0x10) + 0x24, 0x00911030);	/* If it's a UDMA drive on a '5530, set it up */	/* 	 * depending on what the drive can do,	 * set the correct modes,	 */	printf("wd%d: mw=0x%x, pio=0x%x, pcirev=0x%lx, udma=0x%x\n",		unitno,		mwdma_mode(wp), pio_mode(wp),		pci_revision, udma_mode(wp));	if (/* pci_revision >= 1 && */ udma_mode(wp) >= 2) {		/*outl(iobase_bm + 0x20 + (cookie->unit * 16), 0x00100010);*/		outl(iobase_bm + 0x24 + (cookie->unit * 16), 0x00911030);		/*		 * With the Cx5530, drive configuration should come *after* the		 * controller configuration, to make sure the controller sees 		 * the command and does the right thing.		 */		/* Set UDMA mode 2 on drive */		if (bootverbose)			printf("cyrix_5530_dmainit: setting ultra DMA mode 2\n");		r = wdcmd(WDDMA_UDMA2, wdinfo);		if (!r) {			printf("cyrix_5530_dmainit: setting DMA mode failed\n");			return 0;		}		if (bootverbose)			cyrix_5530_status(cookie);		return 1;	}	/* otherwise, try and program it for MW DMA mode 2 */	else if (mwdma_mode(wp) >= 2 && pio_mode(wp) >= 4) {		/* Set multiword DMA mode 2 on drive */		if (bootverbose)			printf("cyrix_5530_dmainit: setting multiword DMA mode 2\n");		r = wdcmd(WDDMA_MDMA2, wdinfo);		if (!r) {			printf("cyrix_5530_dmainit: setting DMA mode failed\n");			return 0;		}		/* Configure the controller appropriately for MWDMA mode 2 */		/*outl(iobase_bm + 0x20 + (cookie->unit * 16), 0x00100010);*/		outl(iobase_bm + 0x24 + (cookie->unit * 16), 0x00002020);		if (bootverbose)			cyrix_5530_status(cookie);		return 1;	}	return 0;}static struct vendor_fns vs_cyrix_5530 = { 	cyrix_5530_dmainit, 	cyrix_5530_status};static voidpromise_status(struct ide_pci_cookie *cookie){    pcici_t tag;    int i;    u_int32_t port0_command, port0_altstatus;    u_int32_t port1_command, port1_altstatus;    u_int32_t dma_block;    u_int32_t lat_and_interrupt;    u_int32_t drivetiming;    int pa, pb, mb, mc;    tag = cookie->tag;    port0_command = pci_conf_read(tag, 0x10);    port0_altstatus = pci_conf_read(tag, 0x14);    port1_command = pci_conf_read(tag, 0x18);    port1_altstatus = pci_conf_read(tag, 0x1c);    dma_block = pci_conf_read(tag, 0x20);    lat_and_interrupt = pci_conf_read(tag, 0x3c);    printf("promise_status: port0: 0x%lx, port0_alt: 0x%lx, port1: 0x%lx, port1_alt: 0x%lx\n",	(u_long)port0_command, (u_long)port0_altstatus, (u_long)port1_command,	(u_long)port1_altstatus);    printf(	"promise_status: dma control blk address: 0x%lx, int: %d, irq: %d\n",	(u_long)dma_block, (u_int)(lat_and_interrupt >> 8) & 0xff,	(u_int)lat_and_interrupt & 0xff);    for(i=0;i<4;i+=2) {		drivetiming = pci_conf_read(tag, 0x60 + i * 4);		printf("drivebits%d-%d: %b\n", i, i+1, drivetiming,			"\020\05Prefetch\06Iordy\07Errdy\010Sync\025DmaW\026DmaR");	pa = drivetiming & 0xf;	pb = (drivetiming >> 8) & 0x1f;	mb = (drivetiming >> 13) & 0x7;	mc = (drivetiming >> 16) & 0xf;	printf("drivetiming%d: pa: 0x%x, pb: 0x%x, mb: 0x%x, mc: 0x%x\n",		i, pa, pb, mb, mc);	drivetiming = pci_conf_read(tag, 0x60 + (i + 1) * 4);	pa = drivetiming & 0xf;	pb = (drivetiming >> 8) & 0x1f;	mb = (drivetiming >> 13) & 0x7;	mc = (drivetiming >> 16) & 0xf;	printf("drivetiming%d: pa: 0x%x, pb: 0x%x, mb: 0x%x, mc: 0x%x\n",		i + 1, pa, pb, mb, mc);    }}static struct vendor_fns vs_promise = {     generic_dmainit,     promise_status};/* Intel PIIX, PIIX3, and PIIX4 IDE controller subfunctions */static voidintel_piix_dump_drive(char *ctlr,		      int sitre,		      int is_piix4,		      int word40,		      int word44,		      int word48,		      int word4a,		      int drive){	char *ms;	if (!sitre)		ms = "master/slave";	else if (drive == 0)		ms = "master";	else		ms = "slave";	printf("intel_piix_status: %s %s sample = %d, %s recovery = %d\n", 	       ctlr, 	       ms, 	       5 - ((sitre && drive) ?		    ((word44 >> 2) & 3) :		    ((word40 >> 12) & 3)),	       ms,	       4 - ((sitre && drive) ?		    ((word44 >> 0) & 3) :		    ((word40 >> 8) & 3)));	word40 >>= (drive * 4);	printf("intel_piix_status: %s %s fastDMAonly %s, pre/post %s,\n\intel_piix_status:  IORDY sampling %s,\n\intel_piix_status:  fast PIO %s%s\n", 	       ctlr,	       (drive == 0) ? "master" : "slave",	       (word40 & 8) ? "enabled" : "disabled",	       (word40 & 4) ? "enabled" : "disabled",	       (word40 & 2) ? "enabled" : "disabled",	       (word40 & 1) ? "enabled" : "disabled",	       ((word40 & 9) == 9) ? " (overridden by fastDMAonly)" : "" );	if (is_piix4)		printf("intel_piix_status: UltraDMA %s, CT/RP = %d/%d\n",		       word48 ? "enabled": "disabled",		       4 - (word4a & 3),		       6 - (word4a & 3));}static voidintel_piix_status(struct ide_pci_cookie *cookie){	int iobase_wd;	int unit;	int iobase_bm;	pcici_t tag;	pcidi_t type;	int ctlr;	u_long word40, word44, word48;	int sitre, is_piix4;	iobase_wd = cookie->iobase_wd;	unit = cookie->unit;	iobase_bm = cookie->iobase_bm;	tag = cookie->tag;	type = cookie->type;	ctlr = cookie->ctlr;	word40 = pci_conf_read(tag, 0x40);	word44 = pci_conf_read(tag, 0x44);	word48 = pci_conf_read(tag, 0x48);	/* 	 * XXX will not be right for the *next* generation of upward-compatible	 * intel IDE controllers...	 */	is_piix4 = pci_conf_read(tag, PCI_CLASS_REG) == 0x71118086;	sitre = word40 & 0x4000;	switch (ctlr * 2 + unit) {	case 0:		intel_piix_dump_drive("primary", 				      sitre, 				      is_piix4,				      word40 & 0xffff, 				      word44 & 0x0f, 				      word48,				      word48 >> 16,				      0);		break;	case 1:		intel_piix_dump_drive("primary", 				      sitre, 				      is_piix4,				      word40 & 0xffff, 				      word44 & 0x0f, 				      word48 >> 1,				      word48 >> 20,				      1);		break;	case 2:		intel_piix_dump_drive("secondary", 				      sitre, 				      is_piix4,				      (word40 >> 16) & 0xffff, 				      (word44 >> 4) & 0x0f,				      word48 >> 2,				      word48 >> 24,				      0);		break;	case 3:		intel_piix_dump_drive("secondary", 				      sitre, 				      is_piix4,				      (word40 >> 16) & 0xffff, 				      (word44 >> 4) & 0x0f,				      word48 >> 3,				      word48 >> 28,				      1);		break;	default:		printf("intel_piix_status: bad drive or controller number\n");	}}/* * XXX timing values set hereare only good for 30/33MHz buses; should deal * with slower ones too (BTW: you overclock-- you lose) */static intintel_piix_dmainit(struct ide_pci_cookie *cookie, 		   struct wdparams *wp, 		   int(*wdcmd)(int, void *),		   void *wdinfo){	int r;	/* If it's a UDMA drive and a PIIX4, set it up */	if (cookie->type == 0x71118086 && udma_mode(wp) >= 2) {		/* Set UDMA mode 2 on controller */		int unitno, mask, new;		if (bootverbose)			printf("intel_piix_dmainit: setting ultra DMA mode 2\n");		r = wdcmd(WDDMA_UDMA2, wdinfo);		if (!r) {			printf("intel_piix_dmainit: setting DMA mode failed\n");			return 0;		}		unitno = cookie->ctlr * 2 + cookie->unit;		mask = (1 << unitno) + (3 << (16 + unitno * 4));		new  = (1 << unitno) + (2 << (16 + unitno * 4));		pci_conf_write(cookie->tag, 0x48, 			(pci_conf_read(cookie->tag, 0x48) & ~mask) | new);		if (bootverbose)			intel_piix_status(cookie);		return 1;	}	/* 	 * if it's an 82371FB, which can't do independent programming of	 * drive timing, we punt; we're not going to fuss with trying to	 * coordinate timing modes between drives.  if this is you, get a	 * new motherboard.  or contribute patches :)	 *	 * we do now at least see if the modes set are OK to use.  this should	 * satisfy the majority of people, with mwdma mode2 drives.	 */	else if (cookie->type == 0x12308086)	{		u_long word40;		/* can drive do PIO 4 and MW DMA 2? */		if (!(mwdma_mode(wp) >= 2 && pio_mode(wp) >= 4)) 			return 0;		word40 = pci_conf_read(cookie->tag, 0x40);		word40 >>= cookie->ctlr * 16;		/* Check for timing config usable for DMA on controller */		if (!((word40 & 0x3300) == 0x2300 && 		      ((word40 >> (cookie->unit * 4)) & 1) == 1))			return 0;		/* Set multiword DMA mode 2 on drive */		if (bootverbose)			printf("intel_piix_dmainit: setting multiword DMA mode 2\n");		r = wdcmd(WDDMA_MDMA2, wdinfo);		if (!r) {			printf("intel_piix_dmainit: setting DMA mode failed\n");			return 0;		}		return 1;	}	/* otherwise, treat it as a PIIX3 and program it for MW DMA mode 2 */	else if (mwdma_mode(wp) >= 2 && pio_mode(wp) >= 4) {		u_long mask40, mask44, new40, new44;		/* 		 * If SITRE is not set, set it and copy the		 * appropriate bits into the secondary registers.  Do		 * both controllers at once.		 */		if (((pci_conf_read(cookie->tag, 0x40) >> (16 * cookie->ctlr)) 		     & 0x4000) == 0) {			unsigned int word40, word44;			word40 = pci_conf_read(cookie->tag, 0x40);			/* copy bits to secondary register */			word44 = pci_conf_read(cookie->tag, 0x44);			/*			 * I've got a Biostar motherboard with Award			 * BIOS that sets SITRE and secondary timing			 * on one controller but not the other.			 * Bizarre.			 */			if ((word40 & 0x4000) == 0) {				word44 &= ~0xf;				word44 |= ((word40 & 0x3000) >> 10) | 					((word40 & 0x0300) >> 8);			}			if ((word40 & 0x40000000) == 0) {				word44 &= ~0xf0;				word44 |= ((word40 & 0x30000000) >> 22) | 					((word40 & 0x03000000) >> 20);			}			/* set SITRE */			word40 |= 0x40004000;			pci_conf_write(cookie->tag, 0x40, word40);			pci_conf_write(cookie->tag, 0x44, word44);		}		/* Set multiword DMA mode 2 on drive */		if (bootverbose)			printf("intel_piix_dmainit: setting multiword DMA mode 2\n");		r = wdcmd(WDDMA_MDMA2, wdinfo);		if (!r) {			printf("intel_piix_dmainit: setting DMA mode failed\n");			return 0;		}		/* 		 * backward compatible hardware leaves us with such		 * twisted masses of software (aka twiddle the		 * extremely weird register layout on a PIIX3, setting		 * PIO mode 4 and MWDMA mode 2)		 */		if (cookie->unit == 0) {			mask40 = 0x330f;			new40 = 0x2307;			mask44 = 0;			new44 = 0;		} else {			mask40 = 0x00f0;			new40 = 0x0070;			mask44 = 0x000f;			new44 = 0x000b;		}		if (cookie->ctlr) {			mask40 <<= 16;			new40 <<= 16;			mask44 <<= 4;			new44 <<= 4;		}		pci_conf_write(cookie->tag, 0x40, 			       (pci_conf_read(cookie->tag, 0x40) & ~mask40) | new40);		pci_conf_write(cookie->tag, 0x44, 			       (pci_conf_read(cookie->tag, 0x44) & ~mask44) | new44);		if (bootverbose)			intel_piix_status(cookie);		return 1;	}	return 0;}static struct vendor_fns vs_intel_piix = { 	intel_piix_dmainit, 	intel_piix_status};static voidacer_status(struct ide_pci_cookie *cookie) {	/* XXX does not do anything right now */}static intacer_dmainit(struct ide_pci_cookie *cookie,                   struct wdparams *wp,                   int(*wdcmd)(int, void *),                   void *wdinfo){	/* Acer Aladdin DMA setup code. UDMA looks to be sinfully easy to set	   on this thing - just one register. */		u_long word54 = pci_conf_read(cookie->tag, 0x54);		/* Set the default Acer FIFO settings (0x55 = 13-word depth and	   slave operation mode 1) */		word54 |= 0x5555;		/* Is this drive UDMA? Set it up if so... */	if(udma_mode(wp) >= 2) {		/* This is really easy to do. Just write 0xa (enable 		   UDMA mode with 2T timing) into the word at the right		   places. */		word54 |= (0xA << (16 + (cookie->ctlr * 8) + (cookie->unit * 4)));				/* Now set the drive for UDMA2. */		if(!wdcmd(WDDMA_UDMA2, wdinfo)) {			printf("acer_dmainit: could not set UDMA2 mode on wdc%d:%d!\n", cookie->ctlr, cookie->unit);			return 0;		}				/* Write the new config into the registers. I'm not 		   sure if I'm doing this in the right order. */				pci_conf_write(cookie->tag, 0x54, word54);			} else if(mwdma_mode(wp) >= 2 && pio_mode(wp) >=4) {				/* Otherwise, we're already set for regular DMA. */		if(!wdcmd(WDDMA_MDMA2, wdinfo)) {			printf("acer_dmainit: could not set MWDMA2 mode on wdc%d:%d!\n", 			     cookie->ctlr, cookie->unit);			return 0;		}		return 1;	}		return 0;} static struct vendor_fns vs_acer = {	acer_dmainit,	acer_status};		 /* Generic SFF-8038i code-- all code below here, except for PCI probes, * more or less conforms to the SFF-8038i spec as extended for PCI. * There should be no code that goes beyond that feature set below. *//* XXX mkcookie is overloaded with too many parameters */static struct ide_pci_cookie *mkcookie(int iobase_wd, 	int ctlr,	int unit, 	int iobase_bm, 	pcici_t tag, 	pcidi_t type, 	struct vendor_fns *vp,	int altiobase_wd){	struct ide_pci_cookie *cp;	cp = malloc(sizeof *cp, M_DEVBUF, M_NOWAIT);	if (!cp) return 0;	cp->iobase_wd = iobase_wd;	cp->ctlr = ctlr;	cp->unit = unit;	cp->tag = tag;	cp->type = type;	cp->iobase_bm = iobase_bm;	cp->altiobase_wd = altiobase_wd;	bcopy(vp, &cp->vs, sizeof(struct vendor_fns));	if (!prdbuf) {		prdbuf = malloc(PRD_ALLOC_SIZE, M_DEVBUF, M_NOWAIT);		if (!prdbuf) {			FREE(cp, M_DEVBUF);			return 0;		}		if (((int)prdbuf >> PAGE_SHIFT) ^		    (((int)prdbuf + PRD_ALLOC_SIZE - 1) >> PAGE_SHIFT)) {			printf("ide_pci: prdbuf straddles page boundary, no DMA\n");			FREE(cp, M_DEVBUF);			FREE(prdbuf, M_DEVBUF);			return 0;		}		prdbuf_next = prdbuf;	}	if (((char *)prdbuf_next + PRD_BUF_SIZE) > 	    ((char *)prdbuf + PRD_ALLOC_SIZE)) {		printf("ide_pci: mkcookie %04x:%d: no more space for PRDs, no DMA\n",		       iobase_wd, unit);		FREE(cp, M_DEVBUF);		return 0;	}	cp->prd = prdbuf_next;	(char *)prdbuf_next += PRD_BUF_SIZE;

⌨️ 快捷键说明

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