Stefan Reinauer | 3b31402 | 2009-10-26 17:04:28 +0000 | [diff] [blame] | 1 | /* |
| 2 | * This file is part of the coreboot project. |
| 3 | * |
| 4 | * Copyright (C) 2009 coresystems GmbH |
| 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. |
| 14 | * |
| 15 | * You should have received a copy of the GNU General Public License |
| 16 | * along with this program; if not, write to the Free Software |
| 17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA |
| 18 | */ |
| 19 | |
| 20 | #include <types.h> |
| 21 | #include <string.h> |
Aaron Durbin | 40131cf | 2013-04-24 16:39:08 -0500 | [diff] [blame] | 22 | #include <bootstate.h> |
Stefan Reinauer | 3b31402 | 2009-10-26 17:04:28 +0000 | [diff] [blame] | 23 | #include <cbmem.h> |
Kyösti Mälkki | e1ea802 | 2013-09-04 14:11:08 +0300 | [diff] [blame] | 24 | #include <boot/coreboot_tables.h> |
Stefan Reinauer | 3b31402 | 2009-10-26 17:04:28 +0000 | [diff] [blame] | 25 | #include <console/console.h> |
Stefan Reinauer | fd4f413 | 2013-06-19 12:25:44 -0700 | [diff] [blame] | 26 | #include <arch/early_variables.h> |
Stefan Reinauer | e246b31 | 2011-09-23 10:24:49 -0700 | [diff] [blame] | 27 | #if CONFIG_HAVE_ACPI_RESUME && !defined(__PRE_RAM__) |
| 28 | #include <arch/acpi.h> |
| 29 | #endif |
Stefan Reinauer | 3b31402 | 2009-10-26 17:04:28 +0000 | [diff] [blame] | 30 | |
Stefan Reinauer | 3b31402 | 2009-10-26 17:04:28 +0000 | [diff] [blame] | 31 | // The CBMEM TOC reserves 512 bytes to keep |
| 32 | // the other entries somewhat aligned. |
| 33 | // Increase if MAX_CBMEM_ENTRIES exceeds 21 |
| 34 | #define CBMEM_TOC_RESERVED 512 |
| 35 | #define MAX_CBMEM_ENTRIES 16 |
| 36 | #define CBMEM_MAGIC 0x434f5245 |
| 37 | |
Stefan Reinauer | 3b31402 | 2009-10-26 17:04:28 +0000 | [diff] [blame] | 38 | struct cbmem_entry { |
| 39 | u32 magic; |
| 40 | u32 id; |
| 41 | u64 base; |
| 42 | u64 size; |
| 43 | } __attribute__((packed)); |
| 44 | |
Rudolf Marek | c436953 | 2010-12-13 19:59:13 +0000 | [diff] [blame] | 45 | #ifndef __PRE_RAM__ |
Kyösti Mälkki | 0fbbff4 | 2013-06-23 20:03:50 +0300 | [diff] [blame] | 46 | static uint64_t cbmem_base = 0; |
| 47 | static uint64_t cbmem_size = 0; |
Kyösti Mälkki | bc90e15 | 2013-09-04 13:26:11 +0300 | [diff] [blame] | 48 | #endif |
Rudolf Marek | bcaea14 | 2010-11-22 22:00:52 +0000 | [diff] [blame] | 49 | |
Kyösti Mälkki | c04afd6 | 2013-09-04 13:31:39 +0300 | [diff] [blame] | 50 | static void cbmem_trace_location(uint64_t base, uint64_t size, const char *s) |
| 51 | { |
| 52 | if (base && size && s) { |
| 53 | printk(BIOS_DEBUG, "CBMEM region %llx-%llx (%s)\n", |
| 54 | base, base + size - 1, s); |
| 55 | } |
| 56 | } |
Kyösti Mälkki | c04afd6 | 2013-09-04 13:31:39 +0300 | [diff] [blame] | 57 | |
| 58 | static void cbmem_locate_table(uint64_t *base, uint64_t *size) |
| 59 | { |
| 60 | #ifdef __PRE_RAM__ |
| 61 | get_cbmem_table(base, size); |
Rudolf Marek | 475916d | 2010-12-13 20:02:23 +0000 | [diff] [blame] | 62 | #else |
Kyösti Mälkki | 0fbbff4 | 2013-06-23 20:03:50 +0300 | [diff] [blame] | 63 | if (!(cbmem_base && cbmem_size)) { |
| 64 | get_cbmem_table(&cbmem_base, &cbmem_size); |
| 65 | cbmem_trace_location(cbmem_base, cbmem_size, __FUNCTION__); |
Kyösti Mälkki | c04afd6 | 2013-09-04 13:31:39 +0300 | [diff] [blame] | 66 | } |
Kyösti Mälkki | 0fbbff4 | 2013-06-23 20:03:50 +0300 | [diff] [blame] | 67 | *base = cbmem_base; |
| 68 | *size = cbmem_size; |
Kyösti Mälkki | c04afd6 | 2013-09-04 13:31:39 +0300 | [diff] [blame] | 69 | #endif |
| 70 | } |
Rudolf Marek | 475916d | 2010-12-13 20:02:23 +0000 | [diff] [blame] | 71 | |
Kyösti Mälkki | f9f74af | 2013-09-06 10:46:22 +0300 | [diff] [blame] | 72 | struct cbmem_entry *get_cbmem_toc(void) |
Rudolf Marek | 475916d | 2010-12-13 20:02:23 +0000 | [diff] [blame] | 73 | { |
Kyösti Mälkki | c04afd6 | 2013-09-04 13:31:39 +0300 | [diff] [blame] | 74 | uint64_t base, size; |
| 75 | cbmem_locate_table(&base, &size); |
| 76 | return (struct cbmem_entry *)(unsigned long)base; |
Rudolf Marek | 475916d | 2010-12-13 20:02:23 +0000 | [diff] [blame] | 77 | } |
Rudolf Marek | bcaea14 | 2010-11-22 22:00:52 +0000 | [diff] [blame] | 78 | |
Kyösti Mälkki | 1ae305e | 2013-09-04 13:05:01 +0300 | [diff] [blame] | 79 | #if !defined(__PRE_RAM__) |
| 80 | void cbmem_late_set_table(uint64_t base, uint64_t size) |
| 81 | { |
Kyösti Mälkki | c04afd6 | 2013-09-04 13:31:39 +0300 | [diff] [blame] | 82 | cbmem_trace_location(base, size, __FUNCTION__); |
Kyösti Mälkki | 0fbbff4 | 2013-06-23 20:03:50 +0300 | [diff] [blame] | 83 | cbmem_base = base; |
| 84 | cbmem_size = size; |
Kyösti Mälkki | 1ae305e | 2013-09-04 13:05:01 +0300 | [diff] [blame] | 85 | } |
Stefan Reinauer | 3b31402 | 2009-10-26 17:04:28 +0000 | [diff] [blame] | 86 | #endif |
| 87 | |
| 88 | /** |
| 89 | * cbmem is a simple mechanism to do some kind of book keeping of the coreboot |
| 90 | * high tables memory. This is a small amount of memory which is "stolen" from |
| 91 | * the system memory for coreboot purposes. Usually this memory is used for |
| 92 | * - the coreboot table |
| 93 | * - legacy tables (PIRQ, MP table) |
| 94 | * - ACPI tables |
| 95 | * - suspend/resume backup memory |
| 96 | */ |
| 97 | |
Kyösti Mälkki | f8bf5a1 | 2013-10-11 22:08:02 +0300 | [diff] [blame] | 98 | #if CONFIG_EARLY_CBMEM_INIT || !defined(__PRE_RAM__) |
Kyösti Mälkki | 625f103 | 2013-09-04 14:36:31 +0300 | [diff] [blame] | 99 | static void cbmem_init(void) |
Stefan Reinauer | 3b31402 | 2009-10-26 17:04:28 +0000 | [diff] [blame] | 100 | { |
Kyösti Mälkki | 625f103 | 2013-09-04 14:36:31 +0300 | [diff] [blame] | 101 | uint64_t baseaddr, size; |
Stefan Reinauer | 3b31402 | 2009-10-26 17:04:28 +0000 | [diff] [blame] | 102 | struct cbmem_entry *cbmem_toc; |
Stefan Reinauer | 3b31402 | 2009-10-26 17:04:28 +0000 | [diff] [blame] | 103 | |
Kyösti Mälkki | 625f103 | 2013-09-04 14:36:31 +0300 | [diff] [blame] | 104 | cbmem_locate_table(&baseaddr, &size); |
| 105 | cbmem_trace_location(baseaddr, size, __FUNCTION__); |
| 106 | |
| 107 | cbmem_toc = (struct cbmem_entry *)(unsigned long)baseaddr; |
Stefan Reinauer | 3b31402 | 2009-10-26 17:04:28 +0000 | [diff] [blame] | 108 | |
| 109 | if (size < (64 * 1024)) { |
Uwe Hermann | a953f37 | 2010-11-10 00:14:32 +0000 | [diff] [blame] | 110 | printk(BIOS_DEBUG, "Increase CBMEM size!\n"); |
Stefan Reinauer | 3b31402 | 2009-10-26 17:04:28 +0000 | [diff] [blame] | 111 | for (;;) ; |
| 112 | } |
| 113 | |
| 114 | memset(cbmem_toc, 0, CBMEM_TOC_RESERVED); |
| 115 | |
| 116 | cbmem_toc[0] = (struct cbmem_entry) { |
| 117 | .magic = CBMEM_MAGIC, |
| 118 | .id = CBMEM_ID_FREESPACE, |
| 119 | .base = baseaddr + CBMEM_TOC_RESERVED, |
| 120 | .size = size - CBMEM_TOC_RESERVED |
| 121 | }; |
| 122 | } |
Kyösti Mälkki | f8bf5a1 | 2013-10-11 22:08:02 +0300 | [diff] [blame] | 123 | #endif |
Stefan Reinauer | 3b31402 | 2009-10-26 17:04:28 +0000 | [diff] [blame] | 124 | |
Kyösti Mälkki | d50cdf1 | 2013-06-23 17:01:29 +0300 | [diff] [blame] | 125 | int cbmem_reinit(void) |
Stefan Reinauer | 3b31402 | 2009-10-26 17:04:28 +0000 | [diff] [blame] | 126 | { |
Kyösti Mälkki | d50cdf1 | 2013-06-23 17:01:29 +0300 | [diff] [blame] | 127 | uint64_t baseaddr, size; |
Stefan Reinauer | 3b31402 | 2009-10-26 17:04:28 +0000 | [diff] [blame] | 128 | struct cbmem_entry *cbmem_toc; |
Stefan Reinauer | 3b31402 | 2009-10-26 17:04:28 +0000 | [diff] [blame] | 129 | |
Kyösti Mälkki | d50cdf1 | 2013-06-23 17:01:29 +0300 | [diff] [blame] | 130 | cbmem_locate_table(&baseaddr, &size); |
| 131 | cbmem_trace_location(baseaddr, size, __FUNCTION__); |
| 132 | |
| 133 | cbmem_toc = (struct cbmem_entry *)(unsigned long)baseaddr; |
Uwe Hermann | a953f37 | 2010-11-10 00:14:32 +0000 | [diff] [blame] | 134 | |
Stefan Reinauer | 3b31402 | 2009-10-26 17:04:28 +0000 | [diff] [blame] | 135 | return (cbmem_toc[0].magic == CBMEM_MAGIC); |
| 136 | } |
| 137 | |
| 138 | void *cbmem_add(u32 id, u64 size) |
| 139 | { |
| 140 | struct cbmem_entry *cbmem_toc; |
| 141 | int i; |
Vadim Bendebury | 6f72d69 | 2011-09-21 16:12:39 -0700 | [diff] [blame] | 142 | void *p; |
| 143 | |
| 144 | /* |
| 145 | * This could be a restart, check if the section is there already. It |
| 146 | * is remotely possible that the dram contents persisted over the |
| 147 | * bootloader upgrade AND the same section now needs more room, but |
| 148 | * this is quite a remote possibility and it is ignored here. |
| 149 | */ |
| 150 | p = cbmem_find(id); |
| 151 | if (p) { |
| 152 | printk(BIOS_NOTICE, |
| 153 | "CBMEM section %x: using existing location at %p.\n", |
| 154 | id, p); |
| 155 | return p; |
| 156 | } |
| 157 | |
Myles Watson | 84b685a | 2010-03-31 14:57:55 +0000 | [diff] [blame] | 158 | cbmem_toc = get_cbmem_toc(); |
Stefan Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 159 | |
Stefan Reinauer | 3b31402 | 2009-10-26 17:04:28 +0000 | [diff] [blame] | 160 | if (cbmem_toc == NULL) { |
| 161 | return NULL; |
| 162 | } |
| 163 | |
| 164 | if (cbmem_toc[0].magic != CBMEM_MAGIC) { |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 165 | printk(BIOS_ERR, "ERROR: CBMEM was not initialized yet.\n"); |
Stefan Reinauer | 3b31402 | 2009-10-26 17:04:28 +0000 | [diff] [blame] | 166 | return NULL; |
| 167 | } |
| 168 | |
| 169 | /* Will the entry fit at all? */ |
| 170 | if (size > cbmem_toc[0].size) { |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 171 | printk(BIOS_ERR, "ERROR: Not enough memory for table %x\n", id); |
Stefan Reinauer | 3b31402 | 2009-10-26 17:04:28 +0000 | [diff] [blame] | 172 | return NULL; |
| 173 | } |
| 174 | |
| 175 | /* Align size to 512 byte blocks */ |
| 176 | |
Stefan Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 177 | size = ALIGN(size, 512) < cbmem_toc[0].size ? |
Stefan Reinauer | 3b31402 | 2009-10-26 17:04:28 +0000 | [diff] [blame] | 178 | ALIGN(size, 512) : cbmem_toc[0].size; |
| 179 | |
| 180 | /* Now look for the first free/usable TOC entry */ |
| 181 | for (i = 0; i < MAX_CBMEM_ENTRIES; i++) { |
| 182 | if (cbmem_toc[i].id == CBMEM_ID_NONE) |
| 183 | break; |
| 184 | } |
| 185 | |
| 186 | if (i >= MAX_CBMEM_ENTRIES) { |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 187 | printk(BIOS_ERR, "ERROR: No more CBMEM entries available.\n"); |
Stefan Reinauer | 3b31402 | 2009-10-26 17:04:28 +0000 | [diff] [blame] | 188 | return NULL; |
| 189 | } |
| 190 | |
Uwe Hermann | a953f37 | 2010-11-10 00:14:32 +0000 | [diff] [blame] | 191 | printk(BIOS_DEBUG, "Adding CBMEM entry as no. %d\n", i); |
Stefan Reinauer | 3b31402 | 2009-10-26 17:04:28 +0000 | [diff] [blame] | 192 | |
| 193 | cbmem_toc[i] = (struct cbmem_entry) { |
| 194 | .magic = CBMEM_MAGIC, |
| 195 | .id = id, |
| 196 | .base = cbmem_toc[0].base, |
| 197 | .size = size |
| 198 | }; |
| 199 | |
| 200 | cbmem_toc[0].base += size; |
| 201 | cbmem_toc[0].size -= size; |
| 202 | |
Ronald G. Minnich | ef40209 | 2013-11-11 10:36:28 -0800 | [diff] [blame^] | 203 | return (void *)(uintptr_t)cbmem_toc[i].base; |
Stefan Reinauer | 3b31402 | 2009-10-26 17:04:28 +0000 | [diff] [blame] | 204 | } |
| 205 | |
| 206 | void *cbmem_find(u32 id) |
| 207 | { |
| 208 | struct cbmem_entry *cbmem_toc; |
| 209 | int i; |
Myles Watson | 84b685a | 2010-03-31 14:57:55 +0000 | [diff] [blame] | 210 | cbmem_toc = get_cbmem_toc(); |
Stefan Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 211 | |
Stefan Reinauer | 3b31402 | 2009-10-26 17:04:28 +0000 | [diff] [blame] | 212 | if (cbmem_toc == NULL) |
| 213 | return NULL; |
| 214 | |
| 215 | for (i = 0; i < MAX_CBMEM_ENTRIES; i++) { |
| 216 | if (cbmem_toc[i].id == id) |
| 217 | return (void *)(unsigned long)cbmem_toc[i].base; |
| 218 | } |
| 219 | |
| 220 | return (void *)NULL; |
| 221 | } |
| 222 | |
Kyösti Mälkki | f8bf5a1 | 2013-10-11 22:08:02 +0300 | [diff] [blame] | 223 | #if CONFIG_EARLY_CBMEM_INIT || !defined(__PRE_RAM__) |
Martin Roth | cbf2bd7 | 2013-07-09 21:51:14 -0600 | [diff] [blame] | 224 | /* Returns True if it was not initialized before. */ |
Vadim Bendebury | e186060 | 2011-09-20 17:07:14 -0700 | [diff] [blame] | 225 | int cbmem_initialize(void) |
Stefan Reinauer | 3b31402 | 2009-10-26 17:04:28 +0000 | [diff] [blame] | 226 | { |
Vadim Bendebury | e186060 | 2011-09-20 17:07:14 -0700 | [diff] [blame] | 227 | int rv = 0; |
| 228 | |
Vadim Bendebury | e186060 | 2011-09-20 17:07:14 -0700 | [diff] [blame] | 229 | /* We expect the romstage to always initialize it. */ |
Kyösti Mälkki | d50cdf1 | 2013-06-23 17:01:29 +0300 | [diff] [blame] | 230 | if (!cbmem_reinit()) { |
Vadim Bendebury | e186060 | 2011-09-20 17:07:14 -0700 | [diff] [blame] | 231 | #if CONFIG_HAVE_ACPI_RESUME && !defined(__PRE_RAM__) |
| 232 | /* Something went wrong, our high memory area got wiped */ |
| 233 | if (acpi_slp_type == 3 || acpi_slp_type == 2) |
| 234 | acpi_slp_type = 0; |
| 235 | #endif |
Kyösti Mälkki | 625f103 | 2013-09-04 14:36:31 +0300 | [diff] [blame] | 236 | cbmem_init(); |
Vadim Bendebury | e186060 | 2011-09-20 17:07:14 -0700 | [diff] [blame] | 237 | rv = 1; |
| 238 | } |
| 239 | #ifndef __PRE_RAM__ |
Stefan Reinauer | 3b31402 | 2009-10-26 17:04:28 +0000 | [diff] [blame] | 240 | cbmem_arch_init(); |
Vadim Bendebury | e186060 | 2011-09-20 17:07:14 -0700 | [diff] [blame] | 241 | #endif |
Aaron Durbin | 716738a | 2013-05-10 00:33:32 -0500 | [diff] [blame] | 242 | /* Migrate cache-as-ram variables. */ |
| 243 | car_migrate_variables(); |
| 244 | |
Vadim Bendebury | e186060 | 2011-09-20 17:07:14 -0700 | [diff] [blame] | 245 | return rv; |
Stefan Reinauer | 3b31402 | 2009-10-26 17:04:28 +0000 | [diff] [blame] | 246 | } |
Kyösti Mälkki | f8bf5a1 | 2013-10-11 22:08:02 +0300 | [diff] [blame] | 247 | #endif |
Stefan Reinauer | 3b31402 | 2009-10-26 17:04:28 +0000 | [diff] [blame] | 248 | |
Myles Watson | 1d6d45e | 2009-11-06 17:02:51 +0000 | [diff] [blame] | 249 | #ifndef __PRE_RAM__ |
Aaron Durbin | 40131cf | 2013-04-24 16:39:08 -0500 | [diff] [blame] | 250 | static void init_cbmem_post_device(void *unused) |
Aaron Durbin | df3a109 | 2013-03-13 12:41:44 -0500 | [diff] [blame] | 251 | { |
| 252 | cbmem_initialize(); |
| 253 | #if CONFIG_CONSOLE_CBMEM |
| 254 | cbmemc_reinit(); |
| 255 | #endif |
| 256 | } |
| 257 | |
Aaron Durbin | 40131cf | 2013-04-24 16:39:08 -0500 | [diff] [blame] | 258 | BOOT_STATE_INIT_ENTRIES(cbmem_bscb) = { |
| 259 | BOOT_STATE_INIT_ENTRY(BS_POST_DEVICE, BS_ON_ENTRY, |
| 260 | init_cbmem_post_device, NULL), |
| 261 | }; |
| 262 | |
Kyösti Mälkki | e1ea802 | 2013-09-04 14:11:08 +0300 | [diff] [blame] | 263 | int cbmem_base_check(void) |
| 264 | { |
Kyösti Mälkki | 0fbbff4 | 2013-06-23 20:03:50 +0300 | [diff] [blame] | 265 | if (!cbmem_base) { |
Kyösti Mälkki | e1ea802 | 2013-09-04 14:11:08 +0300 | [diff] [blame] | 266 | printk(BIOS_ERR, "ERROR: CBMEM Base is not set.\n"); |
| 267 | // Are there any boards without? |
| 268 | // Stepan thinks we should die() here! |
| 269 | } |
Kyösti Mälkki | 0fbbff4 | 2013-06-23 20:03:50 +0300 | [diff] [blame] | 270 | printk(BIOS_DEBUG, "CBMEM Base is %llx.\n", cbmem_base); |
| 271 | return !!cbmem_base; |
Kyösti Mälkki | e1ea802 | 2013-09-04 14:11:08 +0300 | [diff] [blame] | 272 | } |
| 273 | |
| 274 | void cbmem_add_lb_mem(struct lb_memory *mem) |
| 275 | { |
Kyösti Mälkki | 0fbbff4 | 2013-06-23 20:03:50 +0300 | [diff] [blame] | 276 | lb_add_memory_range(mem, LB_MEM_TABLE, cbmem_base, cbmem_size); |
Kyösti Mälkki | e1ea802 | 2013-09-04 14:11:08 +0300 | [diff] [blame] | 277 | } |
| 278 | |
Stefan Reinauer | 3b31402 | 2009-10-26 17:04:28 +0000 | [diff] [blame] | 279 | void cbmem_list(void) |
| 280 | { |
| 281 | struct cbmem_entry *cbmem_toc; |
| 282 | int i; |
Myles Watson | 84b685a | 2010-03-31 14:57:55 +0000 | [diff] [blame] | 283 | cbmem_toc = get_cbmem_toc(); |
Stefan Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 284 | |
Stefan Reinauer | 3b31402 | 2009-10-26 17:04:28 +0000 | [diff] [blame] | 285 | if (cbmem_toc == NULL) |
Maciej Pijanka | ea92185 | 2009-10-27 14:29:29 +0000 | [diff] [blame] | 286 | return; |
Stefan Reinauer | 3b31402 | 2009-10-26 17:04:28 +0000 | [diff] [blame] | 287 | |
| 288 | for (i = 0; i < MAX_CBMEM_ENTRIES; i++) { |
| 289 | |
| 290 | if (cbmem_toc[i].magic != CBMEM_MAGIC) |
| 291 | continue; |
Aaron Durbin | df3a109 | 2013-03-13 12:41:44 -0500 | [diff] [blame] | 292 | cbmem_print_entry(i, cbmem_toc[i].id, cbmem_toc[i].base, |
| 293 | cbmem_toc[i].size); |
Stefan Reinauer | 3b31402 | 2009-10-26 17:04:28 +0000 | [diff] [blame] | 294 | } |
| 295 | } |
| 296 | #endif |
| 297 | |
Stefan Reinauer | 3b31402 | 2009-10-26 17:04:28 +0000 | [diff] [blame] | 298 | |