diff options
author | Eric Biederman <ebiederm@xmission.com> | 2003-09-02 03:36:25 +0000 |
---|---|---|
committer | Eric Biederman <ebiederm@xmission.com> | 2003-09-02 03:36:25 +0000 |
commit | e9a271e32c53076445ef70da8aec8201c82693ec (patch) | |
tree | af88f51ba907922157d3b97f9713a07480223372 /src | |
parent | d4c14524f53d8e812cf52b57e16c53d259c44ea0 (diff) | |
download | coreboot-e9a271e32c53076445ef70da8aec8201c82693ec.tar.xz |
- Major update of the dynamic device tree so it can handle
* subtractive resources
* merging with the static device tree
* more device types than just pci
- The piece to watch out for is the new enable_resources method that was needed in all of the drivers
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@1096 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'src')
24 files changed, 871 insertions, 377 deletions
diff --git a/src/arch/i386/lib/pci_ops.c b/src/arch/i386/lib/pci_ops.c index c3478ffa96..9a8616a90a 100644 --- a/src/arch/i386/lib/pci_ops.c +++ b/src/arch/i386/lib/pci_ops.c @@ -220,49 +220,49 @@ static const struct pci_ops *pci_check_direct(void) uint8_t pci_read_config8(device_t dev, unsigned where) { uint8_t value; - value = conf->read8(dev->bus->secondary, dev->devfn, where); + value = conf->read8(dev->bus->secondary, dev->path.u.pci.devfn, where); printk_spew("Read config 8 bus %d,devfn 0x%x,reg 0x%x,val 0x%x\n", - dev->bus->secondary, dev->devfn, where, value); + dev->bus->secondary, dev->path.u.pci.devfn, where, value); return value; } uint16_t pci_read_config16(device_t dev, unsigned where) { uint16_t value; - value = conf->read16(dev->bus->secondary, dev->devfn, where); + value = conf->read16(dev->bus->secondary, dev->path.u.pci.devfn, where); printk_spew( "Read config 16 bus %d,devfn 0x%x,reg 0x%x,val 0x%x\n", - dev->bus->secondary, dev->devfn, where, value); + dev->bus->secondary, dev->path.u.pci.devfn, where, value); return value; } uint32_t pci_read_config32(device_t dev, unsigned where) { uint32_t value; - value = conf->read32(dev->bus->secondary, dev->devfn, where); + value = conf->read32(dev->bus->secondary, dev->path.u.pci.devfn, where); printk_spew( "Read config 32 bus %d,devfn 0x%x,reg 0x%x,val 0x%x\n", - dev->bus->secondary, dev->devfn, where, value); + dev->bus->secondary, dev->path.u.pci.devfn, where, value); return value; } void pci_write_config8(device_t dev, unsigned where, uint8_t val) { printk_spew( "Write config 8 bus %d, devfn 0x%x, reg 0x%x, val 0x%x\n", - dev->bus->secondary, dev->devfn, where, val); - conf->write8(dev->bus->secondary, dev->devfn, where, val); + dev->bus->secondary, dev->path.u.pci.devfn, where, val); + conf->write8(dev->bus->secondary, dev->path.u.pci.devfn, where, val); } void pci_write_config16(device_t dev, unsigned where, uint16_t val) { printk_spew( "Write config 16 bus %d, devfn 0x%x, reg 0x%x, val 0x%x\n", - dev->bus->secondary, dev->devfn, where, val); - conf->write16(dev->bus->secondary, dev->devfn, where, val); + dev->bus->secondary, dev->path.u.pci.devfn, where, val); + conf->write16(dev->bus->secondary, dev->path.u.pci.devfn, where, val); } void pci_write_config32(device_t dev, unsigned where, uint32_t val) { printk_spew( "Write config 32 bus %d, devfn 0x%x, reg 0x%x, val 0x%x\n", - dev->bus->secondary, dev->devfn, where, val); - conf->write32(dev->bus->secondary, dev->devfn, where, val); + dev->bus->secondary, dev->path.u.pci.devfn, where, val); + conf->write32(dev->bus->secondary, dev->path.u.pci.devfn, where, val); } /** Set the method to be used for PCI, type I or type II diff --git a/src/arch/ppc/lib/pci_ops.c b/src/arch/ppc/lib/pci_ops.c index 69c9915ad6..eef6eef30c 100644 --- a/src/arch/ppc/lib/pci_ops.c +++ b/src/arch/ppc/lib/pci_ops.c @@ -65,34 +65,34 @@ static int pci_sanity_check(const struct pci_ops *o) return 0; } -uint8_t pci_read_config8(struct device *dev, unsigned where) +uint8_t pci_read_config8(device_t dev, unsigned where) { - return conf->read8(dev->bus->secondary, dev->devfn, where); + return conf->read8(dev->bus->secondary, dev->path.u.pci.devfn, where); } uint16_t pci_read_config16(struct device *dev, unsigned where) { - return conf->read16(dev->bus->secondary, dev->devfn, where); + return conf->read16(dev->bus->secondary, dev->path.u.pci.devfn, where); } uint32_t pci_read_config32(struct device *dev, unsigned where) { - return conf->read32(dev->bus->secondary, dev->devfn, where); + return conf->read32(dev->bus->secondary, dev->path.u.pci.devfn, where); } void pci_write_config8(struct device *dev, unsigned where, uint8_t val) { - conf->write8(dev->bus->secondary, dev->devfn, where, val); + conf->write8(dev->bus->secondary, dev->path.u.pci.devfn, where, val); } void pci_write_config16(struct device *dev, unsigned where, uint16_t val) { - conf->write16(dev->bus->secondary, dev->devfn, where, val); + conf->write16(dev->bus->secondary, dev->path.u.pci.devfn, where, val); } void pci_write_config32(struct device *dev, unsigned where, uint32_t val) { - conf->write32(dev->bus->secondary, dev->devfn, where, val); + conf->write32(dev->bus->secondary, dev->path.u.pci.devfn, where, val); } /** Set the method to be used for PCI diff --git a/src/boot/hardwaremain.c b/src/boot/hardwaremain.c index 11ad8e4b87..6e3aa1b27f 100644 --- a/src/boot/hardwaremain.c +++ b/src/boot/hardwaremain.c @@ -169,9 +169,7 @@ void hardwaremain(int boot_complete) printk_info("Finding PCI configuration type.\n"); pci_set_method(); post_code(0x5f); -#if 0 enumerate_static_devices(); -#endif dev_enumerate(); post_code(0x66); /* Now do the real bus. diff --git a/src/config/Options.lb b/src/config/Options.lb index 4a9dae14b3..9073ae340b 100644 --- a/src/config/Options.lb +++ b/src/config/Options.lb @@ -117,7 +117,7 @@ define OBJCOPY comment "Objcopy command" end define LINUXBIOS_VERSION - default "1.1.2" + default "1.1.3" export always comment "LinuxBIOS version" end diff --git a/src/devices/Config.lb b/src/devices/Config.lb index 199c7da46b..063aa1db92 100644 --- a/src/devices/Config.lb +++ b/src/devices/Config.lb @@ -1,4 +1,5 @@ object device.o +object root_device.o object device_util.o object pci_device.o object chip.o diff --git a/src/devices/chip.c b/src/devices/chip.c index 0074f2bede..b7eace38f0 100644 --- a/src/devices/chip.c +++ b/src/devices/chip.c @@ -5,7 +5,9 @@ * path, etc. */ +#include <console/console.h> #include <device/chip.h> +#include <device/pci.h> void chip_configure(struct chip *root, enum chip_pass pass) @@ -22,3 +24,86 @@ chip_configure(struct chip *root, enum chip_pass pass) chip_configure(c->children, pass); } } + +/** Convert a static struct chip structure to a set of dynamic device structures. + * @param chip Static chip structure to start with. + */ + +void chip_enumerate(struct chip *chip) +{ + struct chip *child; + device_t dev; + int link; + int i; + dev = 0; + link = 0; +#if 1 + if (chip->control && chip->control->name) { + printk_debug("Enumerating: %s\n", chip->control->name); + } +#endif + for(i = 0; i < MAX_CHIP_PATHS; i++) { + int identical_paths; + identical_paths = + (i > 0) && + (path_eq(&chip->path[i - 1].path, &chip->path[i].path)) && + (chip->path[i - 1].channel == chip->path[i].channel); + if (!identical_paths) { + link = 0; + dev = 0; + switch(chip->path[i].path.type) { + case DEVICE_PATH_NONE: + break; + default: + dev = alloc_dev(chip->bus, &chip->path[i].path); + break; + } + } + else { + link += 1; + } + if (dev) { + printk_spew("path %s %s\n", dev_path(dev), identical_paths?"identical":""); + dev->enable = chip->path[i].enable; + dev->links = link + 1; + for(child = chip->children; child; child = child->next) { + if (!child->bus && + child->path[0].channel == i) { + child->bus = &dev->link[link]; + } + } + } + if (dev && !chip->dev) { + chip->dev = dev; + } + } + for(child = chip->children; child; child = child->next) { + if (!child->bus) { + child->bus = &chip->dev->link[0]; + } + } +} + +static void enumerate_static_device_chain(struct chip *root) +{ + struct chip *chip; + for(chip = root; chip; chip = chip->next) { + void (*enumerate)(struct chip *chip); + enumerate = chip_enumerate; + if (chip->control && chip->control->enumerate) { + enumerate = chip->control->enumerate; + } + enumerate(chip); + } + + for(chip = root; chip; chip = chip->next) { + if (chip->children) { + enumerate_static_device_chain(chip->children); + } + } +} + +void enumerate_static_devices(void) +{ + enumerate_static_device_chain(&static_root); +} diff --git a/src/devices/device.c b/src/devices/device.c index 8e6fcb3519..e52cc2a57e 100644 --- a/src/devices/device.c +++ b/src/devices/device.c @@ -1,6 +1,7 @@ /* * (c) 1999--2000 Martin Mares <mj@suse.cz> * (c) 2003 Eric Biederman <ebiederm@xmission.com> + * (c) 2003 Linux Networx */ /* lots of mods by ron minnich (rminnich@lanl.gov), with * the final architecture guidance from Tom Merritt (tjm@codegen.com) @@ -18,12 +19,9 @@ #include <arch/io.h> #include <device/device.h> #include <device/pci.h> +#include <stdlib.h> +#include <string.h> -/** - * This is the root of the device tree. A PCI tree always has - * one bus, bus 0. Bus 0 contains devices and bridges. - */ -struct device dev_root; /* Linked list of ALL devices */ struct device *all_devices = 0; /* pointer to the last device */ @@ -32,16 +30,46 @@ static struct device **last_dev_p = &all_devices; #define DEVICE_MEM_HIGH 0xFEC00000UL /* Reserve 20M for the system */ #define DEVICE_IO_START 0x1000 - -/* Append a new device to the global device chain. - * The chain is used to find devices once everything is set up. +/** Allocate a new device structure */ -void append_device(struct device *dev) +device_t alloc_dev(struct bus *parent, struct device_path *path) { + device_t dev, child; + int link; + /* Find the last child of our parent */ + for(child = parent->children; child && child->sibling; ) { + child = child->sibling; + } + dev = malloc(sizeof(*dev)); + if (dev == 0) { + die("DEV: out of memory.\n"); + } + memset(dev, 0, sizeof(*dev)); + memcpy(&dev->path, path, sizeof(*path)); + + /* Append a new device to the global device chain. + * The chain 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; + } + + /* Add the new device to the children of the bus. */ + dev->bus = parent; + if (child) { + child->sibling = dev; + } else { + parent->children = dev; + } + /* If we don't have any other information about a device enable it */ + dev->enable = 1; + return dev; +} /** round a number to an alignment. * @param val the starting value @@ -71,28 +99,79 @@ static unsigned long round_down(unsigned long val, unsigned long round_down) /** Read the resources on all devices of a given bus. * @param bus bus to read the resources on. */ -static void read_resources(struct device *bus) +static void read_resources(struct bus *bus) { struct device *curdev; - /* Walk through all of the devices and find which resources they need. */ for(curdev = bus->children; curdev; curdev = curdev->sibling) { + unsigned links; + int i; if (curdev->resources > 0) { continue; } + if (!curdev->ops || !curdev->ops->read_resources) { + printk_err("%s missing read_resources\n", + dev_path(curdev)); + continue; + } curdev->ops->read_resources(curdev); + /* Read in subtractive resources behind the current device */ + links = 0; + for(i = 0; i < curdev->resources; i++) { + struct resource *resource; + resource = &curdev->resource[i]; + if ((resource->flags & IORESOURCE_SUBTRACTIVE) && + (!(links & (1 << resource->index)))) + { + links |= (1 << resource->index); + read_resources(&curdev->link[resource->index]); + + } + } } } -static struct device *largest_resource(struct device *bus, struct resource **result_res, - unsigned long type_mask, unsigned long type) +struct pick_largest_state { + struct resource *last; + struct device *result_dev; + struct resource *result; + int seen_last; +}; + +static void pick_largest_resource( + struct pick_largest_state *state, struct device *dev, struct resource *resource) +{ + struct resource *last; + last = state->last; + /* Be certain to pick the successor to last */ + if (resource == last) { + state->seen_last = 1; + return; + } + if (last && ( + (last->align < resource->align) || + ((last->align == resource->align) && + (last->size < resource->size)) || + ((last->align == resource->align) && + (last->size == resource->size) && + (!state->seen_last)))) { + return; + } + if (!state->result || + (state->result->align < resource->align) || + ((state->result->align == resource->align) && + (state->result->size < resource->size))) { + state->result_dev = dev; + state->result = resource; + } + +} + +static void find_largest_resource(struct pick_largest_state *state, + struct bus *bus, unsigned long type_mask, unsigned long type) { struct device *curdev; - struct device *result_dev = 0; - struct resource *last = *result_res; - struct resource *result = 0; - int seen_last = 0; for(curdev = bus->children; curdev; curdev = curdev->sibling) { int i; for(i = 0; i < curdev->resources; i++) { @@ -101,31 +180,33 @@ static struct device *largest_resource(struct device *bus, struct resource **res if ((resource->flags & type_mask) != type) { continue; } - /* Be certain to pick the successor to last */ - if (resource == last) { - seen_last = 1; + /* If it is a subtractive resource recurse */ + if (resource->flags & IORESOURCE_SUBTRACTIVE) { + struct bus *subbus; + subbus = &curdev->link[resource->index]; + find_largest_resource(state, subbus, type_mask, type); continue; } - if (last && ( - (last->align < resource->align) || - ((last->align == resource->align) && - (last->size < resource->size)) || - ((last->align == resource->align) && - (last->size == resource->size) && - (!seen_last)))) { - continue; - } - if (!result || - (result->align < resource->align) || - ((result->align == resource->align) && - (result->size < resource->size))) { - result_dev = curdev; - result = resource; - } + /* See if this is the largest resource */ + pick_largest_resource(state, curdev, resource); } } - *result_res = result; - return result_dev; +} + +static struct device *largest_resource(struct bus *bus, struct resource **result_res, + unsigned long type_mask, unsigned long type) +{ + struct pick_largest_state state; + + state.last = *result_res; + state.result_dev = 0; + state.result = 0; + state.seen_last = 0; + + find_largest_resource(&state, bus, type_mask, type); + + *result_res = state.result; + return state.result_dev; } /* Compute allocate resources is the guts of the resource allocator. @@ -158,7 +239,7 @@ static struct device *largest_resource(struct device *bus, struct resource **res */ void compute_allocate_resource( - struct device *bus, + struct bus *bus, struct resource *bridge, unsigned long type_mask, unsigned long type) @@ -181,9 +262,8 @@ void compute_allocate_resource( min_align = log2(DEVICE_MEM_ALIGN); } - printk_spew("DEV: %02x:%02x.%01x compute_allocate_%s: base: %08lx size: %08lx align: %d gran: %d\n", - bus->bus->secondary, - PCI_SLOT(bus->devfn), PCI_FUNC(bus->devfn), + printk_spew("%s compute_allocate_%s: base: %08lx size: %08lx align: %d gran: %d\n", + dev_path(dev), (bridge->flags & IORESOURCE_IO)? "io": (bridge->flags & IORESOURCE_PREFETCH)? "prefmem" : "mem", base, bridge->size, bridge->align, bridge->gran); @@ -214,6 +294,9 @@ void compute_allocate_resource( if (align < min_align) { align = min_align; } + if (resource->flags & IORESOURCE_FIXED) { + continue; + } if (resource->flags & IORESOURCE_IO) { /* Don't allow potential aliases over the * legacy pci expansion card addresses. @@ -240,9 +323,8 @@ void compute_allocate_resource( base += size; printk_spew( - "DEV: %02x:%02x.%01x %02x * [0x%08lx - 0x%08lx] %s\n", - dev->bus->secondary, - PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), + "%s %02x * [0x%08lx - 0x%08lx] %s\n", + dev_path(dev), resource->index, resource->base, resource->base + resource->size -1, (resource->flags & IORESOURCE_IO)? "io": @@ -258,9 +340,8 @@ void compute_allocate_resource( */ bridge->size = round(base, 1UL << bridge->gran) - bridge->base; - printk_spew("DEV: %02x:%02x.%01x compute_allocate_%s: base: %08lx size: %08lx align: %d gran: %d done\n", - bus->bus->secondary, - PCI_SLOT(bus->devfn), PCI_FUNC(bus->devfn), + printk_spew("%s compute_allocate_%s: base: %08lx size: %08lx align: %d gran: %d done\n", + dev_path(dev), (bridge->flags & IORESOURCE_IO)? "io": (bridge->flags & IORESOURCE_PREFETCH)? "prefmem" : "mem", base, bridge->size, bridge->align, bridge->gran); @@ -270,14 +351,15 @@ void compute_allocate_resource( static void allocate_vga_resource(void) { +#warning "FIXME modify allocate_vga_resource so it is less pci centric!" /* FIXME handle the VGA pallette snooping */ - struct device *dev, *vga, *bus; - bus = vga = 0; + struct device *dev, *vga; + struct bus *bus; + bus = 0; + vga = 0; for(dev = all_devices; dev; dev = dev->next) { - uint32_t class_revision; - class_revision = pci_read_config32(dev, PCI_CLASS_REVISION); - if (((class_revision >> 24) == 0x03) && - ((class_revision >> 16) != 0x380)) { + if (((dev->class >> 16) == 0x03) && + ((dev->class >> 8) != 0x380)) { if (!vga) { printk_debug("Allocating VGA resource\n"); vga = dev; @@ -296,11 +378,8 @@ static void allocate_vga_resource(void) } /* Now walk up the bridges setting the VGA enable */ while(bus) { - uint16_t ctrl; - ctrl = pci_read_config16(bus, PCI_BRIDGE_CONTROL); - ctrl |= PCI_BRIDGE_CTL_VGA; - pci_write_config16(bus, PCI_BRIDGE_CONTROL, ctrl); - bus = (bus == bus->bus)? 0 : bus->bus; + bus->bridge_ctrl |= PCI_BRIDGE_CONTROL; + bus = (bus == bus->dev->bus)? 0 : bus->dev->bus; } } @@ -310,36 +389,35 @@ static void allocate_vga_resource(void) * on this bus. * @param bus Pointer to the structure for this bus */ -void assign_resources(struct device *bus) +void assign_resources(struct bus *bus) { struct device *curdev; printk_debug("ASSIGN RESOURCES, bus %d\n", bus->secondary); for (curdev = bus->children; curdev; curdev = curdev->sibling) { + if (!curdev->ops || !curdev->ops->set_resources) { + printk_err("%s missing set_resources\n", + dev_path(curdev)); + continue; + } curdev->ops->set_resources(curdev); } printk_debug("ASSIGNED RESOURCES, bus %d\n", bus->secondary); } -static void enable_resources(struct device *bus) +void enable_resources(struct device *dev) { - struct device *curdev; - - /* Walk through the chain of all pci devices and enable them. - * This is effectively a breadth first traversal so we should - * not have enalbing ordering problems. + /* Enable the resources for a specific device. + * The parents resources should be enabled first to avoid + * having enabling ordering problems. */ - for (curdev = all_devices; curdev; curdev = curdev->next) { - uint16_t command; - command = pci_read_config16(curdev, PCI_COMMAND); - command |= curdev->command; - printk_debug("DEV: %02x:%02x.%01x cmd <- %02x\n", - curdev->bus->secondary, - PCI_SLOT(curdev->devfn), PCI_FUNC(curdev->devfn), - command); - pci_write_config16(curdev, PCI_COMMAND, command); + if (!dev->ops || !dev->ops->enable_resources) { + printk_err("%s missing enable_resources\n", + dev_path(dev)); + return; } + dev->ops->enable_resources(dev); } /** Enumerate the resources on the PCI by calling pci_init @@ -347,12 +425,10 @@ static void enable_resources(struct device *bus) void dev_enumerate(void) { struct device *root; + unsigned subordinate; printk_info("Enumerating buses..."); root = &dev_root; - if (!root->ops) { - root->ops = &default_pci_ops_root; - } - root->subordinate = root->ops->scan_bus(root, 0); + subordinate = root->ops->scan_bus(root, 0); printk_info("done\n"); } @@ -394,7 +470,7 @@ void dev_configure(void) */ void dev_enable(void) { - printk_info("Enabling resourcess..."); + printk_info("Enabling resourcess...\n"); /* now enable everything. */ enable_resources(&dev_root); @@ -410,14 +486,10 @@ void dev_initialize(void) printk_info("Initializing devices...\n"); for (dev = all_devices; dev; dev = dev->next) { - if (dev->ops->init) { - printk_debug("PCI: %02x:%02x.%01x init\n", - dev->bus->secondary, - PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); + if (dev->ops && dev->ops->init) { + printk_debug("%s init\n", dev_path(dev)); dev->ops->init(dev); } } printk_info("Devices initialized\n"); } - - diff --git a/src/devices/device_util.c b/src/devices/device_util.c index a57ea1f5ae..384a3be8e0 100644 --- a/src/devices/device_util.c +++ b/src/devices/device_util.c @@ -1,5 +1,26 @@ #include <console/console.h> #include <device/device.h> +#include <device/path.h> +#include <device/pci.h> +#include <string.h> + + +/** + * See if a device structure already exists and if not allocate it + * @param bus The bus to find the device on + * @param path The relative path from the bus to the appropriate device + * @return pointer a device structure for the device on bus at path + */ +device_t alloc_find_dev(struct bus *parent, struct device_path *path) +{ + device_t child; + for(child = parent->children; child; child = child->sibling) { + if (path_eq(path, &child->path)) { + return child; + } + } + return alloc_dev(parent, path); +} /** * Given a bus and a devfn number, find the device structure @@ -11,9 +32,12 @@ struct device *dev_find_slot(unsigned int bus, unsigned int devfn) { struct device *dev; - for (dev = all_devices; dev; dev = dev->next) - if (dev->bus->secondary == bus && dev->devfn == devfn) + for (dev = all_devices; dev; dev = dev->next) { + if ((dev->bus->secondary == bus) && + (dev->path.u.pci.devfn == devfn)) { break; + } + } return dev; } @@ -54,3 +78,58 @@ struct device *dev_find_class(unsigned int class, struct device *from) return from; } + +const char *dev_path(device_t dev) +{ + static char buffer[DEVICE_PATH_MAX]; + buffer[0] = '\0'; + if (!dev) { + memcpy(buffer, "<null>", 7); + } + else { + switch(dev->path.type) { + case DEVICE_PATH_PCI: + sprintf(buffer, "PCI: %02x:%02x.%01x", + dev->bus->secondary, + PCI_SLOT(dev->path.u.pci.devfn), PCI_FUNC(dev->path.u.pci.devfn)); + break; + case DEVICE_PATH_PNP: + sprintf(buffer, "PNP: %04x.%01x", + dev->path.u.pnp.port, dev->path.u.pnp.device); + break; + case DEVICE_PATH_I2C: + sprintf(buffer, "I2C: %02x", + dev->path.u.i2c.device); + break; + default: + printk_err("Unknown device path type: %d\n", dev->path.type); + break; + } + } + return buffer; +} + +int path_eq(struct device_path *path1, struct device_path *path2) +{ + int equal = 0; + if (path1->type == path2->type) { + switch(path1->type) { + case DEVICE_PATH_NONE: + break; + case DEVICE_PATH_PCI: + equal = path1->u.pci.devfn == path2->u.pci.devfn; + break; + case DEVICE_PATH_PNP: + equal = (path1->u.pnp.port == path2->u.pnp.port) && + (path1->u.pnp.device == path2->u.pnp.device); + break; + case DEVICE_PATH_I2C: + equal = (path1->u.i2c.device == path2->u.i2c.device); + break; + default: + printk_err("Uknown device type: %d\n", path1->type); + break; + } + } + return equal; +} diff --git a/src/devices/pci_device.c b/src/devices/pci_device.c index 6af920e584..4db0102745 100644 --- a/src/devices/pci_device.c +++ b/src/devices/pci_device.c @@ -17,6 +17,7 @@ #include <device/device.h> #include <device/pci.h> #include <device/pci_ids.h> +#include <part/hard_reset.h> #include <part/fallback_boot.h> /** Given a device and register, read the size of the BAR for that register. @@ -39,8 +40,6 @@ static void pci_get_resource(struct device *dev, struct resource *resource, unsi resource->index = index; addr = pci_read_config32(dev, index); - if (addr == 0xffffffffUL) - return; /* FIXME: more consideration for 64-bit PCI devices, * we currently detect their size but otherwise @@ -71,9 +70,8 @@ static void pci_get_resource(struct device *dev, struct resource *resource, unsi if ((addr == size) && (addr == base)) { if (size != 0) { printk_debug( - "PCI: %02x:%02x.%01x register %02x(%08x), read-only ignoring it\n", - dev->bus->secondary, - PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), + "%s register %02x(%08x), read-only ignoring it\n", + dev_path(dev), index, addr); } resource->flags = 0; @@ -134,9 +132,8 @@ static void pci_get_resource(struct device *dev, struct resource *resource, unsi pci_write_config32(dev, index_hi, 0); } else { - printk_err("PCI: %02x:%02x.%01x Unable to handle 64-bit address\n", - dev->bus->secondary, - PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); + printk_err("%s Unable to handle 64-bit address\n", + dev_path(dev)); resource->flags = IORESOURCE_PCI64; } } @@ -185,7 +182,7 @@ static void pci_bridge_read_bases(struct device *dev) dev->resource[reg].limit = 0xffffUL; dev->resource[reg].flags = IORESOURCE_IO | IORESOURCE_PCI_BRIDGE; dev->resource[reg].index = PCI_IO_BASE; - compute_allocate_resource(dev, &dev->resource[reg], + compute_allocate_resource(&dev->link[0], &dev->resource[reg], IORESOURCE_IO, IORESOURCE_IO); reg++; @@ -197,7 +194,7 @@ static void pci_bridge_read_bases(struct device *dev) dev->resource[reg].limit = 0xffffffffUL; dev->resource[reg].flags = IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_PCI_BRIDGE; dev->resource[reg].index = PCI_PREF_MEMORY_BASE; - compute_allocate_resource(dev, &dev->resource[reg], + compute_allocate_resource(&dev->link[0], &dev->resource[reg], IORESOURCE_MEM | IORESOURCE_PREFETCH, IORESOURCE_MEM | IORESOURCE_PREFETCH); reg++; @@ -210,7 +207,7 @@ static void pci_bridge_read_bases(struct device *dev) dev->resource[reg].limit = 0xffffffffUL; dev->resource[reg].flags = IORESOURCE_MEM | IORESOURCE_PCI_BRIDGE; dev->resource[reg].index = PCI_MEMORY_BASE; - compute_allocate_resource(dev, &dev->resource[reg], + compute_allocate_resource(&dev->link[0], &dev->resource[reg], IORESOURCE_MEM | IORESOURCE_PREFETCH, IORESOURCE_MEM); reg++; @@ -233,7 +230,7 @@ void pci_bus_read_resources(struct device *dev) { uint32_t addr; dev->resources = 0; - memset(&dev->resource[0], 0, sizeof(dev->resource)); + memset(&dev->resource, 0, sizeof(dev->resource)); pci_bridge_read_bases(dev); pci_read_bases(dev, 2); @@ -246,16 +243,14 @@ void pci_bus_read_resources(struct device *dev) static void pci_set_resource(struct device *dev, struct resource *resource) { unsigned long base, limit; - unsigned long bridge_align = PCI_MEM_BRIDGE_ALIGN; unsigned char buf[10]; - + unsigned long align; + /* Make certain the resource has actually been set */ if (!(resource->flags & IORESOURCE_SET)) { #if 1 - printk_err("ERROR: %02x:%02x.%01x %02x not allocated\n", - dev->bus->secondary, - PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), - resource->index); + printk_err("ERROR: %s %02x not allocated\n", + dev_path(dev), resource->index); #endif return; } @@ -263,23 +258,23 @@ static void pci_set_resource(struct device *dev, struct resource *resource) /* Only handle PCI memory and IO resources for now */ if (!(resource->flags & (IORESOURCE_MEM |IORESOURCE_IO))) return; - + if (resource->flags & IORESOURCE_MEM) { dev->command |= PCI_COMMAND_MEMORY; - bridge_align = PCI_MEM_BRIDGE_ALIGN; } if (resource->flags & IORESOURCE_IO) { dev->command |= PCI_COMMAND_IO; - bridge_align = PCI_IO_BRIDGE_ALIGN; } if (resource->flags & IORESOURCE_PCI_BRIDGE) { dev->command |= PCI_COMMAND_MASTER; } /* Get the base address */ base = resource->base; + /* Get the resource alignment */ + align = 1UL << resource->align; /* Get the limit (rounded up) */ - limit = base + ((resource->size + bridge_align - 1UL) & ~(bridge_align -1)) -1UL; + limit = base + ((resource->size + align - 1UL) & ~(align - 1UL)) -1UL; if (!(resource->flags & IORESOURCE_PCI_BRIDGE)) { /* @@ -300,7 +295,7 @@ static void pci_set_resource(struct device *dev, struct resource *resource) /* set the IO ranges * WARNING: we don't really do 32-bit addressing for IO yet! */ - compute_allocate_resource(dev, resource, + compute_allocate_resource(&dev->link[0], resource, IORESOURCE_IO, IORESOURCE_IO); pci_write_config8(dev, PCI_IO_BASE, base >> 8); pci_write_config8(dev, PCI_IO_LIMIT, limit >> 8); @@ -310,7 +305,7 @@ static void pci_set_resource(struct device *dev, struct resource *resource) else if (resource->index == PCI_MEMORY_BASE) { /* set the memory range */ - compute_allocate_resource(dev, resource, + compute_allocate_resource(&dev->link[0], resource, IORESOURCE_MEM | IORESOURCE_PREFETCH, IORESOURCE_MEM); pci_write_config16(dev, PCI_MEMORY_BASE, base >> 16); @@ -320,7 +315,7 @@ static void pci_set_resource(struct device *dev, struct resource *resource) /* set the prefetchable memory range * WARNING: we don't really do 64-bit addressing for prefetchable memory yet! */ - compute_allocate_resource(dev, resource, + compute_allocate_resource(&dev->link[0], resource, IORESOURCE_MEM | IORESOURCE_PREFETCH, IORESOURCE_MEM | IORESOURCE_PREFETCH); pci_write_config16(dev, PCI_PREF_MEMORY_BASE, base >> 16); @@ -334,13 +329,12 @@ static void pci_set_resource(struct device *dev, struct resource *resource) } buf[0] = '\0'; if (resource->flags & IORESOURCE_PCI_BRIDGE) { - sprintf(buf, "bus %d ", dev->secondary); + sprintf(buf, "bus %d ", dev->link[0].secondary); } printk_debug( - "PCI: %02x:%02x.%01x %02x <- [0x%08lx - 0x%08lx] %s%s\n", - dev->bus->secondary, - PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), + "%s %02x <- [0x%08lx - 0x%08lx] %s%s\n", + dev_path(dev), resource->index, resource->base, limit, buf, @@ -352,6 +346,7 @@ static void pci_set_resource(struct device *dev, struct resource *resource) void pci_dev_set_resources(struct device *dev) { struct resource *resource, *last; + unsigned link; uint8_t line; last = &dev->resource[dev->resources]; @@ -359,8 +354,12 @@ void pci_dev_set_resources(struct device *dev) for(resource = &dev->resource[0]; resource < last; resource++) { pci_set_resource(dev, resource); } - if (dev->children) { - assign_resources(dev); + for(link = 0; link < dev->links; link++) { + struct bus *bus; + bus = &dev->link[link]; + if (bus->children) { + assign_resources(bus); + } } /* set a default latency timer */ @@ -380,15 +379,39 @@ void pci_dev_set_resources(struct device *dev) pci_write_config8(dev, PCI_CACHE_LINE_SIZE, 64 >> 2); } +void pci_dev_enable_resources(struct device *dev) +{ + uint16_t command; + command = pci_read_config16(dev, PCI_COMMAND); + command |= dev->command; + printk_debug("%s cmd <- %02x\n", dev_path(dev), command); + pci_write_config16(dev, PCI_COMMAND, command); + + enable_childrens_resources(dev); +} + +void pci_bus_enable_resources(struct device *dev) +{ + uint16_t ctrl; + ctrl = pci_read_config16(dev, PCI_BRIDGE_CONTROL); + ctrl |= dev->link[0].bridge_ctrl; + printk_debug("%s bridge ctrl <- %04x\n", dev_path(dev), ctrl); + pci_write_config16(dev, PCI_BRIDGE_CONTROL, ctrl); + + pci_dev_enable_resources(dev); +} + struct device_operations default_pci_ops_dev = { - .read_resources = pci_dev_read_resources, - .set_resources = pci_dev_set_resources, + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, .init = 0, .scan_bus = 0, }; struct device_operations default_pci_ops_bus = { - .read_resources = pci_bus_read_resources, - .set_resources = pci_dev_set_resources, + .read_resources = pci_bus_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_bus_enable_resources, .init = 0, .scan_bus = pci_scan_bridge, }; @@ -406,10 +429,10 @@ static void set_pci_ops(struct device *dev) (driver->device == dev->device)) { dev->ops = driver->ops; #if 1 - printk_debug("PCI: %02x:%02x.%01x [%04x/%04x] ops\n", - dev->bus->secondary, - PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), - driver->vendor, driver->device + printk_debug("%s [%04x/%04x] %sops\n", + dev_path(dev), + driver->vendor, driver->device, + (driver->ops->scan_bus?"bus ":"") ); #endif return; @@ -429,10 +452,9 @@ static void set_pci_ops(struct device *dev) break; default: bad: - printk_err("PCI: %02x:%02x.%01x [%04x/%04x/%06x] has unknown header " + printk_err("%s [%04x/%04x/%06x] has unknown header " "type %02x, ignoring.\n", - dev->bus->secondary, - PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), + dev_path(dev), dev->vendor, dev->device, dev->class >> 8, dev->hdr_type); } @@ -449,7 +471,7 @@ static struct device *pci_scan_get_dev(struct device **list, unsigned int devfn) { struct device *dev = 0; for(; *list; list = &(*list)->sibling) { - if ((*list)->devfn == devfn) { + if ((*list)->path.u.pci.devfn == devfn) { /* Unlink from the list */ dev = *list; *list = (*list)->sibling; @@ -457,6 +479,20 @@ static struct device *pci_scan_get_dev(struct device **list, unsigned int devfn) break; } } + if (dev) { + device_t child; + /* Find the last child of our parent */ + for(child = dev->bus->children; child && child->sibling; ) { + child = child->sibling; + } + /* Place the device on the list of children of it's parent. */ + if (child) { + child->sibling = dev; + } else { + dev->bus->children = dev; + } + } + return dev; } @@ -468,7 +504,8 @@ void assign_id_set_links(device_t dev, uint8_t *pos, static const uint8_t link_width_to_pow2[]= { 3, 4, 0, 5, 1, 2, 0, 0 }; static const uint8_t pow2_to_link_width[] = { 0x7, 4, 5, 0, 1, 3 }; uint16_t flags; - struct device last, prev_bus, previous; + struct bus prev_bus; + struct device last, previous; unsigned count; uint8_t present_width_cap; uint16_t present_freq_cap; @@ -499,14 +536,17 @@ void assign_id_set_links(device_t dev, uint8_t *pos, /* calculate the previous pos for the host */ *previous_pos = 0x80; previous.bus = &prev_bus; - previous.devfn = 0x18 << 3; + previous.path.type = DEVICE_PATH_PCI; + previous.path.u.pci.devfn = 0x18 << 3; #warning "FIXME we should not hard code this!" } else { - previous.bus = bus; - previous.devfn = previous_unitid << 3; + previous.bus = bus; + previous.path.type = DEVICE_PATH_PCI; + previous.path.u.pci.devfn = previous_unitid << 3; } - last.bus = bus; - last.devfn = last_unitid << 3; + last.bus = bus; + last.path.type = DEVICE_PATH_PCI; + last.path.u.pci.devfn = last_unitid << 3; /* Set link width and frequency */ present_freq_cap = pci_read_config16(&last, (*pos) + PCI_HT_CAP_SLAVE_FREQ_CAP0); @@ -614,16 +654,20 @@ void assign_id_set_links(device_t dev, uint8_t *pos, #define HYPERTRANSPORT_SUPPORT 1 /** Scan the pci bus devices and bridges. - * @param pci_bus pointer to the bus structure + * @param bus pointer to the bus structure + * @param min_devfn minimum devfn to look at in the scan usually 0x00 + * @param max_devfn maximum devfn to look at in the scan usually 0xff * @param max current bus number * @return The maximum bus number found, after scanning all subordinate busses */ -unsigned int pci_scan_bus(struct device *bus, unsigned int max) +unsigned int pci_scan_bus(struct bus *bus, + unsigned min_devfn, unsigned max_devfn, + unsigned int max) { unsigned int devfn; - struct device *dev, **bus_last; - struct device *old_devices; - struct device *child; + device_t dev; + device_t old_devices; + device_t child; #if HYPERTRANSPORT_SUPPORT unsigned next_unitid, last_unitid, previous_unitid; int reset_needed = 0; @@ -634,7 +678,6 @@ unsigned int pci_scan_bus(struct device *bus, unsigned int max) old_devices = bus->children; bus->children = 0; - bus_last = &bus->children; post_code(0x24); @@ -643,15 +686,16 @@ unsigned int pci_scan_bus(struct device *bus, unsigned int max) /* Spin through the devices and collapse any early * hypertransport enumeration. */ - for(devfn = 0; devfn <= 0xff; devfn += 8) { + for(devfn = min_devfn; devfn <= max_devfn; devfn += 8) { struct device dummy; uint32_t id; uint8_t hdr_type, pos; - dummy.bus = bus; - dummy.devfn = devfn; + dummy.bus = bus; + dummy.path.type = DEVICE_PATH_PCI; + dummy.path.u.pci.devfn = devfn; id = pci_read_config32(&dummy, PCI_VENDOR_ID); - if (id == 0xffffffff || id == 0x00000000 || - id == 0x0000ffff || id == 0xffff0000) { + if ( (id == 0xffffffff) || (id == 0x00000000) || + (id == 0x0000ffff) || (id == 0xffff0000)) { continue; } hdr_type = pci_read_config8(&dummy, PCI_HEADER_TYPE); @@ -699,8 +743,9 @@ unsigned int pci_scan_bus(struct device *bus, unsigned int max) last_unitid = next_unitid; /* Read the next unassigned device off the stack */ - dummy.bus = bus; - dummy.devfn = 0; + dummy.bus = bus; + dummy.path.type = DEVICE_PATH_PCI; + dummy.path.u.pci.devfn = 0; id = pci_read_config32(&dummy, PCI_VENDOR_ID); /* If the chain is enumerated quit */ if (id == 0xffffffff || id == 0x00000000 || @@ -745,79 +790,78 @@ unsigned int pci_scan_bus(struct device *bus, unsigned int max) /* probe all devices on this bus with some optimization for non-existance and single funcion devices */ - for (devfn = 0; devfn <= 0xff; devfn++) { - struct device dummy; + for (devfn = min_devfn; devfn <= max_devfn; devfn++) { uint32_t id, class; uint8_t hdr_type; /* First thing setup the device structure */ dev = pci_scan_get_dev(&old_devices, devfn); - dummy.bus = bus; - dummy.devfn = devfn; - id = pci_read_config32(&dummy, PCI_VENDOR_ID); - /* some broken boards return 0 if a slot is empty: */ - if (!dev && - (id == 0xffffffff || id == 0x00000000 || - id == 0x0000ffff || id == 0xffff0000)) { - printk_spew("PCI: devfn 0x%x, bad id 0x%x\n", devfn, id); - if (PCI_FUNC(devfn) == 0x00) { - /* if this is a function 0 device and it is not present, - skip to next device */ - devfn += 0x07; - } - /* multi function device, skip to next function */ - continue; - } - hdr_type = pci_read_config8(&dummy, PCI_HEADER_TYPE); - class = pci_read_config32(&dummy, PCI_CLASS_REVISION); - + /* Detect if a device is present */ if (!dev) { - if ((dev = malloc(sizeof(*dev))) == 0) { - printk_err("PCI: out of memory.\n"); + struct device dummy; + dummy.bus = bus; + dummy.path.type = DEVICE_PATH_PCI; + dummy.path.u.pci.devfn = devfn; + id = pci_read_config32(&dummy, PCI_VENDOR_ID); + /* some broken boards return 0 if a slot is empty: */ + if ( (id == 0xffffffff) || (id == 0x00000000) || + (id == 0x0000ffff) || (id == 0xffff0000)) + { + printk_spew("PCI: devfn 0x%x, bad id 0x%x\n", devfn, id); + if (PCI_FUNC(devfn) == 0x00) { + /* if this is a function 0 device and it is not present, + skip to next device */ + devfn += 0x07; + } + /* multi function device, skip to next function */ continue; } - memset(dev, 0, sizeof(*dev)); - dev->bus = bus; - dev->devfn = devfn; - dev->vendor = id & 0xffff; - dev->device = (id >> 16) & 0xffff; - dev->hdr_type = hdr_type; - /* class code, the upper 3 bytes of PCI_CLASS_REVISION */ - dev->class = class >> 8; - - /* If we don't have prior information about this device enable it */ - dev->enable = 1; + dev = alloc_dev(bus, &dummy.path); + } + else { + /* Run the magic enable/disable sequence for the device */ + if (dev->ops && dev->ops->enable) { + dev->ops->enable(dev); + } + /* Now read the vendor and device id */ + id = pci_read_config32(dev, PCI_VENDOR_ID); } + /* Read the rest of the pci configuration information */ + hdr_type = pci_read_config8(dev, PCI_HEADER_TYPE); + class = pci_read_config32(dev, PCI_CLASS_REVISION); + + /* Store the interesting information in the device structure */ + dev->vendor = id & 0xffff; + dev->device = (id >> 16) & 0xffff; + dev->hdr_type = hdr_type; + /* class code, the upper 3 bytes of PCI_CLASS_REVISION */ + dev->class = class >> 8; + /* Look at the vendor and device id, or at least the * header type and class and figure out which set of configuration * methods to use. */ - set_pci_ops(dev); - /* Kill the device if we don't have some pci operations for it */ if (!dev->ops) { - free(dev); - continue; - } - - /* Now run the magic enable/disable sequence for the device */ - if (dev->ops && dev->ops->enable) { - dev->ops->enable(dev); + set_pci_ops(dev); + /* Error if we don't have some pci operations for it */ + if (!dev->ops) { + printk_err("%s No device operations\n", + dev_path(dev)); + continue; + } + /* Now run the magic enable/disable sequence for the device */ + if (dev->ops && dev->ops->enable) { + dev->ops->enable(dev); + } } - printk_debug("PCI: %02x:%02x.%01x [%04x/%04x] %s\n", - bus->secondary, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), + printk_debug("%s [%04x/%04x] %s\n", + dev_path(dev), dev->vendor, dev->device, dev->enable?"enabled": "disabled"); - /* Put it into the global device chain. */ - append_device(dev); - - /* Now insert it into the list of devices held by the parent bus. */ - *bus_last = dev; - bus_last = &dev->sibling; - if (PCI_FUNC(devfn) == 0x00 && (hdr_type & 0x80) != 0x80) { /* if this is not a multi function device, don't waste time probe another function. Skip to next device. */ @@ -827,10 +871,10 @@ unsigned int pci_scan_bus(struct device *bus, unsigned int max) post_code(0x25); for(child = bus->children; child; child = child->sibling) { - if (!child->ops->scan_bus) + if (!child->ops->scan_bus) { continue; + } max = child->ops->scan_bus(child, max); - } /* * We've scanned the bus and so we know all about what's on @@ -848,10 +892,15 @@ unsigned int pci_scan_bus(struct device *bus, unsigned int max) * @param pci_bus pointer to the bus structure * @return The maximum bus number found, after scanning all subordinate busses */ -unsigned int pci_scan_bridge(struct device *bus, unsigned int max) +unsigned int pci_scan_bridge(struct device *dev, unsigned int max) { + struct bus *bus; uint32_t buses; uint16_t cr; + + bus = &dev->link[0]; + dev->links = 1; + /* Set up the primary, secondary and subordinate bus numbers. We have * no idea how many buses are behind this bridge yet, so we set the * subordinate bus number to 0xff for the moment @@ -860,28 +909,28 @@ unsigned int pci_scan_bridge(struct device *bus, unsigned int max) bus->subordinate = 0xff; /* Clear all status bits and turn off memory, I/O and master enables. */ - cr = pci_read_config16(bus, PCI_COMMAND); - pci_write_config16(bus, PCI_COMMAND, 0x0000); - pci_write_config16(bus, PCI_STATUS, 0xffff); + cr = pci_read_config16(dev, PCI_COMMAND); + pci_write_config16(dev, PCI_COMMAND, 0x0000); + pci_write_config16(dev, PCI_STATUS, 0xffff); /* * Read the existing primary/secondary/subordinate bus * number configuration. */ - buses = pci_read_config32(bus, PCI_PRIMARY_BUS); + buses = pci_read_config32(dev, PCI_PRIMARY_BUS); /* Configure the bus numbers for this bridge: the configuration * transactions will not be propagated by the bridge if it is not * correctly configured */ buses &= 0xff000000; - buses |= (((unsigned int) (bus->bus->secondary) << 0) | + buses |= (((unsigned int) (dev->bus->secondary) << 0) | ((unsigned int) (bus->secondary) << 8) | ((unsigned int) (bus->subordinate) << 16)); - pci_write_config32(bus, PCI_PRIMARY_BUS, buses); + pci_write_config32(dev, PCI_PRIMARY_BUS, buses); /* Now we can scan all subordinate buses i.e. the bus hehind the bridge */ - max = pci_scan_bus(bus, max); + max = pci_scan_bus(bus, 0x00, 0xff, max); /* We know the number of buses behind this bridge. Set the subordinate * bus number to its real value @@ -889,55 +938,8 @@ unsigned int pci_scan_bridge(struct device *bus, unsigned int max) bus->subordinate = max; buses = (buses & 0xff00ffff) | ((unsigned int) (bus->subordinate) << 16); - pci_write_config32(bus, PCI_PRIMARY_BUS, buses); - pci_write_config16(bus, PCI_COMMAND, cr); + pci_write_config32(dev, PCI_PRIMARY_BUS, buses); + pci_write_config16(dev, PCI_COMMAND, cr); return max; } - - -static void pci_root_read_resources(struct device *bus) -{ - int res = 0; - /* Initialize the system wide io space constraints */ - bus->resource[res].base = 0x400; - bus->resource[res].size = 0; - bus->resource[res].align = 0; - bus->resource[res].gran = 0; - bus->resource[res].limit = 0xffffUL; - bus->resource[res].flags = IORESOURCE_IO; - bus->resource[res].index = PCI_IO_BASE; - compute_allocate_resource(bus, &bus->resource[res], - IORESOURCE_IO, IORESOURCE_IO); - res++; - - /* Initialize the system wide memory resources constraints */ - bus->resource[res].base = 0; - bus->resource[res].size = 0; - bus->resource[res].align = 0; - bus->resource[res].gran = 0; - bus->resource[res].limit = 0xffffffffUL; - bus->resource[res].flags = IORESOURCE_MEM; - bus->resource[res].index = PCI_MEMORY_BASE; - compute_allocate_resource(bus, &bus->resource[res], - IORESOURCE_MEM, IORESOURCE_MEM); - res++; - - bus->resources = res; -} -static void pci_root_set_resources(struct device *bus) -{ - compute_allocate_resource(bus, - &bus->resource[0], IORESOURCE_IO, IORESOURCE_IO); - compute_allocate_resource(bus, - &bus->resource[1], IORESOURCE_MEM, IORESOURCE_MEM); - assign_resources(bus); -} - -struct device_operations default_pci_ops_root = { - .read_resources = pci_root_read_resources, - .set_resources = pci_root_set_resources, - .init = 0, - .scan_bus = pci_scan_bus, -}; - diff --git a/src/devices/root_device.c b/src/devices/root_device.c new file mode 100644 index 0000000000..c05a2cd015 --- /dev/null +++ b/src/devices/root_device.c @@ -0,0 +1,127 @@ +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> + +/** + * Read the resources for the root device, + * that encompase the resources for the entire system. + * @param root Pointer to the device structure for the system root device + */ +void root_dev_read_resources(device_t root) +{ + int res = 0; + + /* Initialize the system wide io space constraints */ + root->resource[res].base = 0x400; + root->resource[res].size = 0; + root->resource[res].align = 0; + root->resource[res].gran = 0; + root->resource[res].limit = 0xffffUL; + root->resource[res].flags = IORESOURCE_IO; + root->resource[res].index = 0; + compute_allocate_resource(&root->link[0], &root->resource[res], + IORESOURCE_IO, IORESOURCE_IO); + res++; + + /* Initialize the system wide memory resources constraints */ + root->resource[res].base = 0; + root->resource[res].size = 0; + root->resource[res].align = 0; + root->resource[res].gran = 0; + root->resource[res].limit = 0xffffffffUL; + root->resource[res].flags = IORESOURCE_MEM; + root->resource[res].index = 1; + compute_allocate_resource(&root->link[0], &root->resource[res], + IORESOURCE_MEM, IORESOURCE_MEM); + res++; + + root->resources = res; +} + +/** + * Write the resources for the root device, + * and every device under it which are all of the devices. + * @param root Pointer to the device structure for the system root device + */ +void root_dev_set_resources(device_t root) +{ + struct bus *bus; + bus = &root->link[0]; + compute_allocate_resource(bus, + &root->resource[0], IORESOURCE_IO, IORESOURCE_IO); + compute_allocate_resource(bus, + &root->resource[1], IORESOURCE_MEM, IORESOURCE_MEM); + assign_resources(bus); +} + +/** + * Walk through devices on the motherboard and scan for devices behind + * them. + * @param root Pointer to the device structure for the system root device + * @param max Maximum bus number allowed in the system. + * @return Largest bus number used. + */ +unsigned int walk_static_devices(device_t bus, unsigned int max) +{ + device_t child; + unsigned link; + for(link = 0; link < bus->links; link++) { + for(child = bus->link[link].children; child; child = child->sibling) { + if (child->ops && child->ops->enable) { + child->ops->enable(child); + } + printk_debug("%s %s\n", + dev_path(child), + child->enable?"enabled": "disabled"); + } + } + for(link = 0; link < bus->links; link++) { + for(child = bus->link[link].children; child; child = child->sibling) { + if (!child->ops || !child->ops->scan_bus) + continue; + printk_debug("%s scanning...\n", dev_path(child)); + max = child->ops->scan_bus(child, max); + } + } + return max; +} + +void enable_childrens_resources(device_t dev) +{ + unsigned link; + for(link = 0; link < dev->links; link++) { + device_t child; + for(child = dev->link[link].children; child; child = child->sibling) { + enable_resources(child); + } + } +} + +unsigned int root_dev_scan_pci_bus(device_t root, unsigned int max) +{ + return pci_scan_bus(&root->link[0], 0, 0xff, max); +} + +struct device_operations default_dev_ops_root = { + .read_resources = root_dev_read_resources, + .set_resources = root_dev_set_resources, + .enable_resources = enable_childrens_resources, + .init = 0, + .scan_bus = root_dev_scan_pci_bus, +}; + +/** + * This is the root of the device tree. A PCI tree always has + * one bus, bus 0. Bus 0 contains devices and bridges. + */ +struct device dev_root = { + .ops = &default_dev_ops_root, + .bus = &dev_root.link[0], + .links = 1, + .link = { + [0] = { + .dev = &dev_root, + .link = 0, + }, + }, +}; diff --git a/src/include/device/chip.h b/src/include/device/chip.h index d1132a1f36..a98625a7ab 100644 --- a/src/include/device/chip.h +++ b/src/include/device/chip.h @@ -1,3 +1,7 @@ +#ifndef DEVICE_CHIP_H + +#include <device/path.h> + /* chips are arbitrary chips (superio, southbridge, etc.) * They have private structures that define chip resources and default * settings. They have four externally visible functions for control. @@ -48,23 +52,38 @@ struct chip; /* there is one of these for each TYPE of chip */ struct chip_control { - void (*enable)(struct chip *, enum chip_pass); - char *path; /* the default path. Can be overridden - * by commands in config - */ - // This is the print name for debugging - char *name; + /* This is the print name for debugging */ + char *name; + void (*enable)(struct chip *, enum chip_pass); + void (*enumerate)(struct chip *chip); }; + +struct chip_device_path { + struct device_path path; + unsigned channel; + int enable; +}; + +struct device; +struct bus; + +#ifndef MAX_CHIP_PATHS +#define MAX_CHIP_PATHS 16 +#endif struct chip { - struct chip_control *control; /* for this device */ - char *path; /* can be 0, in which case the default is taken */ - char *configuration; /* can be 0. */ - int irq; - struct chip *next, *children; - /* there is one of these for each INSTANCE of a chip */ - void *chip_info; /* the dreaded "void *" */ + struct chip_control *control; /* for this device */ + struct chip_device_path path[MAX_CHIP_PATHS]; /* can be 0, in which case the default is taken */ + char *configuration; /* can be 0. */ + struct chip *next, *children; + /* there is one of these for each INSTANCE of a chip */ + void *chip_info; /* the dreaded "void *" */ + /* bus and device links into the device tree */ + struct bus *bus; + struct device *dev; }; extern struct chip static_root; extern void chip_configure(struct chip *, enum chip_pass); +extern void chip_enumerate(struct chip *chip); +#endif /* DEVICE_CHIP_H */ diff --git a/src/include/device/device.h b/src/include/device/device.h index 21e5dfc5c8..5529abc7f2 100644 --- a/src/include/device/device.h +++ b/src/include/device/device.h @@ -3,6 +3,7 @@ #include <stdint.h> #include <device/resource.h> +#include <device/path.h> struct device; typedef struct device * device_t; @@ -10,33 +11,42 @@ typedef struct device * device_t; struct device_operations { void (*read_resources)(device_t dev); void (*set_resources)(device_t dev); + void (*enable_resources)(device_t dev); void (*init)(device_t dev); unsigned int (*scan_bus)(device_t bus, unsigned int max); void (*enable)(device_t dev); }; +struct bus { + device_t dev; /* This bridge device */ + device_t children; /* devices behind this bridge */ + unsigned bridge_ctrl; /* Bridge control register */ + unsigned char link; /* The index of this link */ + unsigned char secondary; /* secondary bus number */ + unsigned char subordinate; /* max subordinate bus number */ + unsigned char cap; /* PCi capability offset */ +}; + #define MAX_RESOURCES 6 +#define MAX_LINKS 3 /* * There is one device structure for each slot-number/function-number * combination: */ struct device { - device_t bus; /* bus this device is on */ - device_t children; /* devices behind this bridge */ - device_t sibling; /* next device on this bus */ - device_t next; /* chain of all devices */ + struct bus * bus; /* bus this device is on */ + device_t sibling; /* next device on this bus */ + device_t next; /* chain of all devices */ - unsigned int devfn; /* encoded device & function index */ + struct device_path path; unsigned short vendor; unsigned short device; unsigned int class; /* 3 bytes: (base,sub,prog-if) */ unsigned int hdr_type; /* PCI header type */ unsigned int enable : 1; /* set if we should enable the device */ - unsigned char secondary; /* secondary bus number */ - unsigned char subordinate; /* max subordinate bus number */ uint8_t command; /* * In theory, the irq level can be read from configuration @@ -56,6 +66,10 @@ struct device { */ struct resource resource[MAX_RESOURCES]; unsigned int resources; + + struct bus link[MAX_LINKS]; + unsigned int links; + unsigned long rom_address; struct device_operations *ops; }; @@ -65,19 +79,22 @@ extern struct device *all_devices; /* list of all devices */ /* Generic device interface functions */ +extern device_t alloc_dev(struct bus *parent, struct device_path *path); extern void dev_enumerate(void); extern void dev_configure(void); extern void dev_enable(void); extern void dev_initialize(void); /* Generic device helper functions */ -void append_device(device_t dev); -void compute_allocate_resource(device_t bus, struct resource *bridge, +extern void compute_allocate_resource(struct bus *bus, struct resource *bridge, unsigned long type_mask, unsigned long type); -void assign_resources(device_t bus); -void enumerate_static_device(void); +extern void assign_resources(struct bus *bus); +extern void enable_resources(struct device *dev); +extern void enumerate_static_device(void); +extern const char *dev_path(device_t dev); /* Helper functions */ +device_t alloc_find_dev(struct bus *bus, struct device_path *path); device_t dev_find_device (unsigned int vendor, unsigned int device, device_t from); device_t dev_find_class (unsigned int class, device_t from); device_t dev_find_slot (unsigned int bus, unsigned int devfn); @@ -88,5 +105,10 @@ device_t dev_find_slot (unsigned int bus, unsigned int devfn); #define DEVICE_IO_ALIGN 16 #define DEVICE_MEM_ALIGN 4096 +struct device_operations default_dev_ops_root; +extern void root_dev_read_resources(device_t dev); +extern void root_dev_set_resources(device_t dev); +extern unsigned int walk_static_devices(device_t bus, unsigned int max); +extern void enable_childrens_resources(device_t dev); #endif /* DEVICE_H */ diff --git a/src/include/device/path.h b/src/include/device/path.h new file mode 100644 index 0000000000..cf89a68466 --- /dev/null +++ b/src/include/device/path.h @@ -0,0 +1,41 @@ +#ifndef DEVICE_PATH_H +#define DEVICE_PATH_H + +enum device_path_type { + DEVICE_PATH_NONE = 0, + DEVICE_PATH_PCI, + DEVICE_PATH_PNP, + DEVICE_PATH_I2C, +}; + +struct pci_path +{ + unsigned devfn; +}; + +struct pnp_path +{ + unsigned port; + unsigned device; +}; + +struct i2c_path +{ + unsigned device; +}; + +struct device_path { + enum device_path_type type; + union { + struct pci_path pci; + struct pnp_path pnp; + struct i2c_path i2c; + } u; +}; + + +#define DEVICE_PATH_MAX 30 + +extern int path_eq(struct device_path *path1, struct device_path *path2); + +#endif /* DEVICE_PATH_H */ diff --git a/src/include/device/pci.h b/src/include/device/pci.h index 0b76de321a..aa6778c504 100644 --- a/src/include/device/pci.h +++ b/src/include/device/pci.h @@ -34,13 +34,15 @@ extern struct pci_driver epci_drivers[]; struct device_operations default_pci_ops_dev; struct device_operations default_pci_ops_bus; -struct device_operations default_pci_ops_root; -void pci_dev_read_resources(struct device *dev); -void pci_bus_read_resources(struct device *dev); -void pci_dev_set_resources(struct device *dev); -unsigned int pci_scan_bridge(struct device *bus, unsigned int max); +void pci_dev_read_resources(device_t dev); +void pci_bus_read_resources(device_t dev); +void pci_dev_set_resources(device_t dev); +void pci_dev_enable_resources(device_t dev); +void pci_bus_enable_resources(device_t dev); +unsigned int pci_scan_bridge(device_t bus, unsigned int max); +unsigned int pci_scan_bus(struct bus *bus, unsigned min_devfn, unsigned max_devfn, unsigned int max); #define PCI_IO_BRIDGE_ALIGN 4096 #define PCI_MEM_BRIDGE_ALIGN (1024*1024) diff --git a/src/include/device/resource.h b/src/include/device/resource.h index 30422016df..f90aba19f4 100644 --- a/src/include/device/resource.h +++ b/src/include/device/resource.h @@ -7,7 +7,7 @@ #define IORESOURCE_IO 0x00000100 /* Resource type */ #define IORESOURCE_MEM 0x00000200 #define IORESOURCE_IRQ 0x00000400 -#define IORESOURCE_DMA 0x00000800 +#define IORESOURCE_DRQ 0x00000800 #define IORESOURCE_PREFETCH 0x00001000 /* No side effects */ #define IORESOURCE_READONLY 0x00002000 @@ -15,8 +15,12 @@ #define IORESOURCE_RANGELENGTH 0x00008000 #define IORESOURCE_SHADOWABLE 0x00010000 #define IORESOURCE_BUS_HAS_VGA 0x00020000 +#define IORESOURCE_SUBTRACTIVE 0x00040000 /* This resource filters all of the unclaimed transactions + * to the bus below. + */ -#define IORESOURCE_SET 0x80000000 +#define IORESOURCE_SET 0x80000000 /* An IO resource that has been assigned a value */ +#define IORESOURCE_FIXED 0x40000000 /* An IO resource the allocator must not change */ /* PCI specific resource bits */ #define IORESOURCE_PCI64 (1<<0) /* 64bit long pci resource */ diff --git a/src/mainboard/arima/hdama/Config.lb b/src/mainboard/arima/hdama/Config.lb index 4947698590..80c3bfca11 100644 --- a/src/mainboard/arima/hdama/Config.lb +++ b/src/mainboard/arima/hdama/Config.lb @@ -224,38 +224,38 @@ mainboardinit cpu/k8/disable_mmx_sse.inc dir /pc80 northbridge amd/amdk8 "mc0" - #pci 0:18.0 - #pci 0:18.0 - #pci 0:18.0 - #pci 0:18.1 - #pci 0:18.2 - #pci 0:18.3 + pci 0:18.0 + pci 0:18.0 + pci 0:18.0 + pci 0:18.1 + pci 0:18.2 + pci 0:18.3 southbridge amd/amd8131 "amd8131" - #pci 0:0.0 - #pci 0:0.1 - #pci 0:1.0 - #pci 0:1.1 + pci 0:0.0 + pci 0:0.1 + pci 0:1.0 + pci 0:1.1 end southbridge amd/amd8111 "amd8111" - #pci 0:0.0 - #pci 0:1.0 - #pci 0:1.1 - #pci 0:1.2 - #pci 0:1.3 - #pci 0:1.5 off - #pci 0:1.6 off + pci 0:0.0 + pci 0:1.0 + pci 0:1.1 + pci 0:1.2 + pci 0:1.3 + pci 0:1.5 + pci 0:1.6 superio NSC/pc87360 - #pnp 1:2e.0 - #pnp 1:2e.1 - #pnp 1:2e.2 - #pnp 1:2e.3 - #pnp 1:2e.4 - #pnp 1:2e.5 - #pnp 1:2e.6 - #pnp 1:2e.7 - #pnp 1:2e.8 - #pnp 1:2e.9 - #pnp 1:2e.a + pnp 1:2e.0 + pnp 1:2e.1 + pnp 1:2e.2 + pnp 1:2e.3 + pnp 1:2e.4 + pnp 1:2e.5 + pnp 1:2e.6 + pnp 1:2e.7 + pnp 1:2e.8 + pnp 1:2e.9 + pnp 1:2e.a register "com1" = "{1, 0, 0x3f8, 4}" register "lpt" = "{1}" end diff --git a/src/mainboard/tyan/s2885/ti_firewire.c b/src/mainboard/tyan/s2885/ti_firewire.c index be6cec2f8e..15f83c0983 100644 --- a/src/mainboard/tyan/s2885/ti_firewire.c +++ b/src/mainboard/tyan/s2885/ti_firewire.c @@ -30,10 +30,11 @@ static void ti_firewire_init(struct device *dev) } static struct device_operations ti_firewire_ops = { - .read_resources = pci_dev_read_resources, - .set_resources = pci_dev_set_resources, - .init = ti_firewire_init, - .scan_bus = 0, + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = ti_firewire_init, + .scan_bus = 0, }; static struct pci_driver ti_firewire_driver __pci_driver = { diff --git a/src/southbridge/amd/amd8111/amd8111_acpi.c b/src/southbridge/amd/amd8111/amd8111_acpi.c index 120e0ee426..5fa6fdce29 100644 --- a/src/southbridge/amd/amd8111/amd8111_acpi.c +++ b/src/southbridge/amd/amd8111/amd8111_acpi.c @@ -39,8 +39,9 @@ static void acpi_init(struct device *dev) } static struct device_operations acpi_ops = { - .read_resources = pci_dev_read_resources, - .set_resources = pci_dev_set_resources, + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, .init = acpi_init, .scan_bus = 0, }; diff --git a/src/southbridge/amd/amd8111/amd8111_ide.c b/src/southbridge/amd/amd8111/amd8111_ide.c index 8e034493e8..11f795b0bb 100644 --- a/src/southbridge/amd/amd8111/amd8111_ide.c +++ b/src/southbridge/amd/amd8111/amd8111_ide.c @@ -51,10 +51,11 @@ static void ide_init(struct device *dev) } static struct device_operations ide_ops = { - .read_resources = pci_dev_read_resources, - .set_resources = pci_dev_set_resources, - .init = ide_init, - .scan_bus = 0, + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = ide_init, + .scan_bus = 0, }; static struct pci_driver ide_driver __pci_driver = { diff --git a/src/southbridge/amd/amd8111/amd8111_lpc.c b/src/southbridge/amd/amd8111/amd8111_lpc.c index b78b55bc88..b0c1672f5d 100644 --- a/src/southbridge/amd/amd8111/amd8111_lpc.c +++ b/src/southbridge/amd/amd8111/amd8111_lpc.c @@ -121,11 +121,44 @@ static void lpc_init(struct device *dev) } +static void amd8111_lpc_read_resources(device_t dev) +{ + unsigned int reg; + + /* Get the normal pci resources of this device */ + pci_dev_read_resources(dev); + + /* Find my place in the resource list */ + reg = dev->resources; + + /* Add an extra subtractive resource for both memory and I/O */ + dev->resource[reg].base = 0; + dev->resource[reg].size = 0; + dev->resource[reg].align = 0; + dev->resource[reg].gran = 0; + dev->resource[reg].limit = 0; + dev->resource[reg].flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | IORESOURCE_SET; + dev->resource[reg].index = 0; + reg++; + + dev->resource[reg].base = 0; + dev->resource[reg].size = 0; + dev->resource[reg].align = 0; + dev->resource[reg].gran = 0; + dev->resource[reg].limit = 0; + dev->resource[reg].flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE | IORESOURCE_SET; + dev->resource[reg].index = 0; + reg++; + + dev->resources = reg; +} + static struct device_operations lpc_ops = { - .read_resources = pci_dev_read_resources, - .set_resources = pci_dev_set_resources, - .init = lpc_init, - .scan_bus = 0, + .read_resources = amd8111_lpc_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = lpc_init, + .scan_bus = walk_static_devices, }; static struct pci_driver lpc_driver __pci_driver = { diff --git a/src/southbridge/amd/amd8111/amd8111_usb.c b/src/southbridge/amd/amd8111/amd8111_usb.c index 467e907a99..cfef06dee2 100644 --- a/src/southbridge/amd/amd8111/amd8111_usb.c +++ b/src/southbridge/amd/amd8111/amd8111_usb.c @@ -20,10 +20,11 @@ static void usb_init(struct device *dev) } static struct device_operations usb_ops = { - .read_resources = pci_dev_read_resources, - .set_resources = pci_dev_set_resources, - .init = usb_init, - .scan_bus = 0, + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = usb_init, + .scan_bus = 0, }; static struct pci_driver usb_driver __pci_driver = { diff --git a/src/southbridge/amd/amd8111/amd8111_usb2.c b/src/southbridge/amd/amd8111/amd8111_usb2.c index 5c680ba0ad..924e0e6109 100644 --- a/src/southbridge/amd/amd8111/amd8111_usb2.c +++ b/src/southbridge/amd/amd8111/amd8111_usb2.c @@ -24,10 +24,11 @@ static void usb2_init(struct device *dev) } static struct device_operations usb_ops = { - .read_resources = pci_dev_read_resources, - .set_resources = pci_dev_set_resources, - .init = usb2_init, - .scan_bus = 0, + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = usb2_init, + .scan_bus = 0, }; static struct pci_driver usb2_driver __pci_driver = { diff --git a/src/southbridge/amd/amd8131/amd8131_bridge.c b/src/southbridge/amd/amd8131/amd8131_bridge.c index ba90cad974..dccf962fbd 100644 --- a/src/southbridge/amd/amd8131/amd8131_bridge.c +++ b/src/southbridge/amd/amd8131/amd8131_bridge.c @@ -34,10 +34,11 @@ static void pcix_init(device_t dev) } static struct device_operations pcix_ops = { - .read_resources = pci_bus_read_resources, - .set_resources = pci_dev_set_resources, - .init = pcix_init, - .scan_bus = pci_scan_bridge, + .read_resources = pci_bus_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_bus_enable_resources, + .init = pcix_init, + .scan_bus = pci_scan_bridge, }; static struct pci_driver pcix_driver __pci_driver = { @@ -68,8 +69,9 @@ static void ioapic_enable(device_t dev) } static struct device_operations ioapic_ops = { - .read_resources = pci_dev_read_resources, - .set_resources = pci_dev_set_resources, + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, .init = 0, .scan_bus = 0, .enable = ioapic_enable, diff --git a/src/southbridge/amd/amd8151/amd8151_agp3.c b/src/southbridge/amd/amd8151/amd8151_agp3.c index b7862feff9..2feeded66d 100644 --- a/src/southbridge/amd/amd8151/amd8151_agp3.c +++ b/src/southbridge/amd/amd8151/amd8151_agp3.c @@ -21,10 +21,11 @@ static void agp3bridge_init(device_t dev) } static struct device_operations agp3bridge_ops = { - .read_resources = pci_bus_read_resources, - .set_resources = pci_dev_set_resources, - .init = agp3bridge_init, - .scan_bus = pci_scan_bridge, + .read_resources = pci_bus_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_bus_enable_resources, + .init = agp3bridge_init, + .scan_bus = pci_scan_bridge, }; static struct pci_driver agp3bridge_driver __pci_driver = { @@ -60,8 +61,9 @@ static void agp3dev_enable(device_t dev) } static struct device_operations agp3dev_ops = { - .read_resources = pci_dev_read_resources, - .set_resources = pci_dev_set_resources, + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, .init = 0, .scan_bus = 0, .enable = agp3dev_enable, |