1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2015 Google, Inc
4  */
5 
6 #include <common.h>
7 #include <cpu.h>
8 #include <dm.h>
9 #include <malloc.h>
10 #include <qfw.h>
11 #include <dm/lists.h>
12 #include <dm/uclass-internal.h>
13 #include <dm/root.h>
14 
qemu_cpu_fixup(void)15 int qemu_cpu_fixup(void)
16 {
17 	int ret;
18 	int cpu_num;
19 	int cpu_online;
20 	struct uclass *uc;
21 	struct udevice *dev, *pdev;
22 	struct cpu_plat *plat;
23 	char *cpu;
24 
25 	/* This will cause the CPUs devices to be bound */
26 	ret = uclass_get(UCLASS_CPU, &uc);
27 	if (ret)
28 		return ret;
29 
30 	/* first we need to find '/cpus' */
31 	for (device_find_first_child(dm_root(), &pdev);
32 	     pdev;
33 	     device_find_next_child(&pdev)) {
34 		if (!strcmp(pdev->name, "cpus"))
35 			break;
36 	}
37 	if (!pdev) {
38 		printf("unable to find cpus device\n");
39 		return -ENODEV;
40 	}
41 
42 	/* calculate cpus that are already bound */
43 	cpu_num = 0;
44 	for (uclass_find_first_device(UCLASS_CPU, &dev);
45 	     dev;
46 	     uclass_find_next_device(&dev)) {
47 		cpu_num++;
48 	}
49 
50 	/* get actual cpu number */
51 	cpu_online = qemu_fwcfg_online_cpus();
52 	if (cpu_online < 0) {
53 		printf("unable to get online cpu number: %d\n", cpu_online);
54 		return cpu_online;
55 	}
56 
57 	/* bind addtional cpus */
58 	dev = NULL;
59 	for (; cpu_num < cpu_online; cpu_num++) {
60 		/*
61 		 * allocate device name here as device_bind_driver() does
62 		 * not copy device name, 8 bytes are enough for
63 		 * sizeof("cpu@") + 3 digits cpu number + '\0'
64 		 */
65 		cpu = malloc(8);
66 		if (!cpu) {
67 			printf("unable to allocate device name\n");
68 			return -ENOMEM;
69 		}
70 		sprintf(cpu, "cpu@%d", cpu_num);
71 		ret = device_bind_driver(pdev, "cpu_qemu", cpu, &dev);
72 		if (ret) {
73 			printf("binding cpu@%d failed: %d\n", cpu_num, ret);
74 			return ret;
75 		}
76 		plat = dev_get_parent_plat(dev);
77 		plat->cpu_id = cpu_num;
78 	}
79 	return 0;
80 }
81