X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fdevices%2Fpci_device.c;h=f54e2620bf78c6e6564cf14523bb4a54d587881b;hb=35e912cef3aac245202694736281aa8475e977f1;hp=a4789d22f44b0f6a19413dddd976ecd4a3b07cfa;hpb=99dcf231f48433a07cbd47ecb0c23301a6b5b34e;p=coreboot.git diff --git a/src/devices/pci_device.c b/src/devices/pci_device.c index a4789d22f..f54e2620b 100644 --- a/src/devices/pci_device.c +++ b/src/devices/pci_device.c @@ -1,12 +1,26 @@ /* - * PCI Bus Services, see include/linux/pci.h for further explanation. + * This file is part of the coreboot project. * - * Copyright 1993 -- 1997 Drew Eckhardt, Frederic Potter, - * David Mosberger-Tang + * It was originally based on the Linux kernel (drivers/pci/pci.c). * - * Copyright 1997 -- 1999 Martin Mares - * - * Copyright 2003 -- Eric Biederman + * Modifications are: + * Copyright (C) 2003-2004 Linux Networx + * (Written by Eric Biederman for Linux Networx) + * Copyright (C) 2003-2006 Ronald G. Minnich + * Copyright (C) 2004-2005 Li-Ta Lo + * Copyright (C) 2005-2006 Tyan + * (Written by Yinghai Lu for Tyan) + * Copyright (C) 2005-2009 coresystems GmbH + * (Written by Stefan Reinauer for coresystems GmbH) + */ + +/* + * PCI Bus Services, see include/linux/pci.h for further explanation. + * + * Copyright 1993 -- 1997 Drew Eckhardt, Frederic Potter, + * David Mosberger-Tang + * + * Copyright 1997 -- 1999 Martin Mares */ #include @@ -14,435 +28,807 @@ #include #include #include +#include #include #include #include -#include -#include +#include +#if CONFIG_HYPERTRANSPORT_PLUGIN_SUPPORT == 1 +#include +#endif +#if CONFIG_PCIX_PLUGIN_SUPPORT == 1 +#include +#endif +#if CONFIG_PCIEXP_PLUGIN_SUPPORT == 1 +#include +#endif +#if CONFIG_AGP_PLUGIN_SUPPORT == 1 +#include +#endif +#if CONFIG_CARDBUS_PLUGIN_SUPPORT == 1 +#include +#endif +#if CONFIG_PC80_SYSTEM == 1 +#include +#endif +#if CONFIG_HAVE_ACPI_RESUME && !CONFIG_S3_VGA_ROM_RUN +#include +#endif +#if CONFIG_CHROMEOS +#include +#endif + +u8 pci_moving_config8(struct device *dev, unsigned int reg) +{ + u8 value, ones, zeroes; + + value = pci_read_config8(dev, reg); + + pci_write_config8(dev, reg, 0xff); + ones = pci_read_config8(dev, reg); + + pci_write_config8(dev, reg, 0x00); + zeroes = pci_read_config8(dev, reg); + + pci_write_config8(dev, reg, value); + + return ones ^ zeroes; +} + +u16 pci_moving_config16(struct device *dev, unsigned int reg) +{ + u16 value, ones, zeroes; + + value = pci_read_config16(dev, reg); -/** 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 - * @param index Address of the pci configuration register + pci_write_config16(dev, reg, 0xffff); + ones = pci_read_config16(dev, reg); + + pci_write_config16(dev, reg, 0x0000); + zeroes = pci_read_config16(dev, reg); + + pci_write_config16(dev, reg, value); + + return ones ^ zeroes; +} + +u32 pci_moving_config32(struct device *dev, unsigned int reg) +{ + u32 value, ones, zeroes; + + value = pci_read_config32(dev, reg); + + pci_write_config32(dev, reg, 0xffffffff); + ones = pci_read_config32(dev, reg); + + pci_write_config32(dev, reg, 0x00000000); + zeroes = pci_read_config32(dev, reg); + + pci_write_config32(dev, reg, value); + + return ones ^ zeroes; +} + +/** + * Given a device, a capability type, and a last position, return the next + * matching capability. Always start at the head of the list. + * + * @param dev Pointer to the device structure. + * @param cap PCI_CAP_LIST_ID of the PCI capability we're looking for. + * @param last Location of the PCI capability register to start from. + * @return The next matching capability. */ -static void pci_get_resource(struct device *dev, struct resource *resource, unsigned long index) +unsigned pci_find_next_capability(struct device *dev, unsigned cap, + unsigned last) { - uint32_t addr, size, base; - unsigned long type; + unsigned pos = 0; + u16 status; + unsigned reps = 48; - /* Initialize the resources to nothing */ - resource->base = 0; - resource->size = 0; - resource->align = 0; - resource->gran = 0; - resource->limit = 0; - resource->flags = 0; - resource->index = index; + 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; + } - addr = pci_read_config32(dev, index); + pos = pci_read_config8(dev, pos); + while (reps-- && (pos >= 0x40)) { /* Loop through the linked list. */ + int this_cap; - /* FIXME: more consideration for 64-bit PCI devices, - * we currently detect their size but otherwise - * treat them as 32-bit resources - */ - /* get the size */ - pci_write_config32(dev, index, ~0); - size = pci_read_config32(dev, index); + pos &= ~3; + this_cap = pci_read_config8(dev, pos + PCI_CAP_LIST_ID); + printk(BIOS_SPEW, "Capability: type 0x%02x @ 0x%02x\n", + this_cap, pos); + if (this_cap == 0xff) + break; - /* get the minimum value the bar can be set to */ - pci_write_config32(dev, index, 0); - base = pci_read_config32(dev, index); + if (!last && (this_cap == cap)) + return pos; - /* restore addr */ - pci_write_config32(dev, index, addr); + if (last == pos) + last = 0; + + pos = pci_read_config8(dev, pos + PCI_CAP_LIST_NEXT); + } + return 0; +} + +/** + * Given a device, and a capability type, return the next matching + * capability. Always start at the head of the list. + * + * @param dev Pointer to the device structure. + * @param cap PCI_CAP_LIST_ID of the PCI capability we're looking for. + * @return The next matching capability. + */ +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 index Address of the PCI configuration register. + * @return TODO + */ +struct resource *pci_get_resource(struct device *dev, unsigned long index) +{ + struct resource *resource; + unsigned long value, attr; + resource_t moving, limit; + + /* Initialize the resources to nothing. */ + resource = new_resource(dev, index); + + /* Get the initial value. */ + value = pci_read_config32(dev, index); + + /* See which bits move. */ + moving = pci_moving_config32(dev, index); + + /* Initialize attr to the bits that do not move. */ + attr = value & ~moving; + + /* 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)) { + /* Find the high bits that move. */ + moving |= + ((resource_t) pci_moving_config32(dev, index + 4)) << 32; + } + + /* Find the resource constraints. + * Start by finding the bits that move. From there: + * - Size is the least significant bit of the bits that move. + * - Limit is all of the bits that move plus all of the lower bits. + * See PCI Spec 6.2.5.1. + */ + limit = 0; + if (moving) { + resource->size = 1; + resource->align = resource->gran = 0; + while (!(moving & resource->size)) { + resource->size <<= 1; + resource->align += 1; + resource->gran += 1; + } + resource->limit = limit = moving | (resource->size - 1); + } /* - * some broken hardware has read-only registers that do not - * really size correctly. You can tell this if addr == size - * Example: the acer m7229 has BARs 1-4 normally read-only. + * Some broken hardware has read-only registers that do not + * really size correctly. + * + * Example: the Acer M7229 has BARs 1-4 normally read-only, * so BAR1 at offset 0x10 reads 0x1f1. If you size that register - * by writing 0xffffffff to it, it will read back as 0x1f1 -- a - * violation of the spec. - * We catch this case and ignore it by settting size and type to 0. - * This incidentally catches the common case where registers - * read back as 0 for both address and size. + * by writing 0xffffffff to it, it will read back as 0x1f1 -- which + * is a violation of the spec. + * + * We catch this case and ignore it by observing which bits move. + * + * This also catches the common case of unimplemented registers + * that always read back as 0. */ - if ((addr == size) && (addr == base)) { - if (size != 0) { - printk_debug( - "%s register %02x(%08x), read-only ignoring it\n", - dev_path(dev), - index, addr); + if (moving == 0) { + if (value != 0) { + printk(BIOS_DEBUG, "%s register %02lx(%08lx), " + "read-only ignoring it\n", + dev_path(dev), index, value); } resource->flags = 0; - } - /* Now compute the actual size, See PCI Spec 6.2.5.1 ... */ - else if (size & PCI_BASE_ADDRESS_SPACE_IO) { - type = size & (~PCI_BASE_ADDRESS_IO_MASK); - /* BUG! Top 16 bits can be zero (or not) - * So set them to 0xffff so they go away ... - */ - resource->size = (~((size | 0xffff0000) & PCI_BASE_ADDRESS_IO_MASK)) +1; - resource->align = log2(resource->size); - resource->gran = resource->align; - resource->flags = IORESOURCE_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 { - /* A Memory mapped base address */ - type = size & (~PCI_BASE_ADDRESS_MEM_MASK); - resource->size = (~(size &PCI_BASE_ADDRESS_MEM_MASK)) +1; - resource->align = log2(resource->size); - resource->gran = resource->align; - resource->flags = IORESOURCE_MEM; - if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) { + } else { + /* A Memory mapped base address. */ + attr &= PCI_BASE_ADDRESS_MEM_ATTR_MASK; + resource->flags |= IORESOURCE_MEM; + if (attr & PCI_BASE_ADDRESS_MEM_PREFETCH) resource->flags |= IORESOURCE_PREFETCH; - } - type &= PCI_BASE_ADDRESS_MEM_TYPE_MASK; - if (type == PCI_BASE_ADDRESS_MEM_TYPE_32) { - /* 32bit limit */ + attr &= PCI_BASE_ADDRESS_MEM_LIMIT_MASK; + if (attr == PCI_BASE_ADDRESS_MEM_LIMIT_32) { + /* 32bit limit. */ resource->limit = 0xffffffffUL; - } - else if (type == PCI_BASE_ADDRESS_MEM_TYPE_1M) { - /* 1MB limit */ + } else if (attr == PCI_BASE_ADDRESS_MEM_LIMIT_1M) { + /* 1MB limit. */ resource->limit = 0x000fffffUL; - } - else if (type == PCI_BASE_ADDRESS_MEM_TYPE_64) { - unsigned long index_hi; - /* 64bit limit - * For now just treat this as a 32bit limit - */ - index_hi = index + 4; - resource->limit = 0xffffffffUL; + } else if (attr == PCI_BASE_ADDRESS_MEM_LIMIT_64) { + /* 64bit limit. */ + resource->limit = 0xffffffffffffffffULL; resource->flags |= IORESOURCE_PCI64; - addr = pci_read_config32( dev, index_hi); - /* get the extended size */ - pci_write_config32(dev, index_hi, 0xffffffffUL); - size = pci_read_config32( dev, index_hi); - - /* get the minimum value the bar can be set to */ - pci_write_config32(dev, index_hi, 0); - base = pci_read_config32(dev, index_hi); - - /* restore addr */ - pci_write_config32(dev, index_hi, addr); - - if ((size == 0xffffffff) && (base == 0)) { - /* Clear the top half of the bar */ - pci_write_config32(dev, index_hi, 0); - } - else { - printk_err("%s Unable to handle 64-bit address\n", - dev_path(dev)); - resource->flags = IORESOURCE_PCI64; - } - } - else { - /* Invalid value */ + } else { + /* Invalid value. */ + printk(BIOS_ERR, "Broken BAR with value %lx\n", attr); + printk(BIOS_ERR, " on dev %s at index %02lx\n", + dev_path(dev), index); resource->flags = 0; } } - /* dev->size holds the flags... */ - return; + + /* Don't let the limit exceed which bits can move. */ + if (resource->limit > limit) + resource->limit = limit; + + return resource; } -/** 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) +/** + * Given a device and an index, read the size of the BAR for that register. + * + * @param dev Pointer to the device structure. + * @param index Address of the PCI configuration register. + */ +static void pci_get_rom_resource(struct device *dev, unsigned long index) +{ + struct resource *resource; + unsigned long value; + resource_t moving; + + /* Initialize the resources to nothing. */ + resource = new_resource(dev, index); + + /* Get the initial value. */ + value = pci_read_config32(dev, index); + + /* See which bits move. */ + moving = pci_moving_config32(dev, index); + + /* Clear the Enable bit. */ + moving = moving & ~PCI_ROM_ADDRESS_ENABLE; + + /* Find the resource constraints. + * Start by finding the bits that move. From there: + * - Size is the least significant bit of the bits that move. + * - Limit is all of the bits that move plus all of the lower bits. + * See PCI Spec 6.2.5.1. + */ + if (moving) { + resource->size = 1; + resource->align = resource->gran = 0; + while (!(moving & resource->size)) { + resource->size <<= 1; + resource->align += 1; + resource->gran += 1; + } + resource->limit = moving | (resource->size - 1); + resource->flags |= IORESOURCE_MEM | IORESOURCE_READONLY; + } else { + if (value != 0) { + printk(BIOS_DEBUG, "%s register %02lx(%08lx), " + "read-only ignoring it\n", + dev_path(dev), index, value); + } + resource->flags = 0; + } + 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 int reg; unsigned long index; - reg = dev->resources; - for(index = PCI_BASE_ADDRESS_0; - (reg < MAX_RESOURCES) && (index < PCI_BASE_ADDRESS_0 + (howmany << 2)); ) { + for (index = PCI_BASE_ADDRESS_0; + (index < PCI_BASE_ADDRESS_0 + (howmany << 2));) { struct resource *resource; - resource = &dev->resource[reg]; - pci_get_resource(dev, resource, index); - reg += (resource->flags & (IORESOURCE_IO | IORESOURCE_MEM))? 1:0; - index += (resource->flags & IORESOURCE_PCI64)?8:4; + resource = pci_get_resource(dev, index); + index += (resource->flags & IORESOURCE_PCI64) ? 8 : 4; } - dev->resources = reg; + + compact_resources(dev); } +static void pci_record_bridge_resource(struct device *dev, resource_t moving, + unsigned index, unsigned long type) +{ + struct resource *resource; + unsigned long gran; + resource_t step; + + resource = NULL; + + if (!moving) + return; + + /* Initialize the constraints on the current bus. */ + resource = new_resource(dev, index); + resource->size = 0; + gran = 0; + step = 1; + while ((moving & step) == 0) { + gran += 1; + step <<= 1; + } + resource->gran = gran; + resource->align = gran; + resource->limit = moving | (step - 1); + resource->flags = type | IORESOURCE_PCI_BRIDGE | + IORESOURCE_BRIDGE; +} static void pci_bridge_read_bases(struct device *dev) { - unsigned int reg = dev->resources; - - /* FIXME handle bridges without some of the optional resources */ - - printk_spew("%s: path %s\n", __FUNCTION__, dev_path(dev)); - /* Initialize the io space constraints on the current bus */ - dev->resource[reg].base = 0; - dev->resource[reg].size = 0; - dev->resource[reg].align = log2(PCI_IO_BRIDGE_ALIGN); - dev->resource[reg].gran = log2(PCI_IO_BRIDGE_ALIGN); - 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->link[0], &dev->resource[reg], - IORESOURCE_IO, IORESOURCE_IO); - reg++; - - /* Initiliaze the prefetchable memory constraints on the current bus */ - dev->resource[reg].base = 0; - dev->resource[reg].size = 0; - dev->resource[reg].align = log2(PCI_MEM_BRIDGE_ALIGN); - dev->resource[reg].gran = log2(PCI_MEM_BRIDGE_ALIGN); - 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->link[0], &dev->resource[reg], - IORESOURCE_MEM | IORESOURCE_PREFETCH, - IORESOURCE_MEM | IORESOURCE_PREFETCH); - reg++; - - /* Initialize the memory resources on the current bus */ - dev->resource[reg].base = 0; - dev->resource[reg].size = 0; - dev->resource[reg].align = log2(PCI_MEM_BRIDGE_ALIGN); - dev->resource[reg].gran = log2(PCI_MEM_BRIDGE_ALIGN); - 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->link[0], &dev->resource[reg], - IORESOURCE_MEM | IORESOURCE_PREFETCH, - IORESOURCE_MEM); - reg++; - - dev->resources = reg; - printk_spew("DONE %s: path %s\n", __FUNCTION__, dev_path(dev)); -} + resource_t moving_base, moving_limit, moving; + + /* See if the bridge I/O resources are implemented. */ + moving_base = ((u32) pci_moving_config8(dev, PCI_IO_BASE)) << 8; + moving_base |= + ((u32) pci_moving_config16(dev, PCI_IO_BASE_UPPER16)) << 16; + + moving_limit = ((u32) pci_moving_config8(dev, PCI_IO_LIMIT)) << 8; + moving_limit |= + ((u32) pci_moving_config16(dev, PCI_IO_LIMIT_UPPER16)) << 16; + + moving = moving_base & moving_limit; + + /* Initialize the I/O space constraints on the current bus. */ + pci_record_bridge_resource(dev, moving, PCI_IO_BASE, IORESOURCE_IO); + + /* See if the bridge prefmem resources are implemented. */ + moving_base = + ((resource_t) pci_moving_config16(dev, PCI_PREF_MEMORY_BASE)) << 16; + moving_base |= + ((resource_t) pci_moving_config32(dev, PCI_PREF_BASE_UPPER32)) << 32; + moving_limit = + ((resource_t) pci_moving_config16(dev, PCI_PREF_MEMORY_LIMIT)) << 16; + moving_limit |= + ((resource_t) pci_moving_config32(dev, PCI_PREF_LIMIT_UPPER32)) << 32; + + moving = moving_base & moving_limit; + /* Initialize the prefetchable memory constraints on the current bus. */ + pci_record_bridge_resource(dev, moving, PCI_PREF_MEMORY_BASE, + IORESOURCE_MEM | IORESOURCE_PREFETCH); + + /* See if the bridge mem resources are implemented. */ + moving_base = ((u32) pci_moving_config16(dev, PCI_MEMORY_BASE)) << 16; + moving_limit = ((u32) pci_moving_config16(dev, PCI_MEMORY_LIMIT)) << 16; + + moving = moving_base & moving_limit; + + /* Initialize the memory resources on the current bus. */ + pci_record_bridge_resource(dev, moving, PCI_MEMORY_BASE, + IORESOURCE_MEM); + + compact_resources(dev); +} void pci_dev_read_resources(struct device *dev) { - uint32_t addr; - dev->resources = 0; - memset(&dev->resource[0], 0, sizeof(dev->resource)); pci_read_bases(dev, 6); - addr = pci_read_config32(dev, PCI_ROM_ADDRESS); - dev->rom_address = (addr == 0xffffffff)? 0 : addr; + pci_get_rom_resource(dev, PCI_ROM_ADDRESS); } void pci_bus_read_resources(struct device *dev) { - uint32_t addr; - dev->resources = 0; - memset(&dev->resource, 0, sizeof(dev->resource)); 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; - + pci_get_rom_resource(dev, PCI_ROM_ADDRESS1); } +void pci_domain_read_resources(struct device *dev) +{ + struct resource *res; + + /* Initialize the system-wide I/O space constraints. */ + res = new_resource(dev, IOINDEX_SUBTRACTIVE(0, 0)); + res->limit = 0xffffUL; + res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | + IORESOURCE_ASSIGNED; + + /* Initialize the system-wide memory resources constraints. */ + res = new_resource(dev, IOINDEX_SUBTRACTIVE(1, 0)); + res->limit = 0xffffffffULL; + res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE | + IORESOURCE_ASSIGNED; +} static void pci_set_resource(struct device *dev, struct resource *resource) { - unsigned long base, limit; - 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: %s %02x not allocated\n", - dev_path(dev), resource->index); -#endif + resource_t base, end; + + /* Make certain the resource has actually been assigned a value. */ + if (!(resource->flags & IORESOURCE_ASSIGNED)) { + printk(BIOS_ERR, "ERROR: %s %02lx %s size: 0x%010llx not " + "assigned\n", dev_path(dev), resource->index, + resource_type(resource), resource->size); return; } - /* Only handle PCI memory and IO resources for now */ - if (!(resource->flags & (IORESOURCE_MEM |IORESOURCE_IO))) + /* If this resource is fixed don't worry about it. */ + if (resource->flags & IORESOURCE_FIXED) return; - if (resource->flags & IORESOURCE_MEM) { - dev->command |= PCI_COMMAND_MEMORY; - } - if (resource->flags & IORESOURCE_IO) { - dev->command |= PCI_COMMAND_IO; - } - if (resource->flags & IORESOURCE_PCI_BRIDGE) { - dev->command |= PCI_COMMAND_MASTER; + /* If I have already stored this resource don't worry about it. */ + if (resource->flags & IORESOURCE_STORED) + return; + + /* If the resource is subtractive don't worry about it. */ + if (resource->flags & IORESOURCE_SUBTRACTIVE) + return; + + /* Only handle PCI memory and I/O resources for now. */ + if (!(resource->flags & (IORESOURCE_MEM | IORESOURCE_IO))) + return; + + /* Enable the resources in the command register. */ + if (resource->size) { + if (resource->flags & IORESOURCE_MEM) + dev->command |= PCI_COMMAND_MEMORY; + if (resource->flags & IORESOURCE_IO) + dev->command |= PCI_COMMAND_IO; + if (resource->flags & IORESOURCE_PCI_BRIDGE) + dev->command |= PCI_COMMAND_MASTER; } - /* Get the base address */ + + /* Get the base address. */ base = resource->base; - /* Get the resource alignment */ - align = 1UL << resource->align; - - /* Get the limit (rounded up) */ - limit = base + ((resource->size + align - 1UL) & ~(align - 1UL)) -1UL; - + + /* Get the end. */ + end = resource_end(resource); + + /* Now store the resource. */ + resource->flags |= IORESOURCE_STORED; + + /* + * PCI bridges have no enable bit. They are disabled if the base of + * the range is greater than the limit. If the size is zero, disable + * by setting the base = limit and end = limit - 2^gran. + */ + if (resource->size == 0 && (resource->flags & IORESOURCE_PCI_BRIDGE)) { + base = resource->limit; + end = resource->limit - (1 << resource->gran); + resource->base = base; + } + if (!(resource->flags & IORESOURCE_PCI_BRIDGE)) { + unsigned long base_lo, base_hi; + /* - * 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; - } - pci_write_config32(dev, resource->index, base & 0xffffffff); - if (resource->flags & IORESOURCE_PCI64) { - /* FIXME handle real 64bit base addresses */ - pci_write_config32(dev, resource->index + 4, 0); - } - } - 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); - 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 + * Some chipsets allow us to set/clear the I/O bit + * (e.g. VIA 82C686A). So set it to be safe. */ - compute_allocate_resource(&dev->link[0], resource, - IORESOURCE_MEM | IORESOURCE_PREFETCH, - IORESOURCE_MEM); + base_lo = base & 0xffffffff; + base_hi = (base >> 32) & 0xffffffff; + if (resource->flags & IORESOURCE_IO) + base_lo |= PCI_BASE_ADDRESS_SPACE_IO; + pci_write_config32(dev, resource->index, base_lo); + if (resource->flags & IORESOURCE_PCI64) + pci_write_config32(dev, resource->index + 4, base_hi); + } else if (resource->index == PCI_IO_BASE) { + /* Set the I/O ranges. */ + pci_write_config8(dev, PCI_IO_BASE, base >> 8); + pci_write_config16(dev, PCI_IO_BASE_UPPER16, base >> 16); + pci_write_config8(dev, PCI_IO_LIMIT, end >> 8); + pci_write_config16(dev, PCI_IO_LIMIT_UPPER16, end >> 16); + } else if (resource->index == PCI_MEMORY_BASE) { + /* Set the memory range. */ 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) { - /* set the prefetchable memory range - * 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); - 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 { - printk_err("ERROR: invalid resource->index %x\n", - resource->index); + pci_write_config16(dev, PCI_MEMORY_LIMIT, end >> 16); + } else if (resource->index == PCI_PREF_MEMORY_BASE) { + /* Set the prefetchable memory range. */ + pci_write_config16(dev, PCI_PREF_MEMORY_BASE, base >> 16); + pci_write_config32(dev, PCI_PREF_BASE_UPPER32, base >> 32); + pci_write_config16(dev, PCI_PREF_MEMORY_LIMIT, end >> 16); + pci_write_config32(dev, PCI_PREF_LIMIT_UPPER32, end >> 32); + } else { + /* Don't let me think I stored the resource. */ + resource->flags &= ~IORESOURCE_STORED; + printk(BIOS_ERR, "ERROR: invalid resource->index %lx\n", + 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"); - return; + + report_resource_stored(dev, resource, ""); } void pci_dev_set_resources(struct device *dev) { - struct resource *resource, *last; - unsigned link; - uint8_t line; + struct resource *res; + struct bus *bus; + u8 line; - last = &dev->resource[dev->resources]; + for (res = dev->resource_list; res; res = res->next) + pci_set_resource(dev, res); - for(resource = &dev->resource[0]; resource < last; resource++) { - pci_set_resource(dev, resource); - } - for(link = 0; link < dev->links; link++) { - struct bus *bus; - bus = &dev->link[link]; - if (bus->children) { + for (bus = dev->link_list; bus; bus = bus->next) { + if (bus->children) assign_resources(bus); - } } - /* set a default latency timer */ + /* Set a default latency timer. */ pci_write_config8(dev, PCI_LATENCY_TIMER, 0x40); - /* set a default secondary latency timer */ - if ((dev->hdr_type & 0x7f) == PCI_HEADER_TYPE_BRIDGE) { + /* Set a default secondary latency timer. */ + if ((dev->hdr_type & 0x7f) == PCI_HEADER_TYPE_BRIDGE) pci_write_config8(dev, PCI_SEC_LATENCY_TIMER, 0x40); - } - /* zero the irq settings */ + /* Zero the IRQ settings. */ line = pci_read_config8(dev, PCI_INTERRUPT_PIN); - if (line) { + if (line) pci_write_config8(dev, PCI_INTERRUPT_LINE, 0); - } - /* set the cache line size, so far 64 bytes is good for everyone */ + + /* Set the cache line size, so far 64 bytes is good for everyone. */ pci_write_config8(dev, PCI_CACHE_LINE_SIZE, 64 >> 2); } void pci_dev_enable_resources(struct device *dev) { - uint16_t command; + const struct pci_operations *ops; + u16 command; + + /* Set the subsystem vendor and device ID for mainboard devices. */ + ops = ops_pci(dev); + if (dev->on_mainboard && ops && ops->set_subsystem) { + printk(BIOS_DEBUG, "%s subsystem <- %04x/%04x\n", + dev_path(dev), dev->subsystem_vendor, + dev->subsystem_device); + ops->set_subsystem(dev, dev->subsystem_vendor, + dev->subsystem_device); + } 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); + /* v3 has + * command |= (PCI_COMMAND_PARITY + PCI_COMMAND_SERR); // Error check. + */ + + printk(BIOS_DEBUG, "%s cmd <- %02x\n", dev_path(dev), command); + pci_write_config16(dev, PCI_COMMAND, command); } void pci_bus_enable_resources(struct device *dev) { - uint16_t ctrl; + u16 ctrl; + + /* + * Enable I/O in command register if there is VGA card + * connected with (even it does not claim I/O resource). + */ + if (dev->link_list->bridge_ctrl & PCI_BRIDGE_CTL_VGA) + dev->command |= PCI_COMMAND_IO; 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); + ctrl |= dev->link_list->bridge_ctrl; + ctrl |= (PCI_BRIDGE_CTL_PARITY + PCI_BRIDGE_CTL_SERR); /* Error check. */ + printk(BIOS_DEBUG, "%s bridge ctrl <- %04x\n", dev_path(dev), ctrl); pci_write_config16(dev, PCI_BRIDGE_CONTROL, ctrl); pci_dev_enable_resources(dev); } +void pci_bus_reset(struct bus *bus) +{ + u16 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(struct device *dev, unsigned vendor, unsigned device) +{ + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + ((device & 0xffff) << 16) | (vendor & 0xffff)); +} + +/** Default handler: only runs the relevant PCI BIOS. */ +void pci_dev_init(struct device *dev) +{ +#if CONFIG_PCI_ROM_RUN == 1 || CONFIG_VGA_ROM_RUN == 1 + struct rom_header *rom, *ram; + + if (CONFIG_PCI_ROM_RUN != 1 && /* Only execute VGA ROMs. */ + ((dev->class >> 8) != PCI_CLASS_DISPLAY_VGA)) + return; + + if (CONFIG_VGA_ROM_RUN != 1 && /* Only execute non-VGA ROMs. */ + ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA)) + return; + +#if CONFIG_CHROMEOS + /* In ChromeOS we want to boot blazingly fast. Therefore + * we don't run (VGA) option ROMs, unless we have to print + * something on the screen before the kernel is loaded. + */ + if (!developer_mode_enabled() && !recovery_mode_enabled()) + return; +#endif + + rom = pci_rom_probe(dev); + if (rom == NULL) + return; + + ram = pci_rom_load(dev, rom); + if (ram == NULL) + return; + +#if CONFIG_HAVE_ACPI_RESUME && !CONFIG_S3_VGA_ROM_RUN + /* If S3_VGA_ROM_RUN is disabled, skip running VGA option + * ROMs when coming out of an S3 resume. + */ + if ((acpi_slp_type == 3) && + ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA)) + return; +#endif + run_bios(dev, (unsigned long)ram); +#endif /* CONFIG_PCI_ROM_RUN || CONFIG_VGA_ROM_RUN */ +} + +/** Default device operation for PCI devices */ +static struct pci_operations pci_dev_ops_pci = { + .set_subsystem = pci_dev_set_subsystem, +}; + 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 = pci_dev_init, + .scan_bus = 0, + .enable = 0, + .ops_pci = &pci_dev_ops_pci, }; + +/** Default device operations for PCI bridges */ +static struct pci_operations pci_bus_ops_pci = { + .set_subsystem = 0, +}; + 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, + .enable = 0, + .reset_bus = pci_bus_reset, + .ops_pci = &pci_bus_ops_pci, }; + +/** + * 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 Pointer to the device structure of the bridge. + * @return Appropriate bridge operations. + */ +static struct device_operations *get_pci_bridge_ops(device_t dev) +{ + unsigned int pos; + +#if CONFIG_PCIX_PLUGIN_SUPPORT == 1 + pos = pci_find_capability(dev, PCI_CAP_ID_PCIX); + if (pos) { + printk(BIOS_DEBUG, "%s subordinate bus PCI-X\n", dev_path(dev)); + return &default_pcix_ops_bus; + } +#endif +#if CONFIG_AGP_PLUGIN_SUPPORT == 1 + /* How do I detect a 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))) { + u16 flags; + flags = pci_read_config16(dev, pos + PCI_CAP_FLAGS); + if ((flags >> 13) == 1) { + /* Host or Secondary Interface */ + printk(BIOS_DEBUG, "%s subordinate bus HT\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) { + u16 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(BIOS_DEBUG, "%s subordinate bus PCI Express\n", + dev_path(dev)); + return &default_pciexp_ops_bus; + case PCI_EXP_TYPE_PCI_BRIDGE: + printk(BIOS_DEBUG, "%s subordinate PCI\n", + dev_path(dev)); + return &default_pci_ops_bus; + default: + break; + } + } +#endif + return &default_pci_ops_bus; +} + +/** + * Set up PCI device operation. + * + * Check if it already has a driver. If not, use find_device_operations(), + * or set to a default based on type. + * + * @param dev Pointer to the device whose pci_ops you want to set. + * @see pci_drivers + */ static void set_pci_ops(struct device *dev) { struct pci_driver *driver; - if (dev->ops) { + + if (dev->ops) return; - } - /* Look through the list of setup drivers and find one for - * this pci device + + /* + * 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)) { - 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 + (driver->device == dev->device)) { + dev->ops = (struct device_operations *)driver->ops; + printk(BIOS_SPEW, "%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 */ + + /* If I don't have a specific driver use the default operations. */ + switch (dev->hdr_type & 0x7f) { /* Header type */ + case PCI_HEADER_TYPE_NORMAL: if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) goto bad; dev->ops = &default_pci_ops_dev; @@ -450,199 +836,338 @@ 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; - default: - bad: - 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); +#if CONFIG_CARDBUS_PLUGIN_SUPPORT == 1 + case PCI_HEADER_TYPE_CARDBUS: + dev->ops = &default_cardbus_ops_bus; + break; +#endif +default: +bad: + if (dev->enabled) { + printk(BIOS_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); + } } - return; } /** - * Given a bus and a devfn number, find the device structure - * @param bus The bus structure - * @param devfn a device/function number - * @return pointer to the device structure + * See if we have already allocated a device structure for a given devfn. + * + * Given a linked list of PCI device structures and a devfn number, find the + * device structure correspond to the devfn, if present. This function also + * removes the device structure from the linked list. + * + * @param list The device structure list. + * @param devfn A device/function number. + * @return Pointer to the device structure found or NULL if we have not + * allocated a device for this devfn yet. */ static struct device *pci_scan_get_dev(struct device **list, unsigned int devfn) { - struct device *dev = 0; - for(; *list; list = &(*list)->sibling) { - if ((*list)->path.u.pci.devfn == devfn) { - /* Unlink from the list */ + struct device *dev; + + dev = 0; + for (; *list; list = &(*list)->sibling) { + if ((*list)->path.type != DEVICE_PATH_PCI) { + printk(BIOS_ERR, "child %s not a PCI device\n", + dev_path(*list)); + continue; + } + if ((*list)->path.pci.devfn == devfn) { + /* Unlink from the list. */ dev = *list; *list = (*list)->sibling; - dev->sibling = 0; + dev->sibling = NULL; break; } } + + /* + * Just like alloc_dev() add the device to the list of devices 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; ) { + struct device *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) { + + /* Place the device on the list of children of its parent. */ + if (child) child->sibling = dev; - } else { + else dev->bus->children = dev; + } + + return dev; +} + +/** + * Scan a PCI bus. + * + * Determine the existence of a given PCI device. Allocate a new struct device + * if dev==NULL was passed in and the device exists in hardware. + * + * @param dev Pointer to the dev structure. + * @param bus Pointer to the bus structure. + * @param devfn A device/function number to look at. + * @return The device structure for the device (if found), NULL otherwise. + */ +device_t pci_probe_dev(device_t dev, struct bus *bus, unsigned devfn) +{ + u32 id, class; + u8 hdr_type; + + /* Detect if a device is present. */ + if (!dev) { + struct device dummy; + + dummy.bus = bus; + dummy.path.type = DEVICE_PATH_PCI; + dummy.path.pci.devfn = devfn; + + id = pci_read_config32(&dummy, PCI_VENDOR_ID); + /* + * Have we found something? Some broken boards return 0 if a + * slot is empty, but the expected answer is 0xffffffff. + */ + if (id == 0xffffffff) + return NULL; + + if ((id == 0x00000000) || (id == 0x0000ffff) || + (id == 0xffff0000)) { + printk(BIOS_SPEW, "%s, bad id 0x%x\n", + dev_path(&dummy), 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 magic 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(BIOS_INFO, "PCI: Static device %s not " + "found, disabling it.\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. */ + printk(BIOS_DEBUG, "%s [%04x/%04x] %s%s\n", dev_path(dev), + dev->vendor, dev->device, dev->enabled ? "enabled" : "disabled", + dev->ops ? "" : " No operations"); + return dev; } -/** Scan the pci bus devices and bridges. - * @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 +/** + * 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; - device_t old_devices; - device_t child; + struct device *old_devices; + struct device *child; + +#if CONFIG_PCI_BUS_SEGN_BITS + printk(BIOS_DEBUG, "PCI: pci_scan_bus for bus %04x:%02x\n", + bus->secondary >> 8, bus->secondary & 0xff); +#else + printk(BIOS_DEBUG, "PCI: pci_scan_bus for bus %02x\n", bus->secondary); +#endif - printk_debug("PCI: pci_scan_bus for bus %d\n", bus->secondary); + /* Maximum sane devfn is 0xFF. */ + if (max_devfn > 0xff) { + printk(BIOS_ERR, "PCI: pci_scan_bus limits devfn %x - " + "devfn %x\n", min_devfn, max_devfn); + printk(BIOS_ERR, "PCI: pci_scan_bus upper limit too big. " + "Using 0xff.\n"); + max_devfn=0x08; + } old_devices = bus->children; - bus->children = 0; + bus->children = NULL; post_code(0x24); - - /* probe all devices on this bus with some optimization for non-existance and - single funcion devices */ + /* + * Probe all devices/functions on this bus with some optimization for + * non-existence and single function devices. + */ for (devfn = min_devfn; devfn <= max_devfn; devfn++) { - uint32_t id, class; - uint8_t hdr_type; + struct device *dev; - /* First thing setup the device structure */ + /* First thing setup the device structure. */ + printk(BIOS_INFO, "%s: before pci_scan_get_dev! devfn: %d\n", __func__, devfn); 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; - } - /* multi function device, skip to next function */ - continue; - } - 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); + printk(BIOS_INFO, "%s: after pci_scan_get_dev!\n", __func__); - /* 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; + /* See if a device is present and setup the device structure. */ + printk(BIOS_INFO, "%s: before pci_probe_dev!\n", __func__); + dev = pci_probe_dev(dev, bus, devfn); + printk(BIOS_INFO, "%s: after pci_probe_dev!\n", __func__); - /* 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. + /* + * 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 (!dev->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)); - continue; - } - /* 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->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 ((PCI_FUNC(devfn) == 0x00) && (!dev + || (dev->enabled && ((dev->hdr_type & 0x80) != 0x80)))) { devfn += 0x07; } } + post_code(0x25); - for(child = bus->children; child; child = child->sibling) { - if (!child->ops->scan_bus) { - continue; - } - max = child->ops->scan_bus(child, max); + /* + * Warn if any leftover static devices are are found. + * There's probably a problem in devicetree.cb. + */ + if (old_devices) { + device_t left; + printk(BIOS_WARNING, "PCI: Left over static devices:\n"); + for (left = old_devices; left; left = left->sibling) + printk(BIOS_WARNING, "%s\n", dev_path(left)); + + printk(BIOS_WARNING, "PCI: Check your devicetree.cb.\n"); } + /* - * 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 - * any devices. - * + * For all children that implement scan_bus() (i.e. bridges) + * scan the bus behind that child. + */ + for (child = bus->children; child; child = child->sibling) + max = 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 any devices. * Return how far we've got finding sub-buses. */ - printk_debug("PCI: pci_scan_bus returning with max=%02x\n", max); + printk(BIOS_DEBUG, "PCI: pci_scan_bus returning with max=%03x\n", max); post_code(0x55); return max; } -/** Scan the bus, first for bridges and next for devices. - * @param pci_bus pointer to the bus structure - * @return The maximum bus number found, after scanning all subordinate busses +/** + * 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 assigned up to now. + * @param do_scan_bus TODO + * @return The maximum bus number found, after scanning all subordinate buses. */ -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; - uint16_t cr; - - printk_spew("%s: dev %p, max %d\n", __FUNCTION__, dev, max); - bus = &dev->link[0]; - dev->links = 1; - - /* Set up the primary, secondary and subordinate bus numbers. We have + u32 buses; + u16 cr; + + printk(BIOS_SPEW, "%s for %s\n", __func__, dev_path(dev)); + + if (dev->link_list == NULL) { + struct bus *link; + link = malloc(sizeof(*link)); + if (link == NULL) + die("Couldn't allocate a link!\n"); + memset(link, 0, sizeof(*link)); + link->dev = dev; + dev->link_list = link; + } + + bus = dev->link_list; + + /* + * 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); @@ -654,28 +1179,119 @@ unsigned int pci_scan_bridge(struct device *dev, unsigned int max) */ buses = pci_read_config32(dev, PCI_PRIMARY_BUS); - /* Configure the bus numbers for this bridge: the configuration + /* + * 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)); + buses |= (((unsigned int)(dev->bus->secondary) << 0) | + ((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 */ - 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 + + /* Now we can scan all subordinate buses (those behind the bridge). */ + 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. */ bus->subordinate = max; - buses = (buses & 0xff00ffff) | - ((unsigned int) (bus->subordinate) << 16); + 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); + + printk(BIOS_SPEW, "%s returns max %d\n", __func__, max); + return max; +} + +/** + * 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 assigned up to now. + * @return The maximum bus number found, after scanning all subordinate buses. + */ +unsigned int pci_scan_bridge(struct device *dev, unsigned int max) +{ + return do_pci_scan_bridge(dev, max, pci_scan_bus); +} + +/** + * Scan a PCI domain. + * + * This function is the default scan_bus() method for PCI domains. + * + * @param dev Pointer to the domain. + * @param max The highest bus number assigned up to now. + * @return The maximum bus number found, after scanning all subordinate busses. + */ +unsigned int pci_domain_scan_bus(device_t dev, unsigned int max) +{ + max = pci_scan_bus(dev->link_list, PCI_DEVFN(0, 0), 0xff, max); return max; } + +#if CONFIG_PC80_SYSTEM == 1 +/** + * Assign IRQ numbers. + * + * This function assigns IRQs for all functions contained within the indicated + * device address. If the device does not exist or does not require interrupts + * then this function has no effect. + * + * This function should be called for each PCI slot in your system. + * + * @param bus Pointer to the bus structure. + * @param slot TODO + * @param pIntAtoD An array of IRQ #s that are assigned to PINTA through PINTD + * of this slot. The particular IRQ #s that are passed in depend on the + * routing inside your southbridge and on your board. + */ +void pci_assign_irqs(unsigned bus, unsigned slot, + const unsigned char pIntAtoD[4]) +{ + unsigned int funct; + device_t pdev; + u8 line, irq; + + /* Each slot may contain up to eight functions. */ + for (funct = 0; funct < 8; funct++) { + pdev = dev_find_slot(bus, (slot << 3) + funct); + + if (!pdev) + continue; + + line = pci_read_config8(pdev, PCI_INTERRUPT_PIN); + + /* PCI spec says all values except 1..4 are reserved. */ + if ((line < 1) || (line > 4)) + continue; + + irq = pIntAtoD[line - 1]; + + printk(BIOS_DEBUG, "Assigning IRQ %d to %d:%x.%d\n", + irq, bus, slot, funct); + + pci_write_config8(pdev, PCI_INTERRUPT_LINE, + pIntAtoD[line - 1]); + +#ifdef PARANOID_IRQ_ASSIGNMENTS + irq = pci_read_config8(pdev, PCI_INTERRUPT_LINE); + printk(BIOS_DEBUG, " Readback = %d\n", irq); +#endif + +#if CONFIG_PC80_SYSTEM == 1 + /* Change to level triggered. */ + i8259_configure_irq_trigger(pIntAtoD[line - 1], + IRQ_LEVEL_TRIGGERED); +#endif + } +} +#endif