Root/target/linux/ubicom32/files/arch/ubicom32/kernel/processor.c

1/*
2 * arch/ubicom32/kernel/processor.c
3 * Ubicom32 architecture processor info implementation.
4 *
5 * (C) Copyright 2009, Ubicom, Inc.
6 *
7 * This file is part of the Ubicom32 Linux Kernel Port.
8 *
9 * The Ubicom32 Linux Kernel Port is free software: you can redistribute
10 * it and/or modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation, either version 2 of the
12 * License, or (at your option) any later version.
13 *
14 * The Ubicom32 Linux Kernel Port is distributed in the hope that it
15 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
16 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with the Ubicom32 Linux Kernel Port. If not,
21 * see <http://www.gnu.org/licenses/>.
22 *
23 * Ubicom32 implementation derived from (with many thanks):
24 * arch/m68knommu
25 * arch/blackfin
26 * arch/parisc
27 */
28#include <linux/module.h>
29#include <linux/kernel.h>
30#include <linux/init.h>
31#include <linux/sched.h>
32#include <linux/interrupt.h>
33#include <linux/irq.h>
34#include <linux/profile.h>
35#include <linux/clocksource.h>
36#include <linux/types.h>
37#include <linux/seq_file.h>
38#include <linux/delay.h>
39#include <linux/cpu.h>
40#include <asm/devtree.h>
41#include <asm/processor.h>
42#include <asm/cpu.h>
43#include <asm/ocm_size.h>
44
45struct procnode {
46    struct devtree_node dn;
47    unsigned int threads;
48    unsigned int timers;
49    unsigned int frequency;
50    unsigned int ddr_frequency;
51    unsigned int interrupt0;
52    unsigned int interrupt1;
53    void *socm;
54    void *eocm;
55    void *sdram;
56    void *edram;
57    unsigned int arch_version;
58    void *os_syscall_begin;
59    void *os_syscall_end;
60};
61
62struct procnode *pn;
63
64/*
65 * show_processorinfo()
66 * Print the actual processor information.
67 */
68static void show_processorinfo(struct seq_file *m)
69{
70    char *cpu, *mmu, *fpu;
71    unsigned int clockfreq;
72    unsigned int chipid;
73
74    cpu = CPU;
75    mmu = "none";
76    fpu = "none";
77
78    asm volatile (
79    "move.4 %0, CHIP_ID \n\t"
80    : "=r" (chipid)
81    );
82
83    /*
84     * General Processor Information.
85     */
86    seq_printf(m, "Vendor:\t\t%s\n", "Ubicom");
87    seq_printf(m, "CPU:\t\t%s\n", cpu);
88    seq_printf(m, "MMU:\t\t%s\n", mmu);
89    seq_printf(m, "FPU:\t\t%s\n", fpu);
90    seq_printf(m, "Arch:\t\t%hx\n", chipid >> 16);
91    seq_printf(m, "Rev:\t\t%hx\n", (chipid & 0xffff));
92
93    /*
94     * Now compute the clock frequency in Mhz.
95     */
96    clockfreq = processor_frequency();
97    seq_printf(m, "Clock Freq:\t%u.0 MHz\n",
98           clockfreq / 1000000);
99    seq_printf(m, "DDR Freq:\t%u.0 MHz\n",
100           pn ? pn->ddr_frequency / 1000000 : 0);
101    seq_printf(m, "BogoMips:\t%lu.%02lu\n",
102           (loops_per_jiffy * HZ) / 500000,
103           ((loops_per_jiffy * HZ) / 5000) % 100);
104    seq_printf(m, "Calibration:\t%lu loops\n", (loops_per_jiffy * HZ));
105}
106
107/*
108 * show_cpuinfo()
109 * Get CPU information for use by the procfs.
110 */
111static int show_cpuinfo(struct seq_file *m, void *v)
112{
113    unsigned long n = (unsigned long)v - 1;
114
115#if defined(CONFIG_SMP)
116    struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, n);
117#endif
118
119    /*
120     * Print the general processor information on the first
121     * call.
122     */
123    if (n == 0) {
124        show_processorinfo(m);
125    }
126
127#if defined(CONFIG_SMP)
128    /*
129     * For each hwthread, print if this hwthread is running Linux
130     * or is an I/O thread.
131     */
132    if (cpu_isset(n, cpu_online_map)) {
133        seq_printf(m, "cpu[%02lu]:\tthread id - %lu\n", n, p->tid);
134    } else {
135        seq_printf(m, "cpu[%02lu]:\toff-line\n", n);
136    }
137#endif
138    return 0;
139
140}
141
142static void *c_start(struct seq_file *m, loff_t *pos)
143{
144    unsigned long i = *pos;
145
146    return i < NR_CPUS ? (void *)(i + 1) : NULL;
147}
148
149static void *c_next(struct seq_file *m, void *v, loff_t *pos)
150{
151    ++*pos;
152    return c_start(m, pos);
153}
154
155static void c_stop(struct seq_file *m, void *v)
156{
157}
158
159const struct seq_operations cpuinfo_op = {
160    .start = c_start,
161    .next = c_next,
162    .stop = c_stop,
163    .show = show_cpuinfo,
164};
165
166/*
167 * processor_timers()
168 * Returns the timers available to Linux.
169 */
170unsigned int processor_timers(void)
171{
172    if (!pn) {
173        return 0;
174    }
175    return pn->timers;
176}
177
178/*
179 * processor_threads()
180 * Returns the threads available to Linux.
181 */
182unsigned int processor_threads(void)
183{
184    if (!pn) {
185        return 0;
186    }
187    return pn->threads;
188}
189
190/*
191 * processor_frequency()
192 * Returns the frequency of the system clock.
193 */
194unsigned int processor_frequency(void)
195{
196    if (!pn) {
197        return 0;
198    }
199    return pn->frequency;
200}
201EXPORT_SYMBOL(processor_frequency);
202
203/*
204 * processor_interrupts()
205 * Return the interrupts that are setup at boot time.
206 */
207int processor_interrupts(unsigned int *int0, unsigned int *int1)
208{
209    if (!pn) {
210        return -EFAULT;
211    }
212
213    if (int0) {
214        *int0 = pn->interrupt0;
215    }
216
217    if (int1) {
218        *int1 = pn->interrupt1;
219    }
220    return 0;
221}
222
223/*
224 * processor_ocm()
225 * Returns the start and end of OCM available to Linux.
226 */
227void processor_ocm(unsigned long *socm, unsigned long *eocm)
228{
229    *socm = (unsigned long)pn->socm;
230    *eocm = (unsigned long)pn->eocm;
231}
232
233/*
234 * processor_dram()
235 * Returns the start and end of dram available to Linux.
236 */
237void processor_dram(unsigned long *sdram, unsigned long *edram)
238{
239    *sdram = (unsigned long)pn->sdram;
240    *edram = (unsigned long)pn->edram;
241}
242
243/*
244 * processor_validate_failed()
245 * Returns the dram available to Linux.
246 */
247static noinline void processor_validate_failed(void)
248{
249    while (1)
250        THREAD_STALL;
251}
252
253/*
254 * processor_validate()
255 * Validates the procnode against limitations of this link/built.
256 */
257static void processor_validate(void)
258{
259    void *dram_start = (void *)(KERNELSTART);
260    void *dram_end = (void *)(SDRAMSTART + CONFIG_MIN_RAMSIZE);
261#if APP_OCM_CODE_SIZE || APP_OCM_DATA_SIZE
262    void *ocm_code_start = (void *)(OCMSTART + APP_OCM_CODE_SIZE);
263    void *ocm_data_end = (void *)(OCMEND - APP_OCM_DATA_SIZE);
264#endif
265    extern void __os_syscall_begin;
266    extern void __os_syscall_end;
267    int proc_node_valid = 1;
268
269    if (!pn) {
270        printk(KERN_ERR "ERROR: processor node not found\n");
271        goto error;
272    }
273
274
275    if (dram_start < pn->sdram || dram_end > pn->edram) {
276        printk(KERN_ERR "ERROR: processor dram mismatch %p-%p "
277               "available but we are expecting %p-%p\n",
278               pn->sdram, pn->edram, dram_start, dram_end);
279        proc_node_valid = 0;
280    } else {
281        printk(KERN_ERR "processor dram %p-%p, expecting %p-%p\n",
282               pn->sdram, pn->edram, dram_start, dram_end);
283    }
284    if (&__os_syscall_begin < pn->os_syscall_begin ||
285        &__os_syscall_end > pn->os_syscall_end) {
286        printk(KERN_ERR "ERROR: processor syscall area mismatch "
287               "%p-%p available but we are expecting %p-%p\n",
288               pn->os_syscall_begin, pn->os_syscall_end,
289               &__os_syscall_begin, &__os_syscall_end);
290        proc_node_valid = 0;
291    } else {
292        printk(KERN_ERR "processor dram %p-%p, expecting %p-%p\n",
293               pn->sdram, pn->edram, dram_start, dram_end);
294    }
295#if APP_OCM_CODE_SIZE || APP_OCM_DATA_SIZE
296    if (ocm_code_start < pn->socm || ocm_data_end > pn->eocm) {
297        printk(KERN_ERR "ERROR: processor ocm mismatch %p-%p "
298               "available but we are expecting %p-%p\n",
299               pn->socm, pn->eocm, ocm_code_start, ocm_data_end);
300        proc_node_valid = 0;
301    } else {
302        printk(KERN_INFO "processor ocm %p-%p, expecting %p-%p\n",
303               pn->socm, pn->eocm, ocm_code_start, ocm_data_end);
304
305    }
306#endif
307
308    if (UBICOM32_ARCH_VERSION != pn->arch_version) {
309        printk(KERN_ERR "ERROR: processor arch mismatch, kernel"
310               "compiled for %d found %d\n",
311               UBICOM32_ARCH_VERSION, pn->arch_version);
312        proc_node_valid = 0;
313    }
314
315    if (proc_node_valid)
316        return;
317error:
318    processor_validate_failed();
319}
320
321void __init processor_init(void)
322{
323    /*
324     * If we do not have a trap node in the device tree, we leave the fault
325     * handling to the underlying hardware.
326     */
327    pn = (struct procnode *)devtree_find_node("processor");
328
329    processor_validate();
330
331    /*
332     * If necessary correct the initial range registers to cover the
333     * complete physical space
334     */
335    if (pn->edram > (void *)(SDRAMSTART + CONFIG_MIN_RAMSIZE)) {
336        printk(KERN_INFO "updating range registers for expanded dram\n");
337        asm volatile (
338            " move.4 D_RANGE1_HI, %0 \t\n"
339            " move.4 I_RANGE0_HI, %0 \t\n"
340#ifdef CONFIG_PROTECT_KERNEL
341            " move.4 D_RANGE2_HI, %0 \t\n"
342            " move.4 I_RANGE2_HI, %0 \t\n"
343#endif
344        : : "a"((unsigned long)pn->edram - 4)
345            );
346    }
347
348}
349

Archive Download this file



interactive