sigh
[coreboot.git] / src / northbridge / amd / amdfam10 / northbridge.c
index a25a8df4e831fa14e267f827b3d23971946f3969..018b6c83b0d8e81dc3be08340885918f266e1b5b 100644 (file)
 #endif
 
 #include <cpu/amd/amdfam10_sysconf.h>
+#if CONFIG_SOUTHBRIDGE_AMD_CIMX_SB800
+#include <sb_cimx.h>
+#elif CONFIG_SOUTHBRIDGE_AMD_CIMX_SB900
+#include <SbEarly.h>
+#endif
 
 struct amdfam10_sysconf_t sysconf;
 
@@ -124,7 +129,7 @@ static u32 amdfam10_nodeid(device_t dev)
 #endif
 }
 
-#include "amdfam10_conf.c"
+#include "conf.c"
 
 static void set_vga_enable_reg(u32 nodeid, u32 linkn)
 {
@@ -137,7 +142,7 @@ static void set_vga_enable_reg(u32 nodeid, u32 linkn)
 
 }
 
-static u32 amdfam10_scan_chain(device_t dev, u32 nodeid, u32 link, u32 sblink,
+static u32 amdfam10_scan_chain(device_t dev, u32 nodeid, struct bus *link, u32 link_num, u32 sblink,
                                u32 max, u32 offset_unitid)
 {
 //     I want to put sb chain in bus 0 can I?
@@ -149,7 +154,7 @@ static u32 amdfam10_scan_chain(device_t dev, u32 nodeid, u32 link, u32 sblink,
                u32 ht_unitid_base[4]; // here assume only 4 HT device on chain
                u32 max_bus;
                u32 min_bus;
-               u32 is_sublink1 = (link>3);
+               u32 is_sublink1 = (link_num>3);
                device_t devx;
                u32 busses;
                u32 segn = max>>8;
@@ -162,7 +167,7 @@ static u32 amdfam10_scan_chain(device_t dev, u32 nodeid, u32 link, u32 sblink,
                if(is_sublink1) {
                        u32 regpos;
                        u32 reg;
-                       regpos = 0x170 + 4 * (link&3); // it is only on sublink0
+                       regpos = 0x170 + 4 * (link_num&3); // it is only on sublink0
                        reg = pci_read_config32(dev, regpos);
                        if(reg & 1) return max; // already ganged no sblink1
                        devx = get_node_pci(nodeid, 4);
@@ -171,15 +176,15 @@ static u32 amdfam10_scan_chain(device_t dev, u32 nodeid, u32 link, u32 sblink,
                        devx = dev;
 
 
-               dev->link[link].cap = 0x80 + ((link&3) *0x20);
+               link->cap = 0x80 + ((link_num&3) *0x20);
                do {
-                       link_type = pci_read_config32(devx, dev->link[link].cap + 0x18);
+                       link_type = pci_read_config32(devx, link->cap + 0x18);
                } while(link_type & ConnectionPending);
                if (!(link_type & LinkConnected)) {
                        return max;
                }
                do {
-                       link_type = pci_read_config32(devx, dev->link[link].cap + 0x18);
+                       link_type = pci_read_config32(devx, link->cap + 0x18);
                } while(!(link_type & InitComplete));
                if (!(link_type & NonCoherent)) {
                        return max;
@@ -187,7 +192,7 @@ static u32 amdfam10_scan_chain(device_t dev, u32 nodeid, u32 link, u32 sblink,
                /* See if there is an available configuration space mapping
                 * register in function 1.
                 */
-               ht_c_index = get_ht_c_index(nodeid, link, &sysconf);
+               ht_c_index = get_ht_c_index(nodeid, link_num, &sysconf);
 
 #if CONFIG_EXT_CONF_SUPPORT == 0
                if(ht_c_index>=4) return max;
@@ -199,7 +204,7 @@ static u32 amdfam10_scan_chain(device_t dev, u32 nodeid, u32 link, u32 sblink,
                 */
 #if CONFIG_SB_HT_CHAIN_ON_BUS0 > 0
                // first chain will on bus 0
-               if((nodeid == 0) && (sblink==link)) { // actually max is 0 here
+               if((nodeid == 0) && (sblink==link_num)) { // actually max is 0 here
                        min_bus = max;
                }
        #if CONFIG_SB_HT_CHAIN_ON_BUS0 > 1
@@ -221,26 +226,26 @@ static u32 amdfam10_scan_chain(device_t dev, u32 nodeid, u32 link, u32 sblink,
 #endif
                max_bus = 0xfc | (segn<<8);
 
-               dev->link[link].secondary = min_bus;
-               dev->link[link].subordinate = max_bus;
+               link->secondary = min_bus;
+               link->subordinate = max_bus;
 
                /* Read the existing primary/secondary/subordinate bus
                 * number configuration.
                 */
-               busses = pci_read_config32(devx, dev->link[link].cap + 0x14);
+               busses = pci_read_config32(devx, link->cap + 0x14);
 
                /* Configure the bus numbers for this bridge: the configuration
                 * transactions will not be propagates by the bridge if it is
                 * not correctly configured
                 */
                busses &= 0xffff00ff;
-               busses |= ((u32)(dev->link[link].secondary) << 8);
-               pci_write_config32(devx, dev->link[link].cap + 0x14, busses);
+               busses |= ((u32)(link->secondary) << 8);
+               pci_write_config32(devx, link->cap + 0x14, busses);
 
 
                /* set the config map space */
 
-               set_config_map_reg(nodeid, link, ht_c_index, dev->link[link].secondary, dev->link[link].subordinate, sysconf.segbit, sysconf.nodes);
+               set_config_map_reg(nodeid, link_num, ht_c_index, link->secondary, link->subordinate, sysconf.segbit, sysconf.nodes);
 
                /* Now we can scan all of the subordinate busses i.e. the
                 * chain on the hypertranport link
@@ -255,17 +260,17 @@ static u32 amdfam10_scan_chain(device_t dev, u32 nodeid, u32 link, u32 sblink,
                else
                        max_devfn = (0x1f<<3) | 7;
 
-               max = hypertransport_scan_chain(&dev->link[link], 0, max_devfn, max, ht_unitid_base, offset_unitid);
+               max = hypertransport_scan_chain(link, 0, max_devfn, max, ht_unitid_base, offset_unitid);
 
                /* We know the number of busses behind this bridge.  Set the
                 * subordinate bus number to it's real value
                 */
                if(ht_c_index>3) { // clear the extend reg
-                       clear_config_map_reg(nodeid, link, ht_c_index, (max+1)>>sysconf.segbit, (dev->link[link].subordinate)>>sysconf.segbit, sysconf.nodes);
+                       clear_config_map_reg(nodeid, link_num, ht_c_index, (max+1)>>sysconf.segbit, (link->subordinate)>>sysconf.segbit, sysconf.nodes);
                }
 
-               dev->link[link].subordinate = max;
-               set_config_map_reg(nodeid, link, ht_c_index, dev->link[link].secondary, dev->link[link].subordinate, sysconf.segbit, sysconf.nodes);
+               link->subordinate = max;
+               set_config_map_reg(nodeid, link_num, ht_c_index, link->secondary, link->subordinate, sysconf.segbit, sysconf.nodes);
                sysconf.ht_c_num++;
 
                {
@@ -278,14 +283,14 @@ static u32 amdfam10_scan_chain(device_t dev, u32 nodeid, u32 link, u32 sblink,
                        sysconf.hcdn_reg[ht_c_index] = temp;
 
                }
-       store_ht_c_conf_bus(nodeid, link, ht_c_index, dev->link[link].secondary, dev->link[link].subordinate, &sysconf);
+       store_ht_c_conf_bus(nodeid, link_num, ht_c_index, link->secondary, link->subordinate, &sysconf);
        return max;
 }
 
-static u32 amdfam10_scan_chains(device_t dev, u32 max)
+static unsigned amdfam10_scan_chains(device_t dev, unsigned max)
 {
        unsigned nodeid;
-       u32 link;
+       struct bus *link;
        unsigned sblink = sysconf.sblk;
        unsigned offset_unitid = 0;
 
@@ -297,7 +302,9 @@ static u32 amdfam10_scan_chains(device_t dev, u32 max)
        #if ((CONFIG_HT_CHAIN_UNITID_BASE != 1) || (CONFIG_HT_CHAIN_END_UNITID_BASE != 0x20))
                offset_unitid = 1;
        #endif
-               max = amdfam10_scan_chain(dev, nodeid, sblink, sblink, max, offset_unitid ); // do sb ht chain at first, in case s2885 put sb chain (8131/8111) on link2, but put 8151 on link0
+               for (link = dev->link_list; link; link = link->next)
+                       if (link->link_num == sblink)
+                               max = amdfam10_scan_chain(dev, nodeid, link, sblink, sblink, max, offset_unitid ); // do sb ht chain at first, in case s2885 put sb chain (8131/8111) on link2, but put 8151 on link0
        }
 #endif
 
@@ -305,19 +312,19 @@ static u32 amdfam10_scan_chains(device_t dev, u32 max)
        max = check_segn(dev, max, sysconf.nodes, &sysconf);
 #endif
 
-       for(link = 0; link < dev->links; link++) {
+       for(link = dev->link_list; link; link = link->next) {
 #if CONFIG_SB_HT_CHAIN_ON_BUS0 > 0
-               if( (nodeid == 0) && (sblink == link) ) continue; //already done
+               if( (nodeid == 0) && (sblink == link->link_num) ) continue; //already done
 #endif
                offset_unitid = 0;
                #if ((CONFIG_HT_CHAIN_UNITID_BASE != 1) || (CONFIG_HT_CHAIN_END_UNITID_BASE != 0x20))
                        #if CONFIG_SB_HT_CHAIN_UNITID_OFFSET_ONLY == 1
-                       if((nodeid == 0) && (sblink == link))
+                       if((nodeid == 0) && (sblink == link->link_num))
                        #endif
                                offset_unitid = 1;
                #endif
 
-               max = amdfam10_scan_chain(dev, nodeid, link, sblink, max, offset_unitid);
+               max = amdfam10_scan_chain(dev, nodeid, link, link->link_num, sblink, max, offset_unitid);
        }
        return max;
 }
@@ -482,12 +489,12 @@ static void amdfam10_link_read_bases(device_t dev, u32 nodeid, u32 link)
 
 static void amdfam10_read_resources(device_t dev)
 {
-       u32 nodeid, link;
-
+       u32 nodeid;
+       struct bus *link;
        nodeid = amdfam10_nodeid(dev);
-       for(link = 0; link < dev->links; link++) {
-               if (dev->link[link].children) {
-                       amdfam10_link_read_bases(dev, nodeid, link);
+       for(link = dev->link_list; link; link = link->next) {
+               if (link->children) {
+                       amdfam10_link_read_bases(dev, nodeid, link->link_num);
                }
        }
 }
@@ -496,7 +503,7 @@ static void amdfam10_set_resource(device_t dev, struct resource *resource,
                                u32 nodeid)
 {
        resource_t rbase, rend;
-       unsigned reg, link;
+       unsigned reg, link_num;
        char buf[50];
 
        /* Make certain the resource has actually been set */
@@ -525,46 +532,43 @@ static void amdfam10_set_resource(device_t dev, struct resource *resource,
 
        /* Get the register and link */
        reg  = resource->index & 0xfff; // 4k
-       link = IOINDEX_LINK(resource->index);
+       link_num = IOINDEX_LINK(resource->index);
 
        if (resource->flags & IORESOURCE_IO) {
 
-               set_io_addr_reg(dev, nodeid, link, reg, rbase>>8, rend>>8);
-               store_conf_io_addr(nodeid, link, reg, (resource->index >> 24), rbase>>8, rend>>8);
+               set_io_addr_reg(dev, nodeid, link_num, reg, rbase>>8, rend>>8);
+               store_conf_io_addr(nodeid, link_num, reg, (resource->index >> 24), rbase>>8, rend>>8);
        }
        else if (resource->flags & IORESOURCE_MEM) {
-               set_mmio_addr_reg(nodeid, link, reg, (resource->index >>24), rbase>>8, rend>>8, sysconf.nodes) ;// [39:8]
-               store_conf_mmio_addr(nodeid, link, reg, (resource->index >>24), rbase>>8, rend>>8);
+               set_mmio_addr_reg(nodeid, link_num, reg, (resource->index >>24), rbase>>8, rend>>8, sysconf.nodes) ;// [39:8]
+               store_conf_mmio_addr(nodeid, link_num, reg, (resource->index >>24), rbase>>8, rend>>8);
        }
        resource->flags |= IORESOURCE_STORED;
-       sprintf(buf, " <node %02x link %02x>",
-               nodeid, link);
+       sprintf(buf, " <node %x link %x>",
+               nodeid, link_num);
        report_resource_stored(dev, resource, buf);
 }
 
 /**
- *
  * I tried to reuse the resource allocation code in amdfam10_set_resource()
- * but it is too diffcult to deal with the resource allocation magic.
+ * but it is too difficult to deal with the resource allocation magic.
  */
-#if CONFIG_CONSOLE_VGA_MULTI == 1
-extern device_t vga_pri;       // the primary vga device, defined in device.c
-#endif
 
 static void amdfam10_create_vga_resource(device_t dev, unsigned nodeid)
 {
-       unsigned link;
+       struct bus *link;
 
        /* find out which link the VGA card is connected,
         * we only deal with the 'first' vga card */
-       for (link = 0; link < dev->links; link++) {
-               if (dev->link[link].bridge_ctrl & PCI_BRIDGE_CTL_VGA) {
-#if CONFIG_CONSOLE_VGA_MULTI == 1
-                       printk(BIOS_DEBUG, "VGA: vga_pri bus num = %d dev->link[link] bus range [%d,%d]\n", vga_pri->bus->secondary,
-                               dev->link[link].secondary,dev->link[link].subordinate);
+       for (link = dev->link_list; link; link = link->next) {
+               if (link->bridge_ctrl & PCI_BRIDGE_CTL_VGA) {
+#if CONFIG_MULTIPLE_VGA_ADAPTERS == 1
+                       extern device_t vga_pri; // the primary vga device, defined in device.c
+                       printk(BIOS_DEBUG, "VGA: vga_pri bus num = %d bus range [%d,%d]\n", vga_pri->bus->secondary,
+                               link->secondary,link->subordinate);
                        /* We need to make sure the vga_pri is under the link */
-                       if((vga_pri->bus->secondary >= dev->link[link].secondary ) &&
-                               (vga_pri->bus->secondary <= dev->link[link].subordinate )
+                       if((vga_pri->bus->secondary >= link->secondary ) &&
+                               (vga_pri->bus->secondary <= link->subordinate )
                        )
 #endif
                        break;
@@ -572,16 +576,17 @@ static void amdfam10_create_vga_resource(device_t dev, unsigned nodeid)
        }
 
        /* no VGA card installed */
-       if (link == dev->links)
+       if (link == NULL)
                return;
 
-       printk(BIOS_DEBUG, "VGA: %s (aka node %d) link %d has VGA device\n", dev_path(dev), nodeid, link);
-       set_vga_enable_reg(nodeid, link);
+       printk(BIOS_DEBUG, "VGA: %s (aka node %d) link %d has VGA device\n", dev_path(dev), nodeid, link->link_num);
+       set_vga_enable_reg(nodeid, link->link_num);
 }
 
 static void amdfam10_set_resources(device_t dev)
 {
-       u32 nodeid, link;
+       unsigned nodeid;
+       struct bus *bus;
        struct resource *res;
 
        /* Find the nodeid */
@@ -594,21 +599,13 @@ static void amdfam10_set_resources(device_t dev)
                amdfam10_set_resource(dev, res, nodeid);
        }
 
-       for(link = 0; link < dev->links; link++) {
-               struct bus *bus;
-               bus = &dev->link[link];
+       for(bus = dev->link_list; bus; bus = bus->next) {
                if (bus->children) {
                        assign_resources(bus);
                }
        }
 }
 
-static void amdfam10_enable_resources(device_t dev)
-{
-       pci_dev_enable_resources(dev);
-       enable_childrens_resources(dev);
-}
-
 static void mcf0_control_init(struct device *dev)
 {
 }
@@ -616,7 +613,7 @@ static void mcf0_control_init(struct device *dev)
 static struct device_operations northbridge_operations = {
        .read_resources   = amdfam10_read_resources,
        .set_resources    = amdfam10_set_resources,
-       .enable_resources = amdfam10_enable_resources,
+       .enable_resources = pci_dev_enable_resources,
        .init             = mcf0_control_init,
        .scan_bus         = amdfam10_scan_chains,
        .enable           = 0,
@@ -672,55 +669,36 @@ static void amdfam10_domain_read_resources(device_t dev)
 #if CONFIG_PCI_64BIT_PREF_MEM == 0
        pci_domain_read_resources(dev);
 #else
-       unsigned link;
+       struct bus *link;
        struct resource *resource;
-       for(link=0; link<dev->links; link++) {
+       for(link=dev->link_list; link; link = link->next) {
                /* Initialize the system wide io space constraints */
-               resource = new_resource(dev, 0|(link<<2));
+               resource = new_resource(dev, 0|(link->link_num<<2));
                resource->base  = 0x400;
                resource->limit = 0xffffUL;
                resource->flags = IORESOURCE_IO;
 
                /* Initialize the system wide prefetchable memory resources constraints */
-               resource = new_resource(dev, 1|(link<<2));
+               resource = new_resource(dev, 1|(link->link_num<<2));
                resource->limit = 0xfcffffffffULL;
                resource->flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
 
                /* Initialize the system wide memory resources constraints */
-               resource = new_resource(dev, 2|(link<<2));
+               resource = new_resource(dev, 2|(link->link_num<<2));
                resource->limit = 0xfcffffffffULL;
                resource->flags = IORESOURCE_MEM;
        }
 #endif
+#if CONFIG_MMCONF_SUPPORT
+       struct resource *res = new_resource(dev, 0xc0010058);
+       res->base = CONFIG_MMCONF_BASE_ADDRESS;
+       res->size = CONFIG_MMCONF_BUS_NUMBER * 4096*256;
+       res->flags = IORESOURCE_MEM | IORESOURCE_RESERVE |
+               IORESOURCE_FIXED | IORESOURCE_STORED |  IORESOURCE_ASSIGNED;
+#endif
 }
 
-static void ram_resource(device_t dev, unsigned long index,
-       resource_t basek, resource_t sizek)
-{
-       struct resource *resource;
-
-       if (!sizek) {
-               return;
-       }
-       resource = new_resource(dev, index);
-       resource->base = basek << 10;
-       resource->size = sizek << 10;
-       resource->flags =  IORESOURCE_MEM | IORESOURCE_CACHEABLE | \
-               IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED;
-}
-
-static void tolm_test(void *gp, struct device *dev, struct resource *new)
-{
-       struct resource **best_p = gp;
-       struct resource *best;
-       best = *best_p;
-       if (!best || (best->base > new->base)) {
-               best = new;
-       }
-       *best_p = best;
-}
-
-static u32 find_pci_tolm(struct bus *bus, u32 tolm)
+static u32 my_find_pci_tolm(struct bus *bus, u32 tolm)
 {
        struct resource *min;
        min = 0;
@@ -868,8 +846,23 @@ static void disable_hoist_memory(unsigned long hole_startk, int node_id)
 #endif
 
 #if CONFIG_WRITE_HIGH_TABLES==1
-#define HIGH_TABLES_SIZE 64    // maximum size of high tables in KB
-extern uint64_t high_tables_base, high_tables_size;
+#include <cbmem.h>
+#endif
+
+#if CONFIG_GFXUMA == 1
+extern uint64_t uma_memory_base, uma_memory_size;
+
+static void add_uma_resource(struct device *dev, int index)
+{
+       struct resource *resource;
+
+       printk(BIOS_DEBUG, "Adding UMA memory area\n");
+       resource = new_resource(dev, index);
+       resource->base = (resource_t) uma_memory_base;
+       resource->size = (resource_t) uma_memory_size;
+       resource->flags = IORESOURCE_MEM | IORESOURCE_RESERVE |
+           IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED;
+}
 #endif
 
 static void amdfam10_domain_set_resources(device_t dev)
@@ -881,7 +874,7 @@ static void amdfam10_domain_set_resources(device_t dev)
        unsigned long mmio_basek;
        u32 pci_tolm;
        int i, idx;
-       u32 link;
+       struct bus *link;
 #if CONFIG_HW_MEM_HOLE_SIZEK != 0
        struct hw_mem_hole_info mem_hole;
        u32 reset_memhole = 1;
@@ -889,12 +882,12 @@ static void amdfam10_domain_set_resources(device_t dev)
 
 #if CONFIG_PCI_64BIT_PREF_MEM == 1
 
-       for(link = 0; link < dev->links; link++) {
+       for(link = dev->link_list; link; link = link->next) {
                /* Now reallocate the pci resources memory with the
                 * highest addresses I can manage.
                 */
-               mem1 = find_resource(dev, 1|(link<<2));
-               mem2 = find_resource(dev, 2|(link<<2));
+               mem1 = find_resource(dev, 1|(link->link_num<<2));
+               mem2 = find_resource(dev, 2|(link->link_num<<2));
 
                printk(BIOS_DEBUG, "base1: 0x%08Lx limit1: 0x%08Lx size: 0x%08Lx align: %d\n",
                        mem1->base, mem1->limit, mem1->size, mem1->align);
@@ -939,8 +932,8 @@ static void amdfam10_domain_set_resources(device_t dev)
 #endif
 
        pci_tolm = 0xffffffffUL;
-       for(link = 0; link<dev->links; link++) {
-               pci_tolm = find_pci_tolm(&dev->link[link], pci_tolm);
+       for(link = dev->link_list; link; link = link->next) {
+               pci_tolm = my_find_pci_tolm(link, pci_tolm);
        }
 
        // FIXME handle interleaved nodes. If you fix this here, please fix
@@ -1043,10 +1036,14 @@ static void amdfam10_domain_set_resources(device_t dev)
 #if CONFIG_WRITE_HIGH_TABLES==1
                                        if (high_tables_base==0) {
                                        /* Leave some space for ACPI, PIRQ and MP tables */
-                                               high_tables_base = (mmio_basek - HIGH_TABLES_SIZE) * 1024;
-                                               high_tables_size = HIGH_TABLES_SIZE * 1024;
-                                               printk(BIOS_DEBUG, " split: %dK table at =%08llx\n", HIGH_TABLES_SIZE,
-                                                            high_tables_base);
+#if CONFIG_GFXUMA == 1
+                                               high_tables_base = uma_memory_base - HIGH_MEMORY_SIZE;
+#else
+                                               high_tables_base = (mmio_basek * 1024) - HIGH_MEMORY_SIZE;
+#endif
+                                               high_tables_size = HIGH_MEMORY_SIZE;
+                                               printk(BIOS_DEBUG, " split: %dK table at =%08llx\n",
+                                                       HIGH_MEMORY_SIZE / 1024, high_tables_base);
                                        }
 #endif
                                }
@@ -1071,6 +1068,12 @@ static void amdfam10_domain_set_resources(device_t dev)
                                sizek -= (4*1024*1024 - mmio_basek);
                        }
                }
+
+#if CONFIG_GFXUMA == 1
+               /* Deduct uma memory before reporting because
+                * this is what the mtrr code expects */
+               sizek -= uma_memory_size / 1024;
+#endif
                ram_resource(dev, (idx | i), basek, sizek);
                idx += 0x10;
 #if CONFIG_WRITE_HIGH_TABLES==1
@@ -1078,17 +1081,23 @@ static void amdfam10_domain_set_resources(device_t dev)
                             i, mmio_basek, basek, limitk);
                if (high_tables_base==0) {
                /* Leave some space for ACPI, PIRQ and MP tables */
-                       high_tables_base = (limitk - HIGH_TABLES_SIZE) * 1024;
-                       high_tables_size = HIGH_TABLES_SIZE * 1024;
+#if CONFIG_GFXUMA == 1
+                       high_tables_base = uma_memory_base - HIGH_MEMORY_SIZE;
+#else
+                       high_tables_base = (limitk * 1024) - HIGH_MEMORY_SIZE;
+#endif
+                       high_tables_size = HIGH_MEMORY_SIZE;
                }
 #endif
        }
 
-       for(link = 0; link < dev->links; link++) {
-               struct bus *bus;
-               bus = &dev->link[link];
-               if (bus->children) {
-                       assign_resources(bus);
+#if CONFIG_GFXUMA == 1
+       add_uma_resource(dev, 7);
+#endif
+
+       for(link = dev->link_list; link; link = link->next) {
+               if (link->children) {
+                       assign_resources(link);
                }
        }
 }
@@ -1097,6 +1106,7 @@ static u32 amdfam10_domain_scan_bus(device_t dev, u32 max)
 {
        u32 reg;
        int i;
+       struct bus *link;
        /* Unmap all of the HT chains */
        for(reg = 0xe0; reg <= 0xec; reg += 4) {
                f1_write_config32(reg, 0);
@@ -1114,8 +1124,8 @@ static u32 amdfam10_domain_scan_bus(device_t dev, u32 max)
 #endif
 
 
-       for(i = 0; i < dev->links; i++) {
-               max = pci_scan_bus(&dev->link[i], PCI_DEVFN(CONFIG_CDB, 0), 0xff, max);
+       for(link = dev->link_list; link; link = link->next) {
+               max = pci_scan_bus(link, PCI_DEVFN(CONFIG_CDB, 0), 0xff, max);
        }
 
        /* Tune the hypertransport transaction for best performance.
@@ -1129,12 +1139,12 @@ static u32 amdfam10_domain_scan_bus(device_t dev, u32 max)
                        u32 httc;
                        httc = pci_read_config32(f0_dev, HT_TRANSACTION_CONTROL);
                        httc &= ~HTTC_RSP_PASS_PW;
-                       if (!dev->link[0].disable_relaxed_ordering) {
+                       if (!dev->link_list->disable_relaxed_ordering) {
                                httc |= HTTC_RSP_PASS_PW;
                        }
                        printk(BIOS_SPEW, "%s passpw: %s\n",
                                dev_path(dev),
-                               (!dev->link[0].disable_relaxed_ordering)?
+                               (!dev->link_list->disable_relaxed_ordering)?
                                "enabled":"disabled");
                        pci_write_config32(f0_dev, HT_TRANSACTION_CONTROL, httc);
                }
@@ -1145,8 +1155,8 @@ static u32 amdfam10_domain_scan_bus(device_t dev, u32 max)
 static struct device_operations pci_domain_ops = {
        .read_resources   = amdfam10_domain_read_resources,
        .set_resources    = amdfam10_domain_set_resources,
-       .enable_resources = enable_childrens_resources,
-       .init             = 0,
+       .enable_resources = NULL,
+       .init             = NULL,
        .scan_bus         = amdfam10_domain_scan_bus,
 #if CONFIG_MMCONF_SUPPORT_DEFAULT
        .ops_pci_bus      = &pci_ops_mmconf,
@@ -1197,6 +1207,42 @@ static void sysconf_init(device_t dev) // first node
 #endif
 }
 
+static void add_more_links(device_t dev, unsigned total_links)
+{
+       struct bus *link, *last = NULL;
+       int link_num;
+
+       for (link = dev->link_list; link; link = link->next)
+               last = link;
+
+       if (last) {
+               int links = total_links - last->link_num;
+               link_num = last->link_num;
+               if (links > 0) {
+                       link = malloc(links*sizeof(*link));
+                       if (!link)
+                               die("Couldn't allocate more links!\n");
+                       memset(link, 0, links*sizeof(*link));
+                       last->next = link;
+               }
+       }
+       else {
+               link_num = -1;
+               link = malloc(total_links*sizeof(*link));
+               memset(link, 0, total_links*sizeof(*link));
+               dev->link_list = link;
+       }
+
+       for (link_num = link_num + 1; link_num < total_links; link_num++) {
+               link->link_num = link_num;
+               link->dev = dev;
+               link->next = link + 1;
+               last = link;
+               link = link->next;
+       }
+       last->next = NULL;
+}
+
 static u32 cpu_bus_scan(device_t dev, u32 max)
 {
        struct bus *cpu_bus;
@@ -1250,7 +1296,7 @@ static u32 cpu_bus_scan(device_t dev, u32 max)
                        printk(BIOS_DEBUG, "%s found\n", dev_path(dev_mc));
                        pci_domain = dev_mc->bus->dev;
                        if(pci_domain && (pci_domain->path.type == DEVICE_PATH_PCI_DOMAIN)) {
-                               if((pci_domain->links==1) && (pci_domain->link[0].children == dev_mc)) {
+                               if((pci_domain->link_list) && (pci_domain->link_list->children == dev_mc)) {
                                        printk(BIOS_DEBUG, "%s move to ",dev_path(dev_mc));
                                        dev_mc->bus->secondary = CONFIG_CBB; // move to 0xff
                                        printk(BIOS_DEBUG, "%s\n",dev_path(dev_mc));
@@ -1279,18 +1325,19 @@ static u32 cpu_bus_scan(device_t dev, u32 max)
 
 #if CONFIG_CBB && (NODE_NUMS > 32)
        if(nodes>32) { // need to put node 32 to node 63 to bus 0xfe
-               if(pci_domain->links==1) {
-                       pci_domain->links++; // from 1 to 2
-                       pci_domain->link[1].link = 1;
-                       pci_domain->link[1].dev = pci_domain;
-                       pci_domain->link[1].children = 0;
-                       printk(BIOS_DEBUG, "%s links increase to %d\n", dev_path(pci_domain), pci_domain->links);
+               if(pci_domain->link_list && !pci_domain->link_list->next) {
+                       struct bus *new_link = new_link(pci_domain);
+                       pci_domain->link_list->next = new_link;
+                       new_link->link_num = 1;
+                       new_link->dev = pci_domain;
+                       new_link->children = 0;
+                       printk(BIOS_DEBUG, "%s links now 2\n", dev_path(pci_domain));
                }
-               pci_domain->link[1].secondary = CONFIG_CBB - 1;
+               pci_domain->link_list->next->secondary = CONFIG_CBB - 1;
        }
 #endif
        /* Find which cpus are present */
-       cpu_bus = &dev->link[0];
+       cpu_bus = dev->link_list;
        for(i = 0; i < nodes; i++) {
                device_t cdb_dev, cpu;
                struct device_path cpu_path;
@@ -1304,7 +1351,7 @@ static u32 cpu_bus_scan(device_t dev, u32 max)
                if(i>=32) {
                        busn--;
                        devn-=32;
-                       pbus = &(pci_domain->link[1]);
+                       pbus = pci_domain->link_list->next);
                }
 #endif
 
@@ -1325,21 +1372,13 @@ static u32 cpu_bus_scan(device_t dev, u32 max)
                        /* Ok, We need to set the links for that device.
                         * otherwise the device under it will not be scanned
                         */
-                       int link;
                        int linknum;
 #if CONFIG_HT3_SUPPORT==1
                        linknum = 8;
 #else
                        linknum = 4;
 #endif
-                       if (cdb_dev->links < linknum) {
-                               for(link=cdb_dev->links; link<linknum; link++) {
-                                        cdb_dev->link[link].link = link;
-                                        cdb_dev->link[link].dev = cdb_dev;
-                               }
-                               cdb_dev->links = linknum;
-                               printk(BIOS_DEBUG, "%s links increase to %d\n", dev_path(cdb_dev), cdb_dev->links);
-                       }
+                       add_more_links(cdb_dev, linknum);
                }
 
                cores_found = 0; // one core
@@ -1410,16 +1449,33 @@ static u32 cpu_bus_scan(device_t dev, u32 max)
 
 static void cpu_bus_init(device_t dev)
 {
-       initialize_cpus(&dev->link[0]);
+       initialize_cpus(dev->link_list);
+#if CONFIG_SOUTHBRIDGE_AMD_CIMX_SB800 || CONFIG_SOUTHBRIDGE_AMD_CIMX_SB900
+       sb_After_Pci_Init();
+       sb_Mid_Post_Init();
+#endif
 }
 
 static void cpu_bus_noop(device_t dev)
 {
 }
 
+static void cpu_bus_read_resources(device_t dev)
+{
+}
+
+static void cpu_bus_set_resources(device_t dev)
+{
+       struct resource *resource = find_resource(dev, 0xc0010058);
+       if (resource) {
+               report_resource_stored(dev, resource, " <mmconfig>");
+       }
+       pci_dev_set_resources(dev);
+}
+
 static struct device_operations cpu_bus_ops = {
-       .read_resources   = cpu_bus_noop,
-       .set_resources    = cpu_bus_noop,
+       .read_resources   = cpu_bus_read_resources,
+       .set_resources    = cpu_bus_set_resources,
        .enable_resources = cpu_bus_noop,
        .init             = cpu_bus_init,
        .scan_bus         = cpu_bus_scan,