blob: d970429ff23232379e3daf60b50b8601a47e7b1c [file] [log] [blame]
Uwe Hermannb80dbf02007-04-22 19:08:13 +00001/*
Stefan Reinauer7e61e452008-01-18 10:35:56 +00002 * This file is part of the coreboot project.
Uwe Hermannb80dbf02007-04-22 19:08:13 +00003 *
4 * Copyright (C) 2003-2004 Linux Networx
5 * (Written by Eric Biederman <ebiederman@lnxi.com> for Linux Networx)
6 * Copyright (C) 2003 Greg Watson <jarrah@users.sourceforge.net>
7 * Copyright (C) 2004 Li-Ta Lo <ollie@lanl.gov>
8 * Copyright (C) 2005-2006 Tyan
9 * (Written by Yinghai Lu <yhlu@tyan.com> for Tyan)
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; version 2 of the License.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
Paul Menzela46a7122013-02-23 18:37:27 +010022 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Uwe Hermannb80dbf02007-04-22 19:08:13 +000023 */
24
Eric Biederman8ca8d762003-04-22 19:02:15 +000025#include <console/console.h>
Eric Biederman5899fd82003-04-24 06:25:08 +000026#include <device/device.h>
Eric Biedermane9a271e32003-09-02 03:36:25 +000027#include <device/path.h>
Kyösti Mälkki318066f2014-02-12 14:18:50 +020028#include <device/pci_def.h>
Eric Biedermanf8a2ddd2004-10-30 08:05:41 +000029#include <device/resource.h>
Eric Biedermane9a271e32003-09-02 03:36:25 +000030#include <string.h>
31
Eric Biederman03acab62004-10-14 21:25:53 +000032/**
Uwe Hermannc1ee4292010-10-17 19:01:48 +000033 * See if a device structure exists for path.
Eric Biederman03acab62004-10-14 21:25:53 +000034 *
Uwe Hermannc1ee4292010-10-17 19:01:48 +000035 * @param parent The bus to find the device on.
36 * @param path The relative path from the bus to the appropriate device.
37 * @return Pointer to a device structure for the device on bus at path
38 * or 0/NULL if no device is found.
Eric Biederman03acab62004-10-14 21:25:53 +000039 */
40device_t find_dev_path(struct bus *parent, struct device_path *path)
41{
42 device_t child;
Myles Watson894a3472010-06-09 22:41:35 +000043 for (child = parent->children; child; child = child->sibling) {
Uwe Hermanne4870472010-11-04 23:23:47 +000044 if (path_eq(path, &child->path))
Eric Biederman03acab62004-10-14 21:25:53 +000045 break;
Eric Biederman03acab62004-10-14 21:25:53 +000046 }
47 return child;
48}
Eric Biedermane9a271e32003-09-02 03:36:25 +000049
50/**
Uwe Hermannc1ee4292010-10-17 19:01:48 +000051 * Given a PCI bus and a devfn number, find the device structure.
Li-Ta Loe8b1c9d2004-12-27 04:25:41 +000052 *
Uwe Hermannc1ee4292010-10-17 19:01:48 +000053 * @param bus The bus number.
54 * @param devfn A device/function number.
55 * @return Pointer to the device structure (if found), 0 otherwise.
Eric Biederman8ca8d762003-04-22 19:02:15 +000056 */
57struct device *dev_find_slot(unsigned int bus, unsigned int devfn)
58{
Eric Biederman83b991a2003-10-11 06:20:25 +000059 struct device *dev, *result;
Eric Biederman8ca8d762003-04-22 19:02:15 +000060
Eric Biederman83b991a2003-10-11 06:20:25 +000061 result = 0;
Eric Biedermane9a271e32003-09-02 03:36:25 +000062 for (dev = all_devices; dev; dev = dev->next) {
Eric Biederman5cd81732004-03-11 15:01:31 +000063 if ((dev->path.type == DEVICE_PATH_PCI) &&
Uwe Hermanne4870472010-11-04 23:23:47 +000064 (dev->bus->secondary == bus) &&
65 (dev->path.pci.devfn == devfn)) {
Eric Biederman83b991a2003-10-11 06:20:25 +000066 result = dev;
Eric Biederman8ca8d762003-04-22 19:02:15 +000067 break;
Eric Biedermane9a271e32003-09-02 03:36:25 +000068 }
69 }
Eric Biederman83b991a2003-10-11 06:20:25 +000070 return result;
Eric Biederman8ca8d762003-04-22 19:02:15 +000071}
72
arch import user (historical)98d0d302005-07-06 17:13:46 +000073/**
Uwe Hermannc1ee4292010-10-17 19:01:48 +000074 * Given an SMBus bus and a device number, find the device structure.
arch import user (historical)98d0d302005-07-06 17:13:46 +000075 *
Uwe Hermannc1ee4292010-10-17 19:01:48 +000076 * @param bus The bus number.
77 * @param addr A device number.
78 * @return Pointer to the device structure (if found), 0 otherwise.
arch import user (historical)98d0d302005-07-06 17:13:46 +000079 */
80struct device *dev_find_slot_on_smbus(unsigned int bus, unsigned int addr)
81{
Uwe Hermanne4870472010-11-04 23:23:47 +000082 struct device *dev, *result;
Stefan Reinauer14e22772010-04-27 06:56:47 +000083
Uwe Hermanne4870472010-11-04 23:23:47 +000084 result = 0;
85 for (dev = all_devices; dev; dev = dev->next) {
86 if ((dev->path.type == DEVICE_PATH_I2C) &&
87 (dev->bus->secondary == bus) &&
88 (dev->path.i2c.device == addr)) {
89 result = dev;
90 break;
91 }
92 }
93 return result;
Stefan Reinauer14e22772010-04-27 06:56:47 +000094}
arch import user (historical)98d0d302005-07-06 17:13:46 +000095
Uwe Hermannc1ee4292010-10-17 19:01:48 +000096/**
Vladimir Serbinenko400c05c2014-02-04 14:34:11 +010097 * Given a PnP port and a device number, find the device structure.
98 *
99 * @param port The I/O port.
100 * @param device Logical device number.
101 * @return Pointer to the device structure (if found), 0 otherwise.
102 */
Vladimir Serbinenkob33384a2014-02-08 18:58:39 +0100103struct device *dev_find_slot_pnp(u16 port, u16 device)
Vladimir Serbinenko400c05c2014-02-04 14:34:11 +0100104{
105 struct device *dev;
106
107 for (dev = all_devices; dev; dev = dev->next) {
108 if ((dev->path.type == DEVICE_PATH_PNP) &&
109 (dev->path.pnp.port == port) &&
110 (dev->path.pnp.device == device)) {
111 return dev;
112 }
113 }
114 return 0;
115}
116
117/**
Duncan Laurie6f88a6e2011-07-18 10:41:36 -0700118 * Given a Local APIC ID, find the device structure.
119 *
120 * @param apic_id The Local APIC ID number.
121 * @return Pointer to the device structure (if found), 0 otherwise.
122 */
123device_t dev_find_lapic(unsigned apic_id)
124{
125 device_t dev, result = NULL;
126
127 for (dev = all_devices; dev; dev = dev->next) {
128 if (dev->path.type == DEVICE_PATH_APIC &&
129 dev->path.apic.apic_id == apic_id) {
130 result = dev;
131 break;
132 }
133 }
134 return result;
135}
136
137/**
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000138 * Find a device of a given vendor and type.
139 *
140 * @param vendor A PCI vendor ID (e.g. 0x8086 for Intel).
141 * @param device A PCI device ID.
Uwe Hermanne4870472010-11-04 23:23:47 +0000142 * @param from Pointer to the device structure, used as a starting point in
143 * the linked list of all_devices, which can be 0 to start at the
144 * head of the list (i.e. all_devices).
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000145 * @return Pointer to the device struct.
Eric Biederman8ca8d762003-04-22 19:02:15 +0000146 */
Uwe Hermanne4870472010-11-04 23:23:47 +0000147struct device *dev_find_device(u16 vendor, u16 device, struct device *from)
Eric Biederman8ca8d762003-04-22 19:02:15 +0000148{
149 if (!from)
150 from = all_devices;
151 else
152 from = from->next;
Uwe Hermanne4870472010-11-04 23:23:47 +0000153
154 while (from && (from->vendor != vendor || from->device != device))
Eric Biederman8ca8d762003-04-22 19:02:15 +0000155 from = from->next;
Uwe Hermanne4870472010-11-04 23:23:47 +0000156
Eric Biederman8ca8d762003-04-22 19:02:15 +0000157 return from;
158}
159
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000160/**
161 * Find a device of a given class.
162 *
163 * @param class Class of the device.
Uwe Hermanne4870472010-11-04 23:23:47 +0000164 * @param from Pointer to the device structure, used as a starting point in
165 * the linked list of all_devices, which can be 0 to start at the
166 * head of the list (i.e. all_devices).
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000167 * @return Pointer to the device struct.
Eric Biederman8ca8d762003-04-22 19:02:15 +0000168 */
169struct device *dev_find_class(unsigned int class, struct device *from)
170{
171 if (!from)
172 from = all_devices;
173 else
174 from = from->next;
Uwe Hermanne4870472010-11-04 23:23:47 +0000175
Greg Watson59651692003-12-17 17:39:53 +0000176 while (from && (from->class & 0xffffff00) != class)
Eric Biederman8ca8d762003-04-22 19:02:15 +0000177 from = from->next;
Uwe Hermanne4870472010-11-04 23:23:47 +0000178
Eric Biederman8ca8d762003-04-22 19:02:15 +0000179 return from;
180}
181
Duncan Laurie5f5d9142013-06-10 09:59:17 -0700182/**
183 * Encode the device path into 3 bytes for logging to CMOS.
184 *
185 * @param dev The device path to encode.
186 * @return Device path encoded into lower 3 bytes of dword.
187 */
188u32 dev_path_encode(device_t dev)
189{
190 u32 ret;
191
192 if (!dev)
193 return 0;
194
195 /* Store the device type in 3rd byte. */
196 ret = dev->path.type << 16;
197
198 /* Encode the device specific path in the low word. */
199 switch (dev->path.type) {
200 case DEVICE_PATH_ROOT:
201 break;
202 case DEVICE_PATH_PCI:
203 ret |= dev->bus->secondary << 8 | dev->path.pci.devfn;
204 break;
205 case DEVICE_PATH_PNP:
206 ret |= dev->path.pnp.port << 8 | dev->path.pnp.device;
207 break;
208 case DEVICE_PATH_I2C:
209 ret |= dev->bus->secondary << 8 | dev->path.pnp.device;
210 break;
211 case DEVICE_PATH_APIC:
212 ret |= dev->path.apic.apic_id;
213 break;
214 case DEVICE_PATH_DOMAIN:
215 ret |= dev->path.domain.domain;
216 break;
217 case DEVICE_PATH_CPU_CLUSTER:
218 ret |= dev->path.cpu_cluster.cluster;
219 break;
220 case DEVICE_PATH_CPU:
221 ret |= dev->path.cpu.id;
222 break;
223 case DEVICE_PATH_CPU_BUS:
224 ret |= dev->path.cpu_bus.id;
225 break;
226 case DEVICE_PATH_IOAPIC:
227 ret |= dev->path.ioapic.ioapic_id;
228 break;
229 case DEVICE_PATH_NONE:
230 default:
231 break;
232 }
233
234 return ret;
235}
236
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000237/*
238 * Warning: This function uses a static buffer. Don't call it more than once
239 * from the same print statement!
240 */
Eric Biedermane9a271e32003-09-02 03:36:25 +0000241const char *dev_path(device_t dev)
242{
243 static char buffer[DEVICE_PATH_MAX];
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000244
Eric Biedermane9a271e32003-09-02 03:36:25 +0000245 buffer[0] = '\0';
246 if (!dev) {
247 memcpy(buffer, "<null>", 7);
Uwe Hermanne4870472010-11-04 23:23:47 +0000248 } else {
Eric Biedermane9a271e32003-09-02 03:36:25 +0000249 switch(dev->path.type) {
Eric Biederman83b991a2003-10-11 06:20:25 +0000250 case DEVICE_PATH_ROOT:
251 memcpy(buffer, "Root Device", 12);
252 break;
Eric Biedermane9a271e32003-09-02 03:36:25 +0000253 case DEVICE_PATH_PCI:
Vladimir Serbinenkoa37383d2013-11-26 02:41:26 +0100254 snprintf(buffer, sizeof (buffer),
255 "PCI: %02x:%02x.%01x",
256 dev->bus->secondary,
257 PCI_SLOT(dev->path.pci.devfn),
258 PCI_FUNC(dev->path.pci.devfn));
Eric Biedermane9a271e32003-09-02 03:36:25 +0000259 break;
260 case DEVICE_PATH_PNP:
Vladimir Serbinenkoa37383d2013-11-26 02:41:26 +0100261 snprintf(buffer, sizeof (buffer), "PNP: %04x.%01x",
262 dev->path.pnp.port, dev->path.pnp.device);
Eric Biedermane9a271e32003-09-02 03:36:25 +0000263 break;
264 case DEVICE_PATH_I2C:
Vladimir Serbinenkoa37383d2013-11-26 02:41:26 +0100265 snprintf(buffer, sizeof (buffer), "I2C: %02x:%02x",
266 dev->bus->secondary,
267 dev->path.i2c.device);
Eric Biedermane9a271e32003-09-02 03:36:25 +0000268 break;
Eric Biederman03acab62004-10-14 21:25:53 +0000269 case DEVICE_PATH_APIC:
Vladimir Serbinenkoa37383d2013-11-26 02:41:26 +0100270 snprintf(buffer, sizeof (buffer), "APIC: %02x",
271 dev->path.apic.apic_id);
Eric Biederman03acab62004-10-14 21:25:53 +0000272 break;
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200273 case DEVICE_PATH_IOAPIC:
Vladimir Serbinenkoa37383d2013-11-26 02:41:26 +0100274 snprintf(buffer, sizeof (buffer), "IOAPIC: %02x",
275 dev->path.ioapic.ioapic_id);
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200276 break;
Stefan Reinauer4aff4452013-02-12 14:17:15 -0800277 case DEVICE_PATH_DOMAIN:
Vladimir Serbinenkoa37383d2013-11-26 02:41:26 +0100278 snprintf(buffer, sizeof (buffer), "DOMAIN: %04x",
Stefan Reinauer4aff4452013-02-12 14:17:15 -0800279 dev->path.domain.domain);
Eric Biederman7003ba42004-10-16 06:20:29 +0000280 break;
Stefan Reinauer0aa37c42013-02-12 15:20:54 -0800281 case DEVICE_PATH_CPU_CLUSTER:
Vladimir Serbinenkoa37383d2013-11-26 02:41:26 +0100282 snprintf(buffer, sizeof (buffer), "CPU_CLUSTER: %01x",
Stefan Reinauer0aa37c42013-02-12 15:20:54 -0800283 dev->path.cpu_cluster.cluster);
Eric Biederman7003ba42004-10-16 06:20:29 +0000284 break;
Eric Biedermana9e632c2004-11-18 22:38:08 +0000285 case DEVICE_PATH_CPU:
Vladimir Serbinenkoa37383d2013-11-26 02:41:26 +0100286 snprintf(buffer, sizeof (buffer),
287 "CPU: %02x", dev->path.cpu.id);
Eric Biedermana9e632c2004-11-18 22:38:08 +0000288 break;
289 case DEVICE_PATH_CPU_BUS:
Vladimir Serbinenkoa37383d2013-11-26 02:41:26 +0100290 snprintf(buffer, sizeof (buffer),
291 "CPU_BUS: %02x", dev->path.cpu_bus.id);
Eric Biedermana9e632c2004-11-18 22:38:08 +0000292 break;
Eric Biedermane9a271e32003-09-02 03:36:25 +0000293 default:
Uwe Hermanne4870472010-11-04 23:23:47 +0000294 printk(BIOS_ERR, "Unknown device path type: %d\n",
295 dev->path.type);
Eric Biedermane9a271e32003-09-02 03:36:25 +0000296 break;
297 }
298 }
299 return buffer;
300}
301
Kyösti Mälkki7baadac2012-10-07 14:57:15 +0200302const char *dev_name(device_t dev)
303{
Kyösti Mälkki7d54eb82012-10-10 23:14:28 +0300304 if (dev->name)
305 return dev->name;
306 else if (dev->chip_ops && dev->chip_ops->name)
Kyösti Mälkki7baadac2012-10-07 14:57:15 +0200307 return dev->chip_ops->name;
308 else
309 return "unknown";
310}
311
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000312const char *bus_path(struct bus *bus)
313{
314 static char buffer[BUS_PATH_MAX];
Vladimir Serbinenkoa37383d2013-11-26 02:41:26 +0100315 snprintf(buffer, sizeof (buffer),
316 "%s,%d", dev_path(bus->dev), bus->link_num);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000317 return buffer;
318}
319
Eric Biedermane9a271e32003-09-02 03:36:25 +0000320int path_eq(struct device_path *path1, struct device_path *path2)
321{
322 int equal = 0;
Uwe Hermanne4870472010-11-04 23:23:47 +0000323
324 if (path1->type != path2->type)
325 return 0;
326
327 switch (path1->type) {
328 case DEVICE_PATH_NONE:
329 break;
330 case DEVICE_PATH_ROOT:
331 equal = 1;
332 break;
333 case DEVICE_PATH_PCI:
334 equal = (path1->pci.devfn == path2->pci.devfn);
335 break;
336 case DEVICE_PATH_PNP:
337 equal = (path1->pnp.port == path2->pnp.port) &&
338 (path1->pnp.device == path2->pnp.device);
339 break;
340 case DEVICE_PATH_I2C:
341 equal = (path1->i2c.device == path2->i2c.device);
342 break;
343 case DEVICE_PATH_APIC:
344 equal = (path1->apic.apic_id == path2->apic.apic_id);
345 break;
Stefan Reinauer4aff4452013-02-12 14:17:15 -0800346 case DEVICE_PATH_DOMAIN:
347 equal = (path1->domain.domain == path2->domain.domain);
Uwe Hermanne4870472010-11-04 23:23:47 +0000348 break;
Stefan Reinauer0aa37c42013-02-12 15:20:54 -0800349 case DEVICE_PATH_CPU_CLUSTER:
350 equal = (path1->cpu_cluster.cluster
351 == path2->cpu_cluster.cluster);
Uwe Hermanne4870472010-11-04 23:23:47 +0000352 break;
353 case DEVICE_PATH_CPU:
354 equal = (path1->cpu.id == path2->cpu.id);
355 break;
356 case DEVICE_PATH_CPU_BUS:
357 equal = (path1->cpu_bus.id == path2->cpu_bus.id);
358 break;
359 default:
Martin Roth63373ed2013-07-08 16:24:19 -0600360 printk(BIOS_ERR, "Unknown device type: %d\n", path1->type);
Uwe Hermanne4870472010-11-04 23:23:47 +0000361 break;
Eric Biedermane9a271e32003-09-02 03:36:25 +0000362 }
Uwe Hermanne4870472010-11-04 23:23:47 +0000363
Eric Biedermane9a271e32003-09-02 03:36:25 +0000364 return equal;
365}
Eric Biederman5cd81732004-03-11 15:01:31 +0000366
367/**
Myles Watsonc25cc112010-05-21 14:33:48 +0000368 * Allocate 64 more resources to the free list.
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000369 *
370 * @return TODO.
Myles Watsonc25cc112010-05-21 14:33:48 +0000371 */
372static int allocate_more_resources(void)
373{
374 int i;
375 struct resource *new_res_list;
Uwe Hermanne4870472010-11-04 23:23:47 +0000376
Myles Watsonc25cc112010-05-21 14:33:48 +0000377 new_res_list = malloc(64 * sizeof(*new_res_list));
378
379 if (new_res_list == NULL)
380 return 0;
381
382 memset(new_res_list, 0, 64 * sizeof(*new_res_list));
383
Uwe Hermanne4870472010-11-04 23:23:47 +0000384 for (i = 0; i < 64 - 1; i++)
Myles Watsonc25cc112010-05-21 14:33:48 +0000385 new_res_list[i].next = &new_res_list[i+1];
386
387 free_resources = new_res_list;
388 return 1;
389}
390
391/**
392 * Remove resource res from the device's list and add it to the free list.
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000393 *
394 * @param dev TODO
395 * @param res TODO
396 * @param prev TODO
397 * @return TODO.
Myles Watsonc25cc112010-05-21 14:33:48 +0000398 */
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000399static void free_resource(device_t dev, struct resource *res,
400 struct resource *prev)
Myles Watsonc25cc112010-05-21 14:33:48 +0000401{
402 if (prev)
403 prev->next = res->next;
404 else
405 dev->resource_list = res->next;
Uwe Hermanne4870472010-11-04 23:23:47 +0000406
Myles Watsonc25cc112010-05-21 14:33:48 +0000407 res->next = free_resources;
408 free_resources = res;
409}
410
411/**
Eric Biederman5cd81732004-03-11 15:01:31 +0000412 * See if we have unused but allocated resource structures.
Uwe Hermanne4870472010-11-04 23:23:47 +0000413 *
Eric Biederman5cd81732004-03-11 15:01:31 +0000414 * If so remove the allocation.
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000415 *
416 * @param dev The device to find the resource on.
Eric Biederman5cd81732004-03-11 15:01:31 +0000417 */
418void compact_resources(device_t dev)
419{
Myles Watsonc25cc112010-05-21 14:33:48 +0000420 struct resource *res, *next, *prev = NULL;
Uwe Hermanne4870472010-11-04 23:23:47 +0000421
Eric Biederman5cd81732004-03-11 15:01:31 +0000422 /* Move all of the free resources to the end */
Myles Watson894a3472010-06-09 22:41:35 +0000423 for (res = dev->resource_list; res; res = next) {
Myles Watsonc25cc112010-05-21 14:33:48 +0000424 next = res->next;
425 if (!res->flags)
426 free_resource(dev, res, prev);
427 else
428 prev = res;
Eric Biederman5cd81732004-03-11 15:01:31 +0000429 }
430}
431
432/**
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000433 * See if a resource structure already exists for a given index.
434 *
435 * @param dev The device to find the resource on.
436 * @param index The index of the resource on the device.
437 * @return The resource, if it already exists.
Eric Biederman5cd81732004-03-11 15:01:31 +0000438 */
Eric Biederman03acab62004-10-14 21:25:53 +0000439struct resource *probe_resource(device_t dev, unsigned index)
Eric Biederman5cd81732004-03-11 15:01:31 +0000440{
Myles Watsonc25cc112010-05-21 14:33:48 +0000441 struct resource *res;
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000442
Eric Biederman5cd81732004-03-11 15:01:31 +0000443 /* See if there is a resource with the appropriate index */
Myles Watson894a3472010-06-09 22:41:35 +0000444 for (res = dev->resource_list; res; res = res->next) {
Myles Watsonc25cc112010-05-21 14:33:48 +0000445 if (res->index == index)
Eric Biederman5cd81732004-03-11 15:01:31 +0000446 break;
Eric Biederman5cd81732004-03-11 15:01:31 +0000447 }
Uwe Hermanne4870472010-11-04 23:23:47 +0000448
Myles Watsonc25cc112010-05-21 14:33:48 +0000449 return res;
Eric Biederman03acab62004-10-14 21:25:53 +0000450}
451
452/**
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000453 * See if a resource structure already exists for a given index and if not
454 * allocate one.
455 *
Paul Menzel20923872014-06-07 13:31:29 +0200456 * Then initialize the resource to default values.
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000457 *
458 * @param dev The device to find the resource on.
459 * @param index The index of the resource on the device.
460 * @return TODO.
Eric Biederman03acab62004-10-14 21:25:53 +0000461 */
462struct resource *new_resource(device_t dev, unsigned index)
463{
Myles Watsonc25cc112010-05-21 14:33:48 +0000464 struct resource *resource, *tail;
Eric Biederman03acab62004-10-14 21:25:53 +0000465
Uwe Hermanne4870472010-11-04 23:23:47 +0000466 /* First move all of the free resources to the end. */
Eric Biederman03acab62004-10-14 21:25:53 +0000467 compact_resources(dev);
468
Uwe Hermanne4870472010-11-04 23:23:47 +0000469 /* See if there is a resource with the appropriate index. */
Eric Biederman03acab62004-10-14 21:25:53 +0000470 resource = probe_resource(dev, index);
Eric Biederman5cd81732004-03-11 15:01:31 +0000471 if (!resource) {
Myles Watsonc25cc112010-05-21 14:33:48 +0000472 if (free_resources == NULL && !allocate_more_resources())
473 die("Couldn't allocate more resources.");
474
475 resource = free_resources;
476 free_resources = free_resources->next;
Eric Biederman5cd81732004-03-11 15:01:31 +0000477 memset(resource, 0, sizeof(*resource));
Myles Watsonc25cc112010-05-21 14:33:48 +0000478 resource->next = NULL;
479 tail = dev->resource_list;
480 if (tail) {
481 while (tail->next) tail = tail->next;
482 tail->next = resource;
Uwe Hermanne4870472010-11-04 23:23:47 +0000483 } else {
Myles Watsonc25cc112010-05-21 14:33:48 +0000484 dev->resource_list = resource;
Uwe Hermanne4870472010-11-04 23:23:47 +0000485 }
Eric Biederman5cd81732004-03-11 15:01:31 +0000486 }
Uwe Hermanne4870472010-11-04 23:23:47 +0000487
488 /* Initialize the resource values. */
Eric Biederman5cd81732004-03-11 15:01:31 +0000489 if (!(resource->flags & IORESOURCE_FIXED)) {
490 resource->flags = 0;
491 resource->base = 0;
492 }
493 resource->size = 0;
494 resource->limit = 0;
495 resource->index = index;
496 resource->align = 0;
497 resource->gran = 0;
498
499 return resource;
500}
501
Eric Biederman03acab62004-10-14 21:25:53 +0000502/**
503 * Return an existing resource structure for a given index.
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000504 *
505 * @param dev The device to find the resource on.
506 * @param index The index of the resource on the device.
507 * return TODO.
Eric Biederman03acab62004-10-14 21:25:53 +0000508 */
509struct resource *find_resource(device_t dev, unsigned index)
510{
511 struct resource *resource;
512
Uwe Hermanne4870472010-11-04 23:23:47 +0000513 /* See if there is a resource with the appropriate index. */
Eric Biederman03acab62004-10-14 21:25:53 +0000514 resource = probe_resource(dev, index);
515 if (!resource) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000516 printk(BIOS_EMERG, "%s missing resource: %02x\n",
Uwe Hermanne4870472010-11-04 23:23:47 +0000517 dev_path(dev), index);
Eric Biederman03acab62004-10-14 21:25:53 +0000518 die("");
519 }
520 return resource;
521}
522
Eric Biederman03acab62004-10-14 21:25:53 +0000523/**
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000524 * Round a number up to the next multiple of gran.
525 *
526 * @param val The starting value.
527 * @param gran Granularity we are aligning the number to.
528 * @return The aligned value.
Eric Biederman03acab62004-10-14 21:25:53 +0000529 */
530static resource_t align_up(resource_t val, unsigned long gran)
531{
532 resource_t mask;
533 mask = (1ULL << gran) - 1ULL;
534 val += mask;
535 val &= ~mask;
536 return val;
537}
538
539/**
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000540 * Round a number up to the previous multiple of gran.
541 *
542 * @param val The starting value.
543 * @param gran Granularity we are aligning the number to.
544 * @return The aligned value.
Eric Biederman03acab62004-10-14 21:25:53 +0000545 */
546static resource_t align_down(resource_t val, unsigned long gran)
547{
548 resource_t mask;
549 mask = (1ULL << gran) - 1ULL;
550 val &= ~mask;
551 return val;
552}
553
554/**
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000555 * Compute the maximum address that is part of a resource.
556 *
557 * @param resource The resource whose limit is desired.
558 * @return The end.
Eric Biederman03acab62004-10-14 21:25:53 +0000559 */
560resource_t resource_end(struct resource *resource)
561{
562 resource_t base, end;
Uwe Hermanne4870472010-11-04 23:23:47 +0000563
564 /* Get the base address. */
Eric Biederman03acab62004-10-14 21:25:53 +0000565 base = resource->base;
566
Uwe Hermanne4870472010-11-04 23:23:47 +0000567 /*
568 * For a non bridge resource granularity and alignment are the same.
Eric Biederman03acab62004-10-14 21:25:53 +0000569 * For a bridge resource align is the largest needed alignment below
Uwe Hermanne4870472010-11-04 23:23:47 +0000570 * the bridge. While the granularity is simply how many low bits of
571 * the address cannot be set.
Eric Biederman03acab62004-10-14 21:25:53 +0000572 */
Stefan Reinauer14e22772010-04-27 06:56:47 +0000573
Uwe Hermanne4870472010-11-04 23:23:47 +0000574 /* Get the end (rounded up). */
Eric Biederman03acab62004-10-14 21:25:53 +0000575 end = base + align_up(resource->size, resource->gran) - 1;
576
577 return end;
578}
579
580/**
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000581 * Compute the maximum legal value for resource->base.
582 *
583 * @param resource The resource whose maximum is desired.
584 * @return The maximum.
Eric Biederman03acab62004-10-14 21:25:53 +0000585 */
586resource_t resource_max(struct resource *resource)
587{
588 resource_t max;
589
590 max = align_down(resource->limit - resource->size + 1, resource->align);
591
592 return max;
593}
594
595/**
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000596 * Return the resource type of a resource.
597 *
598 * @param resource The resource type to decode.
599 * @return TODO.
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000600 */
601const char *resource_type(struct resource *resource)
602{
603 static char buffer[RESOURCE_TYPE_MAX];
Vladimir Serbinenkoa37383d2013-11-26 02:41:26 +0100604 snprintf(buffer, sizeof (buffer), "%s%s%s%s",
605 ((resource->flags & IORESOURCE_READONLY) ? "ro" : ""),
606 ((resource->flags & IORESOURCE_PREFETCH) ? "pref" : ""),
607 ((resource->flags == 0) ? "unused" :
608 (resource->flags & IORESOURCE_IO) ? "io" :
609 (resource->flags & IORESOURCE_DRQ) ? "drq" :
610 (resource->flags & IORESOURCE_IRQ) ? "irq" :
611 (resource->flags & IORESOURCE_MEM) ? "mem" : "??????"),
612 ((resource->flags & IORESOURCE_PCI64) ? "64" : ""));
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000613 return buffer;
614}
615
616/**
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000617 * Print the resource that was just stored.
618 *
Martin Roth63373ed2013-07-08 16:24:19 -0600619 * @param dev The device the stored resource lives on.
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000620 * @param resource The resource that was just stored.
621 * @param comment TODO
Eric Biederman03acab62004-10-14 21:25:53 +0000622 */
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000623void report_resource_stored(device_t dev, struct resource *resource,
624 const char *comment)
Eric Biederman03acab62004-10-14 21:25:53 +0000625{
Uwe Hermanne4870472010-11-04 23:23:47 +0000626 char buf[10];
627 unsigned long long base, end;
628
629 if (!(resource->flags & IORESOURCE_STORED))
630 return;
631
632 base = resource->base;
633 end = resource_end(resource);
634 buf[0] = '\0';
635
636 if (resource->flags & IORESOURCE_PCI_BRIDGE) {
Vladimir Serbinenkoa37383d2013-11-26 02:41:26 +0100637 snprintf(buf, sizeof (buf),
638 "bus %02x ", dev->link_list->secondary);
Eric Biederman03acab62004-10-14 21:25:53 +0000639 }
Patrick Georgi51615092012-03-11 19:31:03 +0100640 printk(BIOS_DEBUG, "%s %02lx <- [0x%010llx - 0x%010llx] size 0x%08llx "
Uwe Hermanne4870472010-11-04 23:23:47 +0000641 "gran 0x%02x %s%s%s\n", dev_path(dev), resource->index,
642 base, end, resource->size, resource->gran, buf,
643 resource_type(resource), comment);
Eric Biederman03acab62004-10-14 21:25:53 +0000644}
Eric Biedermanf8a2ddd2004-10-30 08:05:41 +0000645
Uwe Hermanne4870472010-11-04 23:23:47 +0000646void search_bus_resources(struct bus *bus, unsigned long type_mask,
647 unsigned long type, resource_search_t search,
648 void *gp)
Eric Biedermanf8a2ddd2004-10-30 08:05:41 +0000649{
650 struct device *curdev;
Uwe Hermanne4870472010-11-04 23:23:47 +0000651
Myles Watson894a3472010-06-09 22:41:35 +0000652 for (curdev = bus->children; curdev; curdev = curdev->sibling) {
Myles Watsonc25cc112010-05-21 14:33:48 +0000653 struct resource *res;
Uwe Hermanne4870472010-11-04 23:23:47 +0000654
655 /* Ignore disabled devices. */
656 if (!curdev->enabled)
657 continue;
658
Myles Watson894a3472010-06-09 22:41:35 +0000659 for (res = curdev->resource_list; res; res = res->next) {
Uwe Hermanne4870472010-11-04 23:23:47 +0000660 /* If it isn't the right kind of resource ignore it. */
661 if ((res->flags & type_mask) != type)
Eric Biedermanf8a2ddd2004-10-30 08:05:41 +0000662 continue;
Uwe Hermanne4870472010-11-04 23:23:47 +0000663
664 /* If it is a subtractive resource recurse. */
Myles Watsonc25cc112010-05-21 14:33:48 +0000665 if (res->flags & IORESOURCE_SUBTRACTIVE) {
Eric Biedermanf8a2ddd2004-10-30 08:05:41 +0000666 struct bus * subbus;
Uwe Hermanne4870472010-11-04 23:23:47 +0000667 for (subbus = curdev->link_list; subbus;
668 subbus = subbus->next)
669 if (subbus->link_num
670 == IOINDEX_SUBTRACTIVE_LINK(res->index))
Myles Watson894a3472010-06-09 22:41:35 +0000671 break;
Stefan Reinauer58075552011-05-11 15:57:07 -0700672 if (!subbus) /* Why can subbus be NULL? */
673 break;
Uwe Hermanne4870472010-11-04 23:23:47 +0000674 search_bus_resources(subbus, type_mask, type,
675 search, gp);
Eric Biedermanf8a2ddd2004-10-30 08:05:41 +0000676 continue;
677 }
Myles Watsonc25cc112010-05-21 14:33:48 +0000678 search(gp, curdev, res);
Eric Biedermanf8a2ddd2004-10-30 08:05:41 +0000679 }
680 }
681}
682
Uwe Hermanne4870472010-11-04 23:23:47 +0000683void search_global_resources(unsigned long type_mask, unsigned long type,
684 resource_search_t search, void *gp)
Eric Biedermanf8a2ddd2004-10-30 08:05:41 +0000685{
686 struct device *curdev;
Uwe Hermanne4870472010-11-04 23:23:47 +0000687
Myles Watson894a3472010-06-09 22:41:35 +0000688 for (curdev = all_devices; curdev; curdev = curdev->next) {
Myles Watsonc25cc112010-05-21 14:33:48 +0000689 struct resource *res;
Uwe Hermanne4870472010-11-04 23:23:47 +0000690
691 /* Ignore disabled devices. */
692 if (!curdev->enabled)
693 continue;
694
Myles Watson894a3472010-06-09 22:41:35 +0000695 for (res = curdev->resource_list; res; res = res->next) {
Uwe Hermanne4870472010-11-04 23:23:47 +0000696 /* If it isn't the right kind of resource ignore it. */
697 if ((res->flags & type_mask) != type)
Eric Biedermanf8a2ddd2004-10-30 08:05:41 +0000698 continue;
Uwe Hermanne4870472010-11-04 23:23:47 +0000699
700 /* If it is a subtractive resource ignore it. */
701 if (res->flags & IORESOURCE_SUBTRACTIVE)
Eric Biedermanf8a2ddd2004-10-30 08:05:41 +0000702 continue;
Uwe Hermanne4870472010-11-04 23:23:47 +0000703
Myles Watsonc25cc112010-05-21 14:33:48 +0000704 search(gp, curdev, res);
Eric Biedermanf8a2ddd2004-10-30 08:05:41 +0000705 }
706 }
707}
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000708
709void dev_set_enabled(device_t dev, int enable)
710{
Uwe Hermanne4870472010-11-04 23:23:47 +0000711 if (dev->enabled == enable)
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000712 return;
Uwe Hermanne4870472010-11-04 23:23:47 +0000713
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000714 dev->enabled = enable;
715 if (dev->ops && dev->ops->enable) {
716 dev->ops->enable(dev);
Uwe Hermanne4870472010-11-04 23:23:47 +0000717 } else if (dev->chip_ops && dev->chip_ops->enable_dev) {
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000718 dev->chip_ops->enable_dev(dev);
719 }
720}
721
722void disable_children(struct bus *bus)
723{
724 device_t child;
Uwe Hermanne4870472010-11-04 23:23:47 +0000725
Myles Watson894a3472010-06-09 22:41:35 +0000726 for (child = bus->children; child; child = child->sibling) {
727 struct bus *link;
Uwe Hermanne4870472010-11-04 23:23:47 +0000728 for (link = child->link_list; link; link = link->next)
Myles Watson894a3472010-06-09 22:41:35 +0000729 disable_children(link);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000730 dev_set_enabled(child, 0);
731 }
732}
Myles Watsonbb3d8122009-05-11 22:45:35 +0000733
Maciej Pijankaea921852009-10-27 14:29:29 +0000734static void resource_tree(struct device *root, int debug_level, int depth)
Myles Watsonbb3d8122009-05-11 22:45:35 +0000735{
Myles Watson894a3472010-06-09 22:41:35 +0000736 int i = 0;
Myles Watsonbb3d8122009-05-11 22:45:35 +0000737 struct device *child;
Myles Watson894a3472010-06-09 22:41:35 +0000738 struct bus *link;
Myles Watsonc25cc112010-05-21 14:33:48 +0000739 struct resource *res;
Myles Watsonbb3d8122009-05-11 22:45:35 +0000740 char indent[30]; /* If your tree has more levels, it's wrong. */
741
742 for (i = 0; i < depth + 1 && i < 29; i++)
743 indent[i] = ' ';
744 indent[i] = '\0';
745
Myles Watson894a3472010-06-09 22:41:35 +0000746 do_printk(BIOS_DEBUG, "%s%s", indent, dev_path(root));
747 if (root->link_list && root->link_list->children)
748 do_printk(BIOS_DEBUG, " child on link 0 %s",
749 dev_path(root->link_list->children));
750 do_printk(BIOS_DEBUG, "\n");
751
Myles Watsonc25cc112010-05-21 14:33:48 +0000752 for (res = root->resource_list; res; res = res->next) {
Uwe Hermanne4870472010-11-04 23:23:47 +0000753 do_printk(debug_level, "%s%s resource base %llx size %llx "
754 "align %d gran %d limit %llx flags %lx index %lx\n",
755 indent, dev_path(root), res->base, res->size,
756 res->align, res->gran, res->limit, res->flags,
757 res->index);
Myles Watsonbb3d8122009-05-11 22:45:35 +0000758 }
759
Myles Watson894a3472010-06-09 22:41:35 +0000760 for (link = root->link_list; link; link = link->next) {
761 for (child = link->children; child; child = child->sibling)
Myles Watsonbb3d8122009-05-11 22:45:35 +0000762 resource_tree(child, debug_level, depth + 1);
763 }
764}
765
Uwe Hermanne4870472010-11-04 23:23:47 +0000766void print_resource_tree(struct device *root, int debug_level, const char *msg)
Myles Watsonbb3d8122009-05-11 22:45:35 +0000767{
768 /* Bail if root is null. */
769 if (!root) {
770 do_printk(debug_level, "%s passed NULL for root!\n", __func__);
771 return;
772 }
773
774 /* Bail if not printing to screen. */
775 if (!do_printk(debug_level, "Show resources in subtree (%s)...%s\n",
Uwe Hermanne4870472010-11-04 23:23:47 +0000776 dev_path(root), msg))
Myles Watsonbb3d8122009-05-11 22:45:35 +0000777 return;
Uwe Hermanne4870472010-11-04 23:23:47 +0000778
Myles Watsonbb3d8122009-05-11 22:45:35 +0000779 resource_tree(root, debug_level, 0);
780}
781
782void show_devs_tree(struct device *dev, int debug_level, int depth, int linknum)
783{
Marcelo Povoa8404dca2014-02-14 15:42:49 -0800784 char depth_str[20];
Myles Watsonbb3d8122009-05-11 22:45:35 +0000785 int i;
786 struct device *sibling;
Myles Watson894a3472010-06-09 22:41:35 +0000787 struct bus *link;
788
Myles Watsonbb3d8122009-05-11 22:45:35 +0000789 for (i = 0; i < depth; i++)
790 depth_str[i] = ' ';
791 depth_str[i] = '\0';
Uwe Hermanne4870472010-11-04 23:23:47 +0000792
Myles Watsonc25cc112010-05-21 14:33:48 +0000793 do_printk(debug_level, "%s%s: enabled %d\n",
794 depth_str, dev_path(dev), dev->enabled);
Uwe Hermanne4870472010-11-04 23:23:47 +0000795
Myles Watson894a3472010-06-09 22:41:35 +0000796 for (link = dev->link_list; link; link = link->next) {
797 for (sibling = link->children; sibling;
Myles Watsonbb3d8122009-05-11 22:45:35 +0000798 sibling = sibling->sibling)
799 show_devs_tree(sibling, debug_level, depth + 1, i);
800 }
801}
802
803void show_all_devs_tree(int debug_level, const char *msg)
804{
805 /* Bail if not printing to screen. */
Paul Menzeleb605d72015-02-12 00:29:32 +0100806 if (!do_printk(debug_level, "Show all devs in tree form... %s\n", msg))
Myles Watsonbb3d8122009-05-11 22:45:35 +0000807 return;
808 show_devs_tree(all_devices, debug_level, 0, -1);
809}
810
811void show_devs_subtree(struct device *root, int debug_level, const char *msg)
812{
813 /* Bail if not printing to screen. */
Paul Menzeleb605d72015-02-12 00:29:32 +0100814 if (!do_printk(debug_level, "Show all devs in subtree %s... %s\n",
Uwe Hermanne4870472010-11-04 23:23:47 +0000815 dev_path(root), msg))
Myles Watsonbb3d8122009-05-11 22:45:35 +0000816 return;
817 do_printk(debug_level, "%s\n", msg);
818 show_devs_tree(root, debug_level, 0, -1);
819}
820
821void show_all_devs(int debug_level, const char *msg)
822{
823 struct device *dev;
824
825 /* Bail if not printing to screen. */
Paul Menzeleb605d72015-02-12 00:29:32 +0100826 if (!do_printk(debug_level, "Show all devs... %s\n", msg))
Myles Watsonbb3d8122009-05-11 22:45:35 +0000827 return;
828 for (dev = all_devices; dev; dev = dev->next) {
Myles Watsonc25cc112010-05-21 14:33:48 +0000829 do_printk(debug_level, "%s: enabled %d\n",
830 dev_path(dev), dev->enabled);
Myles Watsonbb3d8122009-05-11 22:45:35 +0000831 }
832}
833
834void show_one_resource(int debug_level, struct device *dev,
835 struct resource *resource, const char *comment)
836{
837 char buf[10];
838 unsigned long long base, end;
839 base = resource->base;
840 end = resource_end(resource);
841 buf[0] = '\0';
Uwe Hermanne4870472010-11-04 23:23:47 +0000842
Uwe Hermanne4870472010-11-04 23:23:47 +0000843 do_printk(debug_level, "%s %02lx <- [0x%010llx - 0x%010llx] "
Patrick Georgi51615092012-03-11 19:31:03 +0100844 "size 0x%08llx gran 0x%02x %s%s%s\n", dev_path(dev),
Uwe Hermanne4870472010-11-04 23:23:47 +0000845 resource->index, base, end, resource->size, resource->gran,
846 buf, resource_type(resource), comment);
Myles Watsonbb3d8122009-05-11 22:45:35 +0000847}
848
849void show_all_devs_resources(int debug_level, const char* msg)
850{
851 struct device *dev;
852
Paul Menzeleb605d72015-02-12 00:29:32 +0100853 if (!do_printk(debug_level, "Show all devs with resources... %s\n", msg))
Myles Watsonbb3d8122009-05-11 22:45:35 +0000854 return;
855
856 for (dev = all_devices; dev; dev = dev->next) {
Myles Watsonc25cc112010-05-21 14:33:48 +0000857 struct resource *res;
858 do_printk(debug_level, "%s: enabled %d\n",
859 dev_path(dev), dev->enabled);
860 for (res = dev->resource_list; res; res = res->next)
861 show_one_resource(debug_level, dev, res, "");
Myles Watsonbb3d8122009-05-11 22:45:35 +0000862 }
863}
Uwe Hermann4b42a622010-10-11 19:36:13 +0000864
Kyösti Mälkkiecf1ed42012-07-27 08:37:12 +0300865void fixed_mem_resource(device_t dev, unsigned long index,
866 unsigned long basek, unsigned long sizek, unsigned long type)
Uwe Hermann4b42a622010-10-11 19:36:13 +0000867{
868 struct resource *resource;
869
870 if (!sizek)
871 return;
872
873 resource = new_resource(dev, index);
874 resource->base = ((resource_t)basek) << 10;
875 resource->size = ((resource_t)sizek) << 10;
Kyösti Mälkkiecf1ed42012-07-27 08:37:12 +0300876 resource->flags = IORESOURCE_MEM | IORESOURCE_FIXED |
877 IORESOURCE_STORED | IORESOURCE_ASSIGNED;
Uwe Hermann4b42a622010-10-11 19:36:13 +0000878
Kyösti Mälkkiecf1ed42012-07-27 08:37:12 +0300879 resource->flags |= type;
Kyösti Mälkki63f8c082012-07-10 13:27:26 +0300880}
881
Uwe Hermann4b42a622010-10-11 19:36:13 +0000882void tolm_test(void *gp, struct device *dev, struct resource *new)
883{
884 struct resource **best_p = gp;
885 struct resource *best;
886
887 best = *best_p;
888
889 if (!best || (best->base > new->base))
890 best = new;
891
892 *best_p = best;
893}
894
895u32 find_pci_tolm(struct bus *bus)
896{
897 struct resource *min = NULL;
898 u32 tolm;
899
900 search_bus_resources(bus, IORESOURCE_MEM, IORESOURCE_MEM,
901 tolm_test, &min);
902
903 tolm = 0xffffffffUL;
904
905 if (min && tolm > min->base)
906 tolm = min->base;
907
908 return tolm;
909}
Stefan Reinauerdc8448fd2012-03-30 13:52:58 -0700910
911/* Count of enabled CPUs */
912int dev_count_cpu(void)
913{
914 device_t cpu;
915 int count = 0;
916
917 for (cpu = all_devices; cpu; cpu = cpu->next) {
918 if ((cpu->path.type != DEVICE_PATH_APIC) ||
Stefan Reinauer0aa37c42013-02-12 15:20:54 -0800919 (cpu->bus->dev->path.type != DEVICE_PATH_CPU_CLUSTER))
Stefan Reinauerdc8448fd2012-03-30 13:52:58 -0700920 continue;
921 if (!cpu->enabled)
922 continue;
923 count++;
924 }
925
926 return count;
927}