blob: 02641c162e0706f6bf053a4677decdca3b7debfb [file] [log] [blame]
Angel Ponsc74dae92020-04-02 23:48:16 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Uwe Hermannb80dbf02007-04-22 19:08:13 +00002
Elyes Haouas04c3b5a2022-10-07 10:08:05 +02003#include <commonlib/bsd/helpers.h>
Eric Biederman8ca8d762003-04-22 19:02:15 +00004#include <console/console.h>
Eric Biederman5899fd82003-04-24 06:25:08 +00005#include <device/device.h>
Kyösti Mälkki318066f2014-02-12 14:18:50 +02006#include <device/pci_def.h>
Elyes HAOUASede8dd02019-06-23 06:57:53 +02007#include <stdlib.h>
Eric Biedermane9a271e32003-09-02 03:36:25 +00008#include <string.h>
Elyes Haouas04c3b5a2022-10-07 10:08:05 +02009#include <types.h>
Eric Biedermane9a271e32003-09-02 03:36:25 +000010
Eric Biederman03acab62004-10-14 21:25:53 +000011/**
Duncan Laurie6f88a6e2011-07-18 10:41:36 -070012 * Given a Local APIC ID, find the device structure.
13 *
14 * @param apic_id The Local APIC ID number.
15 * @return Pointer to the device structure (if found), 0 otherwise.
16 */
Martin Roth38ddbfb2019-10-23 21:41:00 -060017struct device *dev_find_lapic(unsigned int apic_id)
Duncan Laurie6f88a6e2011-07-18 10:41:36 -070018{
Aaron Durbinf0349022017-11-10 10:47:54 -070019 struct device *dev;
20 struct device *result = NULL;
Duncan Laurie6f88a6e2011-07-18 10:41:36 -070021
22 for (dev = all_devices; dev; dev = dev->next) {
23 if (dev->path.type == DEVICE_PATH_APIC &&
24 dev->path.apic.apic_id == apic_id) {
25 result = dev;
26 break;
27 }
28 }
29 return result;
30}
31
32/**
Uwe Hermannc1ee4292010-10-17 19:01:48 +000033 * Find a device of a given vendor and type.
34 *
35 * @param vendor A PCI vendor ID (e.g. 0x8086 for Intel).
36 * @param device A PCI device ID.
Uwe Hermanne4870472010-11-04 23:23:47 +000037 * @param from Pointer to the device structure, used as a starting point in
38 * the linked list of all_devices, which can be 0 to start at the
39 * head of the list (i.e. all_devices).
Uwe Hermannc1ee4292010-10-17 19:01:48 +000040 * @return Pointer to the device struct.
Eric Biederman8ca8d762003-04-22 19:02:15 +000041 */
Uwe Hermanne4870472010-11-04 23:23:47 +000042struct device *dev_find_device(u16 vendor, u16 device, struct device *from)
Eric Biederman8ca8d762003-04-22 19:02:15 +000043{
44 if (!from)
45 from = all_devices;
46 else
47 from = from->next;
Uwe Hermanne4870472010-11-04 23:23:47 +000048
49 while (from && (from->vendor != vendor || from->device != device))
Eric Biederman8ca8d762003-04-22 19:02:15 +000050 from = from->next;
Uwe Hermanne4870472010-11-04 23:23:47 +000051
Eric Biederman8ca8d762003-04-22 19:02:15 +000052 return from;
53}
54
Uwe Hermannc1ee4292010-10-17 19:01:48 +000055/**
56 * Find a device of a given class.
57 *
58 * @param class Class of the device.
Uwe Hermanne4870472010-11-04 23:23:47 +000059 * @param from Pointer to the device structure, used as a starting point in
60 * the linked list of all_devices, which can be 0 to start at the
61 * head of the list (i.e. all_devices).
Uwe Hermannc1ee4292010-10-17 19:01:48 +000062 * @return Pointer to the device struct.
Eric Biederman8ca8d762003-04-22 19:02:15 +000063 */
64struct device *dev_find_class(unsigned int class, struct device *from)
65{
66 if (!from)
67 from = all_devices;
68 else
69 from = from->next;
Uwe Hermanne4870472010-11-04 23:23:47 +000070
Greg Watson59651692003-12-17 17:39:53 +000071 while (from && (from->class & 0xffffff00) != class)
Eric Biederman8ca8d762003-04-22 19:02:15 +000072 from = from->next;
Uwe Hermanne4870472010-11-04 23:23:47 +000073
Eric Biederman8ca8d762003-04-22 19:02:15 +000074 return from;
75}
76
Duncan Laurie5f5d9142013-06-10 09:59:17 -070077/**
78 * Encode the device path into 3 bytes for logging to CMOS.
79 *
80 * @param dev The device path to encode.
81 * @return Device path encoded into lower 3 bytes of dword.
82 */
Subrata Banik564547f2018-05-02 10:27:36 +053083u32 dev_path_encode(const struct device *dev)
Duncan Laurie5f5d9142013-06-10 09:59:17 -070084{
85 u32 ret;
86
87 if (!dev)
88 return 0;
89
90 /* Store the device type in 3rd byte. */
91 ret = dev->path.type << 16;
92
93 /* Encode the device specific path in the low word. */
94 switch (dev->path.type) {
95 case DEVICE_PATH_ROOT:
96 break;
97 case DEVICE_PATH_PCI:
Arthur Heymans7fcd4d52023-08-24 15:12:19 +020098 ret |= dev->upstream->segment_group << 16 | dev->upstream->secondary << 8 | dev->path.pci.devfn;
Duncan Laurie5f5d9142013-06-10 09:59:17 -070099 break;
100 case DEVICE_PATH_PNP:
101 ret |= dev->path.pnp.port << 8 | dev->path.pnp.device;
102 break;
103 case DEVICE_PATH_I2C:
Duncan Laurieb7ce5fe2016-05-07 19:49:37 -0700104 ret |= dev->path.i2c.mode_10bit << 8 | dev->path.i2c.device;
Duncan Laurie5f5d9142013-06-10 09:59:17 -0700105 break;
106 case DEVICE_PATH_APIC:
107 ret |= dev->path.apic.apic_id;
108 break;
109 case DEVICE_PATH_DOMAIN:
110 ret |= dev->path.domain.domain;
111 break;
112 case DEVICE_PATH_CPU_CLUSTER:
113 ret |= dev->path.cpu_cluster.cluster;
114 break;
115 case DEVICE_PATH_CPU:
116 ret |= dev->path.cpu.id;
117 break;
118 case DEVICE_PATH_CPU_BUS:
119 ret |= dev->path.cpu_bus.id;
120 break;
121 case DEVICE_PATH_IOAPIC:
122 ret |= dev->path.ioapic.ioapic_id;
123 break;
Duncan Laurie4650f5b2016-05-07 20:01:34 -0700124 case DEVICE_PATH_GENERIC:
125 ret |= dev->path.generic.subid << 8 | dev->path.generic.id;
126 break;
Furquan Shaikh7606c372017-02-11 10:57:23 -0800127 case DEVICE_PATH_SPI:
128 ret |= dev->path.spi.cs;
129 break;
Duncan Lauriebae9f852018-05-07 14:18:13 -0700130 case DEVICE_PATH_USB:
Karthikeyan Ramasubramanian19398242019-07-11 12:23:35 -0600131 ret |= dev->path.usb.port_type << 8 | dev->path.usb.port_id;
Duncan Lauriebae9f852018-05-07 14:18:13 -0700132 break;
Michael Niewöhnerdbb667a2020-12-11 21:26:02 +0100133 case DEVICE_PATH_GPIO:
134 ret |= dev->path.gpio.id;
135 break;
Mario Scheithauer67f63e72022-11-02 15:57:10 +0100136 case DEVICE_PATH_MDIO:
137 ret |= dev->path.mdio.addr;
138 break;
Duncan Laurie5f5d9142013-06-10 09:59:17 -0700139 case DEVICE_PATH_NONE:
Justin TerAvestca2ed9f2018-01-17 16:36:30 -0800140 case DEVICE_PATH_MMIO: /* don't care */
Duncan Laurie5f5d9142013-06-10 09:59:17 -0700141 default:
142 break;
143 }
144
145 return ret;
146}
147
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000148/*
149 * Warning: This function uses a static buffer. Don't call it more than once
150 * from the same print statement!
151 */
Lubomir Rintel9ba8f7c2018-04-26 00:00:22 +0200152const char *dev_path(const struct device *dev)
Eric Biedermane9a271e32003-09-02 03:36:25 +0000153{
154 static char buffer[DEVICE_PATH_MAX];
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000155
Eric Biedermane9a271e32003-09-02 03:36:25 +0000156 buffer[0] = '\0';
157 if (!dev) {
Angel Ponsd7df3832021-08-18 08:32:45 +0200158 strcpy(buffer, "<null>");
Uwe Hermanne4870472010-11-04 23:23:47 +0000159 } else {
Elyes HAOUAS0ce41f12018-11-13 10:03:31 +0100160 switch (dev->path.type) {
Patrick Rudolph6a811842017-11-01 11:33:00 +0100161 case DEVICE_PATH_NONE:
Angel Ponsd7df3832021-08-18 08:32:45 +0200162 strcpy(buffer, "NONE");
Patrick Rudolph6a811842017-11-01 11:33:00 +0100163 break;
Eric Biederman83b991a2003-10-11 06:20:25 +0000164 case DEVICE_PATH_ROOT:
Angel Ponsd7df3832021-08-18 08:32:45 +0200165 strcpy(buffer, "Root Device");
Eric Biederman83b991a2003-10-11 06:20:25 +0000166 break;
Eric Biedermane9a271e32003-09-02 03:36:25 +0000167 case DEVICE_PATH_PCI:
Elyes HAOUASb7482212018-05-16 12:58:19 +0200168 snprintf(buffer, sizeof(buffer),
Felix Held3b5b66d2024-01-11 22:26:18 +0100169 "PCI: %02x:%02x:%02x.%01x",
Arthur Heymans7fcd4d52023-08-24 15:12:19 +0200170 dev->upstream->segment_group,
171 dev->upstream->secondary,
Vladimir Serbinenkoa37383d2013-11-26 02:41:26 +0100172 PCI_SLOT(dev->path.pci.devfn),
173 PCI_FUNC(dev->path.pci.devfn));
Eric Biedermane9a271e32003-09-02 03:36:25 +0000174 break;
175 case DEVICE_PATH_PNP:
Elyes HAOUASb7482212018-05-16 12:58:19 +0200176 snprintf(buffer, sizeof(buffer), "PNP: %04x.%01x",
Vladimir Serbinenkoa37383d2013-11-26 02:41:26 +0100177 dev->path.pnp.port, dev->path.pnp.device);
Eric Biedermane9a271e32003-09-02 03:36:25 +0000178 break;
179 case DEVICE_PATH_I2C:
Elyes HAOUASb7482212018-05-16 12:58:19 +0200180 snprintf(buffer, sizeof(buffer), "I2C: %02x:%02x",
Arthur Heymans7fcd4d52023-08-24 15:12:19 +0200181 dev->upstream->secondary,
Vladimir Serbinenkoa37383d2013-11-26 02:41:26 +0100182 dev->path.i2c.device);
Eric Biedermane9a271e32003-09-02 03:36:25 +0000183 break;
Eric Biederman03acab62004-10-14 21:25:53 +0000184 case DEVICE_PATH_APIC:
Elyes HAOUASb7482212018-05-16 12:58:19 +0200185 snprintf(buffer, sizeof(buffer), "APIC: %02x",
Vladimir Serbinenkoa37383d2013-11-26 02:41:26 +0100186 dev->path.apic.apic_id);
Eric Biederman03acab62004-10-14 21:25:53 +0000187 break;
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200188 case DEVICE_PATH_IOAPIC:
Elyes HAOUASb7482212018-05-16 12:58:19 +0200189 snprintf(buffer, sizeof(buffer), "IOAPIC: %02x",
Vladimir Serbinenkoa37383d2013-11-26 02:41:26 +0100190 dev->path.ioapic.ioapic_id);
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200191 break;
Stefan Reinauer4aff4452013-02-12 14:17:15 -0800192 case DEVICE_PATH_DOMAIN:
Patrick Rudolphdb779802024-01-19 20:04:31 +0100193 snprintf(buffer, sizeof(buffer), "DOMAIN: %08x",
Stefan Reinauer4aff4452013-02-12 14:17:15 -0800194 dev->path.domain.domain);
Eric Biederman7003ba42004-10-16 06:20:29 +0000195 break;
Stefan Reinauer0aa37c42013-02-12 15:20:54 -0800196 case DEVICE_PATH_CPU_CLUSTER:
Elyes HAOUASb7482212018-05-16 12:58:19 +0200197 snprintf(buffer, sizeof(buffer), "CPU_CLUSTER: %01x",
Stefan Reinauer0aa37c42013-02-12 15:20:54 -0800198 dev->path.cpu_cluster.cluster);
Eric Biederman7003ba42004-10-16 06:20:29 +0000199 break;
Eric Biedermana9e632c2004-11-18 22:38:08 +0000200 case DEVICE_PATH_CPU:
Elyes HAOUASb7482212018-05-16 12:58:19 +0200201 snprintf(buffer, sizeof(buffer),
Vladimir Serbinenkoa37383d2013-11-26 02:41:26 +0100202 "CPU: %02x", dev->path.cpu.id);
Eric Biedermana9e632c2004-11-18 22:38:08 +0000203 break;
204 case DEVICE_PATH_CPU_BUS:
Elyes HAOUASb7482212018-05-16 12:58:19 +0200205 snprintf(buffer, sizeof(buffer),
Vladimir Serbinenkoa37383d2013-11-26 02:41:26 +0100206 "CPU_BUS: %02x", dev->path.cpu_bus.id);
Eric Biedermana9e632c2004-11-18 22:38:08 +0000207 break;
Duncan Laurie4650f5b2016-05-07 20:01:34 -0700208 case DEVICE_PATH_GENERIC:
Elyes HAOUASb7482212018-05-16 12:58:19 +0200209 snprintf(buffer, sizeof(buffer),
Duncan Laurie4650f5b2016-05-07 20:01:34 -0700210 "GENERIC: %d.%d", dev->path.generic.id,
211 dev->path.generic.subid);
212 break;
Furquan Shaikh7606c372017-02-11 10:57:23 -0800213 case DEVICE_PATH_SPI:
Elyes HAOUASb7482212018-05-16 12:58:19 +0200214 snprintf(buffer, sizeof(buffer), "SPI: %02x",
Furquan Shaikh7606c372017-02-11 10:57:23 -0800215 dev->path.spi.cs);
216 break;
Duncan Lauriebae9f852018-05-07 14:18:13 -0700217 case DEVICE_PATH_USB:
Elyes HAOUASb7482212018-05-16 12:58:19 +0200218 snprintf(buffer, sizeof(buffer), "USB%u port %u",
Duncan Lauriebae9f852018-05-07 14:18:13 -0700219 dev->path.usb.port_type, dev->path.usb.port_id);
220 break;
Justin TerAvestca2ed9f2018-01-17 16:36:30 -0800221 case DEVICE_PATH_MMIO:
Jacob Garberd552aca2019-07-16 12:55:00 -0600222 snprintf(buffer, sizeof(buffer), "MMIO: %08lx",
Justin TerAvestca2ed9f2018-01-17 16:36:30 -0800223 dev->path.mmio.addr);
224 break;
Michael Niewöhnerdbb667a2020-12-11 21:26:02 +0100225 case DEVICE_PATH_GPIO:
226 snprintf(buffer, sizeof(buffer), "GPIO: %d", dev->path.gpio.id);
227 break;
Mario Scheithauer67f63e72022-11-02 15:57:10 +0100228 case DEVICE_PATH_MDIO:
229 snprintf(buffer, sizeof(buffer), "MDIO: %02x", dev->path.mdio.addr);
230 break;
Eric Biedermane9a271e32003-09-02 03:36:25 +0000231 default:
Uwe Hermanne4870472010-11-04 23:23:47 +0000232 printk(BIOS_ERR, "Unknown device path type: %d\n",
233 dev->path.type);
Eric Biedermane9a271e32003-09-02 03:36:25 +0000234 break;
235 }
236 }
237 return buffer;
238}
239
Furquan Shaikh5b5c2332020-04-24 21:31:35 -0700240const char *dev_name(const struct device *dev)
Kyösti Mälkki7baadac2012-10-07 14:57:15 +0200241{
Kyösti Mälkki7d54eb82012-10-10 23:14:28 +0300242 if (dev->name)
243 return dev->name;
244 else if (dev->chip_ops && dev->chip_ops->name)
Kyösti Mälkki7baadac2012-10-07 14:57:15 +0200245 return dev->chip_ops->name;
246 else
247 return "unknown";
248}
249
Patrick Rudolphab6bcd22024-01-19 08:24:36 +0100250/* Returns the PCI domain for the given PCI device */
251struct device *dev_get_pci_domain(struct device *dev)
252{
253 /* Walk up the tree up to the PCI domain */
Arthur Heymans7fcd4d52023-08-24 15:12:19 +0200254 while (dev && dev->upstream && !is_root_device(dev)) {
255 dev = dev->upstream->dev;
Patrick Rudolphab6bcd22024-01-19 08:24:36 +0100256 if (dev->path.type == DEVICE_PATH_DOMAIN)
257 return dev;
258 }
259
260 return NULL;
261}
262
Eric Biederman5cd81732004-03-11 15:01:31 +0000263/**
Myles Watsonc25cc112010-05-21 14:33:48 +0000264 * Allocate 64 more resources to the free list.
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000265 *
266 * @return TODO.
Myles Watsonc25cc112010-05-21 14:33:48 +0000267 */
268static int allocate_more_resources(void)
269{
270 int i;
271 struct resource *new_res_list;
Uwe Hermanne4870472010-11-04 23:23:47 +0000272
Myles Watsonc25cc112010-05-21 14:33:48 +0000273 new_res_list = malloc(64 * sizeof(*new_res_list));
274
275 if (new_res_list == NULL)
276 return 0;
277
278 memset(new_res_list, 0, 64 * sizeof(*new_res_list));
279
Uwe Hermanne4870472010-11-04 23:23:47 +0000280 for (i = 0; i < 64 - 1; i++)
Myles Watsonc25cc112010-05-21 14:33:48 +0000281 new_res_list[i].next = &new_res_list[i+1];
282
283 free_resources = new_res_list;
284 return 1;
285}
286
287/**
288 * Remove resource res from the device's list and add it to the free list.
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000289 *
290 * @param dev TODO
291 * @param res TODO
292 * @param prev TODO
293 * @return TODO.
Myles Watsonc25cc112010-05-21 14:33:48 +0000294 */
Aaron Durbinf0349022017-11-10 10:47:54 -0700295static void free_resource(struct device *dev, struct resource *res,
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000296 struct resource *prev)
Myles Watsonc25cc112010-05-21 14:33:48 +0000297{
298 if (prev)
299 prev->next = res->next;
300 else
301 dev->resource_list = res->next;
Uwe Hermanne4870472010-11-04 23:23:47 +0000302
Myles Watsonc25cc112010-05-21 14:33:48 +0000303 res->next = free_resources;
304 free_resources = res;
305}
306
307/**
Eric Biederman5cd81732004-03-11 15:01:31 +0000308 * See if we have unused but allocated resource structures.
Uwe Hermanne4870472010-11-04 23:23:47 +0000309 *
Eric Biederman5cd81732004-03-11 15:01:31 +0000310 * If so remove the allocation.
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000311 *
312 * @param dev The device to find the resource on.
Eric Biederman5cd81732004-03-11 15:01:31 +0000313 */
Aaron Durbinf0349022017-11-10 10:47:54 -0700314void compact_resources(struct device *dev)
Eric Biederman5cd81732004-03-11 15:01:31 +0000315{
Myles Watsonc25cc112010-05-21 14:33:48 +0000316 struct resource *res, *next, *prev = NULL;
Uwe Hermanne4870472010-11-04 23:23:47 +0000317
Eric Biederman5cd81732004-03-11 15:01:31 +0000318 /* Move all of the free resources to the end */
Myles Watson894a3472010-06-09 22:41:35 +0000319 for (res = dev->resource_list; res; res = next) {
Myles Watsonc25cc112010-05-21 14:33:48 +0000320 next = res->next;
321 if (!res->flags)
322 free_resource(dev, res, prev);
323 else
324 prev = res;
Eric Biederman5cd81732004-03-11 15:01:31 +0000325 }
326}
327
328/**
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000329 * See if a resource structure already exists for a given index.
330 *
331 * @param dev The device to find the resource on.
332 * @param index The index of the resource on the device.
333 * @return The resource, if it already exists.
Eric Biederman5cd81732004-03-11 15:01:31 +0000334 */
Martin Roth38ddbfb2019-10-23 21:41:00 -0600335struct resource *probe_resource(const struct device *dev, unsigned int index)
Eric Biederman5cd81732004-03-11 15:01:31 +0000336{
Myles Watsonc25cc112010-05-21 14:33:48 +0000337 struct resource *res;
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000338
Eric Biederman5cd81732004-03-11 15:01:31 +0000339 /* See if there is a resource with the appropriate index */
Myles Watson894a3472010-06-09 22:41:35 +0000340 for (res = dev->resource_list; res; res = res->next) {
Myles Watsonc25cc112010-05-21 14:33:48 +0000341 if (res->index == index)
Eric Biederman5cd81732004-03-11 15:01:31 +0000342 break;
Eric Biederman5cd81732004-03-11 15:01:31 +0000343 }
Uwe Hermanne4870472010-11-04 23:23:47 +0000344
Myles Watsonc25cc112010-05-21 14:33:48 +0000345 return res;
Eric Biederman03acab62004-10-14 21:25:53 +0000346}
347
348/**
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000349 * See if a resource structure already exists for a given index and if not
350 * allocate one.
351 *
Paul Menzel20923872014-06-07 13:31:29 +0200352 * Then initialize the resource to default values.
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000353 *
354 * @param dev The device to find the resource on.
355 * @param index The index of the resource on the device.
356 * @return TODO.
Eric Biederman03acab62004-10-14 21:25:53 +0000357 */
Martin Roth38ddbfb2019-10-23 21:41:00 -0600358struct resource *new_resource(struct device *dev, unsigned int index)
Eric Biederman03acab62004-10-14 21:25:53 +0000359{
Myles Watsonc25cc112010-05-21 14:33:48 +0000360 struct resource *resource, *tail;
Eric Biederman03acab62004-10-14 21:25:53 +0000361
Uwe Hermanne4870472010-11-04 23:23:47 +0000362 /* First move all of the free resources to the end. */
Eric Biederman03acab62004-10-14 21:25:53 +0000363 compact_resources(dev);
364
Uwe Hermanne4870472010-11-04 23:23:47 +0000365 /* See if there is a resource with the appropriate index. */
Eric Biederman03acab62004-10-14 21:25:53 +0000366 resource = probe_resource(dev, index);
Eric Biederman5cd81732004-03-11 15:01:31 +0000367 if (!resource) {
Myles Watsonc25cc112010-05-21 14:33:48 +0000368 if (free_resources == NULL && !allocate_more_resources())
369 die("Couldn't allocate more resources.");
370
371 resource = free_resources;
372 free_resources = free_resources->next;
Eric Biederman5cd81732004-03-11 15:01:31 +0000373 memset(resource, 0, sizeof(*resource));
Myles Watsonc25cc112010-05-21 14:33:48 +0000374 resource->next = NULL;
375 tail = dev->resource_list;
376 if (tail) {
Frans Hendriksa9caa502021-02-01 11:44:37 +0100377 while (tail->next)
378 tail = tail->next;
Myles Watsonc25cc112010-05-21 14:33:48 +0000379 tail->next = resource;
Uwe Hermanne4870472010-11-04 23:23:47 +0000380 } else {
Myles Watsonc25cc112010-05-21 14:33:48 +0000381 dev->resource_list = resource;
Uwe Hermanne4870472010-11-04 23:23:47 +0000382 }
Eric Biederman5cd81732004-03-11 15:01:31 +0000383 }
Uwe Hermanne4870472010-11-04 23:23:47 +0000384
385 /* Initialize the resource values. */
Eric Biederman5cd81732004-03-11 15:01:31 +0000386 if (!(resource->flags & IORESOURCE_FIXED)) {
387 resource->flags = 0;
388 resource->base = 0;
389 }
390 resource->size = 0;
391 resource->limit = 0;
392 resource->index = index;
393 resource->align = 0;
394 resource->gran = 0;
395
396 return resource;
397}
398
Eric Biederman03acab62004-10-14 21:25:53 +0000399/**
400 * Return an existing resource structure for a given index.
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000401 *
402 * @param dev The device to find the resource on.
403 * @param index The index of the resource on the device.
404 * return TODO.
Eric Biederman03acab62004-10-14 21:25:53 +0000405 */
Martin Roth38ddbfb2019-10-23 21:41:00 -0600406struct resource *find_resource(const struct device *dev, unsigned int index)
Eric Biederman03acab62004-10-14 21:25:53 +0000407{
408 struct resource *resource;
409
Uwe Hermanne4870472010-11-04 23:23:47 +0000410 /* See if there is a resource with the appropriate index. */
Eric Biederman03acab62004-10-14 21:25:53 +0000411 resource = probe_resource(dev, index);
Nico Huber6a07db22023-05-12 15:46:24 +0200412 if (!resource)
413 die("%s missing resource: %02x\n", dev_path(dev), index);
Eric Biederman03acab62004-10-14 21:25:53 +0000414 return resource;
415}
416
Eric Biederman03acab62004-10-14 21:25:53 +0000417/**
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000418 * Round a number up to the next multiple of gran.
419 *
420 * @param val The starting value.
421 * @param gran Granularity we are aligning the number to.
422 * @return The aligned value.
Eric Biederman03acab62004-10-14 21:25:53 +0000423 */
424static resource_t align_up(resource_t val, unsigned long gran)
425{
426 resource_t mask;
427 mask = (1ULL << gran) - 1ULL;
428 val += mask;
429 val &= ~mask;
430 return val;
431}
432
433/**
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000434 * Round a number up to the previous multiple of gran.
435 *
436 * @param val The starting value.
437 * @param gran Granularity we are aligning the number to.
438 * @return The aligned value.
Eric Biederman03acab62004-10-14 21:25:53 +0000439 */
440static resource_t align_down(resource_t val, unsigned long gran)
441{
442 resource_t mask;
443 mask = (1ULL << gran) - 1ULL;
444 val &= ~mask;
445 return val;
446}
447
448/**
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000449 * Compute the maximum address that is part of a resource.
450 *
451 * @param resource The resource whose limit is desired.
452 * @return The end.
Eric Biederman03acab62004-10-14 21:25:53 +0000453 */
Kyösti Mälkkib2287712021-06-14 11:29:51 +0300454resource_t resource_end(const struct resource *resource)
Eric Biederman03acab62004-10-14 21:25:53 +0000455{
456 resource_t base, end;
Uwe Hermanne4870472010-11-04 23:23:47 +0000457
458 /* Get the base address. */
Eric Biederman03acab62004-10-14 21:25:53 +0000459 base = resource->base;
460
Uwe Hermanne4870472010-11-04 23:23:47 +0000461 /*
462 * For a non bridge resource granularity and alignment are the same.
Eric Biederman03acab62004-10-14 21:25:53 +0000463 * For a bridge resource align is the largest needed alignment below
Uwe Hermanne4870472010-11-04 23:23:47 +0000464 * the bridge. While the granularity is simply how many low bits of
465 * the address cannot be set.
Eric Biederman03acab62004-10-14 21:25:53 +0000466 */
Stefan Reinauer14e22772010-04-27 06:56:47 +0000467
Uwe Hermanne4870472010-11-04 23:23:47 +0000468 /* Get the end (rounded up). */
Eric Biederman03acab62004-10-14 21:25:53 +0000469 end = base + align_up(resource->size, resource->gran) - 1;
470
471 return end;
472}
473
474/**
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000475 * Compute the maximum legal value for resource->base.
476 *
477 * @param resource The resource whose maximum is desired.
478 * @return The maximum.
Eric Biederman03acab62004-10-14 21:25:53 +0000479 */
Kyösti Mälkkib2287712021-06-14 11:29:51 +0300480resource_t resource_max(const struct resource *resource)
Eric Biederman03acab62004-10-14 21:25:53 +0000481{
482 resource_t max;
483
484 max = align_down(resource->limit - resource->size + 1, resource->align);
485
486 return max;
487}
488
489/**
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000490 * Return the resource type of a resource.
491 *
492 * @param resource The resource type to decode.
493 * @return TODO.
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000494 */
Kyösti Mälkkib2287712021-06-14 11:29:51 +0300495const char *resource_type(const struct resource *resource)
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000496{
497 static char buffer[RESOURCE_TYPE_MAX];
Elyes HAOUASb7482212018-05-16 12:58:19 +0200498 snprintf(buffer, sizeof(buffer), "%s%s%s%s",
Vladimir Serbinenkoa37383d2013-11-26 02:41:26 +0100499 ((resource->flags & IORESOURCE_READONLY) ? "ro" : ""),
500 ((resource->flags & IORESOURCE_PREFETCH) ? "pref" : ""),
501 ((resource->flags == 0) ? "unused" :
502 (resource->flags & IORESOURCE_IO) ? "io" :
503 (resource->flags & IORESOURCE_DRQ) ? "drq" :
504 (resource->flags & IORESOURCE_IRQ) ? "irq" :
505 (resource->flags & IORESOURCE_MEM) ? "mem" : "??????"),
506 ((resource->flags & IORESOURCE_PCI64) ? "64" : ""));
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000507 return buffer;
508}
509
510/**
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000511 * Print the resource that was just stored.
512 *
Martin Roth63373ed2013-07-08 16:24:19 -0600513 * @param dev The device the stored resource lives on.
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000514 * @param resource The resource that was just stored.
515 * @param comment TODO
Eric Biederman03acab62004-10-14 21:25:53 +0000516 */
Kyösti Mälkkib2287712021-06-14 11:29:51 +0300517void report_resource_stored(struct device *dev, const struct resource *resource,
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000518 const char *comment)
Eric Biederman03acab62004-10-14 21:25:53 +0000519{
Uwe Hermanne4870472010-11-04 23:23:47 +0000520 char buf[10];
521 unsigned long long base, end;
522
523 if (!(resource->flags & IORESOURCE_STORED))
524 return;
525
526 base = resource->base;
527 end = resource_end(resource);
528 buf[0] = '\0';
529
Arthur Heymans7fcd4d52023-08-24 15:12:19 +0200530 if (dev->downstream && (resource->flags & IORESOURCE_PCI_BRIDGE)) {
Elyes HAOUASb7482212018-05-16 12:58:19 +0200531 snprintf(buf, sizeof(buf),
Arthur Heymans7fcd4d52023-08-24 15:12:19 +0200532 "seg %02x bus %02x ", dev->downstream->segment_group,
533 dev->downstream->secondary);
Eric Biederman03acab62004-10-14 21:25:53 +0000534 }
Gang Chencfb90fd2022-07-02 01:24:09 +0800535 printk(BIOS_DEBUG, "%s %02lx <- [0x%016llx - 0x%016llx] size 0x%08llx "
Uwe Hermanne4870472010-11-04 23:23:47 +0000536 "gran 0x%02x %s%s%s\n", dev_path(dev), resource->index,
537 base, end, resource->size, resource->gran, buf,
538 resource_type(resource), comment);
Eric Biederman03acab62004-10-14 21:25:53 +0000539}
Eric Biedermanf8a2ddd2004-10-30 08:05:41 +0000540
Uwe Hermanne4870472010-11-04 23:23:47 +0000541void search_bus_resources(struct bus *bus, unsigned long type_mask,
542 unsigned long type, resource_search_t search,
543 void *gp)
Eric Biedermanf8a2ddd2004-10-30 08:05:41 +0000544{
545 struct device *curdev;
Uwe Hermanne4870472010-11-04 23:23:47 +0000546
Myles Watson894a3472010-06-09 22:41:35 +0000547 for (curdev = bus->children; curdev; curdev = curdev->sibling) {
Myles Watsonc25cc112010-05-21 14:33:48 +0000548 struct resource *res;
Uwe Hermanne4870472010-11-04 23:23:47 +0000549
550 /* Ignore disabled devices. */
551 if (!curdev->enabled)
552 continue;
553
Myles Watson894a3472010-06-09 22:41:35 +0000554 for (res = curdev->resource_list; res; res = res->next) {
Uwe Hermanne4870472010-11-04 23:23:47 +0000555 /* If it isn't the right kind of resource ignore it. */
556 if ((res->flags & type_mask) != type)
Eric Biedermanf8a2ddd2004-10-30 08:05:41 +0000557 continue;
Uwe Hermanne4870472010-11-04 23:23:47 +0000558
559 /* If it is a subtractive resource recurse. */
Myles Watsonc25cc112010-05-21 14:33:48 +0000560 if (res->flags & IORESOURCE_SUBTRACTIVE) {
Arthur Heymans7fcd4d52023-08-24 15:12:19 +0200561 if (curdev->downstream)
562 search_bus_resources(curdev->downstream, type_mask, type,
Arthur Heymans80c79a52023-08-24 15:12:19 +0200563 search, gp);
Eric Biedermanf8a2ddd2004-10-30 08:05:41 +0000564 continue;
565 }
Myles Watsonc25cc112010-05-21 14:33:48 +0000566 search(gp, curdev, res);
Eric Biedermanf8a2ddd2004-10-30 08:05:41 +0000567 }
568 }
569}
570
Uwe Hermanne4870472010-11-04 23:23:47 +0000571void search_global_resources(unsigned long type_mask, unsigned long type,
572 resource_search_t search, void *gp)
Eric Biedermanf8a2ddd2004-10-30 08:05:41 +0000573{
574 struct device *curdev;
Uwe Hermanne4870472010-11-04 23:23:47 +0000575
Myles Watson894a3472010-06-09 22:41:35 +0000576 for (curdev = all_devices; curdev; curdev = curdev->next) {
Myles Watsonc25cc112010-05-21 14:33:48 +0000577 struct resource *res;
Uwe Hermanne4870472010-11-04 23:23:47 +0000578
579 /* Ignore disabled devices. */
580 if (!curdev->enabled)
581 continue;
582
Myles Watson894a3472010-06-09 22:41:35 +0000583 for (res = curdev->resource_list; res; res = res->next) {
Uwe Hermanne4870472010-11-04 23:23:47 +0000584 /* If it isn't the right kind of resource ignore it. */
585 if ((res->flags & type_mask) != type)
Eric Biedermanf8a2ddd2004-10-30 08:05:41 +0000586 continue;
Uwe Hermanne4870472010-11-04 23:23:47 +0000587
588 /* If it is a subtractive resource ignore it. */
589 if (res->flags & IORESOURCE_SUBTRACTIVE)
Eric Biedermanf8a2ddd2004-10-30 08:05:41 +0000590 continue;
Uwe Hermanne4870472010-11-04 23:23:47 +0000591
Shuo Liu0640c282022-08-02 01:50:36 +0800592 /* If the resource is not assigned ignore it. */
593 if (!(res->flags & IORESOURCE_ASSIGNED))
594 continue;
595
Myles Watsonc25cc112010-05-21 14:33:48 +0000596 search(gp, curdev, res);
Eric Biedermanf8a2ddd2004-10-30 08:05:41 +0000597 }
598 }
599}
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000600
Aaron Durbinf0349022017-11-10 10:47:54 -0700601void dev_set_enabled(struct device *dev, int enable)
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000602{
Uwe Hermanne4870472010-11-04 23:23:47 +0000603 if (dev->enabled == enable)
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000604 return;
Uwe Hermanne4870472010-11-04 23:23:47 +0000605
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000606 dev->enabled = enable;
Frans Hendriksa9caa502021-02-01 11:44:37 +0100607 if (dev->ops && dev->ops->enable)
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000608 dev->ops->enable(dev);
Frans Hendriksa9caa502021-02-01 11:44:37 +0100609 else if (dev->chip_ops && dev->chip_ops->enable_dev)
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000610 dev->chip_ops->enable_dev(dev);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000611}
612
613void disable_children(struct bus *bus)
614{
Aaron Durbinf0349022017-11-10 10:47:54 -0700615 struct device *child;
Uwe Hermanne4870472010-11-04 23:23:47 +0000616
Myles Watson894a3472010-06-09 22:41:35 +0000617 for (child = bus->children; child; child = child->sibling) {
Arthur Heymans7fcd4d52023-08-24 15:12:19 +0200618 if (child->downstream)
619 disable_children(child->downstream);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000620 dev_set_enabled(child, 0);
621 }
622}
Myles Watsonbb3d8122009-05-11 22:45:35 +0000623
Patrick Rudolpha6909f82017-05-22 18:30:27 +0200624/*
625 * Returns true if the device is an enabled bridge that has at least
Patrick Rudolphbd7739f2019-04-24 09:35:51 +0200626 * one enabled device on its secondary bus that is not of type NONE.
Patrick Rudolpha6909f82017-05-22 18:30:27 +0200627 */
Aaron Durbinf0349022017-11-10 10:47:54 -0700628bool dev_is_active_bridge(struct device *dev)
Patrick Rudolpha6909f82017-05-22 18:30:27 +0200629{
Aaron Durbinf0349022017-11-10 10:47:54 -0700630 struct device *child;
Patrick Rudolpha6909f82017-05-22 18:30:27 +0200631
632 if (!dev || !dev->enabled)
633 return 0;
634
Arthur Heymans7fcd4d52023-08-24 15:12:19 +0200635 if (!dev->downstream || !dev->downstream->children)
Patrick Rudolpha6909f82017-05-22 18:30:27 +0200636 return 0;
637
Arthur Heymans7fcd4d52023-08-24 15:12:19 +0200638 for (child = dev->downstream->children; child; child = child->sibling) {
Arthur Heymans80c79a52023-08-24 15:12:19 +0200639 if (child->path.type == DEVICE_PATH_NONE)
640 continue;
641 if (child->enabled)
642 return 1;
Patrick Rudolpha6909f82017-05-22 18:30:27 +0200643 }
644
645 return 0;
646}
647
Lubomir Rintel9ba8f7c2018-04-26 00:00:22 +0200648static void resource_tree(const struct device *root, int debug_level, int depth)
Myles Watsonbb3d8122009-05-11 22:45:35 +0000649{
Myles Watson894a3472010-06-09 22:41:35 +0000650 int i = 0;
Myles Watsonbb3d8122009-05-11 22:45:35 +0000651 struct device *child;
Myles Watsonc25cc112010-05-21 14:33:48 +0000652 struct resource *res;
Myles Watsonbb3d8122009-05-11 22:45:35 +0000653 char indent[30]; /* If your tree has more levels, it's wrong. */
654
655 for (i = 0; i < depth + 1 && i < 29; i++)
656 indent[i] = ' ';
657 indent[i] = '\0';
658
Nico Huber7cc14ac2021-03-27 20:03:02 +0100659 printk(BIOS_DEBUG, "%s%s", indent, dev_path(root));
Arthur Heymans7fcd4d52023-08-24 15:12:19 +0200660 if (root->downstream && root->downstream->children)
Nico Huber7cc14ac2021-03-27 20:03:02 +0100661 printk(BIOS_DEBUG, " child on link 0 %s",
Arthur Heymans7fcd4d52023-08-24 15:12:19 +0200662 dev_path(root->downstream->children));
Nico Huber7cc14ac2021-03-27 20:03:02 +0100663 printk(BIOS_DEBUG, "\n");
Myles Watson894a3472010-06-09 22:41:35 +0000664
Myles Watsonc25cc112010-05-21 14:33:48 +0000665 for (res = root->resource_list; res; res = res->next) {
Nico Huber7cc14ac2021-03-27 20:03:02 +0100666 printk(debug_level, "%s%s resource base %llx size %llx "
Uwe Hermanne4870472010-11-04 23:23:47 +0000667 "align %d gran %d limit %llx flags %lx index %lx\n",
668 indent, dev_path(root), res->base, res->size,
669 res->align, res->gran, res->limit, res->flags,
670 res->index);
Myles Watsonbb3d8122009-05-11 22:45:35 +0000671 }
672
Arthur Heymans7fcd4d52023-08-24 15:12:19 +0200673 if (!root->downstream)
Arthur Heymans80c79a52023-08-24 15:12:19 +0200674 return;
675
Arthur Heymans7fcd4d52023-08-24 15:12:19 +0200676 for (child = root->downstream->children; child; child = child->sibling)
Arthur Heymans80c79a52023-08-24 15:12:19 +0200677 resource_tree(child, debug_level, depth + 1);
Myles Watsonbb3d8122009-05-11 22:45:35 +0000678}
679
Elyes HAOUASe3480662018-05-06 20:32:23 +0200680void print_resource_tree(const struct device *root, int debug_level,
681 const char *msg)
Myles Watsonbb3d8122009-05-11 22:45:35 +0000682{
683 /* Bail if root is null. */
684 if (!root) {
Nico Huber7cc14ac2021-03-27 20:03:02 +0100685 printk(debug_level, "%s passed NULL for root!\n", __func__);
Myles Watsonbb3d8122009-05-11 22:45:35 +0000686 return;
687 }
688
689 /* Bail if not printing to screen. */
Nico Huber7cc14ac2021-03-27 20:03:02 +0100690 if (!printk(debug_level, "Show resources in subtree (%s)...%s\n",
Uwe Hermanne4870472010-11-04 23:23:47 +0000691 dev_path(root), msg))
Myles Watsonbb3d8122009-05-11 22:45:35 +0000692 return;
Uwe Hermanne4870472010-11-04 23:23:47 +0000693
Myles Watsonbb3d8122009-05-11 22:45:35 +0000694 resource_tree(root, debug_level, 0);
695}
696
Lubomir Rintel9ba8f7c2018-04-26 00:00:22 +0200697void show_devs_tree(const struct device *dev, int debug_level, int depth)
Myles Watsonbb3d8122009-05-11 22:45:35 +0000698{
Marcelo Povoa8404dca2014-02-14 15:42:49 -0800699 char depth_str[20];
Myles Watsonbb3d8122009-05-11 22:45:35 +0000700 int i;
701 struct device *sibling;
Myles Watson894a3472010-06-09 22:41:35 +0000702
Myles Watsonbb3d8122009-05-11 22:45:35 +0000703 for (i = 0; i < depth; i++)
704 depth_str[i] = ' ';
705 depth_str[i] = '\0';
Uwe Hermanne4870472010-11-04 23:23:47 +0000706
Nico Huber7cc14ac2021-03-27 20:03:02 +0100707 printk(debug_level, "%s%s: enabled %d\n",
Myles Watsonc25cc112010-05-21 14:33:48 +0000708 depth_str, dev_path(dev), dev->enabled);
Uwe Hermanne4870472010-11-04 23:23:47 +0000709
Arthur Heymans7fcd4d52023-08-24 15:12:19 +0200710 if (!dev->downstream)
Arthur Heymans80c79a52023-08-24 15:12:19 +0200711 return;
712
Arthur Heymans7fcd4d52023-08-24 15:12:19 +0200713 for (sibling = dev->downstream->children; sibling; sibling = sibling->sibling)
Arthur Heymans80c79a52023-08-24 15:12:19 +0200714 show_devs_tree(sibling, debug_level, depth + 1);
Myles Watsonbb3d8122009-05-11 22:45:35 +0000715}
716
717void show_all_devs_tree(int debug_level, const char *msg)
718{
719 /* Bail if not printing to screen. */
Nico Huber7cc14ac2021-03-27 20:03:02 +0100720 if (!printk(debug_level, "Show all devs in tree form... %s\n", msg))
Myles Watsonbb3d8122009-05-11 22:45:35 +0000721 return;
Kyösti Mälkki3d3c8c32016-08-15 10:04:21 +0300722 show_devs_tree(all_devices, debug_level, 0);
Myles Watsonbb3d8122009-05-11 22:45:35 +0000723}
724
725void show_devs_subtree(struct device *root, int debug_level, const char *msg)
726{
727 /* Bail if not printing to screen. */
Nico Huber7cc14ac2021-03-27 20:03:02 +0100728 if (!printk(debug_level, "Show all devs in subtree %s... %s\n",
Uwe Hermanne4870472010-11-04 23:23:47 +0000729 dev_path(root), msg))
Myles Watsonbb3d8122009-05-11 22:45:35 +0000730 return;
Nico Huber7cc14ac2021-03-27 20:03:02 +0100731 printk(debug_level, "%s\n", msg);
Kyösti Mälkki3d3c8c32016-08-15 10:04:21 +0300732 show_devs_tree(root, debug_level, 0);
Myles Watsonbb3d8122009-05-11 22:45:35 +0000733}
734
735void show_all_devs(int debug_level, const char *msg)
736{
737 struct device *dev;
738
739 /* Bail if not printing to screen. */
Nico Huber7cc14ac2021-03-27 20:03:02 +0100740 if (!printk(debug_level, "Show all devs... %s\n", msg))
Myles Watsonbb3d8122009-05-11 22:45:35 +0000741 return;
742 for (dev = all_devices; dev; dev = dev->next) {
Nico Huber7cc14ac2021-03-27 20:03:02 +0100743 printk(debug_level, "%s: enabled %d\n",
Myles Watsonc25cc112010-05-21 14:33:48 +0000744 dev_path(dev), dev->enabled);
Myles Watsonbb3d8122009-05-11 22:45:35 +0000745 }
746}
747
748void show_one_resource(int debug_level, struct device *dev,
749 struct resource *resource, const char *comment)
750{
751 char buf[10];
752 unsigned long long base, end;
753 base = resource->base;
754 end = resource_end(resource);
755 buf[0] = '\0';
Uwe Hermanne4870472010-11-04 23:23:47 +0000756
Gang Chencfb90fd2022-07-02 01:24:09 +0800757 printk(debug_level, "%s %02lx <- [0x%016llx - 0x%016llx] "
Patrick Georgi51615092012-03-11 19:31:03 +0100758 "size 0x%08llx gran 0x%02x %s%s%s\n", dev_path(dev),
Uwe Hermanne4870472010-11-04 23:23:47 +0000759 resource->index, base, end, resource->size, resource->gran,
760 buf, resource_type(resource), comment);
Myles Watsonbb3d8122009-05-11 22:45:35 +0000761}
762
Frans Hendriksa9caa502021-02-01 11:44:37 +0100763void show_all_devs_resources(int debug_level, const char *msg)
Myles Watsonbb3d8122009-05-11 22:45:35 +0000764{
765 struct device *dev;
766
Nico Huber7cc14ac2021-03-27 20:03:02 +0100767 if (!printk(debug_level, "Show all devs with resources... %s\n", msg))
Myles Watsonbb3d8122009-05-11 22:45:35 +0000768 return;
769
770 for (dev = all_devices; dev; dev = dev->next) {
Myles Watsonc25cc112010-05-21 14:33:48 +0000771 struct resource *res;
Nico Huber7cc14ac2021-03-27 20:03:02 +0100772 printk(debug_level, "%s: enabled %d\n",
Myles Watsonc25cc112010-05-21 14:33:48 +0000773 dev_path(dev), dev->enabled);
774 for (res = dev->resource_list; res; res = res->next)
775 show_one_resource(debug_level, dev, res, "");
Myles Watsonbb3d8122009-05-11 22:45:35 +0000776 }
777}
Uwe Hermann4b42a622010-10-11 19:36:13 +0000778
Kyösti Mälkkice345962021-06-11 19:31:22 +0300779const struct resource *fixed_resource_range_idx(struct device *dev, unsigned long index,
780 uint64_t base, uint64_t size, unsigned long flags)
Uwe Hermann4b42a622010-10-11 19:36:13 +0000781{
782 struct resource *resource;
Kyösti Mälkkice345962021-06-11 19:31:22 +0300783 if (!size)
784 return NULL;
Uwe Hermann4b42a622010-10-11 19:36:13 +0000785
786 resource = new_resource(dev, index);
Kyösti Mälkkice345962021-06-11 19:31:22 +0300787 resource->base = base;
788 resource->size = size;
789 resource->flags = IORESOURCE_FIXED | IORESOURCE_ASSIGNED;
790 resource->flags |= flags;
Uwe Hermann4b42a622010-10-11 19:36:13 +0000791
Kyösti Mälkkice345962021-06-11 19:31:22 +0300792 printk(BIOS_SPEW, "dev: %s, index: 0x%lx, base: 0x%llx, size: 0x%llx\n",
793 dev_path(dev), resource->index, resource->base, resource->size);
794
795 return resource;
Kyösti Mälkki63f8c082012-07-10 13:27:26 +0300796}
797
Kyösti Mälkkid0525d42021-06-13 10:09:51 +0300798const struct resource *lower_ram_end(struct device *dev, unsigned long index, uint64_t end)
799{
800 return ram_from_to(dev, index, 0, end);
801}
802
803const struct resource *upper_ram_end(struct device *dev, unsigned long index, uint64_t end)
804{
805 if (end <= 4ull * GiB)
806 return NULL;
807
808 printk(BIOS_INFO, "Available memory above 4GB: %lluM\n", (end - 4ull * GiB) / MiB);
809
810 return ram_from_to(dev, index, 4ull * GiB, end);
811}
812
Angel Pons90be7542021-01-20 13:03:58 +0100813void mmconf_resource(struct device *dev, unsigned long index)
Kyösti Mälkkie25b5ef2016-12-02 08:56:05 +0200814{
Angel Pons90be7542021-01-20 13:03:58 +0100815 struct resource *resource = new_resource(dev, index);
Shelley Chen4e9bb332021-10-20 15:43:45 -0700816 resource->base = CONFIG_ECAM_MMCONF_BASE_ADDRESS;
817 resource->size = CONFIG_ECAM_MMCONF_LENGTH;
Kyösti Mälkkie25b5ef2016-12-02 08:56:05 +0200818 resource->flags = IORESOURCE_MEM | IORESOURCE_RESERVE |
819 IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED;
820
Angel Ponsd19cc112021-07-04 11:41:31 +0200821 printk(BIOS_DEBUG, "Adding PCIe enhanced config space BAR 0x%08lx-0x%08lx.\n",
822 (unsigned long)(resource->base),
Kyösti Mälkkie25b5ef2016-12-02 08:56:05 +0200823 (unsigned long)(resource->base + resource->size));
824}
825
Uwe Hermann4b42a622010-10-11 19:36:13 +0000826void tolm_test(void *gp, struct device *dev, struct resource *new)
827{
828 struct resource **best_p = gp;
829 struct resource *best;
830
831 best = *best_p;
832
Furquan Shaikhafaae8a2020-05-18 16:00:53 -0700833 /*
834 * If resource is not allocated any space i.e. size is zero,
835 * then do not consider this resource in tolm calculations.
836 */
837 if (new->size == 0)
838 return;
839
Uwe Hermann4b42a622010-10-11 19:36:13 +0000840 if (!best || (best->base > new->base))
841 best = new;
842
843 *best_p = best;
844}
845
846u32 find_pci_tolm(struct bus *bus)
847{
848 struct resource *min = NULL;
849 u32 tolm;
Furquan Shaikhafaae8a2020-05-18 16:00:53 -0700850 unsigned long mask_match = IORESOURCE_MEM | IORESOURCE_ASSIGNED;
Uwe Hermann4b42a622010-10-11 19:36:13 +0000851
Furquan Shaikhafaae8a2020-05-18 16:00:53 -0700852 search_bus_resources(bus, mask_match, mask_match, tolm_test, &min);
Uwe Hermann4b42a622010-10-11 19:36:13 +0000853
854 tolm = 0xffffffffUL;
855
856 if (min && tolm > min->base)
857 tolm = min->base;
858
859 return tolm;
860}
Stefan Reinauerdc8448fd2012-03-30 13:52:58 -0700861
862/* Count of enabled CPUs */
863int dev_count_cpu(void)
864{
Aaron Durbinf0349022017-11-10 10:47:54 -0700865 struct device *cpu;
Stefan Reinauerdc8448fd2012-03-30 13:52:58 -0700866 int count = 0;
867
868 for (cpu = all_devices; cpu; cpu = cpu->next) {
Fabio Aiuto45aae7f2022-09-23 16:51:34 +0200869 if (!is_enabled_cpu(cpu))
Stefan Reinauerdc8448fd2012-03-30 13:52:58 -0700870 continue;
871 count++;
872 }
873
874 return count;
875}
Lee Leahya95baf92016-02-13 06:10:04 -0800876
877/* Get device path name */
878const char *dev_path_name(enum device_path_type type)
879{
880 static const char *const type_names[] = DEVICE_PATH_NAMES;
881 const char *type_name = "Unknown";
882
883 /* Translate the type value into a string */
884 if (type < ARRAY_SIZE(type_names))
885 type_name = type_names[type];
886 return type_name;
887}
Kyösti Mälkki68e6dc92021-06-14 00:40:22 +0300888
Nico Huber577c6b92022-08-15 00:08:58 +0200889bool dev_path_hotplug(const struct device *dev)
890{
Arthur Heymans7fcd4d52023-08-24 15:12:19 +0200891 for (dev = dev->upstream->dev; dev != dev->upstream->dev; dev = dev->upstream->dev) {
Nico Huber577c6b92022-08-15 00:08:58 +0200892 if (dev->hotplug_port)
893 return true;
894 }
895 return false;
896}
897
Kyösti Mälkki68e6dc92021-06-14 00:40:22 +0300898void log_resource(const char *type, const struct device *dev, const struct resource *res,
899 const char *srcfile, const int line)
900{
901 printk(BIOS_SPEW, "%s:%d res: %s, dev: %s, index: 0x%lx, base: 0x%llx, "
902 "end: 0x%llx, size_kb: 0x%llx\n",
903 srcfile, line, type, dev_path(dev), res->index, res->base,
904 resource_end(res), res->size / KiB);
905}
Fabio Aiutoc5573d62022-09-10 14:23:38 +0200906
907bool is_cpu(const struct device *cpu)
908{
909 return cpu->path.type == DEVICE_PATH_APIC &&
Arthur Heymans7fcd4d52023-08-24 15:12:19 +0200910 cpu->upstream->dev->path.type == DEVICE_PATH_CPU_CLUSTER;
Fabio Aiutoc5573d62022-09-10 14:23:38 +0200911}
912
913bool is_enabled_cpu(const struct device *cpu)
914{
915 return is_cpu(cpu) && cpu->enabled;
916}
Fabio Aiuto4fce79f2022-09-30 11:22:09 +0200917
918bool is_pci(const struct device *pci)
919{
920 return pci->path.type == DEVICE_PATH_PCI;
921}
922
923bool is_enabled_pci(const struct device *pci)
924{
925 return is_pci(pci) && pci->enabled;
926}
927
928bool is_pci_dev_on_bus(const struct device *pci, unsigned int bus)
929{
Arthur Heymans7fcd4d52023-08-24 15:12:19 +0200930 return is_pci(pci) && pci->upstream->segment_group == 0
931 && pci->upstream->secondary == bus;
Fabio Aiuto4fce79f2022-09-30 11:22:09 +0200932}