/*
 * Should only be called after the calling cpus knows its cpu
 * number and main/secondary status. Should be called first
 * by the main processor, before the others are started.
*/
void
m8820x_cpu_configuration_print(int main)
{
	struct m8820x_cmmu *cmmu;
	int pid = get_cpu_pid();
	int proctype = (pid & PID_ARN) >> ARN_SHIFT;
	int procvers = (pid & PID_VN) >> VN_SHIFT;
	int reported, nmmu, mmu, cnt, cpu = cpu_number();
#ifdef M88200_HAS_SPLIT_ADDRESS
	int aline, abit, amask;
#endif

	printf("cpu%d: ", cpu);
	switch (proctype) {
	default:
		printf("unknown model arch 0x%x rev 0x%x",
		    proctype, procvers);
		break;
	case ARN_88100:
		printf("M88100 rev 0x%x", procvers);
#ifdef MULTIPROCESSOR
		if (main == 0)
			printf(", secondary");
#endif
		nmmu = 1 << cmmu_shift;
#ifdef M88200_HAS_ASYMMETRICAL_ASSOCIATION
		mmu = cpu << cmmu_shift;
		cmmu = m8820x_cmmu + mmu;
		for (cnt = 1 << cmmu_shift; cnt != 0; cnt--, mmu++, cmmu++)
			if (cmmu->cmmu_regs == NULL)
				nmmu--;
#endif
		printf(", %d CMMU", nmmu);

		mmu = cpu << cmmu_shift;
		cmmu = m8820x_cmmu + mmu;
		reported = 0;
		for (cnt = 1 << cmmu_shift; cnt != 0; cnt--, mmu++, cmmu++) {
			int idr, mmuid;

#ifdef M88200_HAS_ASYMMETRICAL_ASSOCIATION
			if (cmmu->cmmu_regs == NULL)
				continue;
#endif

			idr = cmmu->cmmu_regs[CMMU_IDR];
			mmuid = CMMU_TYPE(idr);

			if (reported++ % 2 == 0)
				printf("\ncpu%d: ", cpu);
			else
				printf(", ");

			switch (mmuid) {
			case M88200_ID:
				printf("M88200 (16K)");
				break;
			case M88204_ID:
				printf("M88204 (64K)");
				break;
			default:
				printf("unknown CMMU id 0x%x", mmuid);
				break;
			}
			printf(" rev 0x%x,", CMMU_VERSION(idr));
#ifdef M88200_HAS_SPLIT_ADDRESS
			/*
			 * Print address lines
			 */
			amask = cmmu->cmmu_addr_mask;
			if (amask != 0) {
				aline = 0;
				while (amask != 0) {
					abit = ff1(amask);
					if ((cmmu->cmmu_addr &
					    (1 << abit)) != 0)
						printf("%cA%02d",
						    aline != 0 ? '/' : ' ',
						    abit);
					else
						printf("%cA%02d*",
						    aline != 0 ? '/' : ' ',
						    abit);
					amask ^= 1 << abit;
				}
			} else if (cmmu_shift != 1) {
				/* unknown split scheme */
				printf(" split");
			} else
#endif
				printf(" full");
			printf(" %ccache",
			    CMMU_MODE(mmu) == INST_CMMU ? 'I' : 'D');
		}
		break;
	}
	printf("\n");

#ifndef ERRATA__XXX_USR
	{
		static int errata_warn = 0;

		if (proctype == ARN_88100 && procvers <= 10) {
			if (!errata_warn++)
				printf("WARNING: M88100 bug workaround code "
				    "not enabled.\nPlease recompile the kernel "
				    "with option ERRATA__XXX_USR !\n");
		}
	}
#endif
}
/*
 * Initialize the set of CMMUs tied to a particular CPU.
 */
void
m8820x_initialize_cpu(cpuid_t cpu)
{
	struct cpu_info *ci;
	struct m8820x_cmmu *cmmu;
	u_int line, cnt;
	int cssp, type;
	apr_t apr;

	apr = ((0x00000 << PG_BITS) | CACHE_WT | CACHE_GLOBAL | CACHE_INH) &
	    ~APR_V;

	cmmu = m8820x_cmmu + (cpu << cmmu_shift);

	/*
	 * Setup CMMU pointers for faster exception processing.
	 * This relies on the board-dependent code putting instruction
	 * CMMUs and data CMMUs interleaved with instruction CMMUs first.
	 */
	ci = &m88k_cpus[cpu];
	switch (cmmu_shift) {
	default:
		/* exception code may not use ci_pfsr fields, compute anyway */
		/* FALLTHROUGH */
	case 2:
		ci->ci_pfsr_d1 = (u_int)cmmu[3].cmmu_regs + CMMU_PFSR * 4;
		ci->ci_pfsr_i1 = (u_int)cmmu[2].cmmu_regs + CMMU_PFSR * 4;
		/* FALLTHROUGH */
	case 1:
		ci->ci_pfsr_d0 = (u_int)cmmu[1].cmmu_regs + CMMU_PFSR * 4;
		ci->ci_pfsr_i0 = (u_int)cmmu[0].cmmu_regs + CMMU_PFSR * 4;
		break;
	}

	for (cnt = 1 << cmmu_shift; cnt != 0; cnt--, cmmu++) {
#ifdef M88200_HAS_ASYMMETRICAL_ASSOCIATION
		if (cmmu->cmmu_regs == NULL)
			continue;
#endif
		type = CMMU_TYPE(cmmu->cmmu_regs[CMMU_IDR]);

		/*
		 * Reset cache
		 */
		for (cssp = type == M88204_ID ? 3 : 0; cssp >= 0; cssp--)
			for (line = 0; line <= 255; line++) {
				cmmu->cmmu_regs[CMMU_SAR] =
				    line << MC88200_CACHE_SHIFT;
				if (cmmu->cmmu_regs[CMMU_CSSP(cssp)] &
				    (CMMU_CSSP_D3 | CMMU_CSSP_D2 |
				     CMMU_CSSP_D1 | CMMU_CSSP_D0)) {
					printf("cpu%d: CMMU@%p has disabled"
					    " cache lines in set 0x%03x,"
					    " cssp %08x\n",
					    cpu, cmmu->cmmu_regs,
					    (cssp << 8) | line,
					    cmmu->cmmu_regs[CMMU_CSSP(cssp)]);
				}
				cmmu->cmmu_regs[CMMU_CSSP(cssp)] =
				    (cmmu->cmmu_regs[CMMU_CSSP(cssp)] &
				     ~(CMMU_CSSP_D3 | CMMU_CSSP_D2 |
				       CMMU_CSSP_D1 | CMMU_CSSP_D0)) |
				    CMMU_CSSP_L5 | CMMU_CSSP_L4 |
				    CMMU_CSSP_L3 | CMMU_CSSP_L2 |
				    CMMU_CSSP_L1 | CMMU_CSSP_L0 |
				    CMMU_CSSP_VV(3, CMMU_VV_INVALID) |
				    CMMU_CSSP_VV(2, CMMU_VV_INVALID) |
				    CMMU_CSSP_VV(1, CMMU_VV_INVALID) |
				    CMMU_CSSP_VV(0, CMMU_VV_INVALID);
			}

		/*
		 * Set the SCTR, SAPR, and UAPR to some known state.
		 * Snooping is always enabled, so that we do not need to
		 * writeback userland code pages when they first get filled
		 * as data pages.
		 */
		cmmu->cmmu_regs[CMMU_SCTR] = CMMU_SCTR_SE;

		cmmu->cmmu_regs[CMMU_SAPR] = cmmu->cmmu_regs[CMMU_UAPR] = apr;

		cmmu->cmmu_regs[CMMU_BWP0] = cmmu->cmmu_regs[CMMU_BWP1] =
		cmmu->cmmu_regs[CMMU_BWP2] = cmmu->cmmu_regs[CMMU_BWP3] =
		cmmu->cmmu_regs[CMMU_BWP4] = cmmu->cmmu_regs[CMMU_BWP5] =
		cmmu->cmmu_regs[CMMU_BWP6] = cmmu->cmmu_regs[CMMU_BWP7] = 0;
		cmmu->cmmu_regs[CMMU_SCR] = CMMU_FLUSH_CACHE_INV_ALL;
		(void)cmmu->cmmu_regs[CMMU_SSR];
		cmmu->cmmu_regs[CMMU_SCR] = CMMU_FLUSH_SUPER_ALL;
		cmmu->cmmu_regs[CMMU_SCR] = CMMU_FLUSH_USER_ALL;
	}

	/*
	 * Enable instruction cache.
	 * Data cache will be enabled later.
	 */
	apr &= ~CACHE_INH;
	m8820x_cmmu_set_reg(CMMU_SAPR, apr, MODE_VAL, cpu, INST_CMMU);

	ci->ci_zeropage = m8820x_zeropage;
	ci->ci_copypage = m8820x_copypage;
}
Exemple #3
0
/*
 * This routine sets up the CPU/CMMU configuration.
 */
void
m8820x_setup_board_config()
{
	struct m8820x_cmmu *cmmu;
	int num;

	master_cpu = 0;	/* temp to get things going */

	m8820x_cmmu[0].cmmu_regs = (void *)CMMU_I0;
	m8820x_cmmu[1].cmmu_regs = (void *)CMMU_D0;
	m8820x_cmmu[2].cmmu_regs = (void *)CMMU_I1;
	m8820x_cmmu[3].cmmu_regs = (void *)CMMU_D1;
	m8820x_cmmu[4].cmmu_regs = (void *)CMMU_I2;
	m8820x_cmmu[5].cmmu_regs = (void *)CMMU_D2;
	m8820x_cmmu[6].cmmu_regs = (void *)CMMU_I3;
	m8820x_cmmu[7].cmmu_regs = (void *)CMMU_D3;

	/*
	 * Probe all CMMU address to discover if the CPU slots are populated.
	 */
	cmmu = m8820x_cmmu;
	for (max_cmmus = 0; max_cmmus < 8; max_cmmus++, cmmu++) {
		if (badwordaddr((vaddr_t)cmmu->cmmu_regs) != 0)
			break;
	}

	max_cpus = max_cmmus >> 1;
	max_cmmus = max_cpus << 1;
	cmmu_shift = 1;	/* fixed 2:1 configuration */

#ifdef DEBUG
	/*
	 * Check CMMU type
	 */
	for (num = 0; num < max_cmmus; num++) {
		volatile unsigned *cr = m8820x_cmmu[num].cmmu_regs;
		if (badwordaddr((vaddr_t)cr) == 0) {
			int type;

			type = CMMU_TYPE(cr[CMMU_IDR]);
			if (type != M88200_ID && type != M88204_ID) {
				printf("WARNING: non M8820x circuit found "
				    "at CMMU address %p\n", cr);
				continue;	/* will probably die quickly */
			}
		}
	}
#endif

	/*
	 * Now that we know which CMMUs are there, report every association
	 */
	for (num = 0; num < max_cpus; num++) {
		int type;

		cpu_sets[num] = 1;   /* This cpu installed... */
		type = CMMU_TYPE(m8820x_cmmu[num << cmmu_shift].
		    cmmu_regs[CMMU_IDR]);

		printf("CPU%d is associated to %d MC8820%c CMMUs\n",
		    num, 1 << cmmu_shift, type == M88204_ID ? '4' : '0');
	}
}