+static void tolm_test(void *gp, struct device *dev, struct resource *new)
+{
+ struct resource **best_p = gp;
+ struct resource *best;
+ best = *best_p;
+ /* Skip VGA. */
+ if (!best || (best->base > new->base && new->base > 0xa0000)) {
+ best = new;
+ }
+ *best_p = best;
+}
+
+static uint32_t find_pci_tolm(struct bus *bus)
+{
+ struct resource *min;
+ uint32_t tolm;
+ min = 0;
+ search_bus_resources(bus, IORESOURCE_MEM, IORESOURCE_MEM, tolm_test, &min);
+ tolm = 0xffffffffUL;
+ if (min && tolm > min->base) {
+ tolm = min->base;
+ }
+ return tolm;
+}
+
+#if CONFIG_HW_MEM_HOLE_SIZEK != 0
+
+struct hw_mem_hole_info {
+ unsigned hole_startk;
+ int node_id;
+};
+
+static struct hw_mem_hole_info get_hw_mem_hole_info(void)
+{
+ struct hw_mem_hole_info mem_hole;
+ int i;
+
+ mem_hole.hole_startk = CONFIG_HW_MEM_HOLE_SIZEK;
+ mem_hole.node_id = -1;
+
+ for (i = 0; i < fx_devs; i++) {
+ uint32_t base;
+ uint32_t hole;
+ base = f1_read_config32(0x40 + (i << 3));
+ if ((base & ((1<<1)|(1<<0))) != ((1<<1)|(1<<0))) {
+ continue;
+ }
+
+ hole = pci_read_config32(__f1_dev[i], 0xf0);
+ if(hole & 1) { // we find the hole
+ mem_hole.hole_startk = (hole & (0xff<<24)) >> 10;
+ mem_hole.node_id = i; // record the node No with hole
+ break; // only one hole
+ }
+ }
+
+ //We need to double check if there is speical set on base reg and limit reg are not continous instead of hole, it will find out it's hole_startk
+ if(mem_hole.node_id==-1) {
+ uint32_t limitk_pri = 0;
+ for(i=0; i<8; i++) {
+ uint32_t base, limit;
+ unsigned base_k, limit_k;
+ base = f1_read_config32(0x40 + (i << 3));
+ if ((base & ((1<<1)|(1<<0))) != ((1<<1)|(1<<0))) {
+ continue;
+ }
+
+ base_k = (base & 0xffff0000) >> 2;
+ if(limitk_pri != base_k) { // we find the hole
+ mem_hole.hole_startk = limitk_pri;
+ mem_hole.node_id = i;
+ break; //only one hole
+ }
+
+ limit = f1_read_config32(0x44 + (i << 3));
+ limit_k = ((limit + 0x00010000) & 0xffff0000) >> 2;
+ limitk_pri = limit_k;
+ }
+ }
+
+ return mem_hole;
+
+}
+
+static void disable_hoist_memory(unsigned long hole_startk, int node_id)
+{
+ int i;
+ device_t dev;
+ uint32_t base, limit;
+ uint32_t hoist;
+ uint32_t hole_sizek;
+
+
+ //1. find which node has hole
+ //2. change limit in that node.
+ //3. change base and limit in later node
+ //4. clear that node f0
+
+ //if there is not mem hole enabled, we need to change it's base instead
+
+ hole_sizek = (4*1024*1024) - hole_startk;
+
+ for(i=7;i>node_id;i--) {
+
+ base = f1_read_config32(0x40 + (i << 3));
+ if ((base & ((1<<1)|(1<<0))) != ((1<<1)|(1<<0))) {
+ continue;
+ }
+ limit = f1_read_config32(0x44 + (i << 3));
+ f1_write_config32(0x44 + (i << 3),limit - (hole_sizek << 2));
+ f1_write_config32(0x40 + (i << 3),base - (hole_sizek << 2));
+ }
+ limit = f1_read_config32(0x44 + (node_id << 3));
+ f1_write_config32(0x44 + (node_id << 3),limit - (hole_sizek << 2));
+ dev = __f1_dev[node_id];
+ if (dev == NULL) {
+ printk_err("%s: node %x is NULL!\n", __func__, node_id);
+ return;
+ }
+ hoist = pci_read_config32(dev, 0xf0);
+ if(hoist & 1)
+ pci_write_config32(dev, 0xf0, 0);
+ else {
+ base = pci_read_config32(dev, 0x40 + (node_id << 3));
+ f1_write_config32(0x40 + (node_id << 3),base - (hole_sizek << 2));
+ }
+}
+
+static uint32_t hoist_memory(unsigned long hole_startk, int node_id)