- First stab at running linuxbios without the old static device tree.
[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                 case DEVICE_PATH_PCI_DOMAIN:
137                         sprintf(buffer, "PCI_DOMAIN: %04x",
138                                 dev->path.u.pci_domain.domain);
139                         break;
140                 case DEVICE_PATH_APIC_CLUSTER:
141                         sprintf(buffer, "APIC_CLUSTER: %01x",
142                                 dev->path.u.apic_cluster.cluster);
143                         break;
144                 default:
145                         printk_err("Unknown device path type: %d\n", dev->path.type);
146                         break;
147                 }
148         }
149         return buffer;
150 }
151
152 int path_eq(struct device_path *path1, struct device_path *path2)
153 {
154         int equal = 0;
155         if (path1->type == path2->type) {
156                 switch(path1->type) {
157                 case DEVICE_PATH_NONE:
158                         break;
159                 case DEVICE_PATH_ROOT:
160                         equal = 1;
161                         break;
162                 case DEVICE_PATH_DEFAULT_CPU:
163                         equal = 1;
164                         break;
165                 case DEVICE_PATH_PCI:
166                         equal = (path1->u.pci.devfn == path2->u.pci.devfn);
167                         break;
168                 case DEVICE_PATH_PNP:
169                         equal = (path1->u.pnp.port == path2->u.pnp.port) &&
170                                 (path1->u.pnp.device == path2->u.pnp.device);
171                         break;
172                 case DEVICE_PATH_I2C:
173                         equal = (path1->u.i2c.device == path2->u.i2c.device);
174                         break;
175                 case DEVICE_PATH_APIC:
176                         equal = (path1->u.apic.apic_id == path2->u.apic.apic_id);
177                         break;
178                 case DEVICE_PATH_PCI_DOMAIN:
179                         equal = (path1->u.pci_domain.domain == path2->u.pci_domain.domain);
180                         break;
181                 case DEVICE_PATH_APIC_CLUSTER:
182                         equal = (path1->u.apic_cluster.cluster == path2->u.apic_cluster.cluster);
183                         break;
184                 default:
185                         printk_err("Uknown device type: %d\n", path1->type);
186                         break;
187                 }
188         }
189         return equal;
190 }
191
192 /**
193  * See if we have unused but allocated resource structures.
194  * If so remove the allocation.
195  * @param dev The device to find the resource on
196  */
197 void compact_resources(device_t dev)
198 {
199         struct resource *resource;
200         int i;
201         /* Move all of the free resources to the end */
202         for(i = 0; i < dev->resources;) {
203                 resource = &dev->resource[i];
204                 if (!resource->flags) {
205                         memmove(resource, resource + 1, dev->resources - i);
206                         dev->resources -= 1;
207                         memset(&dev->resource[dev->resources], 0, sizeof(*resource));
208                 } else {
209                         i++;
210                 }
211         }
212 }
213
214
215 /**
216  * See if a resource structure already exists for a given index
217  * @param dev The device to find the resource on
218  * @param index  The index of the resource on the device.
219  * @return the resource if it already exists
220  */
221 struct resource *probe_resource(device_t dev, unsigned index)
222 {
223         struct resource *resource;
224         int i;
225         /* See if there is a resource with the appropriate index */
226         resource = 0;
227         for(i = 0; i < dev->resources; i++) {
228                 if (dev->resource[i].index == index) {
229                         resource = &dev->resource[i];
230                         break;
231                 }
232         }
233         return resource;
234 }
235
236 /**
237  * See if a resource structure already exists for a given index and if
238  * not allocate one.  Then initialize the initialize the resource
239  * to default values.
240  * @param dev The device to find the resource on
241  * @param index  The index of the resource on the device.
242  */
243 struct resource *new_resource(device_t dev, unsigned index)
244 {
245         struct resource *resource;
246
247         /* First move all of the free resources to the end */
248         compact_resources(dev);
249
250         /* See if there is a resource with the appropriate index */
251         resource = probe_resource(dev, index);
252         if (!resource) {
253                 if (dev->resources == MAX_RESOURCES) {
254                         die("MAX_RESOURCES exceeded.");
255                 }
256                 resource = &dev->resource[dev->resources];
257                 memset(resource, 0, sizeof(*resource));
258                 dev->resources++;
259         }
260         /* Initialize the resource values */
261         if (!(resource->flags & IORESOURCE_FIXED)) {
262                 resource->flags = 0;
263                 resource->base = 0;
264         }
265         resource->size  = 0;
266         resource->limit = 0;
267         resource->index = index;
268         resource->align = 0;
269         resource->gran  = 0;
270
271         return resource;
272 }
273
274 /**
275  * Return an existing resource structure for a given index.
276  * @param dev The device to find the resource on
277  * @param index  The index of the resource on the device.
278  */
279 struct resource *find_resource(device_t dev, unsigned index)
280 {
281         struct resource *resource;
282
283         /* See if there is a resource with the appropriate index */
284         resource = probe_resource(dev, index);
285         if (!resource) {
286                 printk_emerg("%s missing resource: %02x\n",
287                         dev_path(dev), index);
288                 die("");
289         }
290         return resource;
291 }
292
293
294 /**
295  * @brief round a number up to the next multiple of gran
296  * @param val the starting value
297  * @param gran granularity we are aligning the number to.
298  * @returns aligned value
299  */
300 static resource_t align_up(resource_t val, unsigned long gran)
301 {
302         resource_t mask;
303         mask = (1ULL << gran) - 1ULL;
304         val += mask;
305         val &= ~mask;
306         return val;
307 }
308
309 /**
310  * @brief round a number up to the previous multiple of gran
311  * @param val the starting value
312  * @param gran granularity we are aligning the number to.
313  * @returns aligned value
314  */
315 static resource_t align_down(resource_t val, unsigned long gran)
316 {
317         resource_t mask;
318         mask = (1ULL << gran) - 1ULL;
319         val &= ~mask;
320         return val;
321 }
322
323 /**
324  * @brief Compute the maximum address that is part of a resource
325  * @param resource the resource whose limit is desired
326  * @returns the end
327  */
328 resource_t resource_end(struct resource *resource)
329 {
330         resource_t base, end;
331         /* get the base address */
332         base = resource->base;
333
334         /* For a non bridge resource granularity and alignment are the same.
335          * For a bridge resource align is the largest needed alignment below
336          * the bridge.  While the granularity is simply how many low bits of the
337          * address cannot be set.
338          */
339         
340         /* Get the end (rounded up) */
341         end = base + align_up(resource->size, resource->gran) - 1;
342
343         return end;
344 }
345
346 /**
347  * @brief Compute the maximum legal value for resource->base
348  * @param resource the resource whose maximum is desired
349  * @returns the maximum
350  */
351 resource_t resource_max(struct resource *resource)
352 {
353         resource_t max;
354
355         max = align_down(resource->limit - resource->size + 1, resource->align);
356
357         return max;
358 }
359
360 /**
361  * @brief print the resource that was just stored.
362  * @param dev the device the stored resorce lives on
363  * @param resource the resource that was just stored.
364  */
365 void report_resource_stored(device_t dev, struct resource *resource, const char *comment)
366 {
367         if (resource->flags & IORESOURCE_STORED) {
368                 unsigned char buf[10];
369                 unsigned long long base, end;
370                 base = resource->base;
371                 end = resource_end(resource);
372                 buf[0] = '\0';
373                 if (resource->flags & IORESOURCE_PCI_BRIDGE) {
374                         sprintf(buf, "bus %d ", dev->link[0].secondary);
375                 }
376                 printk_debug(
377                         "%s %02x <- [0x%010Lx - 0x%010Lx] %s%s%s%s\n",
378                         dev_path(dev),
379                         resource->index,
380                         base, end,
381                         buf,
382                         (resource->flags & IORESOURCE_PREFETCH) ? "pref" : "",
383                         (resource->flags & IORESOURCE_IO)? "io":
384                         (resource->flags & IORESOURCE_DRQ)? "drq":
385                         (resource->flags & IORESOURCE_IRQ)? "irq":
386                         (resource->flags & IORESOURCE_MEM)? "mem": 
387                         "????",
388                         comment);
389         }
390 }