Exemple #1
0
int
imc_watchdog_cb(void *v, int period)
{
	uint32_t reg;

	if (period == 0) {
		/* reset... */
		imc_write(IMC_WDOG, 0);
		/* ...and disable */
		reg = imc_read(IMC_CPUCTRL0);
		reg &= ~(IMC_CPUCTRL0_WDOG);
		imc_write(IMC_CPUCTRL0, reg);

		return 0;
	} else {
		/* enable... */
		reg = imc_read(IMC_CPUCTRL0);
		reg |= IMC_CPUCTRL0_WDOG;
		imc_write(IMC_CPUCTRL0, reg);
		/* ...and reset */
		imc_write(IMC_WDOG, 0);

		/*
		 * The watchdog period is not controllable; it will fire
		 * when the 20 bit counter, running on a 64 usec clock,
		 * overflows.
		 */
		return (64 << 20) / 1000000;
	}
}
Exemple #2
0
uint32_t
imc_bus_error(uint32_t hwpend, struct trap_frame *tf)
{
	uint32_t cpustat, giostat;
	int quiet = 0;

	cpustat = imc_read(IMC_CPU_ERRSTAT);
	giostat = imc_read(IMC_GIO_ERRSTAT);

	switch (sys_config.system_type) {
	case SGI_IP28:
		/*
		 * R10000 speculative execution may attempt to access
		 * non-existing memory when in the kernel. We do not
		 * want to flood the console about those.
		 */
		if ((cpustat & IMC_CPU_ERRSTAT_ADDR) &&
		    IS_XKPHYS((vaddr_t)tf->pc))
			quiet = 1;
		/* This happens. No idea why. */
		if (cpustat == 0 && giostat == 0)
			quiet = 1;
		break;
	}

	if (quiet == 0) {
		printf("bus error:");
		if (cpustat != 0) {
			vaddr_t pc = tf->pc;
			uint32_t insn = 0xffffffff;

			if (tf->pc < 0)
				guarded_read_4(pc, &insn);
			else
				copyin((void *)pc, &insn, sizeof insn);

			printf(" cpu_stat %08x addr %08x pc %p insn %08x",
			    cpustat, imc_read(IMC_CPU_ERRADDR), pc, insn);
		}
		if (giostat != 0)
			printf(" gio_stat %08x addr %08x",
			    giostat, imc_read(IMC_GIO_ERRADDR));
		printf("\n");
	}

	if (cpustat != 0)
		imc_write(IMC_CPU_ERRSTAT, 0);
	if (giostat != 0)
		imc_write(IMC_GIO_ERRSTAT, 0);

	return hwpend;
}
Exemple #3
0
int
imc_is_sysad_parity_enabled(void)
{
	uint32_t reg;

	if (ip22_ecc)
		return 0;

	reg = imc_read(IMC_CPUCTRL0);
	return ~reg & IMC_CPUCTRL0_NCHKMEMPAR;
}
Exemple #4
0
void
imc_enable_sysad_parity(void)
{
	uint32_t reg;

	if (ip22_ecc)
		return;

	reg = imc_read(IMC_CPUCTRL0);
	reg &= ~IMC_CPUCTRL0_NCHKMEMPAR;
	imc_write(IMC_CPUCTRL0, reg);
}
Exemple #5
0
void
imc_attach(struct device *parent, struct device *self, void *aux)
{
	struct imc_attach_args iaa;
#if NEISA > 0
	struct eisabus_attach_args eba;
#endif
	uint32_t reg, lastreg;
	uint32_t id, rev;
	int have_eisa;

	id = imc_read(IMC_SYSID);
	rev = id & IMC_SYSID_REVMASK;

	/* EISA exists on Indigo2 only */
	if (sys_config.system_type != SGI_IP20 &&
	    sys_config.system_subtype == IP22_INDIGO2)
		have_eisa = (id & IMC_SYSID_HAVEISA) != 0;
	else
		have_eisa = 0;

	printf(": revision %d\n", rev);

	/* Clear CPU/GIO error status registers to clear any leftover bits. */
	imc_bus_reset();

	/* Disable watchdog if leftover from previous reboot */
	imc_watchdog_cb(self, 0);

	/* Hook the bus error handler into the ISR */
	set_intr(INTPRI_BUSERR, CR_INT_4, imc_bus_error);

	/*
	 * Enable parity reporting on GIO/main memory transactions, except
	 * on systems with the ECC memory controller, where enabling parity
	 * interferes with regular operation and causes sticky false errors.
	 *
	 * Disable parity checking on CPU bus transactions (as turning
	 * it on seems to cause spurious bus errors), but enable parity
	 * checking on CPU reads from main memory (note that this bit
	 * has the opposite sense... Turning it on turns the checks off!).
	 *
	 * Finally, turn on interrupt writes to the CPU from the MC.
	 */
	reg = imc_read(IMC_CPUCTRL0);
	if (ip22_ecc)
		reg &= ~(IMC_CPUCTRL0_GPR | IMC_CPUCTRL0_MPR);
	else
		reg |= IMC_CPUCTRL0_GPR | IMC_CPUCTRL0_MPR;
	reg &= ~IMC_CPUCTRL0_NCHKMEMPAR;
	reg |= IMC_CPUCTRL0_INTENA;
	imc_write(IMC_CPUCTRL0, reg);

	/* Setup the MC write buffer depth */
	/*
	 * XXX This hardcoded value is not documented anywhere, and can be
	 * XXX traced back to DaveM's internship at SGI in 1996, so it can
	 * XXX be considered correct at least for IP24 (and, to a lesser
	 * XXX extent, IP22). IP20 and IP28 systems seem to run happy with
	 * XXX this value as well.
	 */
	reg = imc_read(IMC_CPUCTRL1);
	reg = (reg & ~IMC_CPUCTRL1_MCHWMSK) | 13;

	/*
	 * Force endianness on the onboard HPC and both slots.
	 * This should be safe for Fullhouse, but leave it conditional
	 * for now.
	 */
	switch (sys_config.system_type) {
	case SGI_IP22:
		if (sys_config.system_subtype == IP22_INDIGO2)
			break;
		/* FALLTHROUGH */
	case SGI_IP20:
		reg |= IMC_CPUCTRL1_HPCFX;
		reg |= IMC_CPUCTRL1_EXP0FX;
		reg |= IMC_CPUCTRL1_EXP1FX;
		reg &= ~IMC_CPUCTRL1_HPCLITTLE;
		reg &= ~IMC_CPUCTRL1_EXP0LITTLE;
		reg &= ~IMC_CPUCTRL1_EXP1LITTLE;
		break;
	}
	imc_write(IMC_CPUCTRL1, reg);

	/*
	 * Try and read the GIO64 arbitrator configuration register value.
	 * See comments above the declaration of imc_arb_value for why we
	 * are doing this.
	 */
	reg = 0; lastreg = ~reg;
	while (reg != lastreg || (reg & ~0xffff) != 0) {
		lastreg = reg;
		reg = imc_read(IMC_GIO64ARB);
		/* read another harmless register */
		(void)imc_read(IMC_CPUCTRL0);
	}

	/*
	 * Set GIO64 arbitrator configuration register:
	 *
	 * Preserve PROM-set graphics-related bits, as they seem to depend
	 * on the graphics variant present and I'm not sure how to figure
	 * that out or 100% sure what the correct settings are for each.
	 */
	reg &= (IMC_GIO64ARB_GRX64 | IMC_GIO64ARB_GRXRT | IMC_GIO64ARB_GRXMST);

	/*
	 * Rest of settings are machine/board dependent
	 */
	switch (sys_config.system_type) {
	case SGI_IP20:
		reg |= IMC_GIO64ARB_ONEGIO;
		reg |= IMC_GIO64ARB_EXP0RT | IMC_GIO64ARB_EXP1RT;
		reg |= IMC_GIO64ARB_EXP0MST | IMC_GIO64ARB_EXP1MST;
		reg &= ~(IMC_GIO64ARB_HPC64 |
		     IMC_GIO64ARB_HPCEXP64 | IMC_GIO64ARB_EISA64 |
		     IMC_GIO64ARB_EXP064 | IMC_GIO64ARB_EXP164 |
		     IMC_GIO64ARB_EXP0PIPE | IMC_GIO64ARB_EXP1PIPE);
		break;
	default:
		/*
		 * GIO64 invariant for all IP22 platforms: one GIO bus,
		 * HPC1 @ 64
		 */
		reg |= IMC_GIO64ARB_ONEGIO | IMC_GIO64ARB_HPC64;

		switch (sys_config.system_subtype) {
		default:
		case IP22_INDY:
		case IP22_CHALLS:
			/* XXX is MST mutually exclusive? */
			reg |= IMC_GIO64ARB_EXP0RT | IMC_GIO64ARB_EXP1RT;
			reg |= IMC_GIO64ARB_EXP0MST | IMC_GIO64ARB_EXP1MST;

			/* EISA (VINO, really) can bus-master, is 64-bit */
			reg |= IMC_GIO64ARB_EISAMST | IMC_GIO64ARB_EISA64;
			break;

		case IP22_INDIGO2:
			/*
			 * All Fullhouse boards have a 64-bit HPC2 and pipelined
			 * EXP0 slot.
			 */
			reg |= IMC_GIO64ARB_HPCEXP64 | IMC_GIO64ARB_EXP0PIPE;

			/*
			 * The EISA bus is the real thing, and is a 32-bit bus.
			 */
			reg &= ~IMC_GIO64ARB_EISA64;

			if (rev < 2) {
				/* EXP0 realtime, EXP1 can master */
				reg |= IMC_GIO64ARB_EXP0RT |
				    IMC_GIO64ARB_EXP1MST;
			} else {
				/* EXP1 pipelined as well, EISA masters */
				reg |= IMC_GIO64ARB_EXP1PIPE |
				    IMC_GIO64ARB_EISAMST;
			}
			break;
		}
	}

	imc_write(IMC_GIO64ARB, reg);
	imc_arb_value = reg;

	memset(&iaa, 0, sizeof(iaa));
	iaa.iaa_name = "gio";
	iaa.iaa_st = &imcbus_tag;
	iaa.iaa_dmat = &imc_bus_dma_tag;
	config_found(self, &iaa, imc_print);

#if NEISA > 0
	if (have_eisa) {
		memset(&eba, 0, sizeof(eba));
		eba.eba_busname = "eisa";
		eba.eba_iot = &imcbus_eisa_io_tag;
		eba.eba_memt = &imcbus_eisa_mem_tag;
		eba.eba_dmat = &imc_bus_dma_tag;
		eba.eba_ec = NULL;
		config_found(self, &eba, imc_print);
	}
#endif

	/* Register watchdog */
	wdog_register(imc_watchdog_cb, self);
}
Exemple #6
0
uint32_t
imc_bus_error(uint32_t hwpend, struct trap_frame *tf)
{
	uint32_t cpustat, giostat;
	paddr_t cpuaddr, gioaddr;
	int cpuquiet = 0, gioquiet = 0;

	cpustat = imc_read(IMC_CPU_ERRSTAT);
	cpuaddr = imc_read(IMC_CPU_ERRADDR);
	giostat = imc_read(IMC_GIO_ERRSTAT);
	gioaddr = imc_read(IMC_GIO_ERRADDR);

	switch (sys_config.system_type) {
	case SGI_IP28:
		/*
		 * R10000 speculative execution may attempt to access
		 * non-existing memory when in the kernel. We do not
		 * want to flood the console about those.
		 */
		if (cpustat & IMC_CPU_ERRSTAT_ADDR) {
			if (IS_XKPHYS((vaddr_t)tf->pc))
				cpuquiet = 1;
		}
		if (giostat != 0) {
			/*
			 * Ignore speculative writes to interrupt controller
			 * registers.
			 */
			if ((giostat & IMC_ECC_ERRSTAT_FUW) &&
			    (gioaddr & ~0x3f) == INT2_IP22)
				gioquiet = 1;
			/* XXX is it wise to hide these? */
			if ((giostat & IMC_GIO_ERRSTAT_TMO) &&
			    !IS_GIO_ADDRESS(gioaddr))
				gioquiet = 1;
		}
		break;
	}

	if (cpustat != 0 && cpuquiet == 0) {
		vaddr_t pc = tf->pc;
		uint32_t insn = 0xffffffff;

		if (tf->pc < 0)
			guarded_read_4(pc, &insn);
		else
			copyin((void *)pc, &insn, sizeof insn);

		printf("bus error: cpu_stat %08x addr %08lx pc %p insn %08x\n",
		    cpustat, cpuaddr, (void *)pc, insn);
	}
	if (giostat != 0 && gioquiet == 0) {
		printf("bus error: gio_stat %08x addr %08lx\n",
		    giostat, gioaddr);
	}

	if (cpustat != 0)
		imc_write(IMC_CPU_ERRSTAT, 0);
	if (giostat != 0)
		imc_write(IMC_GIO_ERRSTAT, 0);

	return hwpend;
}