diff options
Diffstat (limited to 'src/devices')
-rw-r--r-- | src/devices/chip.c | 103 | ||||
-rw-r--r-- | src/devices/device.c | 173 | ||||
-rw-r--r-- | src/devices/device_util.c | 7 | ||||
-rw-r--r-- | src/devices/pci_device.c | 296 | ||||
-rw-r--r-- | src/devices/root_device.c | 38 |
5 files changed, 397 insertions, 220 deletions
diff --git a/src/devices/chip.c b/src/devices/chip.c index d8a59e3062..33f3976eb8 100644 --- a/src/devices/chip.c +++ b/src/devices/chip.c @@ -9,8 +9,22 @@ #include <device/chip.h> #include <device/pci.h> -void -chip_configure(struct chip *root, enum chip_pass pass) +/** + * @brief Configure static devices + * + * Starting from the static device 'root', walk the tree and configure each + * device by calling the device specific chip_control::enable(). + * + * This function is only an iterator, the exact definition of 'configure' + * depends on the device specific implementation of chip_control::enable(). + * + * @param root root of the static device tree to be configured. + * @param pass pass of the configuration operation to be perfromed. + * + * @see chip_pass + * @see chip_control::enable + */ +void chip_configure(struct chip *root, enum chip_pass pass) { struct chip *c; @@ -25,24 +39,37 @@ chip_configure(struct chip *root, enum chip_pass pass) } } -/** Convert a static struct chip structure to a set of dynamic device structures. - * @param chip Static chip structure to start with. +/** + * @brief Convert static device structures to dynamic structures. + * + * A static device may contain one or more dynamic devices. Dynamic device + * structures of these devices have to be generated before the enumeration + * of dynamic devices. This function converts a static chip structure to a + * set of dynamic device structures. + * + * This function is the generic method called by enumerate_static_device_chain() + * for static devices. Devices extend this default behavior by defining their + * own chip_controll::enumerate(). Generally, device specific + * chip_control::enumerate() method calls this function as its last operation. + * + * @param chip static chip structure to be converted. + * */ - 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++) { + + for (i = 0; i < MAX_CHIP_PATHS; i++) { int identical_paths; identical_paths = (i > 0) && @@ -55,6 +82,7 @@ void chip_enumerate(struct chip *chip) parent = chip->bus; switch(chip->path[i].path.type) { case DEVICE_PATH_NONE: + /* no dynamic device associated */ break; case DEVICE_PATH_PCI: bus = chip->path[i].path.u.pci.bus; @@ -62,7 +90,7 @@ void chip_enumerate(struct chip *chip) device_t dev; int i = 1; dev = chip->dev; - while(dev && (i != bus)) { + while (dev && (i != bus)) { dev = dev->next; i++; } @@ -75,18 +103,21 @@ void chip_enumerate(struct chip *chip) dev = alloc_dev(parent, &chip->path[i].path); break; } - } - else { + } else { link += 1; } + if (dev) { struct chip_resource *res, *res_limit; - printk_spew("path (%p) %s %s", dev, dev_path(dev), identical_paths?"identical":""); - printk_spew(" parent: (%p) %s\n",dev->bus->dev, dev_path(dev->bus->dev)); + printk_spew("path (%p) %s %s", + dev, dev_path(dev), + identical_paths?"identical":""); + printk_spew(" parent: (%p) %s\n", + dev->bus->dev, dev_path(dev->bus->dev)); dev->chip = chip; dev->enable = chip->path[i].enable; dev->links = link + 1; - for(child = chip->children; child; child = child->next) { + for (child = chip->children; child; child = child->next) { if (!child->bus && child->link == i) { child->bus = &dev->link[link]; } @@ -102,21 +133,42 @@ void chip_enumerate(struct chip *chip) } } } + if (dev && !chip->dev) { chip->dev = dev; } } - for(child = chip->children; child; child = child->next) { + + for (child = chip->children; child; child = child->next) { if (!child->bus) { child->bus = &chip->dev->link[0]; } } } +/** + * @brief Enumerate a static device tree. + * + * A static device chain is a linked list of static device structures which are + * on the same branch of the static device tree. This function does not only + * enumerate the devices on a single chain, as its name suggest, it also walks + * into the subordinary chains. It calls the device specific + * chip_control::enumerate() of the device if one exists or calls the generic + * chip_enumerate(). + * + * This function is only an iterator, the exact definition of 'enumerate' + * depends on the implementation of the generic chip_enumerate() and/or device + * specific chip_control::enumerate(). + * + * @param root static chip structure to start with. + * + * @see chip_control::enumerate() + */ static void enumerate_static_device_chain(struct chip *root) { struct chip *chip; - for(chip = root; chip; chip = chip->next) { + + for (chip = root; chip; chip = chip->next) { void (*enumerate)(struct chip *chip); enumerate = chip_enumerate; if (chip->control && chip->control->enumerate) { @@ -125,13 +177,30 @@ static void enumerate_static_device_chain(struct chip *root) enumerate(chip); } - for(chip = root; chip; chip = chip->next) { + for (chip = root; chip; chip = chip->next) { if (chip->children) { enumerate_static_device_chain(chip->children); } } } +/** + * @brief Enumerate static devices in the system. + * + * \note The definition of 'enumerate' is not clear in this context. Does it mean + * probe ? + * + * \note How do we determine the existence of the static devices ? Static + * devices are listed in the config file and generated at compile time by config + * tool. This function is called at certain point in the early stage of + * LinuxBIOS. It uses the chip_enumerate() function to convert the static + * structures into dynamic ones. What if the static devices listed in the config + * file does actually not exist in the system ? Is there any side effect of + * these 'phantom' device structures + * + * The static device does not necesarry conform to the dynamic device tree in + * the system. + */ void enumerate_static_devices(void) { enumerate_static_device_chain(&static_root); diff --git a/src/devices/device.c b/src/devices/device.c index b54e770294..0186aa977a 100644 --- a/src/devices/device.c +++ b/src/devices/device.c @@ -22,24 +22,41 @@ #include <stdlib.h> #include <string.h> -/* Linked list of ALL devices */ +/** Linked list of ALL devices */ struct device *all_devices = &dev_root; -/* pointer to the last device */ +/** Pointer to the last device */ static struct device **last_dev_p = &dev_root.next; -#define DEVICE_MEM_HIGH 0xFEC00000UL /* Reserve 20M for the system */ +/** The upper limit of MEM resource of the devices. + * Reserve 20M for the system */ +#define DEVICE_MEM_HIGH 0xFEC00000UL +/** The lower limit of IO resource of the devices. + * Reserve 4k for ISA/Legacy devices */ #define DEVICE_IO_START 0x1000 -/** Allocate a new device structure +/** + * @brief Allocate a new device structure. + * + * Allocte a new device structure and attached 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. + * + * @see device_path */ 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; ) { + for (child = parent->children; child && child->sibling; ) { child = child->sibling; } + dev = malloc(sizeof(*dev)); if (dev == 0) { die("DEV: out of memory.\n"); @@ -47,14 +64,14 @@ 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 chain. - * The chain is used to find devices once everything is set up. + /* 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++) { + for (link = 0; link < MAX_LINKS; link++) { dev->link[link].dev = dev; dev->link[link].link = link; } @@ -66,12 +83,15 @@ 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->enable = 1; + return dev; } -/** round a number to an alignment. +/** + * @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 @@ -104,7 +124,7 @@ 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) { + for (curdev = bus->children; curdev; curdev = curdev->sibling) { unsigned links; int i; if (curdev->resources > 0) { @@ -112,20 +132,22 @@ static void read_resources(struct bus *bus) } if (!curdev->ops || !curdev->ops->read_resources) { printk_err("%s missing read_resources\n", - dev_path(curdev)); + dev_path(curdev)); continue; } if (!curdev->enable) { continue; } + curdev->ops->read_resources(curdev); + /* Read in subtractive resources behind the current device */ links = 0; - for(i = 0; i < curdev->resources; i++) { + 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)))) { links |= (1 << resource->index); read_resources(&curdev->link[resource->index]); @@ -142,8 +164,8 @@ struct pick_largest_state { int seen_last; }; -static void pick_largest_resource( - struct pick_largest_state *state, struct device *dev, struct resource *resource) +static void pick_largest_resource(struct pick_largest_state *state, + struct device *dev, struct resource *resource) { struct resource *last; last = state->last; @@ -152,32 +174,33 @@ static void pick_largest_resource( 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)))) { + 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))) { + 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 bus *bus, unsigned long type_mask, + unsigned long type) { struct device *curdev; - for(curdev = bus->children; curdev; curdev = curdev->sibling) { + + for (curdev = bus->children; curdev; curdev = curdev->sibling) { int i; - for(i = 0; i < curdev->resources; i++) { + for (i = 0; i < curdev->resources; i++) { struct resource *resource = &curdev->resource[i]; /* If it isn't the right kind of resource ignore it */ if ((resource->flags & type_mask) != type) { @@ -187,7 +210,8 @@ static void find_largest_resource(struct pick_largest_state *state, if (resource->flags & IORESOURCE_SUBTRACTIVE) { struct bus *subbus; subbus = &curdev->link[resource->index]; - find_largest_resource(state, subbus, type_mask, type); + find_largest_resource(state, subbus, + type_mask, type); continue; } /* See if this is the largest resource */ @@ -196,8 +220,10 @@ static void find_largest_resource(struct pick_largest_state *state, } } -static struct device *largest_resource(struct bus *bus, struct resource **result_res, - unsigned long type_mask, unsigned long type) +static struct device *largest_resource(struct bus *bus, + struct resource **result_res, + unsigned long type_mask, + unsigned long type) { struct pick_largest_state state; @@ -254,12 +280,12 @@ void compute_allocate_resource( min_align = 0; base = bridge->base; - printk_spew("%s compute_allocate_%s: base: %08lx size: %08lx align: %d gran: %d\n", - dev_path(bus->dev), - (bridge->flags & IORESOURCE_IO)? "io": - (bridge->flags & IORESOURCE_PREFETCH)? "prefmem" : "mem", - base, bridge->size, bridge->align, bridge->gran); - + printk_spew("%s compute_allocate_%s: base: %08lx size: %08lx " + "align: %d gran: %d\n", + dev_path(bus->dev), + (bridge->flags & IORESOURCE_IO)? "io": + (bridge->flags & IORESOURCE_PREFETCH)? "prefmem" : "mem", + base, bridge->size, bridge->align, bridge->gran); /* We want different minimum alignments for different kinds of * resources. These minimums are not device type specific @@ -278,8 +304,9 @@ void compute_allocate_resource( /* Remember I haven't found anything yet. */ resource = 0; - /* Walk through all the devices on the current bus and compute the addresses */ - while((dev = largest_resource(bus, &resource, type_mask, type))) { + /* Walk through all the devices on the current bus and compute the + * addresses */ + while ((dev = largest_resource(bus, &resource, type_mask, type))) { unsigned long 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 @@ -357,6 +384,8 @@ void compute_allocate_resource( static void allocate_vga_resource(void) { #warning "FIXME modify allocate_vga_resource so it is less pci centric!" +#warning "This function knows to much about PCI stuff, it should be just a ietrator/visitor." + /* FIXME handle the VGA pallette snooping */ struct device *dev, *vga; struct bus *bus; @@ -422,7 +451,7 @@ void enable_resources(struct device *dev) */ if (!dev->ops || !dev->ops->enable_resources) { printk_err("%s missing enable_resources\n", - dev_path(dev)); + dev_path(dev)); return; } if (!dev->enable) { @@ -431,58 +460,74 @@ void enable_resources(struct device *dev) dev->ops->enable_resources(dev); } -/** Enumerate the resources on the PCI by calling pci_init +/** + * @brief Determine the existence of dynamic devices and construct dynamic + * device tree. + * + * Start for the root device 'dev_root', scan the buses in the system, build + * the dynamic device tree according to the result of the probe. + * + * This function have no idea how to scan and probe the buses and devices at + * all. It depends on the bus/device specific scan_bus() method to do it. + * The scan_bus() function also have to create the device structure and attach + * it to the device tree. */ void dev_enumerate(void) { struct device *root; unsigned subordinate; - printk_info("Enumerating buses..."); + + printk_info("Enumerating buses...\n"); + root = &dev_root; subordinate = root->ops->scan_bus(root, 0); + printk_info("done\n"); } -/** Starting at the root, compute what resources are needed and allocate them. +/** + * @brief Configure devices on the devices tree. + * + * Starting at the root, compute what resources are needed and allocate them. * I/O starts at PCI_IO_START. Since the assignment is hierarchical we * set the values into the dev_root struct. */ void dev_configure(void) { struct device *root = &dev_root; + printk_info("Allocating resources..."); printk_debug("\n"); - root->ops->read_resources(root); - /* Make certain the io devices are allocated somewhere - * safe. - */ + /* 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; - /* Now reallocate the pci resources memory with the - * highest addresses I can manage. - */ + + /* 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); + 1UL << root->resource[1].align); root->resource[1].flags |= IORESOURCE_ASSIGNED; root->resource[1].flags &= ~IORESOURCE_STORED; - /* Allocate the VGA I/O resource.. - */ + /* Allocate the VGA I/O resource.. */ allocate_vga_resource(); - // now just set things into registers ... we hope ... + /* now just set things into registers ... we hope ... */ root->ops->set_resources(root); printk_info("done.\n"); } -/** Starting at the root, walk the tree and enable all devices/bridges. - * What really happens is computed COMMAND bits get set in register 4 +/** + * @brief 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) { @@ -490,22 +535,28 @@ void dev_enable(void) /* now enable everything. */ enable_resources(&dev_root); + printk_info("done.\n"); } -/** Starting at the root, walk the tree and call a driver to - * do device specific setup. +/** + * @brief Initialize all devices in the global device list. + * + * Starting at the first device on the global device link list, + * walk the list and call a driver to do device specific setup. */ void dev_initialize(void) { struct device *dev; printk_info("Initializing devices...\n"); + for (dev = all_devices; dev; dev = dev->next) { if (dev->enable && 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 013501474c..29bb539e1d 100644 --- a/src/devices/device_util.c +++ b/src/devices/device_util.c @@ -6,15 +6,16 @@ /** - * See if a device structure already exists and if not allocate it + * @brief 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 + * @return pointer to 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) { + for (child = parent->children; child; child = child->sibling) { if (path_eq(path, &child->path)) { return child; } diff --git a/src/devices/pci_device.c b/src/devices/pci_device.c index c3f1f6ac8c..4bc4e1f9f0 100644 --- a/src/devices/pci_device.c +++ b/src/devices/pci_device.c @@ -151,7 +151,7 @@ static void pci_read_bases(struct device *dev, unsigned int howmany) { unsigned long index; - for(index = PCI_BASE_ADDRESS_0; (index < PCI_BASE_ADDRESS_0 + (howmany << 2)); ) { + for (index = PCI_BASE_ADDRESS_0; (index < PCI_BASE_ADDRESS_0 + (howmany << 2)); ) { struct resource *resource; resource = pci_get_resource(dev, index); index += (resource->flags & IORESOURCE_PCI64)?8:4; @@ -159,7 +159,6 @@ static void pci_read_bases(struct device *dev, unsigned int howmany) compact_resources(dev); } - static void pci_bridge_read_bases(struct device *dev) { struct resource *resource; @@ -174,7 +173,7 @@ static void pci_bridge_read_bases(struct device *dev) resource->limit = 0xffffUL; resource->flags |= IORESOURCE_IO | IORESOURCE_PCI_BRIDGE; compute_allocate_resource(&dev->link[0], resource, - IORESOURCE_IO, IORESOURCE_IO); + IORESOURCE_IO, IORESOURCE_IO); /* Initiliaze the prefetchable memory constraints on the current bus */ resource = get_resource(dev, PCI_PREF_MEMORY_BASE); @@ -185,8 +184,8 @@ static void pci_bridge_read_bases(struct device *dev) resource->flags = IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_PCI_BRIDGE; resource->index = PCI_PREF_MEMORY_BASE; compute_allocate_resource(&dev->link[0], resource, - IORESOURCE_MEM | IORESOURCE_PREFETCH, - IORESOURCE_MEM | IORESOURCE_PREFETCH); + IORESOURCE_MEM | IORESOURCE_PREFETCH, + IORESOURCE_MEM | IORESOURCE_PREFETCH); /* Initialize the memory resources on the current bus */ resource = get_resource(dev, PCI_MEMORY_BASE); @@ -196,17 +195,18 @@ static void pci_bridge_read_bases(struct device *dev) resource->limit = 0xffffffffUL; resource->flags = IORESOURCE_MEM | IORESOURCE_PCI_BRIDGE; compute_allocate_resource(&dev->link[0], resource, - IORESOURCE_MEM | IORESOURCE_PREFETCH, - IORESOURCE_MEM); + IORESOURCE_MEM | IORESOURCE_PREFETCH, + IORESOURCE_MEM); compact_resources(dev); } - void pci_dev_read_resources(struct device *dev) { uint32_t addr; + pci_read_bases(dev, 6); + addr = pci_read_config32(dev, PCI_ROM_ADDRESS); dev->rom_address = (addr == 0xffffffff)? 0 : addr; } @@ -214,14 +214,29 @@ void pci_dev_read_resources(struct device *dev) void pci_bus_read_resources(struct device *dev) { uint32_t addr; + pci_bridge_read_bases(dev); pci_read_bases(dev, 2); addr = pci_read_config32(dev, PCI_ROM_ADDRESS1); dev->rom_address = (addr == 0xffffffff)? 0 : addr; - } +/** + * @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 + */ +static unsigned long round(unsigned long val, unsigned long roundup) +{ + /* ROUNDUP MUST BE A POWER OF TWO. */ + unsigned long inverse; + inverse = ~(roundup - 1); + val += (roundup - 1); + val &= inverse; + return val; +} static void pci_set_resource(struct device *dev, struct resource *resource) { @@ -230,11 +245,10 @@ static void pci_set_resource(struct device *dev, struct resource *resource) unsigned long gran; /* Make certain the resource has actually been set */ + if (!(resource->flags & IORESOURCE_ASSIGNED)) { -#if 1 printk_err("ERROR: %s %02x not allocated\n", - dev_path(dev), resource->index); -#endif + dev_path(dev), resource->index); return; } @@ -256,8 +270,10 @@ static void pci_set_resource(struct device *dev, struct resource *resource) if (resource->flags & IORESOURCE_PCI_BRIDGE) { dev->command |= PCI_COMMAND_MASTER; } + /* Get the base address */ base = resource->base; + /* Get the resource granularity */ gran = 1UL << resource->gran; @@ -268,15 +284,13 @@ static void pci_set_resource(struct device *dev, struct resource *resource) */ /* Get the limit (rounded up) */ - limit = base + ((resource->size + gran - 1UL) & ~(gran - 1UL)) -1UL; + limit = base + round(resource->size, gran) - 1UL; /* Now store the resource */ resource->flags |= IORESOURCE_STORED; if (!(resource->flags & IORESOURCE_PCI_BRIDGE)) { - /* - * some chipsets allow us to set/clear the IO bit. - * (e.g. VIA 82c686a.) So set it to be safe) - */ + /* some chipsets allow us to set/clear the IO bit. + * (e.g. VIA 82c686a.) So set it to be safe) */ limit = base + resource->size -1; if (resource->flags & IORESOURCE_IO) { base |= PCI_BASE_ADDRESS_SPACE_IO; @@ -286,58 +300,50 @@ static void pci_set_resource(struct device *dev, struct resource *resource) /* FIXME handle real 64bit base addresses */ pci_write_config32(dev, resource->index + 4, 0); } - } - else if (resource->index == PCI_IO_BASE) { + } else if (resource->index == PCI_IO_BASE) { /* set the IO ranges * WARNING: we don't really do 32-bit addressing for IO yet! */ compute_allocate_resource(&dev->link[0], resource, - IORESOURCE_IO, IORESOURCE_IO); + IORESOURCE_IO, IORESOURCE_IO); pci_write_config8(dev, PCI_IO_BASE, base >> 8); pci_write_config8(dev, PCI_IO_LIMIT, limit >> 8); pci_write_config16(dev, PCI_IO_BASE_UPPER16, 0); pci_write_config16(dev, PCI_IO_LIMIT_UPPER16, 0); - } - else if (resource->index == PCI_MEMORY_BASE) { - /* set the memory range - */ + } else if (resource->index == PCI_MEMORY_BASE) { + /* set the memory range */ compute_allocate_resource(&dev->link[0], resource, - IORESOURCE_MEM | IORESOURCE_PREFETCH, - IORESOURCE_MEM); + IORESOURCE_MEM | IORESOURCE_PREFETCH, + IORESOURCE_MEM); pci_write_config16(dev, PCI_MEMORY_BASE, base >> 16); pci_write_config16(dev, PCI_MEMORY_LIMIT, limit >> 16); - } - else if (resource->index == PCI_PREF_MEMORY_BASE) { + } else if (resource->index == PCI_PREF_MEMORY_BASE) { /* set the prefetchable memory range - * WARNING: we don't really do 64-bit addressing for prefetchable memory yet! - */ + * WARNING: we don't really do 64-bit addressing for + * prefetchable memory yet! */ compute_allocate_resource(&dev->link[0], resource, - IORESOURCE_MEM | IORESOURCE_PREFETCH, - IORESOURCE_MEM | IORESOURCE_PREFETCH); + IORESOURCE_MEM | IORESOURCE_PREFETCH, + IORESOURCE_MEM | IORESOURCE_PREFETCH); pci_write_config16(dev, PCI_PREF_MEMORY_BASE, base >> 16); pci_write_config16(dev, PCI_PREF_MEMORY_LIMIT, limit >> 16); pci_write_config32(dev, PCI_PREF_BASE_UPPER32, 0); pci_write_config32(dev, PCI_PREF_LIMIT_UPPER32, 0); - } - else { + } else { /* Don't let me think I stored the resource */ resource->flags &= ~IORESOURCE_STORED; printk_err("ERROR: invalid resource->index %x\n", - resource->index); + resource->index); } + buf[0] = '\0'; if (resource->flags & IORESOURCE_PCI_BRIDGE) { sprintf(buf, "bus %d ", dev->link[0].secondary); } - - printk_debug( - "%s %02x <- [0x%08lx - 0x%08lx] %s%s\n", - dev_path(dev), - resource->index, - resource->base, limit, - buf, - (resource->flags & IORESOURCE_IO)? "io": - (resource->flags & IORESOURCE_PREFETCH)? "prefmem": "mem"); + printk_debug("%s %02x <- [0x%08lx - 0x%08lx] %s%s\n", + dev_path(dev), resource->index, resource->base, + limit, buf, + (resource->flags & IORESOURCE_IO)? "io": + (resource->flags & IORESOURCE_PREFETCH)? "prefmem": "mem"); return; } @@ -348,11 +354,11 @@ void pci_dev_set_resources(struct device *dev) uint8_t line; last = &dev->resource[dev->resources]; - - for(resource = &dev->resource[0]; resource < last; resource++) { + for (resource = &dev->resource[0]; resource < last; resource++) { pci_set_resource(dev, resource); } - for(link = 0; link < dev->links; link++) { + + for (link = 0; link < dev->links; link++) { struct bus *bus; bus = &dev->link[link]; if (bus->children) { @@ -401,43 +407,55 @@ void pci_bus_enable_resources(struct device *dev) pci_dev_enable_resources(dev); } +/** Default device operation for PCI devices */ struct device_operations default_pci_ops_dev = { .read_resources = pci_dev_read_resources, .set_resources = pci_dev_set_resources, .enable_resources = pci_dev_enable_resources, - .init = 0, - .scan_bus = 0, + .init = 0, + .scan_bus = 0, }; + +/** Default device operations for PCI bridges */ struct device_operations default_pci_ops_bus = { .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, + .init = 0, + .scan_bus = pci_scan_bridge, }; + +/** + * @brief Set up PCI device operation + * + * + * @param dev + * + * @see pci_drivers + */ static void set_pci_ops(struct device *dev) { struct pci_driver *driver; + if (dev->ops) { return; } + /* Look through the list of setup drivers and find one for - * this pci device - */ - for(driver = &pci_drivers[0]; driver != &epci_drivers[0]; driver++) { + * this pci device */ + for (driver = &pci_drivers[0]; driver != &epci_drivers[0]; driver++) { if ((driver->vendor == dev->vendor) && - (driver->device == dev->device)) { + (driver->device == dev->device)) { dev->ops = driver->ops; -#if 1 - printk_debug("%s [%04x/%04x] %sops\n", - dev_path(dev), - driver->vendor, driver->device, - (driver->ops->scan_bus?"bus ":"") - ); -#endif + + printk_debug("%s [%04x/%04x] %sops\n", dev_path(dev), + driver->vendor, driver->device, + (driver->ops->scan_bus?"bus ":"")); + return; } } + /* If I don't have a specific driver use the default operations */ switch(dev->hdr_type & 0x7f) { /* header type */ case PCI_HEADER_TYPE_NORMAL: /* standard header */ @@ -454,27 +472,35 @@ static void set_pci_ops(struct device *dev) bad: if (dev->enable) { printk_err("%s [%04x/%04x/%06x] has unknown header " - "type %02x, ignoring.\n", - dev_path(dev), - dev->vendor, dev->device, - dev->class >> 8, dev->hdr_type); + "type %02x, ignoring.\n", + dev_path(dev), + dev->vendor, dev->device, + dev->class >> 8, dev->hdr_type); } } return; } /** - * Given a bus and a devfn number, find the device structure - * @param bus The bus structure + * @brief Find a specific device structure on a list of device structures + * + * Given a linked list of PCI device structures and a devfn number, find the + * device structure correspond to the devfn. + * + * @param list the device structure list * @param devfn a device/function number - * @return pointer to the device structure + * + * @return pointer to the device structure found */ -static struct device *pci_scan_get_dev(struct device **list, unsigned int devfn) +static struct device *pci_scan_get_dev(struct device **list, + unsigned int devfn) { struct device *dev = 0; - for(; *list; list = &(*list)->sibling) { + + for (; *list; list = &(*list)->sibling) { if ((*list)->path.type != DEVICE_PATH_PCI) { - printk_err("child %s not a pci device\n", dev_path(*list)); + printk_err("child %s not a pci device\n", + dev_path(*list)); continue; } if ((*list)->path.u.pci.devfn == devfn) { @@ -485,10 +511,13 @@ static struct device *pci_scan_get_dev(struct device **list, unsigned int devfn) break; } } + + /* FIXME: why are we doing this ? Isn't there some order between the + * structures before ? */ if (dev) { device_t child; /* Find the last child of our parent */ - for(child = dev->bus->children; child && child->sibling; ) { + for (child = dev->bus->children; child && child->sibling; ) { child = child->sibling; } /* Place the device on the list of children of it's parent. */ @@ -502,16 +531,24 @@ static struct device *pci_scan_get_dev(struct device **list, unsigned int devfn) return dev; } -/** Scan the pci bus devices and bridges. +/** + * @brief Scan a PCI bus + * + * Determine the existence of devices and bridges on a PCI bus. If there are + * bridges on the bus, recursively scan the buses behind the bridges. + * + * This function is the default scan_bus() method for the root device + * 'dev_root'. + * * @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 bus *bus, - unsigned min_devfn, unsigned max_devfn, - unsigned int max) +unsigned int pci_scan_bus(struct bus *bus, unsigned min_devfn, + unsigned max_devfn, unsigned int max) { unsigned int devfn; device_t dev; @@ -524,42 +561,50 @@ unsigned int pci_scan_bus(struct bus *bus, bus->children = 0; post_code(0x24); - - /* probe all devices on this bus with some optimization for non-existance and - single funcion devices */ + /* probe all devices on this bus with some optimization for + * non-existence and single funcion devices */ for (devfn = min_devfn; devfn <= max_devfn; devfn++) { uint32_t id, class; uint8_t hdr_type; - /* First thing setup the device structure */ + /* device structures for PCI devices associated with static + * devices are already created during the static device + * enumeration, find out if it is the case for this devfn */ dev = pci_scan_get_dev(&old_devices, devfn); - - /* Detect if a device is present */ + if (!dev) { + /* it's not associated with a static device, detect if + * this device is present */ 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 ((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 */ + /* 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 */ + /* this function in a multi function device is + * not present, skip to next function */ continue; } dev = alloc_dev(bus, &dummy.path); - } - else { - /* Run the magic enable sequence for the device */ - if (dev->chip && dev->chip->control && dev->chip->control->enable_dev) { + } else { + /* Run the magic enable/disable sequence for the + * device */ + /* FIXME: What happen if this PCI device listed as + * static device but does not exist ? This calls + * some arbitray code without any justification */ + if (dev->chip && dev->chip->control && + dev->chip->control->enable_dev) { int enable = dev->enable; dev->enable = 1; dev->chip->control->enable_dev(dev); @@ -580,14 +625,15 @@ unsigned int pci_scan_bus(struct bus *bus, 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. Unless we already have some pci ops. + * header type and class and figure out which set of + * configuration methods to use. Unless we already + * have some pci ops. */ 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)); + dev_path(dev)); continue; } @@ -600,24 +646,28 @@ unsigned int pci_scan_bus(struct bus *bus, } printk_debug("%s [%04x/%04x] %s\n", - dev_path(dev), - dev->vendor, dev->device, - dev->enable?"enabled": "disabled"); + dev_path(dev), + dev->vendor, dev->device, + dev->enable?"enabled": "disabled"); 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. */ + /* if this is not a multi function device, don't + * waste time probe another function. + * Skip to next device. */ devfn += 0x07; } } post_code(0x25); - for(child = bus->children; child; child = child->sibling) { + /* if the child provides scan_bus(), for example a bridge, scan the + * bus behind that child */ + for (child = bus->children; child; child = child->sibling) { 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 * the other side of any bridges that may be on this bus plus @@ -630,8 +680,17 @@ unsigned int pci_scan_bus(struct bus *bus, return max; } -/** Scan the bus, first for bridges and next for devices. - * @param pci_bus pointer to the bus structure +/** + * @brief Scan a PCI bridge and the buses behind the bridge. + * + * Determine the existence of buses behind the bridge. Set up the bridge + * according to the result of the scan. + * + * This function is the default scan_bus() method for PCI bridge devices. + * + * @param dev pointer to the bridge device + * @param max the highest bus number assgined up to now + * * @return The maximum bus number found, after scanning all subordinate busses */ unsigned int pci_scan_bridge(struct device *dev, unsigned int max) @@ -645,47 +704,44 @@ unsigned int pci_scan_bridge(struct device *dev, unsigned int max) /* 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 - */ + * subordinate bus number to 0xff for the moment. */ bus->secondary = ++max; bus->subordinate = 0xff; - + /* Clear all status bits and turn off memory, I/O and master enables. */ 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. - */ + /* Read the existing primary/secondary/subordinate bus + * number configuration. */ 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 - */ + * correctly configured */ buses &= 0xff000000; buses |= (((unsigned int) (dev->bus->secondary) << 0) | - ((unsigned int) (bus->secondary) << 8) | - ((unsigned int) (bus->subordinate) << 16)); + ((unsigned int) (bus->secondary) << 8) | + ((unsigned int) (bus->subordinate) << 16)); pci_write_config32(dev, PCI_PRIMARY_BUS, buses); - /* Now we can scan all subordinate buses i.e. the bus hehind the bridge */ + /* Now we can scan all subordinate buses i.e. the buses behind the + * bridge */ 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 - */ + * bus number to its real value */ bus->subordinate = max; buses = (buses & 0xff00ffff) | ((unsigned int) (bus->subordinate) << 16); pci_write_config32(dev, PCI_PRIMARY_BUS, buses); pci_write_config16(dev, PCI_COMMAND, cr); - + printk_spew("%s returns max %d\n", __FUNCTION__, max); return max; } + /* Tell the EISA int controller this int must be level triggered THIS IS A KLUDGE -- sorry, this needs to get cleaned up. diff --git a/src/devices/root_device.c b/src/devices/root_device.c index 4a076a1bb3..0bf5ea60a8 100644 --- a/src/devices/root_device.c +++ b/src/devices/root_device.c @@ -21,9 +21,9 @@ void root_dev_read_resources(device_t root) root->resource[res].flags = IORESOURCE_IO; root->resource[res].index = 0; printk_spew("%s . link %p, resource %p\n", __FUNCTION__, - &root->link[0], &root->resource[res]); + &root->link[0], &root->resource[res]); compute_allocate_resource(&root->link[0], &root->resource[res], - IORESOURCE_IO, IORESOURCE_IO); + IORESOURCE_IO, IORESOURCE_IO); res++; /* Initialize the system wide memory resources constraints */ @@ -35,9 +35,9 @@ void root_dev_read_resources(device_t root) root->resource[res].flags = IORESOURCE_MEM; root->resource[res].index = 1; printk_spew("%s . link %p, resource %p\n", __FUNCTION__, - &root->link[0], &root->resource[res]); + &root->link[0], &root->resource[res]); compute_allocate_resource(&root->link[0], &root->resource[res], - IORESOURCE_MEM, IORESOURCE_MEM); + IORESOURCE_MEM, IORESOURCE_MEM); res++; root->resources = res; @@ -51,12 +51,12 @@ void root_dev_read_resources(device_t root) */ 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); + struct 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); } @@ -71,18 +71,18 @@ 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) { + + 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"); + 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) { + 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)); @@ -95,9 +95,9 @@ unsigned int walk_static_devices(device_t bus, unsigned int max) void enable_childrens_resources(device_t dev) { unsigned link; - for(link = 0; link < dev->links; link++) { + for (link = 0; link < dev->links; link++) { device_t child; - for(child = dev->link[link].children; child; child = child->sibling) { + for (child = dev->link[link].children; child; child = child->sibling) { enable_resources(child); } } |