diff --git a/arch/x86/amd/model_fxx/dualcore_id.c b/arch/x86/amd/model_fxx/dualcore_id.c new file mode 100644 index 0000000000..05c2fa0f56 --- /dev/null +++ b/arch/x86/amd/model_fxx/dualcore_id.c @@ -0,0 +1,52 @@ +/* We need to get a unified Id that works on dual, quad, whatever. We are going to leave + * this as-is and fix later, working with AMD to improve it. + */ + +/* 2004.12 yhlu add dual core support */ + +//called by bus_cpu_scan too +unsigned int read_nb_cfg_54(void) +{ + msr_t msr; + msr = rdmsr(NB_CFG_MSR); + return ( ( msr.hi >> (54-32)) & 1); +} + +unsigned get_initial_apicid(void) +{ + return ((cpuid_ebx(1) >> 24) & 0xf); +} + +//called by amd_siblings too +#define CORE_ID_BIT 1 +#define NODE_ID_BIT 3 +struct node_core_id get_node_core_id(unsigned nb_cfg_54) +{ + struct node_core_id id; + // get the apicid via cpuid(1) ebx[27:24] + if( nb_cfg_54) { + // when NB_CFG[54] is set, nodeid = ebx[27:25], coreid = ebx[24] + id.coreid = (cpuid_ebx(1) >> 24) & 0xf; + id.nodeid = (id.coreid>>CORE_ID_BIT); + id.coreid &= ((1<> 24) & 0xf; + id.coreid = (id.nodeid>>NODE_ID_BIT); + id.nodeid &= ((1<> NBCAP_CmpCap_SHIFT) & NBCAP_CmpCap_MASK); - if(nb_cfg_54) { - if(j == 0 ) // if it is single core, we need to increase siblings for apic calculation - J = 1; - } - siblings = j; + j = ((pci_conf1_read_config32 + (PCI_BDF(0, 0x18 + i, 3), + NORTHBRIDGE_CAP) >> NBCAP_CmpCap_SHIFT) & + NBCAP_CmpCap_MASK); + if (nb_cfg_54) { + if (j == 0) // if it is single core, we need to increase siblings for apic calculation + J = 1; + } + siblings = j; - unsigned jstart, jend; + unsigned jstart, jend; - if(core_range == 2) { - jstart = 1; - } - else { + if (core_range == 2) { + jstart = 1; + } else { jstart = 0; } - if (disable_siblings || (core_range==1)) { - jend = 0; - } else { - jend = siblings; - } - - - for(j=jstart; j<=jend; j++) { + if (disable_siblings || (core_range == 1)) { + jend = 0; + } else { + jend = siblings; + } - ap_apicid = i * (nb_cfg_54?(siblings+1):1) + j * (nb_cfg_54?1:8); - #if (ENABLE_APIC_EXT_ID == 1) - #if LIFT_BSP_APIC_ID == 0 - if( (i!=0) || (j!=0)) /* except bsp */ - #endif - ap_apicid += APIC_ID_OFFSET; - #endif + for (j = jstart; j <= jend; j++) { - if(ap_apicid == bsp_apicid) continue; + ap_apicid = + i * (nb_cfg_54 ? (siblings + 1) : 1) + + j * (nb_cfg_54 ? 1 : 8); - process_ap(ap_apicid, gp); +#if (ENABLE_APIC_EXT_ID == 1) +#if LIFT_BSP_APIC_ID == 0 + if ((i != 0) || (j != 0)) /* except bsp */ +#endif + ap_apicid += APIC_ID_OFFSET; +#endif - } - } + if (ap_apicid == bsp_apicid) + continue; + + process_ap(ap_apicid, gp); + + } + } } /** @@ -169,43 +175,43 @@ static void for_each_ap(unsigned bsp_apicid, unsigned core_range, process_ap_t p */ static int lapic_remote_read(int apicid, int reg, unsigned int *pvalue) { - int timeout; - unsigned status; - int result; + int timeout; + unsigned status; + int result; /* Wait for the idle state. Could we enter this with the APIC busy? It's possible. */ - lapic_wait_icr_idle(); + lapic_wait_icr_idle(); /* The APIC Interrupt Control Registers define the operations and destinations. * In this case, we set ICR2 to the dest, set the op to REMOTE READ, and set the * reg (which is 16-bit aligned, it seems, hence the >> 4 */ - lapic_write(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid)); - lapic_write(LAPIC_ICR, LAPIC_DM_REMRD | (reg >> 4)); + lapic_write(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid)); + lapic_write(LAPIC_ICR, LAPIC_DM_REMRD | (reg >> 4)); /* it's started. now we wait. */ - timeout = 0; + timeout = 0; - do { + do { /* note here the ICR is command and status. */ /* Why don't we use the lapic_wait_icr_idle() above? */ /* That said, it's a bad idea to mess with this code too much. * APICs (and their code) are quite fragile. */ - status = lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY; - } while (status == LAPIC_ICR_BUSY && timeout++ < 1000); + status = lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY; + } while (status == LAPIC_ICR_BUSY && timeout++ < 1000); /* interesting but the timeout is not checked, hence no error on the send! */ - timeout = 0; - do { - status = lapic_read(LAPIC_ICR) & LAPIC_ICR_RR_MASK; - } while (status == LAPIC_ICR_RR_INPROG && timeout++ < 1000); + timeout = 0; + do { + status = lapic_read(LAPIC_ICR) & LAPIC_ICR_RR_MASK; + } while (status == LAPIC_ICR_RR_INPROG && timeout++ < 1000); - result = -1; - if (status == LAPIC_ICR_RR_VALID) { - *pvalue = lapic_read(LAPIC_RRR); - result = 0; - } - return result; + result = -1; + if (status == LAPIC_ICR_RR_VALID) { + *pvalue = lapic_read(LAPIC_RRR); + result = 0; + } + return result; } #define LAPIC_MSG_REG 0x380 @@ -215,16 +221,22 @@ static int lapic_remote_read(int apicid, int reg, unsigned int *pvalue) static void init_fidvid_ap(unsigned bsp_apicid, unsigned apicid); #endif -static inline __attribute__((always_inline)) void print_apicid_nodeid_coreid(unsigned apicid, struct node_core_id id, const char *str) +static inline __attribute__ ((always_inline)) +void print_apicid_nodeid_coreid(unsigned apicid, struct node_core_id id, + const char *str) { - #if CONFIG_USE_PRINTK_IN_CAR - printk_debug("%s --- { APICID = %02x NODEID = %02x COREID = %02x} ---\r\n", str, apicid, id.nodeid, id.coreid); - #else - printk(BIOS_DEBUG, str); - printk(BIOS_DEBUG, " ---- {APICID = "); print_debug_hex8(apicid); - printk(BIOS_DEBUG, " NODEID = "), print_debug_hex8(id.nodeid); printk(BIOS_DEBUG, " COREID = "), print_debug_hex8(id.coreid); - printk(BIOS_DEBUG, "} --- \r\n"); - #endif +#if CONFIG_USE_PRINTK_IN_CAR + printk_debug + ("%s --- { APICID = %02x NODEID = %02x COREID = %02x} ---\r\n", + str, apicid, id.nodeid, id.coreid); +#else + printk(BIOS_DEBUG, str); + printk(BIOS_DEBUG, " ---- {APICID = "); + print_debug_hex8(apicid); + printk(BIOS_DEBUG, " NODEID = "), print_debug_hex8(id.nodeid); + printk(BIOS_DEBUG, " COREID = "), print_debug_hex8(id.coreid); + printk(BIOS_DEBUG, "} --- \r\n"); +#endif } @@ -237,18 +249,20 @@ static inline __attribute__((always_inline)) void print_apicid_nodeid_coreid(uns */ static unsigned int wait_cpu_state(unsigned apicid, unsigned state) { - unsigned readback = 0; + unsigned readback = 0; unsigned timeout = 1; int loop = 2000000; - while(--loop>0) { - if(lapic_remote_read(apicid, LAPIC_MSG_REG, &readback)!=0) continue; - if((readback & 0xff) == state) { + while (--loop > 0) { + if (lapic_remote_read(apicid, LAPIC_MSG_REG, &readback) != + 0) + continue; + if ((readback & 0xff) == state) { timeout = 0; - break; //target cpu is in stage started + break; //target cpu is in stage started } - } - if(timeout) { - if(readback) { + } + if (timeout) { + if (readback) { timeout = readback; } } @@ -261,16 +275,15 @@ static unsigned int wait_cpu_state(unsigned apicid, unsigned state) * @param ap_apicid the apic id of the CPu * @param gp arbitrary parameter */ -static void wait_ap_started(unsigned ap_apicid, void *gp ) +static void wait_ap_started(unsigned ap_apicid, void *gp) { unsigned timeout; - timeout = wait_cpu_state(ap_apicid, 0x33); // started - if(timeout) { - print_initcpu8_nocr("*", ap_apicid); - print_initcpu("*", timeout); - } - else { - print_initcpu8_nocr(" ", ap_apicid); + timeout = wait_cpu_state(ap_apicid, 0x33); // started + if (timeout) { + print_initcpu8_nocr("*", ap_apicid); + print_initcpu("*", timeout); + } else { + print_initcpu8_nocr(" ", ap_apicid); } } @@ -280,18 +293,18 @@ static void wait_ap_started(unsigned ap_apicid, void *gp ) */ static void wait_all_aps_started(unsigned bsp_apicid) { - for_each_ap(bsp_apicid, 0 , wait_ap_started, (void *)0); + for_each_ap(bsp_apicid, 0, wait_ap_started, (void *) 0); } /** * Wait on all other cores to start. This includes cores on bsp, we think. * @param bsp_apicid The BSP APIC ID */ -static void wait_all_other_cores_started(unsigned bsp_apicid) // all aps other than core0 +static void wait_all_other_cores_started(unsigned bsp_apicid) // all aps other than core0 { - printk(BIOS_DEBUG, "started ap apicid: "); - for_each_ap(bsp_apicid, 2 , wait_ap_started, (void *)0); - printk(BIOS_DEBUG, "\r\n"); + printk(BIOS_DEBUG, "started ap apicid: "); + for_each_ap(bsp_apicid, 2, wait_ap_started, (void *) 0); + printk(BIOS_DEBUG, "\r\n"); } /** @@ -300,13 +313,13 @@ static void wait_all_other_cores_started(unsigned bsp_apicid) // all aps other t */ static void allow_all_aps_stop(unsigned bsp_apicid) { - lapic_write(LAPIC_MSG_REG, (bsp_apicid<<24) | 0x44); // allow aps to stop + lapic_write(LAPIC_MSG_REG, (bsp_apicid << 24) | 0x44); // allow aps to stop } static void STOP_CAR_AND_CPU(void) { - disable_cache_as_ram(); // inline - stop_this_cpu(); // inline, it will stop all cores except node0/core0 the bsp .... + disable_cache_as_ram(); // inline + stop_this_cpu(); // inline, it will stop all cores except node0/core0 the bsp .... } #ifndef MEM_TRAIN_SEQ @@ -315,137 +328,188 @@ static void STOP_CAR_AND_CPU(void) #if MEM_TRAIN_SEQ == 1 -static inline void train_ram_on_node(unsigned nodeid, unsigned coreid, struct sys_info *sysinfo, unsigned retcall); +static inline void train_ram_on_node(unsigned nodeid, unsigned coreid, + struct sys_info *sysinfo, + unsigned retcall); #endif -unsigned int init_cpus(unsigned cpu_init_detectedx ,struct sys_info *sysinfo) +/** + * Init all the CPUs. Part of the process involves setting APIC IDs for all cores on all sockets. The code that is run + * is for the most part the same on all cpus and cores of cpus. + * Since we only support F2 and later Opteron CPUs our job is considerably simplified + * as compared to v2. The basic process it to set up the cpu 0 core 0, then the other cpus, one by one. + * Complications: BSP, a.k.a. cpu 0, comes up with APIC id 0, the others all come up with APIC id 7, including other cpu 0 cores. + * There is also the question of the need to "lift" the BSP APIC id. For some setups, we want the BSP APIC id to be 0; for others, + * a non-zero value is preferred. This means that we have to change the BSP APIC ID on the fly. + * So here we have it, some of the slickest code you'll ever read. Which cores run this function? + * All of them. + * Do they communicate through APIC Interrupts or memory? Yes. Both. APICs before + * memory is ready, memory afterword. What is the state of the cores at the end of this function? + * They are all ready to go, just waiting to be started up. What is the state of memory on all sockets? + * It's all working. + * @param cpu_init_detectedx has this cpu been init'ed before? + * @param sysinfo The sys_info pointer + * @returns the BSP APIC ID + */ +unsigned int init_cpus(unsigned cpu_init_detectedx, + struct sys_info *sysinfo) { - unsigned bsp_apicid = 0; - unsigned apicid; - struct node_core_id id; + unsigned bsp_apicid = 0; + unsigned apicid; + struct node_core_id id; - /* - * MTRR must be set by this point. + /* + * MTRR must be set by this point. + */ + + /* that is from initial apicid, we need nodeid and coreid later */ + id = get_node_core_id_x(); + printk(BIOS_DEBUG, "init_cpus: node %d core %d\n", id.nodeid, id.coreid); + + /* The NB_CFG MSR is shared between cores on a given node. + * Here is an interesting parallel processing bug: if you were to start the + * other cores and THEN make this setting, different cores might read + * a different value! Since ALL cores run this code, it is very important to have + * core0 initialize this setting before any others. + * So do this setting very early in the function to make sure the bit has a + * consistent value on all cores. + */ + if (id.coreid == 0) { + set_apicid_cpuid_lo(); /* only set it on core0 */ + /* Should we enable extended APIC IDs? This feature is used on a number of mainboards. + * It is required when the board requires more than 4 bits of ID. + * the question is, why not use it on all of them? Would it do harm to always enable it? */ +#if ENABLE_APIC_EXT_ID == 1 + enable_apic_ext_id(id.nodeid); +#endif + } - /* that is from initial apicid, we need nodeid and coreid later */ - id = get_node_core_id_x(); - - - /* NB_CFG MSR is shared between cores, so we need make sure core0 is done at first --- use wait_all_core0_started */ - if(id.coreid == 0) { - set_apicid_cpuid_lo(); /* only set it on core0 */ - #if ENABLE_APIC_EXT_ID == 1 - enable_apic_ext_id(id.nodeid); - #endif - } - - enable_lapic(); + enable_lapic(); // init_timer(); // We need TMICT to pass msg for FID/VID change - #if (ENABLE_APIC_EXT_ID == 1) - unsigned initial_apicid = get_initial_apicid(); - #if LIFT_BSP_APIC_ID == 0 - if( initial_apicid != 0 ) // other than bsp - #endif - { - /* use initial apic id to lift it */ - u32 dword = lapic_read(LAPIC_ID); - dword &= ~(0xff<<24); - dword |= (((initial_apicid + APIC_ID_OFFSET) & 0xff)<<24); +#if (ENABLE_APIC_EXT_ID == 1) + unsigned initial_apicid = get_initial_apicid(); + /* We don't always need to lift the BSP APIC ID. + * Again, is there harm if we do it anyway? + */ +#if LIFT_BSP_APIC_ID == 0 + if (initial_apicid != 0) // This CPU is not the BSP so lift it. +#endif + { + /* Use the CPUs initial 4-bit APIC id as the basis for the extended ID */ + u32 dword = lapic_read(LAPIC_ID); + dword &= ~(0xff << 24); + dword |= + (((initial_apicid + APIC_ID_OFFSET) & 0xff) << 24); - lapic_write(LAPIC_ID, dword); - } - - #if LIFT_BSP_APIC_ID == 1 - bsp_apicid += APIC_ID_OFFSET; - #endif - - #endif - - /* get the apicid, it may be lifted already */ - apicid = lapicid(); - -#if 0 - // show our apicid, nodeid, and coreid - if( id.coreid==0 ) { - if (id.nodeid!=0) //all core0 except bsp - print_apicid_nodeid_coreid(apicid, id, " core0: "); - } - #if 0 - else { //all core1 - print_apicid_nodeid_coreid(apicid, id, " core1: "); - } - #endif + lapic_write(LAPIC_ID, dword); + } +#if LIFT_BSP_APIC_ID == 1 + bsp_apicid += APIC_ID_OFFSET; +#endif #endif - if (cpu_init_detectedx) { - print_apicid_nodeid_coreid(apicid, id, "\r\n\r\n\r\nINIT detected from "); - printk(BIOS_DEBUG, "\r\nIssuing SOFT_RESET...\r\n"); - soft_reset(); - } + apicid = lapicid(); - if(id.coreid==0) { - distinguish_cpu_resets(id.nodeid); - // start_other_core(id.nodeid); // start second core in first cpu, only allowed for nb_cfg_54 is not set +#if 1 + // show our apicid, nodeid, and coreid + if (id.coreid == 0) { + if (id.nodeid != 0) //all core0 except bsp + print_apicid_nodeid_coreid(apicid, id, " core0: "); + } +#if 1 + else { //all core non-zero + print_apicid_nodeid_coreid(apicid, id, " core1: "); + } +#endif + +#endif + + if (cpu_init_detectedx) { + print_apicid_nodeid_coreid(apicid, id, + "\r\n\r\n\r\nINIT detected from "); + printk(BIOS_DEBUG, "\r\nIssuing SOFT_RESET...\r\n"); + soft_reset(); + } + + if (id.coreid == 0) { + /* not known what this is yet. */ + distinguish_cpu_resets(id.nodeid); + // start_other_core(id.nodeid); // start second core in first cpu, only allowed for nb_cfg_54 is not set + } + //Indicate to other CPUs that our CPU is running. + lapic_write(LAPIC_MSG_REG, (apicid << 24) | 0x33); + + /* non-BSP CPUs are now set up and need to halt. BSP will train memory on all CPUs. */ + if (apicid != bsp_apicid) { + unsigned timeout = 1; + unsigned loop = 100; +#if K8_SET_FIDVID == 1 +#if (CONFIG_LOGICAL_CPUS == 1) && (K8_SET_FIDVID_CORE0_ONLY == 1) + if (id.coreid == 0) // only need set fid for core0 +#endif + init_fidvid_ap(bsp_apicid, apicid); +#endif + + // We need to stop the CACHE as RAM for this CPU, really? + while (timeout && (loop-- > 0)) { + timeout = wait_cpu_state(bsp_apicid, 0x44); } + if (timeout) { + print_initcpu8 + ("while waiting for BSP signal to STOP, timeout in ap ", + apicid); + } + lapic_write(LAPIC_MSG_REG, (apicid << 24) | 0x44); // bsp can not check it before stop_this_cpu + set_init_ram_access(); +#if MEM_TRAIN_SEQ == 1 + train_ram_on_node(id.nodeid, id.coreid, sysinfo, + STOP_CAR_AND_CPU); +#endif - //here don't need to wait - lapic_write(LAPIC_MSG_REG, (apicid<<24) | 0x33); // mark the cpu is started + STOP_CAR_AND_CPU(); + } - if(apicid != bsp_apicid) { - unsigned timeout=1; - unsigned loop = 100; - #if K8_SET_FIDVID == 1 - #if (CONFIG_LOGICAL_CPUS == 1) && (K8_SET_FIDVID_CORE0_ONLY == 1) - if(id.coreid == 0 ) // only need set fid for core0 - #endif - init_fidvid_ap(bsp_apicid, apicid); - #endif - - // We need to stop the CACHE as RAM for this CPU, really? - while(timeout && (loop-->0)) { - timeout = wait_cpu_state(bsp_apicid, 0x44); - } - if(timeout) { - print_initcpu8("while waiting for BSP signal to STOP, timeout in ap ", apicid); - } - lapic_write(LAPIC_MSG_REG, (apicid<<24) | 0x44); // bsp can not check it before stop_this_cpu - set_init_ram_access(); - #if MEM_TRAIN_SEQ == 1 - train_ram_on_node(id.nodeid, id.coreid, sysinfo, STOP_CAR_AND_CPU); - #endif - - STOP_CAR_AND_CPU(); - } - - return bsp_apicid; + return bsp_apicid; } -static unsigned is_core0_started(unsigned nodeid) +/** + * Given a node, find out if core0 is started. + * @param nodeid the node ID + * @returns non-zero if node is started + */ +static unsigned int is_core0_started(unsigned nodeid) { - u32 htic; - struct device * device; - device = PCI_DEV(0, 0x18 + nodeid, 0); - htic = pci_conf1_read_config32(device, HT_INIT_CONTROL); - htic &= HTIC_INIT_Detect; - return htic; + u32 htic; + u32 device; + device = PCI_BDF(0, 0x18 + nodeid, 0); + htic = pci_conf1_read_config32(device, HT_INIT_CONTROL); + htic &= HTIC_INIT_Detect; + return htic; } +/** + * Wait for all core 0s on all CPUs to start up. + */ static void wait_all_core0_started(void) { //When core0 is started, it will distingush_cpu_resets. So wait for that + // whatever that means unsigned i; unsigned nodes = get_nodes(); - printk(BIOS_DEBUG, "core0 started: "); - for(i=1;i