arch/sparc/kernel/leon_kernel.c

Source file repositories/reference/linux-study-clean/arch/sparc/kernel/leon_kernel.c

File Facts

System
Linux kernel
Corpus path
arch/sparc/kernel/leon_kernel.c
Extension
.c
Size
13937 bytes
Lines
509
Domain
Architecture Layer
Bucket
arch/sparc
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 (ampopts == 0) {
			/* Skip this instance, resource already
			 * allocated by other OS */
			nnp = np;
			goto retry;
		}
	}

	/* Select Timer-Instance on Timer Core. Default is zero */
	leon3_gptimer_idx = ampopts & 0x7;

	pp = of_find_property(np, "reg", &len);
	if (pp)
		leon3_gptimer_regs = *(struct leon3_gptimer_regs_map **)
					pp->value;
	pp = of_find_property(np, "interrupts", &len);
	if (pp)
		leon3_gptimer_irq = *(unsigned int *)pp->value;

	if (!(leon3_gptimer_regs && leon3_irqctrl_regs && leon3_gptimer_irq))
		goto bad;

	ctrl = LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl);
	LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl,
			      ctrl | LEON3_GPTIMER_CTRL_PENDING);
	ctrl = LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl);

	if ((ctrl & LEON3_GPTIMER_CTRL_PENDING) != 0)
		leon3_gptimer_ackmask = ~LEON3_GPTIMER_CTRL_PENDING;
	else
		leon3_gptimer_ackmask = ~0;

	LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].val, 0);
	LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].rld,
				(((1000000 / HZ) - 1)));
	LEON3_BYPASS_STORE_PA(
			&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl, 0);

	/*
	 * The IRQ controller may (if implemented) consist of multiple
	 * IRQ controllers, each mapped on a 4Kb boundary.
	 * Each CPU may be routed to different IRQCTRLs, however
	 * we assume that all CPUs (in SMP system) is routed to the
	 * same IRQ Controller, and for non-SMP only one IRQCTRL is
	 * accessed anyway.
	 * In AMP systems, Linux must run on CPU0 for the time being.
	 */
	icsel = LEON3_BYPASS_LOAD_PA(&leon3_irqctrl_regs->icsel[boot_cpu_id/8]);
	icsel = (icsel >> ((7 - (boot_cpu_id&0x7)) * 4)) & 0xf;
	leon3_irqctrl_regs += icsel;

	/* Mask all IRQs on boot-cpu IRQ controller */
	LEON3_BYPASS_STORE_PA(&leon3_irqctrl_regs->mask[boot_cpu_id], 0);

	/* Probe extended IRQ controller */
	eirq = (LEON3_BYPASS_LOAD_PA(&leon3_irqctrl_regs->mpstatus)
		>> 16) & 0xf;
	if (eirq != 0)
		leon_eirq_setup(eirq);

#ifdef CONFIG_SMP
	{
		unsigned long flags;

		/*
		 * In SMP, sun4m adds a IPI handler to IRQ trap handler that
		 * LEON never must take, sun4d and LEON overwrites the branch
		 * with a NOP.
		 */
		local_irq_save(flags);
		patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */
		local_ops->cache_all();
		local_irq_restore(flags);
	}
#endif

	config = LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->config);
	if (config & (1 << LEON3_GPTIMER_SEPIRQ))
		leon3_gptimer_irq += leon3_gptimer_idx;
	else if ((config & LEON3_GPTIMER_TIMERS) > 1)
		pr_warn("GPTIMER uses shared irqs, using other timers of the same core will fail.\n");

#ifdef CONFIG_SMP
	/* Install per-cpu IRQ handler for broadcasted ticker */
	irq = leon_build_device_irq(leon3_gptimer_irq, handle_percpu_irq,
				    "per-cpu", 0);
	err = request_irq(irq, leon_percpu_timer_ce_interrupt,
			  IRQF_PERCPU | IRQF_TIMER, "timer", NULL);
#else
	irq = _leon_build_device_irq(NULL, leon3_gptimer_irq);

Annotation

Implementation Notes