diff options
Diffstat (limited to 'src/devices/pci_device.c')
-rw-r--r-- | src/devices/pci_device.c | 566 |
1 files changed, 371 insertions, 195 deletions
diff --git a/src/devices/pci_device.c b/src/devices/pci_device.c index 3f9a1cadae..f3f53f0688 100644 --- a/src/devices/pci_device.c +++ b/src/devices/pci_device.c @@ -21,8 +21,23 @@ #include <part/hard_reset.h> #include <part/fallback_boot.h> #include <delay.h> +#if CONFIG_HYPERTRANSPORT_PLUGIN_SUPPORT == 1 +#include <device/hypertransport.h> +#endif +#if CONFIG_PCIX_PLUGIN_SUPPORT == 1 +#include <device/pcix.h> +#endif +#if CONFIG_PCIEXP_PLUGIN_SUPPORT == 1 +#include <device/pciexp.h> +#endif +#if CONFGI_AGP_PLUGIN_SUPPORT == 1 +#include <device/agp.h> +#endif +#if CONFIG_CARDBUS_PLUGIN_SUPPORT == 1 +#include <device/cardbus.h> +#endif -static uint8_t pci_moving_config8(struct device *dev, unsigned reg) +uint8_t pci_moving_config8(struct device *dev, unsigned reg) { uint8_t value, ones, zeroes; value = pci_read_config8(dev, reg); @@ -38,7 +53,7 @@ static uint8_t pci_moving_config8(struct device *dev, unsigned reg) return ones ^ zeroes; } -static uint16_t pci_moving_config16(struct device *dev, unsigned reg) +uint16_t pci_moving_config16(struct device *dev, unsigned reg) { uint16_t value, ones, zeroes; value = pci_read_config16(dev, reg); @@ -54,7 +69,7 @@ static uint16_t pci_moving_config16(struct device *dev, unsigned reg) return ones ^ zeroes; } -static uint32_t pci_moving_config32(struct device *dev, unsigned reg) +uint32_t pci_moving_config32(struct device *dev, unsigned reg) { uint32_t value, ones, zeroes; value = pci_read_config32(dev, reg); @@ -70,29 +85,53 @@ static uint32_t pci_moving_config32(struct device *dev, unsigned reg) return ones ^ zeroes; } -unsigned pci_find_capability(device_t dev, unsigned cap) +unsigned pci_find_next_capability(device_t dev, unsigned cap, unsigned last) { unsigned pos; + unsigned status; + unsigned reps = 48; pos = 0; + status = pci_read_config16(dev, PCI_STATUS); + if (!(status & PCI_STATUS_CAP_LIST)) { + return 0; + } switch(dev->hdr_type & 0x7f) { case PCI_HEADER_TYPE_NORMAL: case PCI_HEADER_TYPE_BRIDGE: pos = PCI_CAPABILITY_LIST; break; + case PCI_HEADER_TYPE_CARDBUS: + pos = PCI_CB_CAPABILITY_LIST; + break; + default: + return 0; } - if (pos > PCI_CAP_LIST_NEXT) { - pos = pci_read_config8(dev, pos); - } - while (pos != 0) { /* loop through the linked list */ + pos = pci_read_config8(dev, pos); + while(reps-- && (pos >= 0x40)) { /* loop through the linked list */ int this_cap; + pos &= ~3; this_cap = pci_read_config8(dev, pos + PCI_CAP_LIST_ID); - if (this_cap == cap) { + printk_spew("Capability: 0x%02x @ 0x%02x\n", cap, pos); + if (this_cap == 0xff) { + break; + } + if (!last && (this_cap == cap)) { return pos; } + if (last == pos) { + last = 0; + } + pos = pci_read_config8(dev, pos + PCI_CAP_LIST_NEXT); } return 0; } +unsigned pci_find_capability(device_t dev, unsigned cap) +{ + return pci_find_next_capability(dev, cap, 0); + +} + /** Given a device and register, read the size of the BAR for that register. * @param dev Pointer to the device structure * @param resource Pointer to the resource structure @@ -118,7 +157,7 @@ struct resource *pci_get_resource(struct device *dev, unsigned long index) /* If it is a 64bit resource look at the high half as well */ if (((attr & PCI_BASE_ADDRESS_SPACE_IO) == 0) && - ((attr & PCI_BASE_ADDRESS_MEM_LIMIT_MASK) == PCI_BASE_ADDRESS_MEM_LIMIT_64)) + ((attr & PCI_BASE_ADDRESS_MEM_LIMIT_MASK) == PCI_BASE_ADDRESS_MEM_LIMIT_64)) { /* Find the high bits that move */ moving |= ((resource_t)pci_moving_config32(dev, index + 4)) << 32; @@ -134,7 +173,7 @@ struct resource *pci_get_resource(struct device *dev, unsigned long index) if (moving) { resource->size = 1; resource->align = resource->gran = 0; - while (!(moving & resource->size)) { + while(!(moving & resource->size)) { resource->size <<= 1; resource->align += 1; resource->gran += 1; @@ -154,17 +193,20 @@ struct resource *pci_get_resource(struct device *dev, unsigned long index) */ if (moving == 0) { if (value != 0) { - printk_debug("%s register %02x(%08x), read-only ignoring it\n", - dev_path(dev), index, value); + printk_debug( + "%s register %02x(%08x), read-only ignoring it\n", + dev_path(dev), index, value); } resource->flags = 0; - } else if (attr & PCI_BASE_ADDRESS_SPACE_IO) { + } + else if (attr & PCI_BASE_ADDRESS_SPACE_IO) { /* An I/O mapped base address */ attr &= PCI_BASE_ADDRESS_IO_ATTR_MASK; resource->flags |= IORESOURCE_IO; /* I don't want to deal with 32bit I/O resources */ resource->limit = 0xffff; - } else { + } + else { /* A Memory mapped base address */ attr &= PCI_BASE_ADDRESS_MEM_ATTR_MASK; resource->flags |= IORESOURCE_MEM; @@ -175,14 +217,17 @@ struct resource *pci_get_resource(struct device *dev, unsigned long index) if (attr == PCI_BASE_ADDRESS_MEM_LIMIT_32) { /* 32bit limit */ resource->limit = 0xffffffffUL; - } else if (attr == PCI_BASE_ADDRESS_MEM_LIMIT_1M) { + } + else if (attr == PCI_BASE_ADDRESS_MEM_LIMIT_1M) { /* 1MB limit */ resource->limit = 0x000fffffUL; - } else if (attr == PCI_BASE_ADDRESS_MEM_LIMIT_64) { + } + else if (attr == PCI_BASE_ADDRESS_MEM_LIMIT_64) { /* 64bit limit */ resource->limit = 0xffffffffffffffffULL; resource->flags |= IORESOURCE_PCI64; - } else { + } + else { /* Invalid value */ resource->flags = 0; } @@ -194,18 +239,15 @@ struct resource *pci_get_resource(struct device *dev, unsigned long index) #if 0 if (resource->flags) { printk_debug("%s %02x ->", - dev_path(dev), resource->index); + dev_path(dev), resource->index); printk_debug(" value: 0x%08Lx zeroes: 0x%08Lx ones: 0x%08Lx attr: %08lx\n", - value, zeroes, ones, attr); + value, zeroes, ones, attr); printk_debug( - "%s %02x -> size: 0x%08Lx max: 0x%08Lx %s%s\n ", + "%s %02x -> size: 0x%08Lx max: 0x%08Lx %s\n ", dev_path(dev), resource->index, resource->size, resource->limit, - (resource->flags == 0) ? "unused": - (resource->flags & IORESOURCE_IO)? "io": - (resource->flags & IORESOURCE_PREFETCH)? "prefmem": "mem", - (resource->flags & IORESOURCE_PCI64)?"64":""); + resource_type(resource)); } #endif @@ -272,32 +314,32 @@ static void pci_get_rom_resource(struct device *dev, unsigned long index) resource->flags |= IORESOURCE_MEM | IORESOURCE_READONLY | IORESOURCE_ASSIGNED | IORESOURCE_FIXED; } + + compact_resources(dev); } /** Read the base address registers for a given device. * @param dev Pointer to the dev structure * @param howmany How many registers to read (6 for device, 2 for bridge) */ -static void pci_read_bases(struct device *dev, unsigned int howmany, unsigned long rom) +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; } - if (rom) - pci_get_rom_resource(dev, rom); compact_resources(dev); } static void pci_set_resource(struct device *dev, struct resource *resource); -static void pci_record_bridge_resource( struct device *dev, resource_t moving, - unsigned index, unsigned long mask, - unsigned long type) +static void pci_record_bridge_resource( + struct device *dev, resource_t moving, + unsigned index, unsigned long mask, unsigned long type) { /* Initiliaze the constraints on the current bus */ struct resource *resource; @@ -346,8 +388,10 @@ static void pci_bridge_read_bases(struct device *dev) moving = moving_base & moving_limit; /* Initialize the io space constraints on the current bus */ - pci_record_bridge_resource(dev, moving, PCI_IO_BASE, - IORESOURCE_IO, IORESOURCE_IO); + pci_record_bridge_resource( + dev, moving, PCI_IO_BASE, + IORESOURCE_IO, IORESOURCE_IO); + /* See if the bridge prefmem resources are implemented */ moving_base = ((resource_t)pci_moving_config16(dev, PCI_PREF_MEMORY_BASE)) << 16; @@ -358,9 +402,11 @@ static void pci_bridge_read_bases(struct device *dev) moving = moving_base & moving_limit; /* Initiliaze the prefetchable memory constraints on the current bus */ - pci_record_bridge_resource(dev, moving, PCI_PREF_MEMORY_BASE, - IORESOURCE_MEM | IORESOURCE_PREFETCH, - IORESOURCE_MEM | IORESOURCE_PREFETCH); + pci_record_bridge_resource( + dev, moving, PCI_PREF_MEMORY_BASE, + IORESOURCE_MEM | IORESOURCE_PREFETCH, + IORESOURCE_MEM | IORESOURCE_PREFETCH); + /* See if the bridge mem resources are implemented */ moving_base = ((uint32_t)pci_moving_config16(dev, PCI_MEMORY_BASE)) << 16; @@ -369,26 +415,25 @@ static void pci_bridge_read_bases(struct device *dev) moving = moving_base & moving_limit; /* Initialize the memory resources on the current bus */ - pci_record_bridge_resource(dev, moving, PCI_MEMORY_BASE, - IORESOURCE_MEM | IORESOURCE_PREFETCH, - IORESOURCE_MEM); + pci_record_bridge_resource( + dev, moving, PCI_MEMORY_BASE, + 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, PCI_ROM_ADDRESS); + pci_read_bases(dev, 6); + pci_get_rom_resource(dev, PCI_ROM_ADDRESS); } void pci_bus_read_resources(struct device *dev) { - uint32_t addr; - pci_bridge_read_bases(dev); - pci_read_bases(dev, 2, PCI_ROM_ADDRESS1); + pci_read_bases(dev, 2); + pci_get_rom_resource(dev, PCI_ROM_ADDRESS1); } static void pci_set_resource(struct device *dev, struct resource *resource) @@ -397,8 +442,10 @@ static void pci_set_resource(struct device *dev, struct resource *resource) /* Make certain the resource has actually been set */ if (!(resource->flags & IORESOURCE_ASSIGNED)) { - printk_err("ERROR: %s %02x not allocated\n", - dev_path(dev), resource->index); + printk_err("ERROR: %s %02x %s size: 0x%010Lx not assigned\n", + dev_path(dev), resource->index, + resource_type(resource), + resource->size); return; } @@ -497,10 +544,10 @@ void pci_dev_set_resources(struct device *dev) 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) { @@ -551,14 +598,10 @@ void pci_dev_enable_resources(struct device *dev) void pci_bus_enable_resources(struct device *dev) { uint16_t ctrl; - -#if CONFIG_CONSOLE_VGA == 1 /* enable IO in command register if there is VGA card * connected with (even it does not claim IO resource) */ if (dev->link[0].bridge_ctrl & PCI_BRIDGE_CTL_VGA) dev->command |= PCI_COMMAND_IO; -#endif - ctrl = pci_read_config16(dev, PCI_BRIDGE_CONTROL); ctrl |= dev->link[0].bridge_ctrl; ctrl |= (PCI_BRIDGE_CTL_PARITY + PCI_BRIDGE_CTL_SERR); /* error check */ @@ -570,15 +613,27 @@ void pci_bus_enable_resources(struct device *dev) enable_childrens_resources(dev); } +void pci_bus_reset(struct bus *bus) +{ + unsigned ctl; + ctl = pci_read_config16(bus->dev, PCI_BRIDGE_CONTROL); + ctl |= PCI_BRIDGE_CTL_BUS_RESET; + pci_write_config16(bus->dev, PCI_BRIDGE_CONTROL, ctl); + mdelay(10); + ctl &= ~PCI_BRIDGE_CTL_BUS_RESET; + pci_write_config16(bus->dev, PCI_BRIDGE_CONTROL, ctl); + delay(1); +} + void pci_dev_set_subsystem(device_t dev, unsigned vendor, unsigned device) { pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, ((device & 0xffff) << 16) | (vendor & 0xffff)); } -#if CONFIG_PCI_ROM_RUN == 1 void pci_dev_init(struct device *dev) { +#if CONFIG_PCI_ROM_RUN == 1 struct rom_header *rom, *ram; rom = pci_rom_probe(dev); @@ -589,8 +644,8 @@ void pci_dev_init(struct device *dev) return; run_bios(dev, ram); -} #endif +} /** Default device operation for PCI devices */ static struct pci_operations pci_dev_ops_pci = { @@ -601,11 +656,7 @@ 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, -#if CONFIG_PCI_ROM_RUN == 1 .init = pci_dev_init, -#else - .init = 0, -#endif .scan_bus = 0, .enable = 0, .ops_pci = &pci_dev_ops_pci, @@ -623,10 +674,79 @@ struct device_operations default_pci_ops_bus = { .init = 0, .scan_bus = pci_scan_bridge, .enable = 0, + .reset_bus = pci_bus_reset, .ops_pci = &pci_bus_ops_pci, }; /** + * @brief Detect the type of downstream bridge + * + * This function is a heuristic to detect which type + * of bus is downstream of a pci to pci bridge. This + * functions by looking for various capability blocks + * to figure out the type of downstream bridge. PCI-X + * PCI-E, and Hypertransport all seem to have appropriate + * capabilities. + * + * When only a PCI-Express capability is found the type + * is examined to see which type of bridge we have. + * + * @param dev + * + * @return appropriate bridge operations + */ +static struct device_operations *get_pci_bridge_ops(device_t dev) +{ + unsigned pos; + +#if CONFIG_PCIX_PLUGIN_SUPPORT == 1 + pos = pci_find_capability(dev, PCI_CAP_ID_PCIX); + if (pos) { + printk_debug("%s subbordinate bus PCI-X\n", dev_path(dev)); + return &default_pcix_ops_bus; + } +#endif +#if CONFIG_AGP_PLUGIN_SUPPORT == 1 + /* How do I detect an PCI to AGP bridge? */ +#endif +#if CONFIG_HYPERTRANSPORT_PLUGIN_SUPPORT == 1 + pos = 0; + while((pos = pci_find_next_capability(dev, PCI_CAP_ID_HT, pos))) { + unsigned flags; + flags = pci_read_config16(dev, pos + PCI_CAP_FLAGS); + if ((flags >> 13) == 1) { + /* Host or Secondary Interface */ + printk_debug("%s subbordinate bus Hypertransport\n", + dev_path(dev)); + return &default_ht_ops_bus; + } + } +#endif +#if CONFIG_PCIEXP_PLUGIN_SUPPORT == 1 + pos = pci_find_capability(dev, PCI_CAP_ID_PCIE); + if (pos) { + unsigned flags; + flags = pci_read_config16(dev, pos + PCI_EXP_FLAGS); + switch((flags & PCI_EXP_FLAGS_TYPE) >> 4) { + case PCI_EXP_TYPE_ROOT_PORT: + case PCI_EXP_TYPE_UPSTREAM: + case PCI_EXP_TYPE_DOWNSTREAM: + printk_debug("%s subbordinate bus PCI Express\n", + dev_path(dev)); + return &default_pciexp_ops_bus; + case PCI_EXP_TYPE_PCI_BRIDGE: + printk_debug("%s subbordinate PCI\n", + dev_path(dev)); + return &default_pci_ops_bus; + default: + break; + } + } +#endif + return &default_pci_ops_bus; +} + +/** * @brief Set up PCI device operation * * @@ -644,12 +764,12 @@ static void set_pci_ops(struct device *dev) /* Look through the list of setup drivers and find one for * this pci device */ - for (driver = &pci_drivers[0]; driver != &epci_drivers[0]; driver++) { + 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; - printk_debug("%s [%04x/%04x] %sops\n", + printk_spew("%s [%04x/%04x] %sops\n", dev_path(dev), driver->vendor, driver->device, (driver->ops->scan_bus?"bus ":"")); @@ -667,8 +787,13 @@ static void set_pci_ops(struct device *dev) case PCI_HEADER_TYPE_BRIDGE: if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI) goto bad; - dev->ops = &default_pci_ops_bus; + dev->ops = get_pci_bridge_ops(dev); break; +#if CONFIG_CARDBUS_PLUGIN_SUPPORT == 1 + case PCI_HEADER_TYPE_CARDBUS: + dev->ops = &default_cardbus_ops_bus; + break; +#endif default: bad: if (dev->enabled) { @@ -682,6 +807,8 @@ static void set_pci_ops(struct device *dev) return; } + + /** * @brief See if we have already allocated a device structure for a given devfn. * @@ -702,7 +829,7 @@ static struct device *pci_scan_get_dev(struct device **list, unsigned int devfn) for(; *list; list = &(*list)->sibling) { if ((*list)->path.type != DEVICE_PATH_PCI) { printk_err("child %s not a pci device\n", - dev_path(*list)); + dev_path(*list)); continue; } if ((*list)->path.u.pci.devfn == devfn) { @@ -713,15 +840,15 @@ static struct device *pci_scan_get_dev(struct device **list, unsigned int devfn) break; } } - /* Just like alloc_dev add the device to the list of device on the bus. - * When the list of devices was formed we removed all of the parents - * children, and now we are interleaving static and dynamic devices in + /* Just like alloc_dev add the device to the list of device on the bus. + * When the list of devices was formed we removed all of the parents + * children, and now we are interleaving static and dynamic devices in * order on the bus. */ 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. */ @@ -738,9 +865,128 @@ static struct device *pci_scan_get_dev(struct device **list, unsigned int devfn) /** * @brief Scan a PCI bus. * + * Determine the existence of a given PCI device. + * + * @param bus pointer to the bus structure + * @param devfn to look at + * + * @return The device structure for hte device (if found) + * or the NULL if no device is found. + */ +device_t pci_probe_dev(device_t dev, struct bus *bus, unsigned devfn) +{ + uint32_t id, class; + uint8_t hdr_type; + + /* Detect if a device is present */ + if (!dev) { + 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); + /* Have we found somthing? + * 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); + return NULL; + } + dev = alloc_dev(bus, &dummy.path); + } + else { + /* Enable/disable the device. Once we have + * found the device specific operations this + * operations we will disable the device with + * those as well. + * + * This is geared toward devices that have subfunctions + * that do not show up by default. + * + * If a device is a stuff option on the motherboard + * it may be absent and enable_dev must cope. + * + */ + /* Run the magice enable sequence for the device */ + if (dev->chip_ops && dev->chip_ops->enable_dev) { + dev->chip_ops->enable_dev(dev); + } + /* Now read the vendor and device id */ + id = pci_read_config32(dev, PCI_VENDOR_ID); + + + /* If the device does not have a pci id disable it. + * Possibly this is because we have already disabled + * the device. But this also handles optional devices + * that may not always show up. + */ + /* If the chain is fully enumerated quit */ + if ( (id == 0xffffffff) || (id == 0x00000000) || + (id == 0x0000ffff) || (id == 0xffff0000)) + { + if (dev->enabled) { + printk_info("Disabling static device: %s\n", + dev_path(dev)); + dev->enabled = 0; + } + return dev; + } + } + /* 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; + + + /* Architectural/System devices always need to + * be bus masters. + */ + if ((dev->class >> 16) == PCI_BASE_CLASS_SYSTEM) { + dev->command |= PCI_COMMAND_MASTER; + } + /* 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. + */ + set_pci_ops(dev); + + /* Now run the magic enable/disable sequence for the device */ + if (dev->ops && dev->ops->enable) { + dev->ops->enable(dev); + } + + + /* Display the device and error if we don't have some pci operations + * for it. + */ + printk_debug("%s [%04x/%04x] %s%s\n", + dev_path(dev), + dev->vendor, dev->device, + dev->enabled?"enabled": "disabled", + dev->ops?"" : " No operations" + ); + + return dev; +} + +/** + * @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 @@ -748,11 +994,11 @@ static struct device *pci_scan_get_dev(struct device **list, unsigned int devfn) * * @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; device_t old_devices; device_t child; @@ -762,141 +1008,49 @@ unsigned int pci_scan_bus(struct bus *bus, unsigned min_devfn, unsigned max_devf bus->children = 0; post_code(0x24); - /* probe all devices/functions 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; + device_t dev; /* First thing setup the device structure */ dev = pci_scan_get_dev(&old_devices, devfn); - - /* Detect if a device is present */ - if (!dev) { - 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; - } - /* This function in a multi function device is - * not present, skip to the next function. - */ - continue; - } - dev = alloc_dev(bus, &dummy.path); - } - else { - /* Enable/disable the device. Once we have - * found the device specific operations this - * operations we will disable the device with - * those as well. - * - * This is geared toward devices that have subfunctions - * that do not show up by default. - * - * If a device is a stuff option on the motherboard - * it may be absent and enable_dev must cope. - * - */ - if (dev->chip_ops && dev->chip_ops->enable_dev) - { - dev->chip_ops->enable_dev(dev); - } - /* Now read the vendor and device id */ - id = pci_read_config32(dev, PCI_VENDOR_ID); - - /* If the device does not have a pci id disable it. - * Possibly this is because we have already disabled - * the device. But this also handles optional devices - * that may not always show up. - */ - if (id == 0xffffffff || id == 0x00000000 || - id == 0x0000ffff || id == 0xffff0000) - { - if (dev->enabled) { - printk_info("Disabling static device: %s\n", - dev_path(dev)); - dev->enabled = 0; - } - continue; - } - } - /* 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; - - /* Architectural/System devices always need to - * be bus masters. - */ - if ((dev->class >> 16) == PCI_BASE_CLASS_SYSTEM) { - dev->command |= PCI_COMMAND_MASTER; - } - /* 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. + /* See if a device is present and setup the device + * structure. */ - 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; - } + dev = pci_probe_dev(dev, bus, devfn); - /* Now run the magic enable/disable sequence for the device */ - if (dev->ops && dev->ops->enable) { - dev->ops->enable(dev); - } - - printk_debug("%s [%04x/%04x] %s\n", - dev_path(dev), - dev->vendor, dev->device, - dev->enabled?"enabled": "disabled"); - - if (PCI_FUNC(devfn) == 0x00 && (hdr_type & 0x80) != 0x80) { - /* if this is not a multi function device, - * don't waste time probing another function. - * Skip to next device. - */ + /* if this is not a multi function device, + * or the device is not present don't waste + * time probing another function. + * Skip to next device. + */ + if ((PCI_FUNC(devfn) == 0x00) && + (!dev || (dev->enabled && ((dev->hdr_type & 0x80) != 0x80)))) + { devfn += 0x07; } } post_code(0x25); + /* Die if any leftover Static devices are are found. + * There's probably a problem in the Config.lb. + */ + if(old_devices) { + device_t left; + for(left = old_devices; left; left = left->sibling) { + printk_debug("%s\n", dev_path(left)); + } + die("Left over static devices. Check your Config.lb\n"); + } + /* For all children that implement scan_bus (i.e. bridges) * scan the bus behind that child. */ - for (child = bus->children; child; child = child->sibling) { - if (!child->enabled || - !child->ops || - !child->ops->scan_bus) - { - continue; - } - max = child->ops->scan_bus(child, max); + for(child = bus->children; child; child = child->sibling) { + max = scan_bus(child, max); } /* @@ -911,6 +1065,7 @@ unsigned int pci_scan_bus(struct bus *bus, unsigned min_devfn, unsigned max_devf return max; } + /** * @brief Scan a PCI bridge and the buses behind the bridge. * @@ -924,7 +1079,9 @@ unsigned int pci_scan_bus(struct bus *bus, unsigned min_devfn, unsigned max_devf * * @return The maximum bus number found, after scanning all subordinate busses */ -unsigned int pci_scan_bridge(struct device *dev, unsigned int max) +unsigned int do_pci_scan_bridge(struct device *dev, unsigned int max, + unsigned int (*do_scan_bus)(struct bus *bus, + unsigned min_devfn, unsigned max_devfn, unsigned int max)) { struct bus *bus; uint32_t buses; @@ -960,14 +1117,14 @@ unsigned int pci_scan_bridge(struct device *dev, unsigned int max) */ 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 behind the bridge. */ - max = pci_scan_bus(bus, 0x00, 0xff, max); + max = do_scan_bus(bus, 0x00, 0xff, max); /* We know the number of buses behind this bridge. Set the subordinate * bus number to its real value. @@ -977,11 +1134,29 @@ unsigned int pci_scan_bridge(struct device *dev, unsigned int max) ((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", __func__, max); return max; } +/** + * @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) +{ + return do_pci_scan_bridge(dev, max, pci_scan_bus); +} + /* Tell the EISA int controller this int must be level triggered THIS IS A KLUDGE -- sorry, this needs to get cleaned up. @@ -1026,7 +1201,8 @@ static void pci_level_irq(unsigned char intNum) -kevinh@ispiri.com */ -void pci_assign_irqs(unsigned bus, unsigned slot, const unsigned char pIntAtoD[4]) +void pci_assign_irqs(unsigned bus, unsigned slot, + const unsigned char pIntAtoD[4]) { unsigned functNum; device_t pdev; |