- Updates for 64bit resource support, handling missing devices and cpus in the config...
[coreboot.git] / src / devices / device_util.c
1 #include <console/console.h>
2 #include <device/device.h>
3 #include <device/path.h>
4 #include <device/pci.h>
5 #include <string.h>
6
7 /**
8  * @brief See if a device structure exists for path
9  *
10  * @param bus The bus to find the device on
11  * @param path The relative path from the bus to the appropriate device
12  * @return pointer to a device structure for the device on bus at path
13  *         or 0/NULL if no device is found
14  */
15 device_t find_dev_path(struct bus *parent, struct device_path *path)
16 {
17         device_t child;
18         for(child = parent->children; child; child = child->sibling) {
19                 if (path_eq(path, &child->path)) {
20                         break;
21                 }
22         }
23         return child;
24 }
25
26 /**
27  * @brief See if a device structure already exists and if not allocate it
28  *
29  * @param bus The bus to find the device on
30  * @param path The relative path from the bus to the appropriate device
31  * @return pointer to a device structure for the device on bus at path
32  */
33 device_t alloc_find_dev(struct bus *parent, struct device_path *path)
34 {
35         device_t child;
36         child = find_dev_path(parent, path);
37         if (!child) {
38                 child = alloc_dev(parent, path);
39         }
40         return child;
41 }
42
43 /**
44  * Given a bus and a devfn number, find the device structure
45  * @param bus The bus number
46  * @param devfn a device/function number
47  * @return pointer to the device structure
48  */
49 struct device *dev_find_slot(unsigned int bus, unsigned int devfn)
50 {
51         struct device *dev, *result;
52
53         result = 0;
54         for (dev = all_devices; dev; dev = dev->next) {
55                 if ((dev->path.type == DEVICE_PATH_PCI) &&
56                         (dev->bus->secondary == bus) && 
57                         (dev->path.u.pci.devfn == devfn)) {
58                         result = dev;
59                         break;
60                 }
61         }
62         return result;
63 }
64
65 /** Find a device of a given vendor and type
66  * @param vendor Vendor ID (e.g. 0x8086 for Intel)
67  * @param device Device ID
68  * @param from Pointer to the device structure, used as a starting point
69  *        in the linked list of all_devices, which can be 0 to start at the 
70  *        head of the list (i.e. all_devices)
71  * @return Pointer to the device struct 
72  */
73 struct device *dev_find_device(unsigned int vendor, unsigned int device, struct device *from)
74 {
75         if (!from)
76                 from = all_devices;
77         else
78                 from = from->next;
79         while (from && (from->vendor != vendor || from->device != device)) {
80                 from = from->next;
81         }
82         return from;
83 }
84
85 /** Find a device of a given class
86  * @param class Class of the device
87  * @param from Pointer to the device structure, used as a starting point
88  *        in the linked list of all_devices, which can be 0 to start at the 
89  *        head of the list (i.e. all_devices)
90  * @return Pointer to the device struct 
91  */
92 struct device *dev_find_class(unsigned int class, struct device *from)
93 {
94         if (!from)
95                 from = all_devices;
96         else
97                 from = from->next;
98         while (from && (from->class & 0xffffff00) != class)
99                 from = from->next;
100         return from;
101 }
102
103
104 const char *dev_path(device_t dev)
105 {
106         static char buffer[DEVICE_PATH_MAX];
107         buffer[0] = '\0';
108         if (!dev) {
109                 memcpy(buffer, "<null>", 7);
110         }
111         else {
112                 switch(dev->path.type) {
113                 case DEVICE_PATH_ROOT:
114                         memcpy(buffer, "Root Device", 12);
115                         break;
116                 case DEVICE_PATH_DEFAULT_CPU:
117                         memcpy(buffer, "Default CPU", 12);
118                         break;
119                 case DEVICE_PATH_PCI:
120                         sprintf(buffer, "PCI: %02x:%02x.%01x",
121                                 dev->bus->secondary, 
122                                 PCI_SLOT(dev->path.u.pci.devfn), PCI_FUNC(dev->path.u.pci.devfn));
123                         break;
124                 case DEVICE_PATH_PNP:
125                         sprintf(buffer, "PNP: %04x.%01x",
126                                 dev->path.u.pnp.port, dev->path.u.pnp.device);
127                         break;
128                 case DEVICE_PATH_I2C:
129                         sprintf(buffer, "I2C: %02x",
130                                 dev->path.u.i2c.device);
131                         break;
132                 case DEVICE_PATH_APIC:
133                         sprintf(buffer, "APIC: %02x",
134                                 dev->path.u.apic.apic_id);
135                         break;
136                 default:
137                         printk_err("Unknown device path type: %d\n", dev->path.type);
138                         break;
139                 }
140         }
141         return buffer;
142 }
143
144 int path_eq(struct device_path *path1, struct device_path *path2)
145 {
146         int equal = 0;
147         if (path1->type == path2->type) {
148                 switch(path1->type) {
149                 case DEVICE_PATH_NONE:
150                         break;
151                 case DEVICE_PATH_ROOT:
152                         equal = 1;
153                         break;
154                 case DEVICE_PATH_DEFAULT_CPU:
155                         equal = 1;
156                         break;
157                 case DEVICE_PATH_PCI:
158                         equal = (path1->u.pci.bus == path2->u.pci.bus) &&
159                                 (path1->u.pci.devfn == path2->u.pci.devfn);
160                         break;
161                 case DEVICE_PATH_PNP:
162                         equal = (path1->u.pnp.port == path2->u.pnp.port) &&
163                                 (path1->u.pnp.device == path2->u.pnp.device);
164                         break;
165                 case DEVICE_PATH_I2C:
166                         equal = (path1->u.i2c.device == path2->u.i2c.device);
167                         break;
168                 case DEVICE_PATH_APIC:
169                         equal = (path1->u.apic.apic_id == path2->u.apic.apic_id);
170                         break;
171                 default:
172                         printk_err("Uknown device type: %d\n", path1->type);
173                         break;
174                 }
175         }
176         return equal;
177 }
178
179 /**
180  * See if we have unused but allocated resource structures.
181  * If so remove the allocation.
182  * @param dev The device to find the resource on
183  */
184 void compact_resources(device_t dev)
185 {
186         struct resource *resource;
187         int i;
188         /* Move all of the free resources to the end */
189         for(i = 0; i < dev->resources;) {
190                 resource = &dev->resource[i];
191                 if (!resource->flags) {
192                         memmove(resource, resource + 1, dev->resources - i);
193                         dev->resources -= 1;
194                         memset(&dev->resource[dev->resources], 0, sizeof(*resource));
195                 } else {
196                         i++;
197                 }
198         }
199 }
200
201
202 /**
203  * See if a resource structure already exists for a given index
204  * @param dev The device to find the resource on
205  * @param index  The index of the resource on the device.
206  * @return the resource if it already exists
207  */
208 struct resource *probe_resource(device_t dev, unsigned index)
209 {
210         struct resource *resource;
211         int i;
212         /* See if there is a resource with the appropriate index */
213         resource = 0;
214         for(i = 0; i < dev->resources; i++) {
215                 if (dev->resource[i].index == index) {
216                         resource = &dev->resource[i];
217                         break;
218                 }
219         }
220         return resource;
221 }
222
223 /**
224  * See if a resource structure already exists for a given index and if
225  * not allocate one.  Then initialize the initialize the resource
226  * to default values.
227  * @param dev The device to find the resource on
228  * @param index  The index of the resource on the device.
229  */
230 struct resource *new_resource(device_t dev, unsigned index)
231 {
232         struct resource *resource;
233
234         /* First move all of the free resources to the end */
235         compact_resources(dev);
236
237         /* See if there is a resource with the appropriate index */
238         resource = probe_resource(dev, index);
239         if (!resource) {
240                 if (dev->resources == MAX_RESOURCES) {
241                         die("MAX_RESOURCES exceeded.");
242                 }
243                 resource = &dev->resource[dev->resources];
244                 memset(resource, 0, sizeof(*resource));
245                 dev->resources++;
246         }
247         /* Initialize the resource values */
248         if (!(resource->flags & IORESOURCE_FIXED)) {
249                 resource->flags = 0;
250                 resource->base = 0;
251         }
252         resource->size  = 0;
253         resource->limit = 0;
254         resource->index = index;
255         resource->align = 0;
256         resource->gran  = 0;
257
258         return resource;
259 }
260
261 /**
262  * Return an existing resource structure for a given index.
263  * @param dev The device to find the resource on
264  * @param index  The index of the resource on the device.
265  */
266 struct resource *find_resource(device_t dev, unsigned index)
267 {
268         struct resource *resource;
269
270         /* See if there is a resource with the appropriate index */
271         resource = probe_resource(dev, index);
272         if (!resource) {
273                 printk_emerg("%s missing resource: %02x\n",
274                         dev_path(dev), index);
275                 die("");
276         }
277         return resource;
278 }
279
280
281 /**
282  * @brief round a number up to the next multiple of gran
283  * @param val the starting value
284  * @param gran granularity we are aligning the number to.
285  * @returns aligned value
286  */
287 static resource_t align_up(resource_t val, unsigned long gran)
288 {
289         resource_t mask;
290         mask = (1ULL << gran) - 1ULL;
291         val += mask;
292         val &= ~mask;
293         return val;
294 }
295
296 /**
297  * @brief round a number up to the previous multiple of gran
298  * @param val the starting value
299  * @param gran granularity we are aligning the number to.
300  * @returns aligned value
301  */
302 static resource_t align_down(resource_t val, unsigned long gran)
303 {
304         resource_t mask;
305         mask = (1ULL << gran) - 1ULL;
306         val &= ~mask;
307         return val;
308 }
309
310 /**
311  * @brief Compute the maximum address that is part of a resource
312  * @param resource the resource whose limit is desired
313  * @returns the end
314  */
315 resource_t resource_end(struct resource *resource)
316 {
317         resource_t base, end;
318         /* get the base address */
319         base = resource->base;
320
321         /* For a non bridge resource granularity and alignment are the same.
322          * For a bridge resource align is the largest needed alignment below
323          * the bridge.  While the granularity is simply how many low bits of the
324          * address cannot be set.
325          */
326         
327         /* Get the end (rounded up) */
328         end = base + align_up(resource->size, resource->gran) - 1;
329
330         return end;
331 }
332
333 /**
334  * @brief Compute the maximum legal value for resource->base
335  * @param resource the resource whose maximum is desired
336  * @returns the maximum
337  */
338 resource_t resource_max(struct resource *resource)
339 {
340         resource_t max;
341
342         max = align_down(resource->limit - resource->size + 1, resource->align);
343
344         return max;
345 }
346
347 /**
348  * @brief print the resource that was just stored.
349  * @param dev the device the stored resorce lives on
350  * @param resource the resource that was just stored.
351  */
352 void report_resource_stored(device_t dev, struct resource *resource, const char *comment)
353 {
354         if (resource->flags & IORESOURCE_STORED) {
355                 unsigned char buf[10];
356                 unsigned long long base, end;
357                 base = resource->base;
358                 end = resource_end(resource);
359                 buf[0] = '\0';
360                 if (resource->flags & IORESOURCE_PCI_BRIDGE) {
361                         sprintf(buf, "bus %d ", dev->link[0].secondary);
362                 }
363                 printk_debug(
364                         "%s %02x <- [0x%010Lx - 0x%010Lx] %s%s%s%s\n",
365                         dev_path(dev),
366                         resource->index,
367                         base, end,
368                         buf,
369                         (resource->flags & IORESOURCE_PREFETCH) ? "pref" : "",
370                         (resource->flags & IORESOURCE_IO)? "io":
371                         (resource->flags & IORESOURCE_DRQ)? "drq":
372                         (resource->flags & IORESOURCE_IRQ)? "irq":
373                         (resource->flags & IORESOURCE_MEM)? "mem": 
374                         "????",
375                         comment);
376         }
377 }