1201_ht_bus0_dev0_fidvid_core.diff
[coreboot.git] / src / northbridge / amd / amdk8 / incoherent_ht.c
index bdb2676e39c75c1bda57b79202ee30124de59602..02a0c2dccd3b06563c78c5e7759af2597f2c600e 100644 (file)
@@ -1,17 +1,12 @@
 /*
        This should be done by Eric
        2004.12 yhlu add multi ht chain dynamically support
-
+       2005.11 yhlu add let real sb to use small unitid
 */
 #include <device/pci_def.h>
 #include <device/pci_ids.h>
 #include <device/hypertransport_def.h>
 
-
-/* We can reduce the size of code generated by romcc by
- * changing all of the fixed size types that live in registers
- * into simple unsigned variables. (ie s/uint8_t/unsigned/g)
- */
 #ifndef K8_HT_FREQ_1G_SUPPORT
         #define K8_HT_FREQ_1G_SUPPORT 0
 #endif
        #define K8_SCAN_PCI_BUS 0
 #endif
 
+#ifndef K8_ALLOCATE_IO_RANGE
+        #define K8_ALLOCATE_IO_RANGE 0
+#endif
+
+// Do we need allocate MMIO? Current We direct last 64M to sblink only, We can not lose access to last 4M range to ROM 
+#ifndef K8_ALLOCATE_MMIO_RANGE
+        #define K8_ALLOCATE_MMIO_RANGE 0
+#endif
+
 static inline void print_linkn_in (const char *strval, uint8_t byteval)
 {
-#if 1
 #if CONFIG_USE_INIT
         printk_debug("%s%02x\r\n", strval, byteval); 
 #else
         print_debug(strval); print_debug_hex8(byteval); print_debug("\r\n");
 #endif
-#endif
 }
 
 static uint8_t ht_lookup_capability(device_t dev, uint16_t val)
@@ -74,18 +76,27 @@ static uint8_t ht_lookup_host_capability(device_t dev)
         return ht_lookup_capability(dev, 1); // Host/Secondary Interface Block Format
 }
 
-static void ht_collapse_previous_enumeration(uint8_t bus)
+static void ht_collapse_previous_enumeration(uint8_t bus, unsigned offset_unitid)
 {
        device_t dev;
        uint32_t id;
 
+       //actually, only for one HT device HT chain, and unitid is 0
+#if HT_CHAIN_UNITID_BASE == 0
+       if(offset_unitid) {
+               return;
+       }
+#endif
+
        /* Check if is already collapsed */
-       dev = PCI_DEV(bus, 0, 0);
-        id = pci_read_config32(dev, PCI_VENDOR_ID);
-        if ( ! ( (id == 0xffffffff) || (id == 0x00000000) ||
-            (id == 0x0000ffff) || (id == 0xffff0000) ) ) {
-                     return;
-        }
+       if((!offset_unitid) || (offset_unitid && (!((HT_CHAIN_END_UNITID_BASE == 0) && (HT_CHAIN_END_UNITID_BASE <HT_CHAIN_UNITID_BASE))))) {
+               dev = PCI_DEV(bus, 0, 0);
+               id = pci_read_config32(dev, PCI_VENDOR_ID);
+               if ( ! ( (id == 0xffffffff) || (id == 0x00000000) ||
+                   (id == 0x0000ffff) || (id == 0xffff0000) ) ) {
+                            return;
+               }
+       } 
 
        /* Spin through the devices and collapse any previous
         * hypertransport enumeration.
@@ -136,21 +147,24 @@ static uint16_t ht_read_freq_cap(device_t dev, uint8_t pos)
        /* AMD 8131 Errata 48 */
        if (id == (PCI_VENDOR_ID_AMD | (PCI_DEVICE_ID_AMD_8131_PCIX << 16))) {
                freq_cap &= ~(1 << HT_FREQ_800Mhz);
-       } 
+               return freq_cap;
+       }
 
        /* AMD 8151 Errata 23 */
        if (id == (PCI_VENDOR_ID_AMD | (PCI_DEVICE_ID_AMD_8151_SYSCTRL << 16))) {
                freq_cap &= ~(1 << HT_FREQ_800Mhz);
+               return freq_cap;
        } 
        
        /* AMD K8 Unsupported 1Ghz? */
        if (id == (PCI_VENDOR_ID_AMD | (0x1100 << 16))) {
-#if K8_HT_FREQ_1G_SUPPORT == 1
-               /* Supported starting with E0 */
-               device_t dev_2 = PCI_DEV(0,0x18,2);
-               if(pci_read_config32(dev_2,0x9c) < 0x20f00) 
-#endif
+       #if K8_HT_FREQ_1G_SUPPORT == 1 
+               if (is_cpu_pre_e0()) {  // only E0 later support 1GHz
                        freq_cap &= ~(1 << HT_FREQ_1000Mhz);
+               }
+       #else   
+                freq_cap &= ~(1 << HT_FREQ_1000Mhz);
+       #endif
        }
 
        return freq_cap;
@@ -236,6 +250,7 @@ static int ht_optimize_link(
 
        /* See if I am changing dev1's width */
        old_width = pci_read_config8(dev1, pos1 + LINK_WIDTH(offs1) + 1);
+       old_width &= 0x77;
        needs_reset |= old_width != width;
 
        /* Set dev1's widths */
@@ -246,6 +261,7 @@ static int ht_optimize_link(
 
        /* See if I am changing dev2's width */
        old_width = pci_read_config8(dev2, pos2 + LINK_WIDTH(offs2) + 1);
+       old_width &= 0x77;
        needs_reset |= old_width != width;
 
        /* Set dev2's widths */
@@ -254,8 +270,14 @@ static int ht_optimize_link(
        return needs_reset;
 }
 #if (USE_DCACHE_RAM == 1) && (K8_SCAN_PCI_BUS == 1)
-static int ht_setup_chainx(device_t udev, uint8_t upos, uint8_t bus);
-static int scan_pci_bus( unsigned bus) 
+
+#if RAMINIT_SYSINFO == 1
+static void ht_setup_chainx(device_t udev, uint8_t upos, uint8_t bus, unsigned offset_unitid, struct sys_info *sysinfo);
+static int scan_pci_bus( unsigned bus , struct sys_info *sysinfo) 
+#else
+static int ht_setup_chainx(device_t udev, uint8_t upos, uint8_t bus, unsigned offset_unitid);
+static int scan_pci_bus( unsigned bus)
+#endif
 {
         /*      
                 here we already can access PCI_DEV(bus, 0, 0) to PCI_DEV(bus, 0x1f, 0x7)
@@ -324,24 +346,30 @@ static int scan_pci_bus( unsigned bus)
                                        ((unsigned int) max_bus << 16));
                                pci_write_config32(dev, PCI_PRIMARY_BUS, buses);
                                
-                               {
                                /* here we need to figure out if dev is a ht bridge
                                        if it is ht bridge, we need to call ht_setup_chainx at first
                                   Not verified --- yhlu
                                */
-                                       uint8_t upos;
-                                       upos = ht_lookup_host_capability(dev); // one func one ht sub
-                                       if (upos) { // sub ht chain
-                                               uint8_t busn;
-                                               busn = (new_bus & 0xff);
-                                               /* Make certain the HT bus is not enumerated */
-                                               ht_collapse_previous_enumeration(busn);
-                                               /* scan the ht chain */
-                                               new_bus |= (ht_setup_chainx(dev,upos,busn)<<16); // store reset_needed to upword
-                                       }
-                               }
+                               uint8_t upos;
+                               upos = ht_lookup_host_capability(dev); // one func one ht sub
+                               if (upos) { // sub ht chain
+                                       uint8_t busn;
+                                       busn = (new_bus & 0xff);
+                                       /* Make certain the HT bus is not enumerated */
+                                       ht_collapse_previous_enumeration(busn, 0);
+                                       /* scan the ht chain */
+                                       #if RAMINIT_SYSINFO == 1
+                                       ht_setup_chainx(dev,upos,busn, 0, sysinfo); // don't need offset unitid
+                                       #else
+                                       new_bus |= (ht_setup_chainx(dev, upos, busn, 0)<<16); // store reset_needed to upword
+                                       #endif
+                               }
                                
+                               #if RAMINIT_SYSINFO == 1                                
+                               new_bus = scan_pci_bus(new_bus, sysinfo);
+                               #else
                                new_bus = scan_pci_bus(new_bus);
+                               #endif
                                /* set real max bus num in that */
 
                                buses = (buses & 0xff00ffff) |
@@ -370,14 +398,31 @@ static int scan_pci_bus( unsigned bus)
        return new_bus; 
 }
 #endif
-static int ht_setup_chainx(device_t udev, uint8_t upos, uint8_t bus)
+
+#if RAMINIT_SYSINFO == 1
+static void ht_setup_chainx(device_t udev, uint8_t upos, uint8_t bus, unsigned offset_unitid, struct sys_info *sysinfo)
+#else
+static int ht_setup_chainx(device_t udev, uint8_t upos, uint8_t bus, unsigned offset_unitid)
+#endif
 {
+       //even HT_CHAIN_UNITID_BASE == 0, we still can go through this function, because of end_of_chain check, also We need it to optimize link
+
        uint8_t next_unitid, last_unitid;
        unsigned uoffs;
-       int reset_needed=0;
+
+#if RAMINIT_SYSINFO == 0
+       int reset_needed = 0;
+#endif
+
+#if HT_CHAIN_END_UNITID_BASE < HT_CHAIN_UNITID_BASE
+        //let't record the device of last ht device, So we can set the Unitid to HT_CHAIN_END_UNITID_BASE
+        unsigned real_last_unitid;
+        uint8_t real_last_pos;
+       int ht_dev_num = 0;
+#endif
 
        uoffs = PCI_HT_HOST_OFFS;
-       next_unitid = 1;
+       next_unitid = (offset_unitid) ? HT_CHAIN_UNITID_BASE:1;
 
        do {
                uint32_t id;
@@ -391,11 +436,24 @@ static int ht_setup_chainx(device_t udev, uint8_t upos, uint8_t bus)
                        ctrl = pci_read_config16(udev, upos + LINK_CTRL(uoffs));
                        /* Is this the end of the hypertransport chain? */
                        if (ctrl & (1 << 6)) {
-                               break;
+                               goto end_of_chain;      
                        }
-                       /* Has the link failed */
-                       if (ctrl & (1 << 4)) {
-                               break;
+
+                       if (ctrl & ((1 << 4) | (1 << 8))) {
+                               /*
+                               * Either the link has failed, or we have
+                                * a CRC error.
+                                * Sometimes this can happen due to link
+                                * retrain, so lets knock it down and see
+                                * if its transient
+                                */
+                               ctrl |= ((1 << 6) | (1 <<8)); // Link fail + Crc
+                                pci_write_config16(udev, upos + LINK_CTRL(uoffs), ctrl);
+                                ctrl = pci_read_config16(udev, upos + LINK_CTRL(uoffs));
+                                if (ctrl & ((1 << 4) | (1 << 8))) {
+                                       print_err("Detected error on Hypertransport Link\n");
+                                       break;
+                                }
                        }
                } while((ctrl & (1 << 5)) == 0);
        
@@ -413,7 +471,10 @@ static int ht_setup_chainx(device_t udev, uint8_t upos, uint8_t bus)
 
                pos = ht_lookup_slave_capability(dev);
                if (!pos) {
-                       print_err("HT link capability not found\r\n");
+                        print_err("udev="); print_err_hex32(udev);
+                        print_err("\tupos="); print_err_hex32(upos);
+                        print_err("\tuoffs="); print_err_hex32(uoffs);
+                       print_err("\tHT link capability not found\r\n");
                        break;
                }
 
@@ -441,6 +502,14 @@ static int ht_setup_chainx(device_t udev, uint8_t upos, uint8_t bus)
 
                 /* Compute the number of unitids consumed */
                 count = (flags >> 5) & 0x1f;
+#if HT_CHAIN_END_UNITID_BASE < HT_CHAIN_UNITID_BASE
+               if(offset_unitid) {
+                       real_last_unitid = next_unitid;
+                       real_last_pos = pos;
+                       ht_dev_num++;
+               }
+#endif
+
                 next_unitid += count;
 
                /* Find which side of the ht link we are on,
@@ -449,9 +518,22 @@ static int ht_setup_chainx(device_t udev, uint8_t upos, uint8_t bus)
                 */
                flags = pci_read_config16(dev, pos + PCI_CAP_FLAGS);
                 offs = ((flags>>10) & 1) ? PCI_HT_SLAVE1_OFFS : PCI_HT_SLAVE0_OFFS;
-                
-                /* Setup the Hypertransport link */
-                reset_needed |= ht_optimize_link(udev, upos, uoffs, dev, pos, offs);
+               
+               #if RAMINIT_SYSINFO == 1
+                /* store the link pair here and we will Setup the Hypertransport link later, after we get final FID/VID */
+               {
+                       struct link_pair_st *link_pair = &sysinfo->link_pair[sysinfo->link_pair_num];
+                       link_pair->udev = udev;
+                       link_pair->upos = upos;
+                       link_pair->uoffs = uoffs;
+                       link_pair->dev = dev;
+                       link_pair->pos = pos;
+                       link_pair->offs = offs;
+                       sysinfo->link_pair_num++;
+               }
+               #else
+               reset_needed |= ht_optimize_link(udev, upos, uoffs, dev, pos, offs);
+               #endif
 
 #if CK804_DEVN_BASE==0
                if(id == 0x005e10de) {
@@ -466,11 +548,52 @@ static int ht_setup_chainx(device_t udev, uint8_t upos, uint8_t bus)
 
        } while((last_unitid != next_unitid) && (next_unitid <= 0x1f));
 
+end_of_chain: ;
+       
+#if HT_CHAIN_END_UNITID_BASE < HT_CHAIN_UNITID_BASE
+        if(offset_unitid && (ht_dev_num>0)  ) {
+                uint16_t flags;
+               int i;
+                flags = pci_read_config16(PCI_DEV(bus,real_last_unitid,0), real_last_pos + PCI_CAP_FLAGS);
+                flags &= ~0x1f;
+                flags |= HT_CHAIN_END_UNITID_BASE & 0x1f;
+                pci_write_config16(PCI_DEV(bus, real_last_unitid, 0), real_last_pos + PCI_CAP_FLAGS, flags);
+
+                #if RAMINIT_SYSINFO == 1
+               // Here need to change the dev in the array
+               for(i=0;i<sysinfo->link_pair_num;i++)
+                {
+                        struct link_pair_st *link_pair = &sysinfo->link_pair[i];
+                        if(link_pair->udev == PCI_DEV(bus, real_last_unitid, 0)) {
+                               link_pair->udev = PCI_DEV(bus, HT_CHAIN_END_UNITID_BASE, 0);
+                               continue;
+                       }
+                        if(link_pair->dev == PCI_DEV(bus, real_last_unitid, 0)) {
+                                link_pair->dev = PCI_DEV(bus, HT_CHAIN_END_UNITID_BASE, 0);
+                        }
+                }
+               #endif
+
+        }
+#endif
+
+#if RAMINIT_SYSINFO == 0
        return reset_needed;
+#endif
+
 }
 
+#if RAMINIT_SYSINFO == 1
+static void ht_setup_chain(device_t udev, unsigned upos, struct sys_info *sysinfo)
+#else
 static int ht_setup_chain(device_t udev, unsigned upos)
+#endif
 {
+       unsigned offset_unitid = 0;
+#if HT_CHAIN_UNITID_BASE != 1
+        offset_unitid = 1;
+#endif
+
         /* Assumption the HT chain that is bus 0 has the HT I/O Hub on it.
          * On most boards this just happens.  If a cpu has multiple
          * non Coherent links the appropriate bus registers for the
@@ -478,9 +601,17 @@ static int ht_setup_chain(device_t udev, unsigned upos)
          */
 
         /* Make certain the HT bus is not enumerated */
-        ht_collapse_previous_enumeration(0);
+        ht_collapse_previous_enumeration(0, 0);
 
-        return ht_setup_chainx(udev, upos, 0);
+#if HT_CHAIN_UNITID_BASE != 1
+        offset_unitid = 1;
+#endif
+
+#if RAMINIT_SYSINFO == 1
+       ht_setup_chainx(udev, upos, 0, offset_unitid, sysinfo);
+#else
+        return ht_setup_chainx(udev, upos, 0, offset_unitid);
+#endif
 }
 static int optimize_link_read_pointer(uint8_t node, uint8_t linkn, uint8_t linkt, uint8_t val)
 {
@@ -506,7 +637,7 @@ static int optimize_link_read_pointer(uint8_t node, uint8_t linkn, uint8_t linkt
        return 0;
 }
 
-static int optimize_link_in_coherent(uint8_t ht_c_num)
+static int optimize_link_read_pointers_chain(uint8_t ht_c_num)
 {
        int reset_needed; 
        uint8_t i;
@@ -541,20 +672,28 @@ static int optimize_link_in_coherent(uint8_t ht_c_num)
        return reset_needed;
 }
 
+#if RAMINIT_SYSINFO == 1
+static void ht_setup_chains(uint8_t ht_c_num, struct sys_info *sysinfo)
+#else
 static int ht_setup_chains(uint8_t ht_c_num)
+#endif
 {
        /* Assumption the HT chain that is bus 0 has the HT I/O Hub on it. 
         * On most boards this just happens.  If a cpu has multiple
         * non Coherent links the appropriate bus registers for the
         * links needs to be programed to point at bus 0.
         */
-       int reset_needed; 
         uint8_t upos;
         device_t udev;
        uint8_t i;
 
-       reset_needed = 0;
+#if RAMINIT_SYSINFO == 0
+       int reset_needed = 0;
+#else
+       sysinfo->link_pair_num = 0;
+#endif
 
+       // first one is SB Chain
        for (i = 0; i < ht_c_num; i++) {
                uint32_t reg;
                uint8_t devpos;
@@ -564,6 +703,7 @@ static int ht_setup_chains(uint8_t ht_c_num)
                #if (USE_DCACHE_RAM == 1) && (K8_SCAN_PCI_BUS == 1)
                unsigned bus;
                #endif
+               unsigned offset_unitid = 0;
                
                reg = pci_read_config32(PCI_DEV(0,0x18,1), 0xe0 + i * 4);
 
@@ -576,32 +716,57 @@ static int ht_setup_chains(uint8_t ht_c_num)
                dword &= ~(0xffff<<8);
                dword |= (reg & 0xffff0000)>>8;
                pci_write_config32( PCI_DEV(0, devpos,0), regpos , dword);
-               
+       
+
+        #if HT_CHAIN_UNITID_BASE != 1
+                #if SB_HT_CHAIN_UNITID_OFFSET_ONLY == 1
+                if(i==0) // to check if it is sb ht chain
+                #endif
+                        offset_unitid = 1;
+        #endif
+       
                /* Make certain the HT bus is not enumerated */
-               ht_collapse_previous_enumeration(busn);
+               ht_collapse_previous_enumeration(busn, offset_unitid);
 
                upos = ((reg & 0xf00)>>8) * 0x20 + 0x80;
                udev =  PCI_DEV(0, devpos, 0);
-               
-               reset_needed |= ht_setup_chainx(udev,upos,busn);
+
+#if RAMINIT_SYSINFO == 1
+               ht_setup_chainx(udev,upos,busn, offset_unitid, sysinfo); // all not
+#else
+               reset_needed |= ht_setup_chainx(udev,upos,busn, offset_unitid); //all not
+#endif
 
                #if (USE_DCACHE_RAM == 1) && (K8_SCAN_PCI_BUS == 1)
                /* You can use use this in romcc, because there is function call in romcc, recursive will kill you */
                bus = busn; // we need 32 bit 
-               reset_needed |= (scan_pci_bus(bus)>>16); // take out reset_needed that stored in upword
+#if RAMINIT_SYSINFO == 1
+               scan_pci_bus(bus, sysinfo);
+#else
+               reset_needed |= (scan_pci_bus(bus)>>16); // take out reset_needed that stored in upword
+#endif
                #endif
        }
 
-       reset_needed |= optimize_link_in_coherent(ht_c_num);            
-       
+#if RAMINIT_SYSINFO == 0
+       reset_needed |= optimize_link_read_pointers_chain(ht_c_num);
+
        return reset_needed;
+#endif
+
 }
 
-#ifndef K8_ALLOCATE_IO_RANGE 
-       #define K8_ALLOCATE_IO_RANGE 0
-#endif
+static inline unsigned get_nodes(void)
+{
+        return ((pci_read_config32(PCI_DEV(0, 0x18, 0), 0x60)>>4) & 7) + 1;
+}
 
+
+#if RAMINIT_SYSINFO == 1
+static void ht_setup_chains_x(struct sys_info *sysinfo)
+#else
 static int ht_setup_chains_x(void)
+#endif
 {               
         uint8_t nodeid;
         uint32_t reg; 
@@ -612,11 +777,18 @@ static int ht_setup_chains_x(void)
 #if K8_ALLOCATE_IO_RANGE == 1  
        unsigned next_io_base;
 #endif
-      
+
+       nodes = get_nodes();     
         /* read PCI_DEV(0,0x18,0) 0x64 bit [8:9] to find out SbLink m */
         reg = pci_read_config32(PCI_DEV(0, 0x18, 0), 0x64);
         /* update PCI_DEV(0, 0x18, 1) 0xe0 to 0x05000m03, and next_busn=0x3f+1 */
        print_linkn_in("SBLink=", ((reg>>8) & 3) );
+#if RAMINIT_SYSINFO == 1
+       sysinfo->sblnk = (reg>>8) & 3;
+       sysinfo->sbbusn = 0;
+       sysinfo->nodes = nodes;
+#endif
         tempreg = 3 | ( 0<<4) | (((reg>>8) & 3)<<8) | (0<<16)| (0x3f<<24);
         pci_write_config32(PCI_DEV(0, 0x18, 1), 0xe0, tempreg);
 
@@ -639,8 +811,6 @@ static int ht_setup_chains_x(void)
                pci_write_config32(PCI_DEV(0, 0x18, 1), 0xc0 + ht_c_num * 8, 0);
         }
  
-       nodes = ((pci_read_config32(PCI_DEV(0, 0x18, 0), 0x60)>>4) & 7) + 1;
-
         for(nodeid=0; nodeid<nodes; nodeid++) {
                 device_t dev; 
                 uint8_t linkn;
@@ -671,7 +841,7 @@ static int ht_setup_chains_x(void)
                        /* io range allocation */
                        tempreg = nodeid | (linkn<<4) |  ((next_io_base+0x3)<<12); //limit
                        pci_write_config32(PCI_DEV(0, 0x18, 1), 0xC4 + ht_c_num * 8, tempreg);
-                       tempreg = 3 | ( 3<<4) | (next_io_base<<12);        //base
+                       tempreg = 3 /*| ( 3<<4)*/ | (next_io_base<<12);        //base :ISA and VGA ?
                        pci_write_config32(PCI_DEV(0, 0x18, 1), 0xC0 + ht_c_num * 8, tempreg);
                        next_io_base += 0x3+0x1;
 #endif
@@ -717,6 +887,64 @@ static int ht_setup_chains_x(void)
                }
         }
 
-        return ht_setup_chains(i);
+#if RAMINIT_SYSINFO == 1
+       sysinfo->ht_c_num = i;
+        ht_setup_chains(i, sysinfo);
+#else
+       return ht_setup_chains(i);
+#endif
 
 }
+
+#if RAMINIT_SYSINFO == 1
+static int optimize_link_incoherent_ht(struct sys_info *sysinfo)
+{
+       // We need to use recorded link pair info to optimize the link
+       int i;
+       int reset_needed = 0;
+       
+       unsigned link_pair_num = sysinfo->link_pair_num;
+
+       for(i=0; i< link_pair_num; i++) {       
+               struct link_pair_st *link_pair= &sysinfo->link_pair[i];
+               reset_needed |= ht_optimize_link(link_pair->udev, link_pair->upos, link_pair->uoffs, link_pair->dev, link_pair->pos, link_pair->offs);
+       }
+
+       reset_needed |= optimize_link_read_pointers(sysinfo->ht_c_num);
+
+       return reset_needed;
+
+}
+#endif
+
+
+static unsigned get_sblnk(void)
+{
+        uint32_t reg;
+        /* read PCI_DEV(0,0x18,0) 0x64 bit [8:9] to find out SbLink m */
+        reg = pci_read_config32(PCI_DEV(0, 0x18, 0), 0x64);
+        return ((reg>>8) & 3) ;
+}
+
+/* Look up a which bus a given node/link combination is on.
+ * return 0 when we can't find the answer.
+ */
+static unsigned node_link_to_bus(unsigned node, unsigned link)
+{
+        unsigned reg;
+
+        for(reg = 0xE0; reg < 0xF0; reg += 0x04) {
+                unsigned config_map;
+                config_map = pci_read_config32(PCI_DEV(0, 0x18, 1), reg);
+                if ((config_map & 3) != 3) {
+                        continue;
+                }
+                if ((((config_map >> 4) & 7) == node) &&
+                        (((config_map >> 8) & 3) == link))
+                {
+                        return (config_map >> 16) & 0xff;
+                }
+        }
+        return 0;
+}
+