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

📄 aic7xxx_pci.c

📁 linux-2.4.29操作系统的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
	/*	 * Record our termination setting for the	 * generic initialization routine.	 */	if ((sxfrctl1 & STPWEN) != 0)		ahc->flags |= AHC_TERM_ENB_A;	/*	 * Save chip register configuration data for chip resets	 * that occur during runtime and resume events.	 */	ahc->bus_softc.pci_softc.devconfig =	    ahc_pci_read_config(ahc->dev_softc, DEVCONFIG, /*bytes*/4);	ahc->bus_softc.pci_softc.command =	    ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/1);	ahc->bus_softc.pci_softc.csize_lattime =	    ahc_pci_read_config(ahc->dev_softc, CSIZE_LATTIME, /*bytes*/1);	ahc->bus_softc.pci_softc.dscommand0 = ahc_inb(ahc, DSCOMMAND0);	ahc->bus_softc.pci_softc.dspcistatus = ahc_inb(ahc, DSPCISTATUS);	if ((ahc->features & AHC_DT) != 0) {		u_int sfunct;		sfunct = ahc_inb(ahc, SFUNCT) & ~ALT_MODE;		ahc_outb(ahc, SFUNCT, sfunct | ALT_MODE);		ahc->bus_softc.pci_softc.optionmode = ahc_inb(ahc, OPTIONMODE);		ahc->bus_softc.pci_softc.targcrccnt = ahc_inw(ahc, TARGCRCCNT);		ahc_outb(ahc, SFUNCT, sfunct);		ahc->bus_softc.pci_softc.crccontrol1 =		    ahc_inb(ahc, CRCCONTROL1);	}	if ((ahc->features & AHC_MULTI_FUNC) != 0)		ahc->bus_softc.pci_softc.scbbaddr = ahc_inb(ahc, SCBBADDR);	if ((ahc->features & AHC_ULTRA2) != 0)		ahc->bus_softc.pci_softc.dff_thrsh = ahc_inb(ahc, DFF_THRSH);	/* Core initialization */	error = ahc_init(ahc);	if (error != 0)		return (error);	/*	 * Allow interrupts now that we are completely setup.	 */	error = ahc_pci_map_int(ahc);	if (error != 0)		return (error);	ahc_list_lock(&l);	/*	 * Link this softc in with all other ahc instances.	 */	ahc_softc_insert(ahc);	ahc_list_unlock(&l);	return (0);}/* * Test for the presense of external sram in an * "unshared" configuration. */static intahc_ext_scbram_present(struct ahc_softc *ahc){	u_int chip;	int ramps;	int single_user;	uint32_t devconfig;	chip = ahc->chip & AHC_CHIPID_MASK;	devconfig = ahc_pci_read_config(ahc->dev_softc,					DEVCONFIG, /*bytes*/4);	single_user = (devconfig & MPORTMODE) != 0;	if ((ahc->features & AHC_ULTRA2) != 0)		ramps = (ahc_inb(ahc, DSCOMMAND0) & RAMPS) != 0;	else if (chip == AHC_AIC7895 || chip == AHC_AIC7895C)		/*		 * External SCBRAM arbitration is flakey		 * on these chips.  Unfortunately this means		 * we don't use the extra SCB ram space on the		 * 3940AUW.		 */		ramps = 0;	else if (chip >= AHC_AIC7870)		ramps = (devconfig & RAMPSM) != 0;	else		ramps = 0;	if (ramps && single_user)		return (1);	return (0);}/* * Enable external scbram. */static voidahc_scbram_config(struct ahc_softc *ahc, int enable, int pcheck,		  int fast, int large){	uint32_t devconfig;	if (ahc->features & AHC_MULTI_FUNC) {		/*		 * Set the SCB Base addr (highest address bit)		 * depending on which channel we are.		 */		ahc_outb(ahc, SCBBADDR, ahc_get_pci_function(ahc->dev_softc));	}	ahc->flags &= ~AHC_LSCBS_ENABLED;	if (large)		ahc->flags |= AHC_LSCBS_ENABLED;	devconfig = ahc_pci_read_config(ahc->dev_softc, DEVCONFIG, /*bytes*/4);	if ((ahc->features & AHC_ULTRA2) != 0) {		u_int dscommand0;		dscommand0 = ahc_inb(ahc, DSCOMMAND0);		if (enable)			dscommand0 &= ~INTSCBRAMSEL;		else			dscommand0 |= INTSCBRAMSEL;		if (large)			dscommand0 &= ~USCBSIZE32;		else			dscommand0 |= USCBSIZE32;		ahc_outb(ahc, DSCOMMAND0, dscommand0);	} else {		if (fast)			devconfig &= ~EXTSCBTIME;		else			devconfig |= EXTSCBTIME;		if (enable)			devconfig &= ~SCBRAMSEL;		else			devconfig |= SCBRAMSEL;		if (large)			devconfig &= ~SCBSIZE32;		else			devconfig |= SCBSIZE32;	}	if (pcheck)		devconfig |= EXTSCBPEN;	else		devconfig &= ~EXTSCBPEN;	ahc_pci_write_config(ahc->dev_softc, DEVCONFIG, devconfig, /*bytes*/4);}/* * Take a look to see if we have external SRAM. * We currently do not attempt to use SRAM that is * shared among multiple controllers. */static voidahc_probe_ext_scbram(struct ahc_softc *ahc){	int num_scbs;	int test_num_scbs;	int enable;	int pcheck;	int fast;	int large;	enable = FALSE;	pcheck = FALSE;	fast = FALSE;	large = FALSE;	num_scbs = 0;		if (ahc_ext_scbram_present(ahc) == 0)		goto done;	/*	 * Probe for the best parameters to use.	 */	ahc_scbram_config(ahc, /*enable*/TRUE, pcheck, fast, large);	num_scbs = ahc_probe_scbs(ahc);	if (num_scbs == 0) {		/* The SRAM wasn't really present. */		goto done;	}	enable = TRUE;	/*	 * Clear any outstanding parity error	 * and ensure that parity error reporting	 * is enabled.	 */	ahc_outb(ahc, SEQCTL, 0);	ahc_outb(ahc, CLRINT, CLRPARERR);	ahc_outb(ahc, CLRINT, CLRBRKADRINT);	/* Now see if we can do parity */	ahc_scbram_config(ahc, enable, /*pcheck*/TRUE, fast, large);	num_scbs = ahc_probe_scbs(ahc);	if ((ahc_inb(ahc, INTSTAT) & BRKADRINT) == 0	 || (ahc_inb(ahc, ERROR) & MPARERR) == 0)		pcheck = TRUE;	/* Clear any resulting parity error */	ahc_outb(ahc, CLRINT, CLRPARERR);	ahc_outb(ahc, CLRINT, CLRBRKADRINT);	/* Now see if we can do fast timing */	ahc_scbram_config(ahc, enable, pcheck, /*fast*/TRUE, large);	test_num_scbs = ahc_probe_scbs(ahc);	if (test_num_scbs == num_scbs	 && ((ahc_inb(ahc, INTSTAT) & BRKADRINT) == 0	  || (ahc_inb(ahc, ERROR) & MPARERR) == 0))		fast = TRUE;	/*	 * See if we can use large SCBs and still maintain	 * the same overall count of SCBs.	 */	if ((ahc->features & AHC_LARGE_SCBS) != 0) {		ahc_scbram_config(ahc, enable, pcheck, fast, /*large*/TRUE);		test_num_scbs = ahc_probe_scbs(ahc);		if (test_num_scbs >= num_scbs) {			large = TRUE;			num_scbs = test_num_scbs;	 		if (num_scbs >= 64) {				/*				 * We have enough space to move the				 * "busy targets table" into SCB space				 * and make it qualify all the way to the				 * lun level.				 */				ahc->flags |= AHC_SCB_BTT;			}		}	}done:	/*	 * Disable parity error reporting until we	 * can load instruction ram.	 */	ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS);	/* Clear any latched parity error */	ahc_outb(ahc, CLRINT, CLRPARERR);	ahc_outb(ahc, CLRINT, CLRBRKADRINT);	if (bootverbose && enable) {		printf("%s: External SRAM, %s access%s, %dbytes/SCB\n",		       ahc_name(ahc), fast ? "fast" : "slow", 		       pcheck ? ", parity checking enabled" : "",		       large ? 64 : 32);	}	ahc_scbram_config(ahc, enable, pcheck, fast, large);}/* * Perform some simple tests that should catch situations where * our registers are invalidly mapped. */intahc_pci_test_register_access(struct ahc_softc *ahc){	int	 error;	u_int	 status1;	uint32_t cmd;	uint8_t	 hcntrl;	error = EIO;	/*	 * Enable PCI error interrupt status, but suppress NMIs	 * generated by SERR raised due to target aborts.	 */	cmd = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/2);	ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND,			     cmd & ~PCIM_CMD_SERRESPEN, /*bytes*/2);	/*	 * First a simple test to see if any	 * registers can be read.  Reading	 * HCNTRL has no side effects and has	 * at least one bit that is guaranteed to	 * be zero so it is a good register to	 * use for this test.	 */	hcntrl = ahc_inb(ahc, HCNTRL);	if (hcntrl == 0xFF)		goto fail;	/*	 * Next create a situation where write combining	 * or read prefetching could be initiated by the	 * CPU or host bridge.  Our device does not support	 * either, so look for data corruption and/or flagged	 * PCI errors.	 */	ahc_outb(ahc, HCNTRL, hcntrl|PAUSE);	while (ahc_is_paused(ahc) == 0)		;	/* Clear any PCI errors that occurred before our driver attached. */	status1 = ahc_pci_read_config(ahc->dev_softc,				      PCIR_STATUS + 1, /*bytes*/1);	ahc_pci_write_config(ahc->dev_softc, PCIR_STATUS + 1,			     status1, /*bytes*/1);	ahc_outb(ahc, CLRINT, CLRPARERR);	ahc_outb(ahc, SEQCTL, PERRORDIS);	ahc_outb(ahc, SCBPTR, 0);	ahc_outl(ahc, SCB_BASE, 0x5aa555aa);	if (ahc_inl(ahc, SCB_BASE) != 0x5aa555aa)		goto fail;	status1 = ahc_pci_read_config(ahc->dev_softc,				      PCIR_STATUS + 1, /*bytes*/1);	if ((status1 & STA) != 0)		goto fail;	error = 0;fail:	/* Silently clear any latched errors. */	status1 = ahc_pci_read_config(ahc->dev_softc,				      PCIR_STATUS + 1, /*bytes*/1);	ahc_pci_write_config(ahc->dev_softc, PCIR_STATUS + 1,			     status1, /*bytes*/1);	ahc_outb(ahc, CLRINT, CLRPARERR);	ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS);	ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, cmd, /*bytes*/2);	return (error);}/* * Check the external port logic for a serial eeprom * and termination/cable detection contrls. */static voidcheck_extport(struct ahc_softc *ahc, u_int *sxfrctl1){	struct	seeprom_descriptor sd;	struct	seeprom_config *sc;	int	have_seeprom;	int	have_autoterm;	sd.sd_ahc = ahc;	sd.sd_control_offset = SEECTL;			sd.sd_status_offset = SEECTL;			sd.sd_dataout_offset = SEECTL;			sc = ahc->seep_config;	/*	 * For some multi-channel devices, the c46 is simply too	 * small to work.  For the other controller types, we can	 * get our information from either SEEPROM type.  Set the	 * type to start our probe with accordingly.	 */	if (ahc->flags & AHC_LARGE_SEEPROM)		sd.sd_chip = C56_66;	else		sd.sd_chip = C46;	sd.sd_MS = SEEMS;	sd.sd_RDY = SEERDY;	sd.sd_CS = SEECS;	sd.sd_CK = SEECK;	sd.sd_DO = SEEDO;	sd.sd_DI = SEEDI;	have_seeprom = ahc_acquire_seeprom(ahc, &sd);	if (have_seeprom) {		if (bootverbose) 			printf("%s: Reading SEEPROM...", ahc_name(ahc));		for (;;) {			u_int start_addr;			start_addr = 32 * (ahc->channel - 'A');			have_seeprom = ahc_read_seeprom(&sd, (uint16_t *)sc,							start_addr,							sizeof(*sc)/2);			if (have_seeprom)				have_seeprom = ahc_verify_cksum(sc);			if (have_seeprom != 0 || sd.sd_chip == C56_66) {				if (bootverbose) {					if (have_seeprom == 0)						printf ("checksum error\n");					else						printf ("done.\n");				}				break;			}			sd.sd_chip = C56_66;		}		ahc_release_seeprom(&sd);	}	if (!have_seeprom) {		/*		 * Pull scratch ram settings and treat them as		 * if they are the contents of an seeprom if		 * the 'ADPT' signature is found in SCB2.		 * We manually compose the data as 16bit values		 * to avoid endian issues.		 */		ahc_outb(ahc, SCBPTR, 2);		if (ahc_inb(ahc, SCB_BASE) == 'A'		 && ahc_inb(ahc, SCB_BASE + 1) == 'D'		 && ahc_inb(ahc, SCB_BASE + 2) == 'P'		 && ahc_inb(ahc, SCB_BASE + 3) == 'T') {			uint16_t *sc_data;			int	  i;			sc_data = (uint16_t *)sc;			for (i = 0; i < 32; i++, sc_data++) {				int	j;				j = i * 2;				*sc_data = ahc_inb(ahc, SRAM_BASE + j)					 | ahc_inb(ahc, SRAM_BASE + j + 1) << 8;			}			have_seeprom = ahc_verify_cksum(sc);			if (have_seeprom)				ahc->flags |= AHC_SCB_CONFIG_USED;		}		/*		 * Clear any SCB parity errors in case this data and		 * its associated parity was not initialized by the BIOS		 */		ahc_outb(ahc, CLRINT, CLRPARERR);		ahc_outb(ahc, CLRINT, CLRBRKADRINT);	}	if (!have_seeprom) {		if (bootverbose)			printf("%s: No SEEPROM available.\n", ahc_name(ahc));		ahc->flags |= AHC_USEDEFAULTS;		free(ahc->seep_config, M_DEVBUF);		ahc->seep_config = NULL;		sc = NULL;	} else {		ahc_parse_pci_eeprom(ahc, sc);	}	/*	 * Cards that have the external logic necessary to talk to	 * a SEEPROM, are almost certain to have the remaining logic	 * necessary for auto-termination control.  This assumption	 * hasn't failed yet...	 */	have_autoterm = have_seeprom;	/*	 * Some low-cost chips have SEEPROM and auto-term control built	 * in, instead of using a GAL.  They can tell us directly	 * if the termination logic is enabled.	 */	if ((ahc->features & AHC_SPIOCAP) != 0) {		if ((ahc_inb(ahc, SPIOCAP) & SSPIOCPS) == 0)			have_autoterm = FALSE;	}	if (have_autoterm) {		ahc->flags |= AHC_HAS_TERM_LOGIC;		ahc_acquire_seeprom(ahc, &sd);		configure_termination(ahc, &sd, sc->adapter_control, sxfrctl1);		ahc_release_seeprom(&sd);	} else if (have_seeprom) {		*sxfrctl1 &= ~STPWEN;		if ((sc->adapter_control & CFSTERM) != 0)			*sxfrctl1 |= STPWEN;		if (bootverbose)			printf("%s: Low byte termination %sabled\n",			       ahc_name(ahc),			       (*sxfrctl1 & STPWEN) ? "en" : "dis");	}}static voidahc_parse_pci_eeprom(struct ahc_softc *ahc, struct seeprom_config *sc){	/*	 * Put the data we've collected down into SRAM	 * where ahc_init will find it.	 */	int	 i;	int	 max_targ = sc->max_targets & CFMAXTARG;	u_int	 scsi_conf;	uint16_t discenable;	uint16_t ultraenb;	discenable = 0;	ultraenb = 0;	if ((sc->adapter_control & CFULTRAEN) != 0) {		/*		 * Determine if this adapter has a "newstyle"

⌨️ 快捷键说明

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