Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 1 | /* |
Stefan Reinauer | 7e61e45 | 2008-01-18 10:35:56 +0000 | [diff] [blame] | 2 | * This file is part of the coreboot project. |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 3 | * |
| 4 | * Copyright (C) 2007 Advanced Micro Devices, Inc. |
| 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License as published by |
| 8 | * the Free Software Foundation; version 2 of the License. |
| 9 | * |
| 10 | * This program is distributed in the hope that it will be useful, |
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 | * GNU General Public License for more details. |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 14 | */ |
| 15 | |
| 16 | |
| 17 | #include <console/console.h> |
| 18 | #include <cpu/cpu.h> |
| 19 | #include <cpu/x86/lapic.h> |
| 20 | #include <device/device.h> |
| 21 | #include <device/pci.h> |
| 22 | #include <pc80/mc146818rtc.h> |
| 23 | #include <smp/spinlock.h> |
| 24 | #include <cpu/x86/mtrr.h> |
Stefan Reinauer | 991f184 | 2015-11-22 23:40:29 +0100 | [diff] [blame] | 25 | #include <cpu/amd/msr.h> |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 26 | #include <cpu/amd/model_10xxx_rev.h> |
| 27 | #include <cpu/amd/amdfam10_sysconf.h> |
| 28 | |
| 29 | extern device_t get_node_pci(u32 nodeid, u32 fn); |
| 30 | |
| 31 | #if 0 |
| 32 | static int first_time = 1; |
| 33 | #endif |
| 34 | |
| 35 | #include "quadcore_id.c" |
| 36 | |
| 37 | static u32 get_max_siblings(u32 nodes) |
| 38 | { |
| 39 | device_t dev; |
| 40 | u32 nodeid; |
| 41 | u32 siblings=0; |
| 42 | |
| 43 | //get max siblings from all the nodes |
| 44 | for(nodeid=0; nodeid<nodes; nodeid++){ |
| 45 | int j; |
| 46 | dev = get_node_pci(nodeid, 3); |
| 47 | j = (pci_read_config32(dev, 0xe8) >> 12) & 3; |
| 48 | if(siblings < j) { |
| 49 | siblings = j; |
| 50 | } |
| 51 | } |
| 52 | |
| 53 | return siblings; |
| 54 | } |
| 55 | |
| 56 | |
| 57 | static void enable_apic_ext_id(u32 nodes) |
| 58 | { |
| 59 | device_t dev; |
| 60 | u32 nodeid; |
| 61 | |
| 62 | //enable APIC_EXIT_ID all the nodes |
| 63 | for(nodeid=0; nodeid<nodes; nodeid++){ |
| 64 | u32 val; |
| 65 | dev = get_node_pci(nodeid, 0); |
| 66 | val = pci_read_config32(dev, 0x68); |
| 67 | val |= (1<<17)|(1<<18); |
| 68 | pci_write_config32(dev, 0x68, val); |
| 69 | } |
| 70 | } |
| 71 | |
| 72 | |
| 73 | u32 get_apicid_base(u32 ioapic_num) |
| 74 | { |
| 75 | u32 apicid_base; |
| 76 | u32 siblings; |
| 77 | u32 nb_cfg_54; |
| 78 | |
| 79 | u32 disable_siblings = !CONFIG_LOGICAL_CPUS; |
| 80 | |
Myles Watson | 4839e2c | 2010-04-08 15:06:44 +0000 | [diff] [blame] | 81 | get_option(&disable_siblings, "multi_core"); |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 82 | |
| 83 | siblings = get_max_siblings(sysconf.nodes); |
| 84 | |
| 85 | if(sysconf.bsp_apicid > 0) { // io apic could start from 0 |
| 86 | return 0; |
| 87 | } else if (sysconf.enabled_apic_ext_id) { // enabled ext id but bsp = 0 |
| 88 | return 1; |
| 89 | } |
| 90 | |
| 91 | nb_cfg_54 = read_nb_cfg_54(); |
| 92 | |
| 93 | |
Martin Roth | 4c3ab73 | 2013-07-08 16:23:54 -0600 | [diff] [blame] | 94 | //Construct apicid_base |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 95 | |
| 96 | if((!disable_siblings) && (siblings>0) ) { |
Martin Roth | 4c3ab73 | 2013-07-08 16:23:54 -0600 | [diff] [blame] | 97 | /* for 8 way dual core, we will used up apicid 16:16, actually |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 98 | 16 is not allowed by current kernel and the kernel will try |
| 99 | to get one that is small than 16 to make io apic work. I don't |
| 100 | know when the kernel can support 256 apic id. |
| 101 | (APIC_EXT_ID is enabled) */ |
| 102 | |
| 103 | //4:10 for two way 8:12 for four way 16:16 for eight way |
| 104 | //Use CONFIG_MAX_PHYSICAL_CPUS instead of nodes for better consistency? |
| 105 | apicid_base = nb_cfg_54 ? (siblings+1) * sysconf.nodes : 8 * siblings + sysconf.nodes; |
| 106 | |
| 107 | } else { |
| 108 | apicid_base = sysconf.nodes; |
| 109 | } |
| 110 | |
| 111 | if((apicid_base+ioapic_num-1)>0xf) { |
| 112 | // We need to enable APIC EXT ID |
Stefan Reinauer | 64ed2b7 | 2010-03-31 14:47:43 +0000 | [diff] [blame] | 113 | printk(BIOS_SPEW, "if the IO APIC device doesn't support 256 apic id, \n you need to set CONFIG_ENABLE_APIC_EXT_ID in MB Option.lb so you can spare 16 id for ioapic\n"); |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 114 | enable_apic_ext_id(sysconf.nodes); |
| 115 | } |
| 116 | |
| 117 | return apicid_base; |
| 118 | } |