sb_machdep.c revision 247297
1181641Skmacy/*-
2181641Skmacy * Copyright (c) 2007 Bruce M. Simpson.
3181641Skmacy * All rights reserved.
4181641Skmacy *
5181641Skmacy * Redistribution and use in source and binary forms, with or without
6181641Skmacy * modification, are permitted provided that the following conditions
7181641Skmacy * are met:
8181641Skmacy * 1. Redistributions of source code must retain the above copyright
9181641Skmacy *    notice, this list of conditions and the following disclaimer.
10181641Skmacy * 2. Redistributions in binary form must reproduce the above copyright
11181641Skmacy *    notice, this list of conditions and the following disclaimer in the
12181641Skmacy *    documentation and/or other materials provided with the distribution.
13181641Skmacy *
14181641Skmacy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15181641Skmacy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16181641Skmacy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17181641Skmacy * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18181641Skmacy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19181641Skmacy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20181641Skmacy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21181641Skmacy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22181641Skmacy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23181641Skmacy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24181641Skmacy * SUCH DAMAGE.
25181641Skmacy */
26181641Skmacy
27181641Skmacy#include <sys/cdefs.h>
28181641Skmacy__FBSDID("$FreeBSD: head/sys/mips/sibyte/sb_machdep.c 247297 2013-02-26 01:00:11Z attilio $");
29181641Skmacy
30181641Skmacy#include "opt_ddb.h"
31181641Skmacy#include "opt_kdb.h"
32181641Skmacy
33181641Skmacy#include <sys/param.h>
34181641Skmacy#include <sys/conf.h>
35181641Skmacy#include <sys/kernel.h>
36181641Skmacy#include <sys/systm.h>
37181641Skmacy#include <sys/imgact.h>
38181641Skmacy#include <sys/bio.h>
39181641Skmacy#include <sys/buf.h>
40181641Skmacy#include <sys/bus.h>
41181641Skmacy#include <sys/cpu.h>
42181641Skmacy#include <sys/cons.h>
43181641Skmacy#include <sys/exec.h>
44181641Skmacy#include <sys/ucontext.h>
45181641Skmacy#include <sys/proc.h>
46181641Skmacy#include <sys/kdb.h>
47181641Skmacy#include <sys/ptrace.h>
48181641Skmacy#include <sys/reboot.h>
49181641Skmacy#include <sys/signalvar.h>
50181641Skmacy#include <sys/sysent.h>
51181641Skmacy#include <sys/sysproto.h>
52181641Skmacy#include <sys/user.h>
53181641Skmacy#include <sys/timetc.h>
54181641Skmacy
55181641Skmacy#include <vm/vm.h>
56181641Skmacy#include <vm/vm_object.h>
57181641Skmacy#include <vm/vm_page.h>
58181641Skmacy
59181641Skmacy#include <machine/cache.h>
60181641Skmacy#include <machine/clock.h>
61181641Skmacy#include <machine/cpu.h>
62181641Skmacy#include <machine/cpuinfo.h>
63181641Skmacy#include <machine/cpufunc.h>
64181641Skmacy#include <machine/cpuregs.h>
65181641Skmacy#include <machine/hwfunc.h>
66181641Skmacy#include <machine/intr_machdep.h>
67181641Skmacy#include <machine/locore.h>
68181641Skmacy#include <machine/md_var.h>
69181641Skmacy#include <machine/pte.h>
70181641Skmacy#include <machine/sigframe.h>
71181641Skmacy#include <machine/trap.h>
72181641Skmacy#include <machine/vmparam.h>
73181641Skmacy
74181641Skmacy#ifdef SMP
75181641Skmacy#include <sys/smp.h>
76181641Skmacy#include <machine/smp.h>
77181641Skmacy#endif
78181641Skmacy
79181641Skmacy#ifdef CFE
80181641Skmacy#include <dev/cfe/cfe_api.h>
81181641Skmacy#endif
82181641Skmacy
83181641Skmacy#include "sb_scd.h"
84181641Skmacy
85181641Skmacy#ifdef DDB
86181641Skmacy#ifndef KDB
87181641Skmacy#error KDB must be enabled in order for DDB to work!
88181641Skmacy#endif
89181641Skmacy#endif
90181641Skmacy
91181641Skmacy#ifdef CFE_ENV
92181641Skmacyextern void cfe_env_init(void);
93181641Skmacy#endif
94181641Skmacy
95181641Skmacyextern int *edata;
96181641Skmacyextern int *end;
97181641Skmacy
98181641Skmacyextern char MipsTLBMiss[], MipsTLBMissEnd[];
99181641Skmacy
100181641Skmacyvoid
101181641Skmacyplatform_cpu_init()
102181641Skmacy{
103181641Skmacy	/* Nothing special */
104181641Skmacy}
105181641Skmacy
106181641Skmacystatic void
107181641Skmacysb_intr_init(int cpuid)
108181641Skmacy{
109181641Skmacy	int intrnum, intsrc;
110181641Skmacy
111181641Skmacy	/*
112181641Skmacy	 * Disable all sources to the interrupt mapper and setup the mapping
113181641Skmacy	 * between an interrupt source and the mips hard interrupt number.
114241498Salc	 */
115195949Skib	for (intsrc = 0; intsrc < NUM_INTSRC; ++intsrc) {
116181641Skmacy		intrnum = sb_route_intsrc(intsrc);
117181641Skmacy		sb_disable_intsrc(cpuid, intsrc);
118181641Skmacy		sb_write_intmap(cpuid, intsrc, intrnum);
119181641Skmacy#ifdef SMP
120181641Skmacy		/*
121181641Skmacy		 * Set up the mailbox interrupt mapping.
122228923Salc		 *
123228923Salc		 * The mailbox interrupt is "special" in that it is not shared
124181641Skmacy		 * with any other interrupt source.
125181641Skmacy		 */
126181641Skmacy		if (intsrc == INTSRC_MAILBOX3) {
127181641Skmacy			intrnum = platform_ipi_intrnum();
128181641Skmacy			sb_write_intmap(cpuid, INTSRC_MAILBOX3, intrnum);
129181641Skmacy			sb_enable_intsrc(cpuid, INTSRC_MAILBOX3);
130181641Skmacy		}
131181641Skmacy#endif
132181641Skmacy	}
133181641Skmacy}
134181641Skmacy
135181641Skmacystatic void
136181641Skmacymips_init(void)
137181641Skmacy{
138181641Skmacy	int i, j, cfe_mem_idx, tmp;
139181641Skmacy	uint64_t maxmem;
140181641Skmacy
141181641Skmacy#ifdef CFE_ENV
142181641Skmacy	cfe_env_init();
143181641Skmacy#endif
144181641Skmacy
145181641Skmacy	TUNABLE_INT_FETCH("boothowto", &boothowto);
146181641Skmacy
147181641Skmacy	if (boothowto & RB_VERBOSE)
148181641Skmacy		bootverbose++;
149181641Skmacy
150181641Skmacy#ifdef MAXMEM
151186557Skmacy	tmp = MAXMEM;
152181641Skmacy#else
153181641Skmacy	tmp = 0;
154181641Skmacy#endif
155181641Skmacy	TUNABLE_INT_FETCH("hw.physmem", &tmp);
156181641Skmacy	maxmem = (uint64_t)tmp * 1024;
157181641Skmacy
158181641Skmacy	/*
159181641Skmacy	 * XXX
160181641Skmacy	 * If we used vm_paddr_t consistently in pmap, etc., we could
161181641Skmacy	 * use 64-bit page numbers on !n64 systems, too, like i386
162181641Skmacy	 * does with PAE.
163181641Skmacy	 */
164208651Salc#if !defined(__mips_n64)
165181641Skmacy	if (maxmem == 0 || maxmem > 0xffffffff)
166208651Salc		maxmem = 0xffffffff;
167204041Sed#endif
168208651Salc
169204041Sed#ifdef CFE
170202628Sed	/*
171204041Sed	 * Query DRAM memory map from CFE.
172181641Skmacy	 */
173181641Skmacy	physmem = 0;
174181641Skmacy	cfe_mem_idx = 0;
175181641Skmacy	for (i = 0; i < 10; i += 2) {
176181641Skmacy		int result;
177181641Skmacy		uint64_t addr, len, type;
178181641Skmacy
179181641Skmacy		result = cfe_enummem(cfe_mem_idx++, 0, &addr, &len, &type);
180181641Skmacy		if (result < 0) {
181181641Skmacy			phys_avail[i] = phys_avail[i + 1] = 0;
182181641Skmacy			break;
183181641Skmacy		}
184181641Skmacy
185181641Skmacy		KASSERT(type == CFE_MI_AVAILABLE,
186181641Skmacy			("CFE DRAM region is not available?"));
187181641Skmacy
188181641Skmacy		if (bootverbose)
189181641Skmacy			printf("cfe_enummem: 0x%016jx/%ju.\n", addr, len);
190181641Skmacy
191181641Skmacy		if (maxmem != 0) {
192181641Skmacy			if (addr >= maxmem) {
193181641Skmacy				printf("Ignoring %ju bytes of memory at 0x%jx "
194181641Skmacy				       "that is above maxmem %dMB\n",
195181641Skmacy				       len, addr,
196216960Scperciva				       (int)(maxmem / (1024 * 1024)));
197216960Scperciva				continue;
198216960Scperciva			}
199216960Scperciva
200216960Scperciva			if (addr + len > maxmem) {
201181641Skmacy				printf("Ignoring %ju bytes of memory "
202181641Skmacy				       "that is above maxmem %dMB\n",
203181641Skmacy				       (addr + len) - maxmem,
204181641Skmacy				       (int)(maxmem / (1024 * 1024)));
205181641Skmacy				len = maxmem - addr;
206181641Skmacy			}
207181641Skmacy		}
208181641Skmacy
209181641Skmacy		phys_avail[i] = addr;
210181641Skmacy		if (i == 0 && addr == 0) {
211182902Skmacy			/*
212181641Skmacy			 * If this is the first physical memory segment probed
213181641Skmacy			 * from CFE, omit the region at the start of physical
214181641Skmacy			 * memory where the kernel has been loaded.
215181641Skmacy			 */
216181641Skmacy			phys_avail[i] += MIPS_KSEG0_TO_PHYS(kernel_kseg0_end);
217181641Skmacy		}
218181641Skmacy		phys_avail[i + 1] = addr + len;
219228923Salc		physmem += len;
220228923Salc	}
221196726Sadrian
222196726Sadrian	realmem = btoc(physmem);
223181641Skmacy#endif
224241498Salc
225241498Salc	for (j = 0; j < i; j++)
226241498Salc		dump_avail[j] = phys_avail[j];
227241498Salc
228241498Salc	physmem = realmem;
229241498Salc
230241498Salc	init_param1();
231181641Skmacy	init_param2(physmem);
232181641Skmacy	mips_cpu_init();
233236240Salc
234181641Skmacy	/*
235181641Skmacy	 * Sibyte has a L1 data cache coherent with DMA. This includes
236181641Skmacy	 * on-chip network interfaces as well as PCI/HyperTransport bus
237181641Skmacy	 * masters.
238181641Skmacy	 */
239181641Skmacy	cpuinfo.cache_coherent_dma = TRUE;
240181641Skmacy
241181641Skmacy	/*
242181641Skmacy	 * XXX
243181641Skmacy	 * The kernel is running in 32-bit mode but the CFE is running in
244181641Skmacy	 * 64-bit mode. So the SR_KX bit in the status register is turned
245181641Skmacy	 * on by the CFE every time we call into it - for e.g. CFE_CONSOLE.
246181641Skmacy	 *
247181641Skmacy	 * This means that if get a TLB miss for any address above 0xc0000000
248181641Skmacy	 * and the SR_KX bit is set then we will end up in the XTLB exception
249181641Skmacy	 * vector.
250181641Skmacy	 *
251181641Skmacy	 * For now work around this by copying the TLB exception handling
252267964Sjhb	 * code to the XTLB exception vector.
253204160Skmacy	 */
254267964Sjhb	{
255181641Skmacy		bcopy(MipsTLBMiss, (void *)MIPS_XTLB_MISS_EXC_VEC,
256181641Skmacy		      MipsTLBMissEnd - MipsTLBMiss);
257181641Skmacy
258181641Skmacy		mips_icache_sync_all();
259181641Skmacy		mips_dcache_wbinv_all();
260181641Skmacy	}
261181641Skmacy
262181641Skmacy	pmap_bootstrap();
263181641Skmacy	mips_proc0_init();
264181641Skmacy	mutex_init();
265181641Skmacy
266181641Skmacy	kdb_init();
267181641Skmacy#ifdef KDB
268181641Skmacy	if (boothowto & RB_KDB)
269181641Skmacy		kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger");
270181641Skmacy#endif
271181641Skmacy}
272181641Skmacy
273181641Skmacyvoid
274181641Skmacyplatform_reset(void)
275181641Skmacy{
276181641Skmacy
277181641Skmacy	/*
278181641Skmacy	 * XXX SMP
279181641Skmacy	 * XXX flush data caches
280181641Skmacy	 */
281236378Salc	sb_system_reset();
282181641Skmacy}
283236291Salc
284208651Salcstatic void
285208651Salckseg0_map_coherent(void)
286208651Salc{
287181641Skmacy	uint32_t config;
288181641Skmacy	const int CFG_K0_COHERENT = 5;
289181641Skmacy
290228923Salc	config = mips_rd_config();
291228923Salc	config &= ~MIPS_CONFIG_K0_MASK;
292181641Skmacy	config |= CFG_K0_COHERENT;
293181641Skmacy	mips_wr_config(config);
294181641Skmacy}
295181641Skmacy
296181641Skmacy#ifdef SMP
297181641Skmacyvoid
298181641Skmacyplatform_ipi_send(int cpuid)
299181641Skmacy{
300181641Skmacy	KASSERT(cpuid == 0 || cpuid == 1,
301270439Skib		("platform_ipi_send: invalid cpuid %d", cpuid));
302181641Skmacy
303270439Skib	sb_set_mailbox(cpuid, 1ULL);
304240126Salc}
305181641Skmacy
306181641Skmacyvoid
307181641Skmacyplatform_ipi_clear(void)
308181641Skmacy{
309181641Skmacy	int cpuid;
310196725Sadrian
311181747Skmacy	cpuid = PCPU_GET(cpuid);
312181641Skmacy	sb_clear_mailbox(cpuid, 1ULL);
313181641Skmacy}
314181641Skmacy
315181641Skmacyint
316181641Skmacyplatform_ipi_intrnum(void)
317181641Skmacy{
318181641Skmacy
319181641Skmacy	return (4);
320181641Skmacy}
321181641Skmacy
322181641Skmacystruct cpu_group *
323181641Skmacyplatform_smp_topo(void)
324181641Skmacy{
325181641Skmacy
326181641Skmacy	return (smp_topo_none());
327181641Skmacy}
328181641Skmacy
329181641Skmacyvoid
330181641Skmacyplatform_init_ap(int cpuid)
331181641Skmacy{
332181641Skmacy	int ipi_int_mask, clock_int_mask;
333181641Skmacy
334181641Skmacy	KASSERT(cpuid == 1, ("AP has an invalid cpu id %d", cpuid));
335181641Skmacy
336181641Skmacy	/*
337181641Skmacy	 * Make sure that kseg0 is mapped cacheable-coherent
338181641Skmacy	 */
339181641Skmacy	kseg0_map_coherent();
340181641Skmacy
341181641Skmacy	sb_intr_init(cpuid);
342181641Skmacy
343181641Skmacy	/*
344181641Skmacy	 * Unmask the clock and ipi interrupts.
345181641Skmacy	 */
346181641Skmacy	clock_int_mask = hard_int_mask(5);
347181641Skmacy	ipi_int_mask = hard_int_mask(platform_ipi_intrnum());
348181641Skmacy	set_intr_mask(ipi_int_mask | clock_int_mask);
349181641Skmacy}
350181641Skmacy
351181641Skmacyint
352181641Skmacyplatform_start_ap(int cpuid)
353181641Skmacy{
354181641Skmacy#ifdef CFE
355181641Skmacy	int error;
356181641Skmacy
357181641Skmacy	if ((error = cfe_cpu_start(cpuid, mpentry, 0, 0, 0))) {
358181641Skmacy		printf("cfe_cpu_start error: %d\n", error);
359181641Skmacy		return (-1);
360181641Skmacy	} else {
361181641Skmacy		return (0);
362181641Skmacy	}
363181641Skmacy#else
364181641Skmacy	return (-1);
365181641Skmacy#endif	/* CFE */
366181641Skmacy}
367181641Skmacy#endif	/* SMP */
368181641Skmacy
369181641Skmacystatic u_int
370181641Skmacysb_get_timecount(struct timecounter *tc)
371228923Salc{
372228923Salc
373228923Salc	return ((u_int)sb_zbbus_cycle_count());
374228923Salc}
375228923Salc
376181641Skmacystatic void
377181641Skmacysb_timecounter_init(void)
378181641Skmacy{
379181641Skmacy	static struct timecounter sb_timecounter = {
380181641Skmacy		sb_get_timecount,
381181641Skmacy		NULL,
382181641Skmacy		~0u,
383181641Skmacy		0,
384181641Skmacy		"sibyte_zbbus_counter",
385181641Skmacy		2000
386181641Skmacy	};
387181641Skmacy
388181641Skmacy	/*
389222813Sattilio	 * The ZBbus cycle counter runs at half the cpu frequency.
390181641Skmacy	 */
391241498Salc	sb_timecounter.tc_frequency = sb_cpu_speed() / 2;
392241498Salc	platform_timecounter = &sb_timecounter;
393241498Salc}
394241498Salc
395241498Salcvoid
396241498Salcplatform_start(__register_t a0, __register_t a1, __register_t a2,
397181641Skmacy	       __register_t a3)
398181641Skmacy{
399181641Skmacy	/*
400181641Skmacy	 * Make sure that kseg0 is mapped cacheable-coherent
401181641Skmacy	 */
402183342Skmacy	kseg0_map_coherent();
403183342Skmacy
404181641Skmacy	/* clear the BSS and SBSS segments */
405181641Skmacy	memset(&edata, 0, (vm_offset_t)&end - (vm_offset_t)&edata);
406181641Skmacy	mips_postboot_fixup();
407181641Skmacy
408181641Skmacy	sb_intr_init(0);
409181641Skmacy	sb_timecounter_init();
410181641Skmacy
411181641Skmacy	/* Initialize pcpu stuff */
412181641Skmacy	mips_pcpu0_init();
413181641Skmacy
414181641Skmacy#ifdef CFE
415181641Skmacy	/*
416181641Skmacy	 * Initialize CFE firmware trampolines before
417181641Skmacy	 * we initialize the low-level console.
418181641Skmacy	 *
419181641Skmacy	 * CFE passes the following values in registers:
420181641Skmacy	 * a0: firmware handle
421181641Skmacy	 * a2: firmware entry point
422181641Skmacy	 * a3: entry point seal
423181641Skmacy	 */
424204160Skmacy	if (a3 == CFE_EPTSEAL)
425204160Skmacy		cfe_init(a0, a2);
426181641Skmacy#endif
427181641Skmacy	cninit();
428181641Skmacy
429181641Skmacy	mips_init();
430181641Skmacy
431181641Skmacy	mips_timer_init_params(sb_cpu_speed(), 0);
432181641Skmacy}
433181641Skmacy