/** Linked list of ALL devices */
struct device *all_devices = &dev_root;
/** Pointer to the last device */
-extern struct device **last_dev_p;
+extern struct device *last_dev;
/** Linked list of free resources */
struct resource *free_resources = NULL;
+DECLARE_SPIN_LOCK(dev_lock)
/**
- * @brief Allocate a new device structure.
+ * Allocate a new device structure.
*
- * Allocte a new device structure and attached it to the device tree as a
+ * Allocte a new device structure and attach it to the device tree as a
* child of the parent bus.
*
- * @param parent parent bus the newly created device attached to.
- * @param path path to the device to be created.
- *
- * @return pointer to the newly created device structure.
+ * @param parent Parent bus the newly created device should be attached to.
+ * @param path Path to the device to be created.
+ * @return Pointer to the newly created device structure.
*
* @see device_path
*/
-
-DECLARE_SPIN_LOCK(dev_lock)
-
device_t alloc_dev(struct bus *parent, struct device_path *path)
{
device_t dev, child;
- int link;
spin_lock(&dev_lock);
memset(dev, 0, sizeof(*dev));
memcpy(&dev->path, path, sizeof(*path));
- /* 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;
/* 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;
+ last_dev->next = dev;
+ last_dev = dev;
spin_unlock(&dev_lock);
return dev;
}
/**
- * @brief round a number up to an alignment.
- * @param val the starting value
- * @param roundup Alignment as a power of two
- * @returns rounded up number
+ * Round a number up to an alignment.
+ *
+ * @param val The starting value.
+ * @param roundup Alignment as a power of two.
+ * @return Rounded up number.
*/
static resource_t round(resource_t val, unsigned long pow)
{
return val;
}
-/** Read the resources on all devices of a given bus.
- * @param bus bus to read the resources on.
+/**
+ * Read the resources on all devices of a given bus.
+ *
+ * @param bus Bus to read the resources on.
*/
static void read_resources(struct bus *bus)
{
struct device *curdev;
- printk(BIOS_SPEW, "%s %s bus %x link: %d\n", dev_path(bus->dev), __func__,
- bus->secondary, bus->link);
+ printk(BIOS_SPEW, "%s %s bus %x link: %d\n", dev_path(bus->dev),
+ __func__, bus->secondary, bus->link_num);
/* Walk through all devices and find which resources they need. */
for (curdev = bus->children; curdev; curdev = curdev->sibling) {
- int i;
+ struct bus *link;
if (!curdev->enabled) {
continue;
}
curdev->ops->read_resources(curdev);
/* Read in the resources behind the current device's links. */
- for (i = 0; i < curdev->links; i++)
- read_resources(&curdev->link[i]);
+ for (link = curdev->link_list; link; link = link->next)
+ read_resources(link);
}
printk(BIOS_SPEW, "%s read_resources bus %d link: %d done\n",
- dev_path(bus->dev), bus->secondary, bus->link);
+ dev_path(bus->dev), bus->secondary, bus->link_num);
}
struct pick_largest_state {
return state.result_dev;
}
-/* Compute allocate resources is the guts of the resource allocator.
+/**
+ * Compute allocate resources is the guts of the resource allocator.
*
* The problem.
* - Allocate resource locations for every device.
* a device with a couple of resources, and not need to special case it in
* the allocator. Also this allows handling of other types of bridges.
*
+ * @param bus The bus we are traversing.
+ * @param bridge The bridge resource which must contain the bus' resources.
+ * @param type_mask This value gets ANDed with the resource type.
+ * @param type This value must match the result of the AND.
+ * @return TODO
*/
static void compute_resources(struct bus *bus, struct resource *bridge,
unsigned long type_mask, unsigned long type)
for (dev = bus->children; dev; dev = dev->sibling) {
struct resource *child_bridge;
- if (!dev->links)
+ if (!dev->link_list)
continue;
/* Find the resources with matching type flags. */
for (child_bridge = dev->resource_list; child_bridge;
child_bridge = child_bridge->next) {
- unsigned link;
+ struct bus* link;
if (!(child_bridge->flags & IORESOURCE_BRIDGE) ||
(child_bridge->flags & type_mask) != type)
* need it separated. Add the PREFETCH flag to the
* type_mask and type.
*/
- link = IOINDEX_LINK(child_bridge->index);
- compute_resources(&dev->link[link], child_bridge,
+ link = dev->link_list;
+ while (link && link->link_num !=
+ IOINDEX_LINK(child_bridge->index))
+ link = link->next;
+ if (link == NULL)
+ printk(BIOS_ERR, "link %ld not found on %s\n",
+ IOINDEX_LINK(child_bridge->index),
+ dev_path(dev));
+ compute_resources(link, child_bridge,
type_mask | IORESOURCE_PREFETCH,
type | (child_bridge->flags &
IORESOURCE_PREFETCH));
*
* @param bus The bus we are traversing.
* @param bridge The bridge resource which must contain the bus' resources.
- * @param type_mask This value gets anded with the resource type.
- * @param type This value must match the result of the and.
+ * @param type_mask This value gets ANDed with the resource type.
+ * @param type This value must match the result of the AND.
*/
static void allocate_resources(struct bus *bus, struct resource *bridge,
unsigned long type_mask, unsigned long type)
for (dev = bus->children; dev; dev = dev->sibling) {
struct resource *child_bridge;
- if (!dev->links)
+ if (!dev->link_list)
continue;
/* Find the resources with matching type flags. */
for (child_bridge = dev->resource_list; child_bridge;
child_bridge = child_bridge->next) {
- unsigned link;
+ struct bus* link;
if (!(child_bridge->flags & IORESOURCE_BRIDGE) ||
(child_bridge->flags & type_mask) != type)
* need it separated. Add the PREFETCH flag to the
* type_mask and type.
*/
- link = IOINDEX_LINK(child_bridge->index);
- allocate_resources(&dev->link[link], child_bridge,
+ link = dev->link_list;
+ while (link && link->link_num !=
+ IOINDEX_LINK(child_bridge->index))
+ link = link->next;
+ if (link == NULL)
+ printk(BIOS_ERR, "link %ld not found on %s\n",
+ IOINDEX_LINK(child_bridge->index),
+ dev_path(dev));
+ allocate_resources(link, child_bridge,
type_mask | IORESOURCE_PREFETCH,
type | (child_bridge->flags &
IORESOURCE_PREFETCH));
}
#if CONFIG_PCI_64BIT_PREF_MEM == 1
- #define MEM_MASK (IORESOURCE_PREFETCH | IORESOURCE_MEM)
+#define MEM_MASK (IORESOURCE_PREFETCH | IORESOURCE_MEM)
#else
- #define MEM_MASK (IORESOURCE_MEM)
+#define MEM_MASK (IORESOURCE_MEM)
#endif
+
#define IO_MASK (IORESOURCE_IO)
#define PREF_TYPE (IORESOURCE_PREFETCH | IORESOURCE_MEM)
#define MEM_TYPE (IORESOURCE_MEM)
struct device *child;
struct resource *res;
struct resource *lim;
- int i;
+ struct bus *link;
printk(BIOS_SPEW, "%s: %s\n", __func__, dev_path(dev));
else
continue;
- /* Is it already outside the limits? */
+ /* Is it a fixed resource outside the current known region?
+ If so, we don't have to consider it - it will be handled
+ correctly and doesn't affect current region's limits */
if (((res->base + res->size -1) < lim->base) || (res->base > lim->limit))
continue;
}
/* Descend into every enabled child and look for fixed resources. */
- for (i = 0; i < dev->links; i++)
- for (child = dev->link[i].children; child;
+ for (link = dev->link_list; link; link = link->next)
+ for (child = link->children; child;
child = child->sibling)
if (child->enabled)
constrain_resources(child, limits);
#endif
/**
- * @brief Assign the computed resources to the devices on the bus.
- *
- * @param bus Pointer to the structure for this bus
+ * Assign the computed resources to the devices on the bus.
*
* Use the device specific set_resources method to store the computed
* resources to hardware. For bridge devices, the set_resources() method
* Mutual recursion:
* assign_resources() -> device_operation::set_resources()
* device_operation::set_resources() -> assign_resources()
+ *
+ * @param bus Pointer to the structure for this bus.
*/
void assign_resources(struct bus *bus)
{
struct device *curdev;
printk(BIOS_SPEW, "%s assign_resources, bus %d link: %d\n",
- dev_path(bus->dev), bus->secondary, bus->link);
+ dev_path(bus->dev), bus->secondary, bus->link_num);
for (curdev = bus->children; curdev; curdev = curdev->sibling) {
if (!curdev->enabled || !curdev->resource_list) {
curdev->ops->set_resources(curdev);
}
printk(BIOS_SPEW, "%s assign_resources, bus %d link: %d\n",
- dev_path(bus->dev), bus->secondary, bus->link);
+ dev_path(bus->dev), bus->secondary, bus->link_num);
}
/**
- * @brief Enable the resources for a specific device
- *
- * @param dev the device whose resources are to be enabled
+ * Enable the resources for devices on a link.
*
* Enable resources of the device by calling the device specific
* enable_resources() method.
*
* The parent's resources should be enabled first to avoid having enabling
* order problem. This is done by calling the parent's enable_resources()
- * method and let that method to call it's children's enable_resoruces()
- * method via the (global) enable_childrens_resources().
+ * method before its childrens' enable_resources() methods.
*
- * Indirect mutual recursion:
- * enable_resources() -> device_operations::enable_resource()
- * device_operations::enable_resource() -> enable_children_resources()
- * enable_children_resources() -> enable_resources()
+ * @param link The link whose devices' resources are to be enabled.
*/
-void enable_resources(struct device *dev)
+static void enable_resources(struct bus *link)
{
- if (!dev->enabled) {
- return;
+ struct device *dev;
+ struct bus *c_link;
+
+ for (dev = link->children; dev; dev = dev->sibling) {
+ if (dev->enabled && dev->ops && dev->ops->enable_resources) {
+ dev->ops->enable_resources(dev);
+ }
}
- if (!dev->ops || !dev->ops->enable_resources) {
- printk(BIOS_ERR, "%s missing enable_resources\n", dev_path(dev));
- return;
+
+ for (dev = link->children; dev; dev = dev->sibling) {
+ for (c_link = dev->link_list; c_link; c_link = c_link->next) {
+ enable_resources(c_link);
+ }
}
- dev->ops->enable_resources(dev);
}
/**
- * @brief Reset all of the devices a bus
- *
* Reset all of the devices on a bus and clear the bus's reset_needed flag.
*
- * @param bus pointer to the bus structure
- *
+ * @param bus Pointer to the bus structure.
* @return 1 if the bus was successfully reset, 0 otherwise.
- *
*/
int reset_bus(struct bus *bus)
{
}
/**
- * @brief Scan for devices on a bus.
+ * Scan for devices on a bus.
*
* If there are bridges on the bus, recursively scan the buses behind the
* bridges. If the setting up and tuning of the bus causes a reset to be
do_scan_bus = 1;
while (do_scan_bus) {
- int link;
+ struct bus *link;
new_max = busdev->ops->scan_bus(busdev, max);
do_scan_bus = 0;
- for (link = 0; link < busdev->links; link++) {
- if (busdev->link[link].reset_needed) {
- if (reset_bus(&busdev->link[link])) {
+ for (link = busdev->link_list; link; link = link->next) {
+ if (link->reset_needed) {
+ if (reset_bus(link)) {
do_scan_bus = 1;
} else {
busdev->bus->reset_needed = 1;
}
/**
- * @brief Determine the existence of devices and extend the device tree.
+ * Determine the existence of devices and extend the device tree.
*
* Most of the devices in the system are listed in the mainboard Config.lb
* file. The device structures for these devices are generated at compile
}
/**
- * @brief Configure devices on the devices tree.
+ * Configure devices on the devices tree.
*
* Starting at the root of the device tree, travel it recursively in two
* passes. In the first pass, we compute and allocate resources (ranges)
/* Read the resources for the entire tree. */
printk(BIOS_INFO, "Reading resources...\n");
- read_resources(&root->link[0]);
+ read_resources(root->link_list);
printk(BIOS_INFO, "Done reading resources.\n");
print_resource_tree(root, BIOS_SPEW, "After reading.");
/* Compute resources for all domains. */
- for (child = root->link[0].children; child; child = child->sibling) {
+ for (child = root->link_list->children; child; child = child->sibling) {
if (!(child->path.type == DEVICE_PATH_PCI_DOMAIN))
continue;
for (res = child->resource_list; res; res = res->next) {
if (res->flags & IORESOURCE_FIXED)
continue;
if (res->flags & IORESOURCE_PREFETCH) {
- compute_resources(&child->link[0],
+ compute_resources(child->link_list,
res, MEM_MASK, PREF_TYPE);
continue;
}
if (res->flags & IORESOURCE_MEM) {
- compute_resources(&child->link[0],
+ compute_resources(child->link_list,
res, MEM_MASK, MEM_TYPE);
continue;
}
if (res->flags & IORESOURCE_IO) {
- compute_resources(&child->link[0],
+ compute_resources(child->link_list,
res, IO_MASK, IO_TYPE);
continue;
}
}
/* For all domains. */
- for (child = root->link[0].children; child; child=child->sibling)
+ for (child = root->link_list->children; child; child=child->sibling)
if (child->path.type == DEVICE_PATH_PCI_DOMAIN)
avoid_fixed_resources(child);
/* Now we need to adjust the resources. MEM resources need to start at
* the highest address managable.
*/
- for (child = root->link[0].children; child; child = child->sibling) {
+ for (child = root->link_list->children; child; child = child->sibling) {
if (child->path.type != DEVICE_PATH_PCI_DOMAIN)
continue;
for (res = child->resource_list; res; res = res->next) {
/* Store the computed resource allocations into device registers ... */
printk(BIOS_INFO, "Setting resources...\n");
- for (child = root->link[0].children; child; child = child->sibling) {
+ for (child = root->link_list->children; child; child = child->sibling) {
if (!(child->path.type == DEVICE_PATH_PCI_DOMAIN))
continue;
for (res = child->resource_list; res; res = res->next) {
if (res->flags & IORESOURCE_FIXED)
continue;
if (res->flags & IORESOURCE_PREFETCH) {
- allocate_resources(&child->link[0],
+ allocate_resources(child->link_list,
res, MEM_MASK, PREF_TYPE);
continue;
}
if (res->flags & IORESOURCE_MEM) {
- allocate_resources(&child->link[0],
+ allocate_resources(child->link_list,
res, MEM_MASK, MEM_TYPE);
continue;
}
if (res->flags & IORESOURCE_IO) {
- allocate_resources(&child->link[0],
+ allocate_resources(child->link_list,
res, IO_MASK, IO_TYPE);
continue;
}
}
}
- assign_resources(&root->link[0]);
+ assign_resources(root->link_list);
printk(BIOS_INFO, "Done setting resources.\n");
print_resource_tree(root, BIOS_SPEW, "After assigning values.");
}
/**
- * @brief Enable devices on the device tree.
+ * Enable devices on the device tree.
*
* Starting at the root, walk the tree and enable all devices/bridges by
* calling the device's enable_resources() method.
*/
void dev_enable(void)
{
+ struct bus *link;
+
printk(BIOS_INFO, "Enabling resources...\n");
/* now enable everything. */
- enable_resources(&dev_root);
+ for (link = dev_root.link_list; link; link = link->next)
+ enable_resources(link);
printk(BIOS_INFO, "done.\n");
}
/**
- * @brief Initialize all devices in the global device list.
+ * Initialize a specific device.
*
- * Starting at the first device on the global device link list,
- * walk the list and call the device's init() method to do deivce
- * specific setup.
+ * The parent should be initialized first to avoid having an ordering
+ * problem. This is done by calling the parent's init()
+ * method before its childrens' init() methods.
+ *
+ * @param dev The device to be initialized.
*/
-void dev_initialize(void)
+static void init_dev(struct device *dev)
+{
+ if (!dev->enabled) {
+ return;
+ }
+
+ if (!dev->initialized && dev->ops && dev->ops->init) {
+ if (dev->path.type == DEVICE_PATH_I2C) {
+ printk(BIOS_DEBUG, "smbus: %s[%d]->",
+ dev_path(dev->bus->dev), dev->bus->link_num);
+ }
+
+ printk(BIOS_DEBUG, "%s init\n", dev_path(dev));
+ dev->initialized = 1;
+ dev->ops->init(dev);
+ }
+}
+
+static void init_link(struct bus *link)
{
struct device *dev;
+ struct bus *c_link;
- printk(BIOS_INFO, "Initializing devices...\n");
- for (dev = all_devices; dev; dev = dev->next) {
- if (dev->enabled && !dev->initialized &&
- dev->ops && dev->ops->init) {
- if (dev->path.type == DEVICE_PATH_I2C) {
- printk(BIOS_DEBUG, "smbus: %s[%d]->",
- dev_path(dev->bus->dev),
- dev->bus->link);
- }
- printk(BIOS_DEBUG, "%s init\n", dev_path(dev));
- dev->initialized = 1;
- dev->ops->init(dev);
+ for (dev = link->children; dev; dev = dev->sibling) {
+ init_dev(dev);
+ }
+
+ for (dev = link->children; dev; dev = dev->sibling) {
+ for (c_link = dev->link_list; c_link; c_link = c_link->next) {
+ init_link(c_link);
}
}
+}
+
+/**
+ * Initialize all devices in the global device tree.
+ *
+ * Starting at the root device, call the device's init() method to do
+ * device-specific setup, then call each child's init() method.
+ */
+void dev_initialize(void)
+{
+ struct bus *link;
+
+ printk(BIOS_INFO, "Initializing devices...\n");
+
+ /* First call the mainboard init. */
+ init_dev(&dev_root);
+
+ /* now initialize everything. */
+ for (link = dev_root.link_list; link; link = link->next)
+ init_link(link);
+
printk(BIOS_INFO, "Devices initialized\n");
show_all_devs(BIOS_SPEW, "After init.");
}