arch/mips/kernel/mips-cm.c

Source file repositories/reference/linux-study-clean/arch/mips/kernel/mips-cm.c

File Facts

System
Linux kernel
Corpus path
arch/mips/kernel/mips-cm.c
Extension
.c
Size
15576 bytes
Lines
558
Domain
Architecture Layer
Bucket
arch/mips
Inferred role
Architecture Layer: implementation source
Status
source implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

if (cm_rev >= CM_REV_CM3_5) {
			if (cluster != cpu_cluster(&current_cpu_data))
				val |= CM_GCR_Cx_OTHER_CLUSTER_EN;
			val |= CM_GCR_Cx_OTHER_GIC_EN;
			val |= FIELD_PREP(CM_GCR_Cx_OTHER_CLUSTER, cluster);
			val |= FIELD_PREP(CM_GCR_Cx_OTHER_BLOCK, block);
		} else {
			WARN_ON(cluster != 0);
			WARN_ON(block != CM_GCR_Cx_OTHER_BLOCK_LOCAL);
		}

		/*
		 * We need to disable interrupts in SMP systems in order to
		 * ensure that we don't interrupt the caller with code which
		 * may modify the redirect register. We do so here in a
		 * slightly obscure way by using a spin lock, since this has
		 * the neat property of also catching any nested uses of
		 * mips_cm_lock_other() leading to a deadlock or a nice warning
		 * with lockdep enabled.
		 */
		spin_lock_irqsave(this_cpu_ptr(&cm_core_lock),
				  *this_cpu_ptr(&cm_core_lock_flags));
	} else {
		WARN_ON(cluster != 0);
		WARN_ON(block != CM_GCR_Cx_OTHER_BLOCK_LOCAL);

		/*
		 * We only have a GCR_CL_OTHER per core in systems with
		 * CM 2.5 & older, so have to ensure other VP(E)s don't
		 * race with us.
		 */
		curr_core = cpu_core(&current_cpu_data);
		spin_lock_irqsave(&per_cpu(cm_core_lock, curr_core),
				  per_cpu(cm_core_lock_flags, curr_core));

		val = FIELD_PREP(CM_GCR_Cx_OTHER_CORENUM, core);
	}

	write_gcr_cl_other(val);

	/*
	 * Ensure the core-other region reflects the appropriate core &
	 * VP before any accesses to it occur.
	 */
	mb();
}

void mips_cm_unlock_other(void)
{
	unsigned int curr_core;

	if (mips_cm_revision() < CM_REV_CM3) {
		curr_core = cpu_core(&current_cpu_data);
		spin_unlock_irqrestore(&per_cpu(cm_core_lock, curr_core),
				       per_cpu(cm_core_lock_flags, curr_core));
	} else {
		spin_unlock_irqrestore(this_cpu_ptr(&cm_core_lock),
				       *this_cpu_ptr(&cm_core_lock_flags));
	}

	preempt_enable();
}

void mips_cm_error_report(void)
{
	u64 cm_error, cm_addr, cm_other;
	unsigned long revision;
	int ocause, cause;
	char buf[256];

	if (!mips_cm_present())
		return;

	revision = mips_cm_revision();
	cm_error = read_gcr_error_cause();
	cm_addr = read_gcr_error_addr();
	cm_other = read_gcr_error_mult();

	if (revision < CM_REV_CM3) { /* CM2 */
		cause = FIELD_GET(CM_GCR_ERROR_CAUSE_ERRTYPE, cm_error);
		ocause = FIELD_GET(CM_GCR_ERROR_MULT_ERR2ND, cm_other);

		if (!cause)
			return;

		if (cause < 16) {
			unsigned long cca_bits = (cm_error >> 15) & 7;
			unsigned long tr_bits = (cm_error >> 12) & 7;
			unsigned long cmd_bits = (cm_error >> 7) & 0x1f;
			unsigned long stag_bits = (cm_error >> 3) & 15;

Annotation

Implementation Notes