sb_machdep.c revision 210910
1/*-
2 * Copyright (c) 2007 Bruce M. Simpson.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/sys/mips/sibyte/sb_machdep.c 210910 2010-08-06 05:24:41Z neel $");
29
30#include <sys/param.h>
31
32#include "opt_ddb.h"
33#include "opt_kdb.h"
34
35#include <sys/param.h>
36#include <sys/conf.h>
37#include <sys/kernel.h>
38#include <sys/systm.h>
39#include <sys/imgact.h>
40#include <sys/bio.h>
41#include <sys/buf.h>
42#include <sys/bus.h>
43#include <sys/cpu.h>
44#include <sys/cons.h>
45#include <sys/exec.h>
46#include <sys/ucontext.h>
47#include <sys/proc.h>
48#include <sys/kdb.h>
49#include <sys/ptrace.h>
50#include <sys/reboot.h>
51#include <sys/signalvar.h>
52#include <sys/sysent.h>
53#include <sys/sysproto.h>
54#include <sys/user.h>
55#include <sys/timetc.h>
56
57#include <vm/vm.h>
58#include <vm/vm_object.h>
59#include <vm/vm_page.h>
60#include <vm/vm_pager.h>
61
62#include <machine/cache.h>
63#include <machine/clock.h>
64#include <machine/cpu.h>
65#include <machine/cpuinfo.h>
66#include <machine/cpufunc.h>
67#include <machine/cpuregs.h>
68#include <machine/hwfunc.h>
69#include <machine/intr_machdep.h>
70#include <machine/locore.h>
71#include <machine/md_var.h>
72#include <machine/pte.h>
73#include <machine/sigframe.h>
74#include <machine/trap.h>
75#include <machine/vmparam.h>
76
77#ifdef SMP
78#include <sys/smp.h>
79#include <machine/smp.h>
80#endif
81
82#ifdef CFE
83#include <dev/cfe/cfe_api.h>
84#endif
85
86#include "sb_scd.h"
87
88#ifdef DDB
89#ifndef KDB
90#error KDB must be enabled in order for DDB to work!
91#endif
92#endif
93
94#ifdef CFE_ENV
95extern void cfe_env_init(void);
96#endif
97
98extern int *edata;
99extern int *end;
100
101extern char MipsTLBMiss[], MipsTLBMissEnd[];
102
103void
104platform_cpu_init()
105{
106	/* Nothing special */
107}
108
109static void
110sb_intr_init(int cpuid)
111{
112	int intrnum, intsrc;
113
114	/*
115	 * Disable all sources to the interrupt mapper and setup the mapping
116	 * between an interrupt source and the mips hard interrupt number.
117	 */
118	for (intsrc = 0; intsrc < NUM_INTSRC; ++intsrc) {
119		intrnum = sb_route_intsrc(intsrc);
120		sb_disable_intsrc(cpuid, intsrc);
121		sb_write_intmap(cpuid, intsrc, intrnum);
122#ifdef SMP
123		/*
124		 * Set up the mailbox interrupt mapping.
125		 *
126		 * The mailbox interrupt is "special" in that it is not shared
127		 * with any other interrupt source.
128		 */
129		if (intsrc == INTSRC_MAILBOX3) {
130			intrnum = platform_ipi_intrnum();
131			sb_write_intmap(cpuid, INTSRC_MAILBOX3, intrnum);
132			sb_enable_intsrc(cpuid, INTSRC_MAILBOX3);
133		}
134#endif
135	}
136}
137
138static void
139mips_init(void)
140{
141	int i, cfe_mem_idx, tmp;
142	uint64_t maxmem;
143
144#ifdef CFE_ENV
145	cfe_env_init();
146#endif
147
148	TUNABLE_INT_FETCH("boothowto", &boothowto);
149
150	if (boothowto & RB_VERBOSE)
151		bootverbose++;
152
153#ifdef MAXMEM
154	tmp = MAXMEM;
155#else
156	tmp = 0;
157#endif
158	TUNABLE_INT_FETCH("hw.physmem", &tmp);
159	maxmem = (uint64_t)tmp * 1024;
160
161	/*
162	 * XXX
163	 * If we used vm_paddr_t consistently in pmap, etc., we could
164	 * use 64-bit page numbers on !n64 systems, too, like i386
165	 * does with PAE.
166	 */
167#if !defined(__mips_n64)
168	if (maxmem == 0 || maxmem > 0xffffffff)
169		maxmem = 0xffffffff;
170#endif
171
172#ifdef CFE
173	/*
174	 * Query DRAM memory map from CFE.
175	 */
176	physmem = 0;
177	cfe_mem_idx = 0;
178	for (i = 0; i < 10; i += 2) {
179		int result;
180		uint64_t addr, len, type;
181
182		result = cfe_enummem(cfe_mem_idx++, 0, &addr, &len, &type);
183		if (result < 0) {
184			phys_avail[i] = phys_avail[i + 1] = 0;
185			break;
186		}
187
188		KASSERT(type == CFE_MI_AVAILABLE,
189			("CFE DRAM region is not available?"));
190
191		if (bootverbose)
192			printf("cfe_enummem: 0x%016jx/%ju.\n", addr, len);
193
194		if (maxmem != 0) {
195			if (addr >= maxmem) {
196				printf("Ignoring %ju bytes of memory at 0x%jx "
197				       "that is above maxmem %dMB\n",
198				       len, addr,
199				       (int)(maxmem / (1024 * 1024)));
200				continue;
201			}
202
203			if (addr + len > maxmem) {
204				printf("Ignoring %ju bytes of memory "
205				       "that is above maxmem %dMB\n",
206				       (addr + len) - maxmem,
207				       (int)(maxmem / (1024 * 1024)));
208				len = maxmem - addr;
209			}
210		}
211
212		phys_avail[i] = addr;
213		if (i == 0 && addr == 0) {
214			/*
215			 * If this is the first physical memory segment probed
216			 * from CFE, omit the region at the start of physical
217			 * memory where the kernel has been loaded.
218			 */
219			phys_avail[i] += MIPS_KSEG0_TO_PHYS(kernel_kseg0_end);
220		}
221		phys_avail[i + 1] = addr + len;
222		physmem += len;
223	}
224
225	realmem = btoc(physmem);
226#endif
227
228	physmem = realmem;
229
230	init_param1();
231	init_param2(physmem);
232	mips_cpu_init();
233
234	/*
235	 * Sibyte has a L1 data cache coherent with DMA. This includes
236	 * on-chip network interfaces as well as PCI/HyperTransport bus
237	 * masters.
238	 */
239	cpuinfo.cache_coherent_dma = TRUE;
240
241	/*
242	 * XXX
243	 * The kernel is running in 32-bit mode but the CFE is running in
244	 * 64-bit mode. So the SR_KX bit in the status register is turned
245	 * on by the CFE every time we call into it - for e.g. CFE_CONSOLE.
246	 *
247	 * This means that if get a TLB miss for any address above 0xc0000000
248	 * and the SR_KX bit is set then we will end up in the XTLB exception
249	 * vector.
250	 *
251	 * For now work around this by copying the TLB exception handling
252	 * code to the XTLB exception vector.
253	 */
254	{
255		bcopy(MipsTLBMiss, (void *)MIPS3_XTLB_MISS_EXC_VEC,
256		      MipsTLBMissEnd - MipsTLBMiss);
257
258		mips_icache_sync_all();
259		mips_dcache_wbinv_all();
260	}
261
262	pmap_bootstrap();
263	mips_proc0_init();
264	mutex_init();
265
266	kdb_init();
267#ifdef KDB
268	if (boothowto & RB_KDB)
269		kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger");
270#endif
271}
272
273void
274platform_halt(void)
275{
276
277}
278
279
280void
281platform_identify(void)
282{
283
284}
285
286void
287platform_reset(void)
288{
289
290	/*
291	 * XXX SMP
292	 * XXX flush data caches
293	 */
294	sb_system_reset();
295}
296
297void
298platform_trap_enter(void)
299{
300
301}
302
303void
304platform_trap_exit(void)
305{
306
307}
308
309static void
310kseg0_map_coherent(void)
311{
312	uint32_t config;
313	const int CFG_K0_COHERENT = 5;
314
315	config = mips_rd_config();
316	config &= ~MIPS3_CONFIG_K0_MASK;
317	config |= CFG_K0_COHERENT;
318	mips_wr_config(config);
319}
320
321#ifdef SMP
322void
323platform_ipi_send(int cpuid)
324{
325	KASSERT(cpuid == 0 || cpuid == 1,
326		("platform_ipi_send: invalid cpuid %d", cpuid));
327
328	sb_set_mailbox(cpuid, 1ULL);
329}
330
331void
332platform_ipi_clear(void)
333{
334	int cpuid;
335
336	cpuid = PCPU_GET(cpuid);
337	sb_clear_mailbox(cpuid, 1ULL);
338}
339
340int
341platform_ipi_intrnum(void)
342{
343
344	return (4);
345}
346
347struct cpu_group *
348platform_smp_topo(void)
349{
350
351	return (smp_topo_none());
352}
353
354void
355platform_init_ap(int cpuid)
356{
357	int ipi_int_mask, clock_int_mask;
358
359	KASSERT(cpuid == 1, ("AP has an invalid cpu id %d", cpuid));
360
361	/*
362	 * Make sure that kseg0 is mapped cacheable-coherent
363	 */
364	kseg0_map_coherent();
365
366	sb_intr_init(cpuid);
367
368	/*
369	 * Unmask the clock and ipi interrupts.
370	 */
371	clock_int_mask = hard_int_mask(5);
372	ipi_int_mask = hard_int_mask(platform_ipi_intrnum());
373	set_intr_mask(MIPS_SR_INT_MASK & ~(ipi_int_mask | clock_int_mask));
374}
375
376int
377platform_start_ap(int cpuid)
378{
379#ifdef CFE
380	int error;
381
382	if ((error = cfe_cpu_start(cpuid, mpentry, 0, 0, 0))) {
383		printf("cfe_cpu_start error: %d\n", error);
384		return (-1);
385	} else {
386		return (0);
387	}
388#else
389	return (-1);
390#endif	/* CFE */
391}
392#endif	/* SMP */
393
394static u_int
395sb_get_timecount(struct timecounter *tc)
396{
397
398	return ((u_int)sb_zbbus_cycle_count());
399}
400
401static void
402sb_timecounter_init(void)
403{
404	static struct timecounter sb_timecounter = {
405		sb_get_timecount,
406		NULL,
407		~0u,
408		0,
409		"sibyte_zbbus_counter",
410		2000
411	};
412
413	/*
414	 * The ZBbus cycle counter runs at half the cpu frequency.
415	 */
416	sb_timecounter.tc_frequency = sb_cpu_speed() / 2;
417	platform_timecounter = &sb_timecounter;
418}
419
420void
421platform_start(__register_t a0, __register_t a1, __register_t a2,
422	       __register_t a3)
423{
424	/*
425	 * Make sure that kseg0 is mapped cacheable-coherent
426	 */
427	kseg0_map_coherent();
428
429	/* clear the BSS and SBSS segments */
430	memset(&edata, 0, (vm_offset_t)&end - (vm_offset_t)&edata);
431	mips_postboot_fixup();
432
433	sb_intr_init(0);
434	sb_timecounter_init();
435
436	/* Initialize pcpu stuff */
437	mips_pcpu0_init();
438
439#ifdef CFE
440	/*
441	 * Initialize CFE firmware trampolines before
442	 * we initialize the low-level console.
443	 *
444	 * CFE passes the following values in registers:
445	 * a0: firmware handle
446	 * a2: firmware entry point
447	 * a3: entry point seal
448	 */
449	if (a3 == CFE_EPTSEAL)
450		cfe_init(a0, a2);
451#endif
452	cninit();
453
454	mips_init();
455
456	mips_timer_init_params(sb_cpu_speed(), 0);
457}
458