summaryrefslogtreecommitdiff
path: root/src/devices/device.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/device.c')
-rw-r--r--src/devices/device.c103
1 files changed, 66 insertions, 37 deletions
diff --git a/src/devices/device.c b/src/devices/device.c
index 4b7d8728fd..7ef65e2fe4 100644
--- a/src/devices/device.c
+++ b/src/devices/device.c
@@ -22,6 +22,7 @@
#include <device/pci_ids.h>
#include <stdlib.h>
#include <string.h>
+#include <smp/spinlock.h>
/** Linked list of ALL devices */
struct device *all_devices = &dev_root;
@@ -30,7 +31,7 @@ static struct device **last_dev_p = &dev_root.next;
/** The upper limit of MEM resource of the devices.
* Reserve 20M for the system */
-#define DEVICE_MEM_HIGH 0xFEC00000UL
+#define DEVICE_MEM_HIGH 0xFEBFFFFFUL
/** The lower limit of IO resource of the devices.
* Reserve 4k for ISA/Legacy devices */
#define DEVICE_IO_START 0x1000
@@ -53,6 +54,7 @@ device_t alloc_dev(struct bus *parent, struct device_path *path)
device_t dev, child;
int link;
+ spin_lock(&dev_lock);
/* Find the last child of our parent */
for(child = parent->children; child && child->sibling; ) {
child = child->sibling;
@@ -64,17 +66,15 @@ device_t alloc_dev(struct bus *parent, struct device_path *path)
memset(dev, 0, sizeof(*dev));
memcpy(&dev->path, path, sizeof(*path));
- /* Append a new device to the global device list.
- * The list is used to find devices once everything is set up.
- */
- *last_dev_p = dev;
- last_dev_p = &dev->next;
/* Initialize the back pointers in the link fields */
for(link = 0; link < MAX_LINKS; link++) {
dev->link[link].dev = dev;
dev->link[link].link = link;
}
+
+ /* By default devices are enabled */
+ dev->enabled = 1;
/* Add the new device to the list of children of the bus. */
dev->bus = parent;
@@ -83,9 +83,14 @@ device_t alloc_dev(struct bus *parent, struct device_path *path)
} else {
parent->children = dev;
}
- /* If we don't have any other information about a device enable it */
- dev->enabled = 1;
+ /* Append a new device to the global device list.
+ * The list is used to find devices once everything is set up.
+ */
+ *last_dev_p = dev;
+ last_dev_p = &dev->next;
+
+ spin_unlock(&dev_lock);
return dev;
}
@@ -269,7 +274,7 @@ void compute_allocate_resource(
{
struct device *dev;
struct resource *resource;
- unsigned long base;
+ resource_t base;
unsigned long align, min_align;
min_align = 0;
base = bridge->base;
@@ -302,7 +307,7 @@ void compute_allocate_resource(
* compute the addresses.
*/
while((dev = largest_resource(bus, &resource, type_mask, type))) {
- unsigned long size;
+ resource_t size;
/* Do NOT I repeat do not ignore resources which have zero size.
* If they need to be ignored dev->read_resources should not even
* return them. Some resources must be set even when they have
@@ -314,6 +319,15 @@ void compute_allocate_resource(
bridge->align = resource->align;
}
+ /* Propogate the resource limit to the bridge register */
+ if (bridge->limit > resource->limit) {
+ bridge->limit = resource->limit;
+ }
+ /* Artificially deny limits between DEVICE_MEM_HIGH and 0xffffffff */
+ if ((bridge->limit > DEVICE_MEM_HIGH) && (bridge->limit <= 0xffffffff)) {
+ bridge->limit = DEVICE_MEM_HIGH;
+ }
+
/* Make certain we are dealing with a good minimum size */
size = resource->size;
align = resource->align;
@@ -341,19 +355,20 @@ void compute_allocate_resource(
base = 0x3e0;
}
}
- if (((round(base, 1UL << align) + size) -1) <= resource->limit) {
+ if (((round(base, align) + size) -1) <= resource->limit) {
/* base must be aligned to size */
- base = round(base, 1UL << align);
+ base = round(base, align);
resource->base = base;
resource->flags |= IORESOURCE_ASSIGNED;
resource->flags &= ~IORESOURCE_STORED;
base += size;
printk_spew(
- "%s %02x * [0x%08lx - 0x%08lx] %s\n",
+ "%s %02x * [0x%08Lx - 0x%08Lx] %s\n",
dev_path(dev),
resource->index,
- resource->base, resource->base + resource->size - 1,
+ resource->base,
+ resource->base + resource->size - 1,
(resource->flags & IORESOURCE_IO)? "io":
(resource->flags & IORESOURCE_PREFETCH)? "prefmem": "mem");
}
@@ -364,10 +379,10 @@ void compute_allocate_resource(
* know not to place something else at an address postitively
* decoded by the bridge.
*/
- bridge->size = round(base, 1UL << bridge->gran) - bridge->base;
+ bridge->size = round(base, bridge->gran) - bridge->base;
printk_spew("%s compute_allocate_%s: base: %08lx size: %08lx align: %d gran: %d done\n",
- dev_path(dev),
+ dev_path(bus->dev),
(bridge->flags & IORESOURCE_IO)? "io":
(bridge->flags & IORESOURCE_PREFETCH)? "prefmem" : "mem",
base, bridge->size, bridge->align, bridge->gran);
@@ -387,7 +402,8 @@ static void allocate_vga_resource(void)
vga = 0;
for(dev = all_devices; dev; dev = dev->next) {
if (((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) &&
- ((dev->class >> 8) != PCI_CLASS_DISPLAY_OTHER)) {
+ ((dev->class >> 8) != PCI_CLASS_DISPLAY_OTHER))
+ {
if (!vga) {
printk_debug("Allocating VGA resource %s\n",
dev_path(dev));
@@ -423,20 +439,22 @@ void assign_resources(struct bus *bus)
{
struct device *curdev;
- printk_debug("ASSIGN RESOURCES, bus %d\n", bus->secondary);
+ printk_spew("%s assign_resources, bus %d link: %d\n",
+ dev_path(bus->dev), bus->secondary, bus->link);
- for (curdev = bus->children; curdev; curdev = curdev->sibling) {
+ for(curdev = bus->children; curdev; curdev = curdev->sibling) {
+ if (!curdev->enabled || !curdev->resources) {
+ continue;
+ }
if (!curdev->ops || !curdev->ops->set_resources) {
printk_err("%s missing set_resources\n",
dev_path(curdev));
continue;
}
- if (!curdev->enabled) {
- continue;
- }
curdev->ops->set_resources(curdev);
}
- printk_debug("ASSIGNED RESOURCES, bus %d\n", bus->secondary);
+ printk_spew("%s assign_resources, bus %d link: %d\n",
+ dev_path(bus->dev), bus->secondary, bus->link);
}
/**
@@ -456,11 +474,11 @@ void assign_resources(struct bus *bus)
*/
void enable_resources(struct device *dev)
{
- if (!dev->ops || !dev->ops->enable_resources) {
- printk_err("%s missing enable_resources\n", dev_path(dev));
+ if (!dev->enabled) {
return;
}
- if (!dev->enabled) {
+ if (!dev->ops || !dev->ops->enable_resources) {
+ printk_err("%s missing enable_resources\n", dev_path(dev));
return;
}
dev->ops->enable_resources(dev);
@@ -493,11 +511,12 @@ void dev_enumerate(void)
printk_info("done\n");
}
+
/**
* @brief Configure devices on the devices tree.
*
* Starting at the root of the dynamic device tree, travel recursively,
- * compute resources needed by each device and allocate them.
+ * and compute resources needed by each device and allocate them.
*
* I/O resources start at DEVICE_IO_START and grow upward. MEM resources start
* at DEVICE_MEM_START and grow downward.
@@ -507,6 +526,7 @@ void dev_enumerate(void)
*/
void dev_configure(void)
{
+ struct resource *io, *mem;
struct device *root;
printk_info("Allocating resources...\n");
@@ -522,18 +542,19 @@ void dev_configure(void)
}
root->ops->read_resources(root);
+ /* Get the resources */
+ io = &root->resource[0];
+ mem = &root->resource[1];
/* Make certain the io devices are allocated somewhere safe. */
- root->resource[0].base = DEVICE_IO_START;
- root->resource[0].flags |= IORESOURCE_ASSIGNED;
- root->resource[0].flags &= ~IORESOURCE_STORED;
+ io->base = DEVICE_IO_START;
+ io->flags |= IORESOURCE_ASSIGNED;
+ io->flags &= ~IORESOURCE_STORED;
/* Now reallocate the pci resources memory with the
* highest addresses I can manage.
*/
- root->resource[1].base =
- round_down(DEVICE_MEM_HIGH - root->resource[1].size,
- 1UL << root->resource[1].align);
- root->resource[1].flags |= IORESOURCE_ASSIGNED;
- root->resource[1].flags &= ~IORESOURCE_STORED;
+ mem->base = resource_max(&root->resource[1]);
+ mem->flags |= IORESOURCE_ASSIGNED;
+ mem->flags &= ~IORESOURCE_STORED;
/* Allocate the VGA I/O resource.. */
allocate_vga_resource();
@@ -541,6 +562,11 @@ void dev_configure(void)
/* Store the computed resource allocations into device registers ... */
root->ops->set_resources(root);
+#if 0
+ mem->flags |= IORESOURCE_STORED;
+ report_resource_stored(root, mem, "");
+#endif
+
printk_info("done.\n");
}
@@ -571,9 +597,12 @@ void dev_initialize(void)
struct device *dev;
printk_info("Initializing devices...\n");
- for (dev = all_devices; dev; dev = dev->next) {
- if (dev->enabled && dev->ops && dev->ops->init) {
+ for(dev = all_devices; dev; dev = dev->next) {
+ if (dev->enabled && !dev->initialized &&
+ dev->ops && dev->ops->init)
+ {
printk_debug("%s init\n", dev_path(dev));
+ dev->initialized = 1;
dev->ops->init(dev);
}
}