Home | History | Annotate | Line # | Download | only in arm32
cpu.c revision 1.22
      1 /*	$NetBSD: cpu.c,v 1.22 2002/03/10 00:44:09 bjh21 Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1995 Mark Brinicombe.
      5  * Copyright (c) 1995 Brini.
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  * 3. All advertising materials mentioning features or use of this software
     17  *    must display the following acknowledgement:
     18  *	This product includes software developed by Brini.
     19  * 4. The name of the company nor the name of the author may be used to
     20  *    endorse or promote products derived from this software without specific
     21  *    prior written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
     24  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     25  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     26  * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
     27  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     28  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     29  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33  * SUCH DAMAGE.
     34  *
     35  * RiscBSD kernel project
     36  *
     37  * cpu.c
     38  *
     39  * Probing and configuration for the master cpu
     40  *
     41  * Created      : 10/10/95
     42  */
     43 
     44 #include "opt_armfpe.h"
     45 #include "opt_cputypes.h"
     46 
     47 #include <sys/param.h>
     48 
     49 __RCSID("$NetBSD: cpu.c,v 1.22 2002/03/10 00:44:09 bjh21 Exp $");
     50 
     51 #include <sys/systm.h>
     52 #include <sys/malloc.h>
     53 #include <sys/device.h>
     54 #include <sys/proc.h>
     55 #include <uvm/uvm_extern.h>
     56 #include <machine/conf.h>
     57 #include <machine/cpu.h>
     58 #include <arm/undefined.h>
     59 
     60 #include <arm/cpus.h>
     61 
     62 #ifdef ARMFPE
     63 #include <machine/bootconfig.h> /* For boot args */
     64 #include <arm/fpe-arm/armfpe.h>
     65 #endif
     66 
     67 cpu_t cpus[MAX_CPUS];
     68 
     69 char cpu_model[256];
     70 volatile int undefined_test;	/* Used for FPA test */
     71 
     72 /* Prototypes */
     73 void identify_master_cpu(struct device *dv, int cpu_number);
     74 void identify_arm_cpu(struct device *dv, int cpu_number, struct cpu_info *);
     75 void identify_arm_fpu(struct device *dv, int cpu_number);
     76 int fpa_test(u_int, u_int, trapframe_t *, int);
     77 int fpa_handler(u_int, u_int, trapframe_t *, int);
     78 
     79 /*
     80  * void cpusattach(struct device *parent, struct device *dev, void *aux)
     81  *
     82  * Attach the main cpu
     83  */
     84 
     85 void
     86 cpu_attach(struct device *dv)
     87 {
     88 
     89 	identify_master_cpu(dv, CPU_MASTER);
     90 }
     91 
     92 /*
     93  * Used to test for an FPA. The following function is installed as a coproc1
     94  * handler on the undefined instruction vector and then we issue a FPA
     95  * instruction. If undefined_test is non zero then the FPA did not handle
     96  * the instruction so must be absent.
     97  */
     98 
     99 int
    100 fpa_test(u_int address, u_int instruction, trapframe_t *frame, int fault_code)
    101 {
    102 
    103 	frame->tf_pc += INSN_SIZE;
    104 	++undefined_test;
    105 	return(0);
    106 }
    107 
    108 /*
    109  * If an FPA was found then this function is installed as the coproc1 handler
    110  * on the undefined instruction vector. Currently we don't support FPA's
    111  * so this just triggers an exception.
    112  */
    113 
    114 int
    115 fpa_handler(u_int address, u_int instruction, trapframe_t *frame,
    116     int fault_code)
    117 {
    118 	u_int fpsr;
    119 
    120 	__asm __volatile("rfs %0" : "=r" (fpsr));
    121 
    122 	printf("FPA exception: fpsr = %08x\n", fpsr);
    123 
    124 	return(1);
    125 }
    126 
    127 
    128 /*
    129  * Identify the master (boot) CPU
    130  * This also probes for an FPU and will install an FPE if necessary
    131  */
    132 
    133 void
    134 identify_master_cpu(struct device *dv, int cpu_number)
    135 {
    136 	u_int fpsr;
    137 	void *uh;
    138 
    139 	evcnt_attach_dynamic(&curcpu()->ci_arm700bugcount, EVCNT_TYPE_MISC,
    140 	    NULL, dv->dv_xname, "arm700swibug");
    141 
    142 	/* Get the cpu ID from coprocessor 15 */
    143 
    144 	curcpu()->ci_cpuid = cpu_id();
    145 
    146 	identify_arm_cpu(dv, cpu_number, curcpu());
    147 
    148 	if ((curcpu()->ci_cpuid & CPU_ID_CPU_MASK) == CPU_ID_SA110
    149 	    && (curcpu()->ci_cpuid & CPU_ID_REVISION_MASK) < 3) {
    150 		printf("%s: SA-110 with bugged STM^ instruction\n",
    151 		       dv->dv_xname);
    152 	}
    153 
    154 #ifdef CPU_ARM8
    155 	if ((curcpu()->ci_cpuid & CPU_ID_CPU_MASK) == CPU_ID_ARM810) {
    156 		int clock = arm8_clock_config(0, 0);
    157 		char *fclk;
    158 		printf("%s: ARM810 cp15=%02x", dv->dv_xname, clock);
    159 		printf(" clock:%s", (clock & 1) ? " dynamic" : "");
    160 		printf("%s", (clock & 2) ? " sync" : "");
    161 		switch ((clock >> 2) & 3) {
    162 		case 0:
    163 			fclk = "bus clock";
    164 			break;
    165 		case 1:
    166 			fclk = "ref clock";
    167 			break;
    168 		case 3:
    169 			fclk = "pll";
    170 			break;
    171 		default:
    172 			fclk = "illegal";
    173 			break;
    174 		}
    175 		printf(" fclk source=%s\n", fclk);
    176  	}
    177 #endif
    178 
    179 	/*
    180 	 * Ok now we test for an FPA
    181 	 * At this point no floating point emulator has been installed.
    182 	 * This means any FP instruction will cause undefined exception.
    183 	 * We install a temporay coproc 1 handler which will modify
    184 	 * undefined_test if it is called.
    185 	 * We then try to read the FP status register. If undefined_test
    186 	 * has been decremented then the instruction was not handled by
    187 	 * an FPA so we know the FPA is missing. If undefined_test is
    188 	 * still 1 then we know the instruction was handled by an FPA.
    189 	 * We then remove our test handler and look at the
    190 	 * FP status register for identification.
    191 	 */
    192 
    193 	uh = install_coproc_handler(FP_COPROC, fpa_test);
    194 
    195 	undefined_test = 0;
    196 
    197 	__asm __volatile("rfs %0" : "=r" (fpsr));
    198 
    199 	remove_coproc_handler(uh);
    200 
    201 	if (undefined_test == 0) {
    202 		cpus[cpu_number].fpu_type = (fpsr >> 24);
    203 	        switch (fpsr >> 24) {
    204 		case 0x81:
    205 			cpus[cpu_number].fpu_class = FPU_CLASS_FPA;
    206 			break;
    207 
    208 		default:
    209 			cpus[cpu_number].fpu_class = FPU_CLASS_FPU;
    210 			break;
    211 		}
    212 		install_coproc_handler(FP_COPROC, fpa_handler);
    213 	} else {
    214 		cpus[cpu_number].fpu_class = FPU_CLASS_NONE;
    215 
    216 		/*
    217 		 * Ok if ARMFPE is defined and the boot options request the
    218 		 * ARM FPE then it will be installed as the FPE.
    219 		 * This is just while I work on integrating the new FPE.
    220 		 * It means the new FPE gets installed if compiled int (ARMFPE
    221 		 * defined) and also gives me a on/off option when I boot in
    222 		 * case the new FPE is causing panics.
    223 		 */
    224 
    225 #ifdef ARMFPE
    226 		if (boot_args) {
    227 			int usearmfpe = 1;
    228 
    229 			get_bootconf_option(boot_args, "armfpe",
    230 			    BOOTOPT_TYPE_BOOLEAN, &usearmfpe);
    231 			if (usearmfpe) {
    232 				if (initialise_arm_fpe(&cpus[cpu_number]) != 0)
    233 					identify_arm_fpu(dv, cpu_number);
    234 			}
    235 		}
    236 
    237 #endif
    238 	}
    239 
    240 	identify_arm_fpu(dv, cpu_number);
    241 }
    242 
    243 enum cpu_class {
    244 	CPU_CLASS_NONE,
    245 	CPU_CLASS_ARM2,
    246 	CPU_CLASS_ARM2AS,
    247 	CPU_CLASS_ARM3,
    248 	CPU_CLASS_ARM6,
    249 	CPU_CLASS_ARM7,
    250 	CPU_CLASS_ARM7TDMI,
    251 	CPU_CLASS_ARM8,
    252 	CPU_CLASS_ARM9TDMI,
    253 	CPU_CLASS_ARM9ES,
    254 	CPU_CLASS_SA1,
    255 	CPU_CLASS_XSCALE,
    256 };
    257 
    258 static const char *generic_steppings[16] = {
    259 	"rev 0",	"rev 1",	"rev 2",	"rev 3",
    260 	"rev 4",	"rev 5",	"rev 6",	"rev 7",
    261 	"rev 8",	"rev 9",	"rev 10",	"rev 11",
    262 	"rev 12",	"rev 13",	"rev 14",	"rev 15",
    263 };
    264 
    265 static const char *sa110_steppings[16] = {
    266 	"rev 0",	"step J",	"step K",	"step S",
    267 	"step T",	"rev 5",	"rev 6",	"rev 7",
    268 	"rev 8",	"rev 9",	"rev 10",	"rev 11",
    269 	"rev 12",	"rev 13",	"rev 14",	"rev 15",
    270 };
    271 
    272 static const char *sa1100_steppings[16] = {
    273 	"rev 0",	"step B",	"step C",	"rev 3",
    274 	"rev 4",	"rev 5",	"rev 6",	"rev 7",
    275 	"step D",	"step E",	"rev 10"	"step G",
    276 	"rev 12",	"rev 13",	"rev 14",	"rev 15",
    277 };
    278 
    279 static const char *sa1110_steppings[16] = {
    280 	"step A-0",	"rev 1",	"rev 2",	"rev 3",
    281 	"step B-0",	"step B-1",	"step B-2",	"step B-3",
    282 	"step B-4",	"step B-5",	"rev 10",	"rev 11",
    283 	"rev 12",	"rev 13",	"rev 14",	"rev 15",
    284 };
    285 
    286 static const char *i80200_steppings[16] = {
    287 	"step A-0",	"step A-1",	"step B-0",	"step C-0",
    288 	"rev 4",	"rev 5",	"rev 6",	"rev 7",
    289 	"rev 8",	"rev 9",	"rev 10",	"rev 11",
    290 	"rev 12",	"rev 13",	"rev 14",	"rev 15",
    291 };
    292 
    293 struct cpuidtab {
    294 	u_int32_t	cpuid;
    295 	enum		cpu_class cpu_class;
    296 	const char	*cpu_name;
    297 	const char	**cpu_steppings;
    298 };
    299 
    300 const struct cpuidtab cpuids[] = {
    301 	{ CPU_ID_ARM2,		CPU_CLASS_ARM2,		"ARM2",
    302 	  generic_steppings },
    303 	{ CPU_ID_ARM250,	CPU_CLASS_ARM2AS,	"ARM250",
    304 	  generic_steppings },
    305 
    306 	{ CPU_ID_ARM3,		CPU_CLASS_ARM3,		"ARM3",
    307 	  generic_steppings },
    308 
    309 	{ CPU_ID_ARM600,	CPU_CLASS_ARM6,		"ARM600",
    310 	  generic_steppings },
    311 	{ CPU_ID_ARM610,	CPU_CLASS_ARM6,		"ARM610",
    312 	  generic_steppings },
    313 	{ CPU_ID_ARM620,	CPU_CLASS_ARM6,		"ARM620",
    314 	  generic_steppings },
    315 
    316 	{ CPU_ID_ARM700,	CPU_CLASS_ARM7,		"ARM700",
    317 	  generic_steppings },
    318 	{ CPU_ID_ARM710,	CPU_CLASS_ARM7,		"ARM710",
    319 	  generic_steppings },
    320 	{ CPU_ID_ARM7500,	CPU_CLASS_ARM7,		"ARM7500",
    321 	  generic_steppings },
    322 	{ CPU_ID_ARM710A,	CPU_CLASS_ARM7,		"ARM710a",
    323 	  generic_steppings },
    324 	{ CPU_ID_ARM7500FE,	CPU_CLASS_ARM7,		"ARM7500FE",
    325 	  generic_steppings },
    326 	{ CPU_ID_ARM710T,	CPU_CLASS_ARM7TDMI,	"ARM710T",
    327 	  generic_steppings },
    328 	{ CPU_ID_ARM720T,	CPU_CLASS_ARM7TDMI,	"ARM720T",
    329 	  generic_steppings },
    330 	{ CPU_ID_ARM740T8K,	CPU_CLASS_ARM7TDMI, "ARM740T (8 KB cache)",
    331 	  generic_steppings },
    332 	{ CPU_ID_ARM740T4K,	CPU_CLASS_ARM7TDMI, "ARM740T (4 KB cache)",
    333 	  generic_steppings },
    334 
    335 	{ CPU_ID_ARM810,	CPU_CLASS_ARM8,		"ARM810",
    336 	  generic_steppings },
    337 
    338 	{ CPU_ID_ARM920T,	CPU_CLASS_ARM9TDMI,	"ARM920T",
    339 	  generic_steppings },
    340 	{ CPU_ID_ARM922T,	CPU_CLASS_ARM9TDMI,	"ARM922T",
    341 	  generic_steppings },
    342 	{ CPU_ID_ARM940T,	CPU_CLASS_ARM9TDMI,	"ARM940T",
    343 	  generic_steppings },
    344 	{ CPU_ID_ARM946ES,	CPU_CLASS_ARM9ES,	"ARM946E-S",
    345 	  generic_steppings },
    346 	{ CPU_ID_ARM966ES,	CPU_CLASS_ARM9ES,	"ARM966E-S",
    347 	  generic_steppings },
    348 	{ CPU_ID_ARM966ESR1,	CPU_CLASS_ARM9ES,	"ARM966E-S",
    349 	  generic_steppings },
    350 
    351 	{ CPU_ID_SA110,		CPU_CLASS_SA1,		"SA-110",
    352 	  sa110_steppings },
    353 	{ CPU_ID_SA1100,	CPU_CLASS_SA1,		"SA-1100",
    354 	  sa1100_steppings },
    355 	{ CPU_ID_SA1110,	CPU_CLASS_SA1,		"SA-1110",
    356 	  sa1110_steppings },
    357 
    358 	{ CPU_ID_I80200,	CPU_CLASS_XSCALE,	"i80200",
    359 	  i80200_steppings },
    360 
    361 	{ 0, CPU_CLASS_NONE, NULL, NULL }
    362 };
    363 
    364 struct cpu_classtab {
    365 	const char	*class_name;
    366 	const char	*class_option;
    367 };
    368 
    369 const struct cpu_classtab cpu_classes[] = {
    370 	{ "unknown",	NULL },			/* CPU_CLASS_NONE */
    371 	{ "ARM2",	"CPU_ARM2" },		/* CPU_CLASS_ARM2 */
    372 	{ "ARM2as",	"CPU_ARM250" },		/* CPU_CLASS_ARM2AS */
    373 	{ "ARM3",	"CPU_ARM3" },		/* CPU_CLASS_ARM3 */
    374 	{ "ARM6",	"CPU_ARM6" },		/* CPU_CLASS_ARM6 */
    375 	{ "ARM7",	"CPU_ARM7" },		/* CPU_CLASS_ARM7 */
    376 	{ "ARM7TDMI",	"CPU_ARM7TDMI" },	/* CPU_CLASS_ARM7TDMI */
    377 	{ "ARM8",	"CPU_ARM8" },		/* CPU_CLASS_ARM8 */
    378 	{ "ARM9TDMI",	NULL },			/* CPU_CLASS_ARM9TDMI */
    379 	{ "ARM9E-S",	NULL },			/* CPU_CLASS_ARM9ES */
    380 	{ "SA-1",	"CPU_SA110" },		/* CPU_CLASS_SA1 */
    381 	{ "XScale",	"CPU_XSCALE" },		/* CPU_CLASS_XSCALE */
    382 };
    383 
    384 /*
    385  * Report the type of the specifed arm processor. This uses the generic and
    386  * arm specific information in the cpu structure to identify the processor.
    387  * The remaining fields in the cpu structure are filled in appropriately.
    388  */
    389 
    390 static const char *wtnames[] = {
    391 	"write-through",
    392 	"write-back",
    393 	"write-back",
    394 	"**unknown 3**",
    395 	"**unknown 4**",
    396 	"write-back-locking",		/* XXX XScale-specific? */
    397 	"write-back-locking-A",
    398 	"write-back-locking-B",
    399 	"**unknown 8**",
    400 	"**unknown 9**",
    401 	"**unknown 10**",
    402 	"**unknown 11**",
    403 	"**unknown 12**",
    404 	"**unknown 13**",
    405 	"**unknown 14**",
    406 	"**unknown 15**",
    407 };
    408 
    409 void
    410 identify_arm_cpu(struct device *dv, int cpu_number, struct cpu_info *ci)
    411 {
    412 	cpu_t *cpu;
    413 	u_int cpuid;
    414 	enum cpu_class cpu_class;
    415 	int i;
    416 
    417 	cpu = &cpus[cpu_number];
    418 	cpuid = ci->ci_cpuid;
    419 
    420 	if (cpuid == 0) {
    421 		printf("Processor failed probe - no CPU ID\n");
    422 		return;
    423 	}
    424 
    425 	for (i = 0; cpuids[i].cpuid != 0; i++)
    426 		if (cpuids[i].cpuid == (cpuid & CPU_ID_CPU_MASK)) {
    427 			cpu_class = cpuids[i].cpu_class;
    428 			sprintf(cpu_model, "%s %s (%s core)",
    429 			    cpuids[i].cpu_name,
    430 			    cpuids[i].cpu_steppings[cpuid &
    431 						    CPU_ID_REVISION_MASK],
    432 			    cpu_classes[cpu_class].class_name);
    433 			break;
    434 		}
    435 
    436 	if (cpuids[i].cpuid == 0)
    437 		sprintf(cpu_model, "unknown CPU (ID = 0x%x)", cpuid);
    438 
    439 	switch (cpu_class) {
    440 	case CPU_CLASS_ARM6:
    441 	case CPU_CLASS_ARM7:
    442 	case CPU_CLASS_ARM7TDMI:
    443 	case CPU_CLASS_ARM8:
    444 		if ((ci->ci_ctrl & CPU_CONTROL_IDC_ENABLE) == 0)
    445 			strcat(cpu_model, " IDC disabled");
    446 		else
    447 			strcat(cpu_model, " IDC enabled");
    448 		break;
    449 	case CPU_CLASS_ARM9TDMI:
    450 	case CPU_CLASS_SA1:
    451 	case CPU_CLASS_XSCALE:
    452 		if ((ci->ci_ctrl & CPU_CONTROL_DC_ENABLE) == 0)
    453 			strcat(cpu_model, " DC disabled");
    454 		else
    455 			strcat(cpu_model, " DC enabled");
    456 		if ((ci->ci_ctrl & CPU_CONTROL_IC_ENABLE) == 0)
    457 			strcat(cpu_model, " IC disabled");
    458 		else
    459 			strcat(cpu_model, " IC enabled");
    460 		break;
    461 	default:
    462 		break;
    463 	}
    464 	if ((ci->ci_ctrl & CPU_CONTROL_WBUF_ENABLE) == 0)
    465 		strcat(cpu_model, " WB disabled");
    466 	else
    467 		strcat(cpu_model, " WB enabled");
    468 
    469 	if (ci->ci_ctrl & CPU_CONTROL_LABT_ENABLE)
    470 		strcat(cpu_model, " LABT");
    471 	else
    472 		strcat(cpu_model, " EABT");
    473 
    474 	if (ci->ci_ctrl & CPU_CONTROL_BPRD_ENABLE)
    475 		strcat(cpu_model, " branch prediction enabled");
    476 
    477 	/* Print the info */
    478 	printf(": %s\n", cpu_model);
    479 
    480 	/* Print cache info. */
    481 	if (arm_picache_line_size == 0 && arm_pdcache_line_size == 0)
    482 		goto skip_pcache;
    483 
    484 	if (arm_pcache_unified) {
    485 		printf("%s: %dKB/%dB %d-way %s unified cache\n",
    486 		    dv->dv_xname, arm_pdcache_size / 1024,
    487 		    arm_pdcache_line_size, arm_pdcache_ways,
    488 		    wtnames[arm_pcache_type]);
    489 	} else {
    490 		printf("%s: %dKB/%dB %d-way Instruction cache\n",
    491 		    dv->dv_xname, arm_picache_size / 1024,
    492 		    arm_picache_line_size, arm_picache_ways);
    493 		printf("%s: %dKB/%dB %d-way %s Data cache\n",
    494 		    dv->dv_xname, arm_pdcache_size / 1024,
    495 		    arm_pdcache_line_size, arm_pdcache_ways,
    496 		    wtnames[arm_pcache_type]);
    497 	}
    498 
    499  skip_pcache:
    500 
    501 	switch (cpu_class) {
    502 #ifdef CPU_ARM2
    503 	case CPU_CLASS_ARM2:
    504 #endif
    505 #ifdef CPU_ARM250
    506 	case CPU_CLASS_ARM2AS:
    507 #endif
    508 #ifdef CPU_ARM3
    509 	case CPU_CLASS_ARM3:
    510 #endif
    511 #ifdef CPU_ARM6
    512 	case CPU_CLASS_ARM6:
    513 #endif
    514 #ifdef CPU_ARM7
    515 	case CPU_CLASS_ARM7:
    516 #endif
    517 #ifdef CPU_ARM7TDMI
    518 	case CPU_CLASS_ARM7TDMI:
    519 #endif
    520 #ifdef CPU_ARM8
    521 	case CPU_CLASS_ARM8:
    522 #endif
    523 #ifdef CPU_ARM9
    524 	case CPU_CLASS_ARM9TDMI:
    525 #endif
    526 #ifdef CPU_SA110
    527 	case CPU_CLASS_SA1:
    528 #endif
    529 #ifdef CPU_XSCALE
    530 	case CPU_CLASS_XSCALE:
    531 #endif
    532 		break;
    533 	default:
    534 		if (cpu_classes[cpu_class].class_option != NULL)
    535 			printf("%s: %s does not fully support this CPU."
    536 			       "\n", dv->dv_xname, ostype);
    537 		else {
    538 			printf("%s: This kernel does not fully support "
    539 			       "this CPU.\n", dv->dv_xname);
    540 			printf("%s: Recompile with \"options %s\" to "
    541 			       "correct this.\n", dv->dv_xname,
    542 			       cpu_classes[cpu_class].class_option);
    543 		}
    544 		break;
    545 	}
    546 
    547 }
    548 
    549 
    550 /*
    551  * Report the type of the specifed arm fpu. This uses the generic and arm
    552  * specific information in the cpu structure to identify the fpu. The
    553  * remaining fields in the cpu structure are filled in appropriately.
    554  */
    555 
    556 void
    557 identify_arm_fpu(struct device *dv, int cpu_number)
    558 {
    559 	cpu_t *cpu;
    560 
    561 	cpu = &cpus[cpu_number];
    562 
    563 	/* Now for the FP info */
    564 
    565 	switch (cpu->fpu_class) {
    566 	case FPU_CLASS_NONE :
    567 		strcpy(cpu->fpu_model, "None");
    568 		break;
    569 	case FPU_CLASS_FPE :
    570 		printf("%s: FPE: %s\n", dv->dv_xname, cpu->fpu_model);
    571 		printf("%s: no FP hardware found\n", dv->dv_xname);
    572 		break;
    573 	case FPU_CLASS_FPA :
    574 		printf("%s: FPE: %s\n", dv->dv_xname, cpu->fpu_model);
    575 		if (cpu->fpu_type == FPU_TYPE_FPA11) {
    576 			strcpy(cpu->fpu_model, "FPA11");
    577 			printf("%s: FPA11 found\n", dv->dv_xname);
    578 		} else {
    579 			strcpy(cpu->fpu_model, "FPA");
    580 			printf("%s: FPA10 found\n", dv->dv_xname);
    581 		}
    582 	case FPU_CLASS_FPU :
    583 		sprintf(cpu->fpu_model, "Unknown FPU (ID=%02x)\n",
    584 		    cpu->fpu_type);
    585 		printf("%s: %s\n", dv->dv_xname, cpu->fpu_model);
    586 		break;
    587 	}
    588 }
    589 
    590 /* End of cpu.c */
    591