diff options
Diffstat (limited to 'src/devices/pci_device.c')
-rw-r--r-- | src/devices/pci_device.c | 124 |
1 files changed, 64 insertions, 60 deletions
diff --git a/src/devices/pci_device.c b/src/devices/pci_device.c index 734b982a6d..c3f1f6ac8c 100644 --- a/src/devices/pci_device.c +++ b/src/devices/pci_device.c @@ -27,19 +27,14 @@ * @param resource Pointer to the resource structure * @param index Address of the pci configuration register */ -static void pci_get_resource(struct device *dev, struct resource *resource, unsigned long index) +static struct resource *pci_get_resource(struct device *dev, unsigned long index) { + struct resource *resource; uint32_t addr, size, base; unsigned long type; /* 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; + resource = get_resource(dev, index); addr = pci_read_config32(dev, index); @@ -87,7 +82,7 @@ static void pci_get_resource(struct device *dev, struct resource *resource, unsi resource->size = (~((size | 0xffff0000) & PCI_BASE_ADDRESS_IO_MASK)) +1; resource->align = log2(resource->size); resource->gran = resource->align; - resource->flags = IORESOURCE_IO; + resource->flags |= IORESOURCE_IO; resource->limit = 0xffff; } else { @@ -96,7 +91,7 @@ static void pci_get_resource(struct device *dev, struct resource *resource, unsi resource->size = (~(size &PCI_BASE_ADDRESS_MEM_MASK)) +1; resource->align = log2(resource->size); resource->gran = resource->align; - resource->flags = IORESOURCE_MEM; + resource->flags |= IORESOURCE_MEM; if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) { resource->flags |= IORESOURCE_PREFETCH; } @@ -145,7 +140,7 @@ static void pci_get_resource(struct device *dev, struct resource *resource, unsi } } /* dev->size holds the flags... */ - return; + return resource; } /** Read the base address registers for a given device. @@ -154,75 +149,63 @@ static void pci_get_resource(struct device *dev, struct resource *resource, unsi */ 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; + resource = pci_get_resource(dev, index); index += (resource->flags & IORESOURCE_PCI64)?8:4; } - dev->resources = reg; + compact_resources(dev); } static void pci_bridge_read_bases(struct device *dev) { - unsigned int reg = dev->resources; + struct resource *resource; /* FIXME handle bridges without some of the optional resources */ /* 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], + resource = get_resource(dev, PCI_IO_BASE); + resource->size = 0; + resource->align = log2(PCI_IO_BRIDGE_ALIGN); + resource->gran = log2(PCI_IO_BRIDGE_ALIGN); + resource->limit = 0xffffUL; + resource->flags |= IORESOURCE_IO | IORESOURCE_PCI_BRIDGE; + compute_allocate_resource(&dev->link[0], resource, 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], + resource = get_resource(dev, PCI_PREF_MEMORY_BASE); + resource->size = 0; + resource->align = log2(PCI_MEM_BRIDGE_ALIGN); + resource->gran = log2(PCI_MEM_BRIDGE_ALIGN); + resource->limit = 0xffffffffUL; + 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); - 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, + resource = get_resource(dev, PCI_MEMORY_BASE); + resource->size = 0; + resource->align = log2(PCI_MEM_BRIDGE_ALIGN); + resource->gran = log2(PCI_MEM_BRIDGE_ALIGN); + resource->limit = 0xffffffffUL; + resource->flags = IORESOURCE_MEM | IORESOURCE_PCI_BRIDGE; + compute_allocate_resource(&dev->link[0], resource, + IORESOURCE_MEM | IORESOURCE_PREFETCH, IORESOURCE_MEM); - reg++; - dev->resources = reg; + 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; @@ -231,8 +214,6 @@ void pci_dev_read_resources(struct device *dev) 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); @@ -246,10 +227,10 @@ static void pci_set_resource(struct device *dev, struct resource *resource) { unsigned long base, limit; unsigned char buf[10]; - unsigned long align; + unsigned long gran; /* Make certain the resource has actually been set */ - if (!(resource->flags & IORESOURCE_SET)) { + if (!(resource->flags & IORESOURCE_ASSIGNED)) { #if 1 printk_err("ERROR: %s %02x not allocated\n", dev_path(dev), resource->index); @@ -257,6 +238,11 @@ static void pci_set_resource(struct device *dev, struct resource *resource) return; } + /* If I have already stored this resource don't worry about it */ + if (resource->flags & IORESOURCE_STORED) { + return; + } + /* Only handle PCI memory and IO resources for now */ if (!(resource->flags & (IORESOURCE_MEM |IORESOURCE_IO))) return; @@ -272,12 +258,20 @@ static void pci_set_resource(struct device *dev, struct resource *resource) } /* Get the base address */ base = resource->base; - /* Get the resource alignment */ - align = 1UL << resource->align; + /* Get the resource granularity */ + gran = 1UL << resource->gran; + + /* For a non bridge resource granularity and alignment are the same. + * For a bridge resource align is the largest needed alignment below + * the bridge. While the granularity is simply how many low bits of the + * address cannot be set. + */ /* Get the limit (rounded up) */ - limit = base + ((resource->size + align - 1UL) & ~(align - 1UL)) -1UL; + limit = base + ((resource->size + gran - 1UL) & ~(gran - 1UL)) -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. @@ -326,6 +320,8 @@ static void pci_set_resource(struct device *dev, struct resource *resource) pci_write_config32(dev, PCI_PREF_LIMIT_UPPER32, 0); } else { + /* Don't let me think I stored the resource */ + resource->flags &= ~IORESOURCE_STORED; printk_err("ERROR: invalid resource->index %x\n", resource->index); } @@ -386,6 +382,7 @@ void pci_dev_enable_resources(struct device *dev) uint16_t command; command = pci_read_config16(dev, PCI_COMMAND); command |= dev->command; + command |= (PCI_COMMAND_PARITY + PCI_COMMAND_SERR); /* error check */ printk_debug("%s cmd <- %02x\n", dev_path(dev), command); pci_write_config16(dev, PCI_COMMAND, command); @@ -397,6 +394,7 @@ void pci_bus_enable_resources(struct device *dev) uint16_t ctrl; ctrl = pci_read_config16(dev, PCI_BRIDGE_CONTROL); ctrl |= dev->link[0].bridge_ctrl; + ctrl |= (PCI_BRIDGE_CTL_PARITY + PCI_BRIDGE_CTL_SERR); /* error check */ printk_debug("%s bridge ctrl <- %04x\n", dev_path(dev), ctrl); pci_write_config16(dev, PCI_BRIDGE_CONTROL, ctrl); @@ -560,9 +558,12 @@ unsigned int pci_scan_bus(struct bus *bus, dev = alloc_dev(bus, &dummy.path); } else { - /* Run the magic enable/disable sequence for the device */ + /* Run the magic enable sequence for the device */ if (dev->chip && dev->chip->control && dev->chip->control->enable_dev) { + int enable = dev->enable; + dev->enable = 1; dev->chip->control->enable_dev(dev); + dev->enable = enable; } /* Now read the vendor and device id */ id = pci_read_config32(dev, PCI_VENDOR_ID); @@ -584,7 +585,7 @@ unsigned int pci_scan_bus(struct bus *bus, */ set_pci_ops(dev); /* Error if we don't have some pci operations for it */ - if (dev->enable && !dev->ops) { + if (!dev->ops) { printk_err("%s No device operations\n", dev_path(dev)); continue; @@ -594,6 +595,9 @@ unsigned int pci_scan_bus(struct bus *bus, if (dev->ops && dev->ops->enable) { dev->ops->enable(dev); } + else if (dev->chip && dev->chip->control && dev->chip->control->enable_dev) { + dev->chip->control->enable_dev(dev); + } printk_debug("%s [%04x/%04x] %s\n", dev_path(dev), |