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