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, *qfwdev;
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 	/* get qfw dev */
43 	ret = qfw_get_dev(&qfwdev);
44 	if (ret) {
45 		printf("unable to find qfw device\n");
46 		return ret;
47 	}
48 
49 	/* calculate cpus that are already bound */
50 	cpu_num = 0;
51 	for (uclass_find_first_device(UCLASS_CPU, &dev);
52 	     dev;
53 	     uclass_find_next_device(&dev)) {
54 		cpu_num++;
55 	}
56 
57 	/* get actual cpu number */
58 	cpu_online = qfw_online_cpus(qfwdev);
59 	if (cpu_online < 0) {
60 		printf("unable to get online cpu number: %d\n", cpu_online);
61 		return cpu_online;
62 	}
63 
64 	/* bind addtional cpus */
65 	dev = NULL;
66 	for (; cpu_num < cpu_online; cpu_num++) {
67 		/*
68 		 * allocate device name here as device_bind_driver() does
69 		 * not copy device name, 8 bytes are enough for
70 		 * sizeof("cpu@") + 3 digits cpu number + '\0'
71 		 */
72 		cpu = malloc(8);
73 		if (!cpu) {
74 			printf("unable to allocate device name\n");
75 			return -ENOMEM;
76 		}
77 		sprintf(cpu, "cpu@%d", cpu_num);
78 		ret = device_bind_driver(pdev, "cpu_qemu", cpu, &dev);
79 		if (ret) {
80 			printf("binding cpu@%d failed: %d\n", cpu_num, ret);
81 			return ret;
82 		}
83 		plat = dev_get_parent_plat(dev);
84 		plat->cpu_id = cpu_num;
85 	}
86 	return 0;
87 }
88