York Yang | d7cba28 | 2016-03-09 10:54:26 -0800 | [diff] [blame] | 1 | /* |
| 2 | * This file is part of the coreboot project. |
| 3 | * |
| 4 | * Copyright (C) 2007-2009 coresystems GmbH |
| 5 | * Copyright (C) 2013 Google Inc. |
| 6 | * Copyright (C) 2015-2016 Intel Corp. |
Werner Zeh | ca0c8e7 | 2018-09-19 08:06:54 +0200 | [diff] [blame] | 7 | * Copyright (C) 2016-2018 Siemens AG |
York Yang | d7cba28 | 2016-03-09 10:54:26 -0800 | [diff] [blame] | 8 | * |
| 9 | * This program is free software; you can redistribute it and/or modify |
| 10 | * it under the terms of the GNU General Public License as published by |
| 11 | * the Free Software Foundation; version 2 of the License. |
| 12 | * |
| 13 | * This program is distributed in the hope that it will be useful, |
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 16 | * GNU General Public License for more details. |
| 17 | */ |
| 18 | |
| 19 | #include <string.h> |
| 20 | #include <types.h> |
Paul Menzel | 8ca2af1 | 2019-02-08 15:19:20 +0100 | [diff] [blame] | 21 | #include <arch/acpi.h> |
York Yang | d7cba28 | 2016-03-09 10:54:26 -0800 | [diff] [blame] | 22 | #include <arch/acpigen.h> |
York Yang | d7cba28 | 2016-03-09 10:54:26 -0800 | [diff] [blame] | 23 | #include <arch/io.h> |
| 24 | #include <arch/smp/mpspec.h> |
| 25 | #include <console/console.h> |
| 26 | #include <cpu/x86/msr.h> |
| 27 | #include <cpu/intel/speedstep.h> |
| 28 | #include <cpu/intel/turbo.h> |
| 29 | #include <device/device.h> |
| 30 | #include <device/pci.h> |
| 31 | #include <device/pci_ids.h> |
| 32 | #include <soc/acpi.h> |
| 33 | #include <soc/iomap.h> |
| 34 | #include <soc/irq.h> |
| 35 | #include <soc/lpc.h> |
| 36 | #include <soc/msr.h> |
| 37 | #include <soc/pattrs.h> |
| 38 | #include <soc/pci_devs.h> |
Werner Zeh | 1cfb555 | 2016-07-27 08:22:50 +0200 | [diff] [blame] | 39 | #include <soc/broadwell_de.h> |
York Yang | d7cba28 | 2016-03-09 10:54:26 -0800 | [diff] [blame] | 40 | #include <chip.h> |
Elyes HAOUAS | 26071aa | 2019-02-15 08:21:33 +0100 | [diff] [blame] | 41 | #include <version.h> |
York Yang | d7cba28 | 2016-03-09 10:54:26 -0800 | [diff] [blame] | 42 | |
| 43 | uint16_t get_pmbase(void) |
| 44 | { |
| 45 | return ACPI_BASE_ADDRESS; |
| 46 | } |
| 47 | |
| 48 | #define MWAIT_RES(state, sub_state) \ |
| 49 | { \ |
| 50 | .addrl = (((state) << 4) | (sub_state)), \ |
| 51 | .space_id = ACPI_ADDRESS_SPACE_FIXED, \ |
| 52 | .bit_width = ACPI_FFIXEDHW_VENDOR_INTEL, \ |
| 53 | .bit_offset = ACPI_FFIXEDHW_CLASS_MWAIT, \ |
| 54 | .access_size = ACPI_FFIXEDHW_FLAG_HW_COORD, \ |
| 55 | } |
| 56 | |
| 57 | /* C-state map */ |
| 58 | static acpi_cstate_t cstate_map[] = { |
| 59 | { |
| 60 | /* C1 */ |
| 61 | .ctype = 1, /* ACPI C1 */ |
| 62 | .latency = 1, |
| 63 | .power = 1000, |
| 64 | .resource = MWAIT_RES(0, 0), |
| 65 | }, |
| 66 | { |
| 67 | /* C3 */ |
| 68 | .ctype = 2, /* ACPI C2 */ |
| 69 | .latency = 15, |
| 70 | .power = 500, |
| 71 | .resource = MWAIT_RES(1, 0), |
| 72 | }, |
| 73 | { |
| 74 | /* C6 */ |
| 75 | .ctype = 3, /* ACPI C3 */ |
| 76 | .latency = 41, |
| 77 | .power = 350, |
| 78 | .resource = MWAIT_RES(2, 0), |
| 79 | } |
| 80 | }; |
| 81 | |
| 82 | static int acpi_sci_irq(void) |
| 83 | { |
Werner Zeh | 93db5a5 | 2016-07-06 12:58:57 +0200 | [diff] [blame] | 84 | uint8_t actl = 0; |
| 85 | static uint8_t sci_irq = 0; |
Kyösti Mälkki | c70eed1 | 2018-05-22 02:18:00 +0300 | [diff] [blame] | 86 | struct device *dev = pcidev_on_root(LPC_DEV, LPC_FUNC); |
Werner Zeh | 93db5a5 | 2016-07-06 12:58:57 +0200 | [diff] [blame] | 87 | |
| 88 | /* If this function was already called, just return the stored value. */ |
| 89 | if (sci_irq) |
| 90 | return sci_irq; |
| 91 | /* Get contents of ACPI control register. */ |
| 92 | actl = pci_read_config8(dev, ACPI_CNTL_OFFSET) & SCIS_MASK; |
| 93 | /* Determine how SCI is routed. */ |
| 94 | switch (actl) { |
| 95 | case SCIS_IRQ9: |
| 96 | case SCIS_IRQ10: |
| 97 | case SCIS_IRQ11: |
| 98 | sci_irq = actl + 9; |
| 99 | break; |
| 100 | case SCIS_IRQ20: |
| 101 | case SCIS_IRQ21: |
| 102 | case SCIS_IRQ22: |
| 103 | case SCIS_IRQ23: |
| 104 | sci_irq = actl - SCIS_IRQ20 + 20; |
| 105 | break; |
| 106 | default: |
| 107 | printk(BIOS_DEBUG, "Invalid SCI route! Defaulting to IRQ9.\n"); |
| 108 | sci_irq = 9; |
| 109 | break; |
| 110 | } |
| 111 | printk(BIOS_DEBUG, "SCI is IRQ%d\n", sci_irq); |
| 112 | return sci_irq; |
York Yang | d7cba28 | 2016-03-09 10:54:26 -0800 | [diff] [blame] | 113 | } |
| 114 | |
| 115 | void acpi_create_intel_hpet(acpi_hpet_t *hpet) |
| 116 | { |
| 117 | acpi_header_t *header = &(hpet->header); |
| 118 | acpi_addr_t *addr = &(hpet->addr); |
| 119 | |
| 120 | memset((void *) hpet, 0, sizeof(acpi_hpet_t)); |
| 121 | |
| 122 | /* fill out header fields */ |
| 123 | memcpy(header->signature, "HPET", 4); |
| 124 | memcpy(header->oem_id, OEM_ID, 6); |
| 125 | memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8); |
| 126 | memcpy(header->asl_compiler_id, ASLC, 4); |
| 127 | |
| 128 | header->length = sizeof(acpi_hpet_t); |
Marc Jones | 8abf6ae | 2018-08-22 19:08:52 -0600 | [diff] [blame] | 129 | header->revision = get_acpi_table_revision(HPET); |
York Yang | d7cba28 | 2016-03-09 10:54:26 -0800 | [diff] [blame] | 130 | |
| 131 | /* fill out HPET address */ |
| 132 | addr->space_id = 0; /* Memory */ |
| 133 | addr->bit_width = 64; |
| 134 | addr->bit_offset = 0; |
| 135 | addr->addrl = (unsigned long long)HPET_BASE_ADDRESS & 0xffffffff; |
| 136 | addr->addrh = (unsigned long long)HPET_BASE_ADDRESS >> 32; |
| 137 | |
| 138 | hpet->id = 0x8086a201; /* Intel */ |
| 139 | hpet->number = 0x00; |
| 140 | hpet->min_tick = 0x0080; |
| 141 | |
| 142 | header->checksum = acpi_checksum((void *) hpet, sizeof(acpi_hpet_t)); |
| 143 | } |
| 144 | |
| 145 | unsigned long acpi_fill_mcfg(unsigned long current) |
| 146 | { |
| 147 | current += acpi_create_mcfg_mmconfig((acpi_mcfg_mmconfig_t *)current, |
| 148 | MCFG_BASE_ADDRESS, 0, 0, 255); |
| 149 | return current; |
| 150 | } |
| 151 | |
| 152 | /** |
| 153 | * Fill in the fadt with generic values that can be overridden later. |
| 154 | */ |
| 155 | |
| 156 | void acpi_fill_in_fadt(acpi_fadt_t *fadt, acpi_facs_t *facs, void *dsdt) |
| 157 | { |
| 158 | acpi_header_t *header = &(fadt->header); |
| 159 | u16 pmbase = get_pmbase(); |
| 160 | |
| 161 | memset((void *) fadt, 0, sizeof(acpi_fadt_t)); |
| 162 | |
| 163 | /* |
| 164 | * Reference section 5.2.9 Fixed ACPI Description Table (FADT) |
| 165 | * in the ACPI 3.0b specification. |
| 166 | */ |
| 167 | |
| 168 | /* FADT Header Structure */ |
| 169 | memcpy(header->signature, "FACP", 4); |
| 170 | header->length = sizeof(acpi_fadt_t); |
Marc Jones | f9ea7ed | 2018-08-22 18:59:26 -0600 | [diff] [blame] | 171 | header->revision = get_acpi_table_revision(FADT); |
York Yang | d7cba28 | 2016-03-09 10:54:26 -0800 | [diff] [blame] | 172 | memcpy(header->oem_id, OEM_ID, 6); |
| 173 | memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8); |
| 174 | memcpy(header->asl_compiler_id, ASLC, 4); |
Elyes HAOUAS | 26071aa | 2019-02-15 08:21:33 +0100 | [diff] [blame] | 175 | header->asl_compiler_revision = asl_revision; |
York Yang | d7cba28 | 2016-03-09 10:54:26 -0800 | [diff] [blame] | 176 | |
| 177 | /* ACPI Pointers */ |
| 178 | fadt->firmware_ctrl = (unsigned long) facs; |
| 179 | fadt->dsdt = (unsigned long) dsdt; |
| 180 | |
| 181 | fadt->model = 0; /* reserved, should be 0 ACPI 3.0 */ |
| 182 | fadt->preferred_pm_profile = 0; |
| 183 | fadt->sci_int = acpi_sci_irq(); |
| 184 | |
| 185 | /* System Management */ |
| 186 | fadt->smi_cmd = 0x00; /* disable SMM */ |
| 187 | fadt->acpi_enable = 0x00; /* unused if SMI_CMD = 0 */ |
| 188 | fadt->acpi_disable = 0x00; /* unused if SMI_CMD = 0 */ |
| 189 | |
| 190 | /* Enable ACPI */ |
| 191 | outl(inl(pmbase + 4) | 0x01, pmbase + 4); |
| 192 | |
| 193 | /* Power Control */ |
| 194 | fadt->s4bios_req = 0x00; |
| 195 | fadt->pstate_cnt = 0x00; |
| 196 | |
| 197 | /* Control Registers - Base Address */ |
| 198 | fadt->pm1a_evt_blk = pmbase + PM1_STS; |
| 199 | fadt->pm1b_evt_blk = 0x00; /* Not Used */ |
| 200 | fadt->pm1a_cnt_blk = pmbase + PM1_CNT; |
| 201 | fadt->pm1b_cnt_blk = 0x00; /* Not Used */ |
| 202 | fadt->pm2_cnt_blk = pmbase + PM2A_CNT_BLK; |
| 203 | fadt->pm_tmr_blk = pmbase + PM1_TMR; |
| 204 | fadt->gpe0_blk = pmbase + GPE0_STS; |
| 205 | fadt->gpe1_blk = 0x00; /* Not Used */ |
| 206 | |
| 207 | /* Control Registers - Length */ |
| 208 | fadt->pm1_evt_len = 4; /* 32 bits */ |
| 209 | fadt->pm1_cnt_len = 2; /* 32 bit register, 16 bits used */ |
| 210 | fadt->pm2_cnt_len = 1; /* 8 bits */ |
| 211 | fadt->pm_tmr_len = 4; /* 32 bits */ |
| 212 | fadt->gpe0_blk_len = 8; /* 64 bits */ |
| 213 | fadt->gpe1_blk_len = 0; |
| 214 | fadt->gpe1_base = 0; |
| 215 | fadt->cst_cnt = 0; |
| 216 | fadt->p_lvl2_lat = ACPI_FADT_C2_NOT_SUPPORTED; |
| 217 | fadt->p_lvl3_lat = ACPI_FADT_C3_NOT_SUPPORTED; |
| 218 | fadt->flush_size = 0; /* set to 0 if WBINVD is 1 in flags */ |
| 219 | fadt->flush_stride = 0; /* set to 0 if WBINVD is 1 in flags */ |
| 220 | fadt->duty_offset = 1; |
| 221 | fadt->duty_width = 0; |
| 222 | |
| 223 | /* RTC Registers */ |
| 224 | fadt->day_alrm = 0x0D; |
| 225 | fadt->mon_alrm = 0x00; |
| 226 | fadt->century = 0x00; |
Paul Menzel | 8ca2af1 | 2019-02-08 15:19:20 +0100 | [diff] [blame] | 227 | fadt->iapc_boot_arch = ACPI_FADT_LEGACY_FREE; |
York Yang | d7cba28 | 2016-03-09 10:54:26 -0800 | [diff] [blame] | 228 | |
| 229 | fadt->flags = ACPI_FADT_WBINVD | ACPI_FADT_C1_SUPPORTED | |
| 230 | ACPI_FADT_C2_MP_SUPPORTED | ACPI_FADT_SLEEP_BUTTON | |
| 231 | ACPI_FADT_RESET_REGISTER | ACPI_FADT_SLEEP_TYPE | |
| 232 | ACPI_FADT_S4_RTC_WAKE | ACPI_FADT_PLATFORM_CLOCK; |
| 233 | |
| 234 | /* Reset Register */ |
| 235 | fadt->reset_reg.space_id = ACPI_ADDRESS_SPACE_IO; |
| 236 | fadt->reset_reg.bit_width = 8; |
| 237 | fadt->reset_reg.bit_offset = 0; |
| 238 | fadt->reset_reg.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS; |
| 239 | fadt->reset_reg.addrl = 0xCF9; |
| 240 | fadt->reset_reg.addrh = 0x00; |
| 241 | fadt->reset_value = 6; |
| 242 | |
Elyes HAOUAS | f5b974e | 2018-11-10 20:29:08 +0100 | [diff] [blame] | 243 | fadt->ARM_boot_arch = 0; /* MUST be 0 ACPI 3.0 */ |
| 244 | fadt->FADT_MinorVersion = 0; /* MUST be 0 ACPI 3.0 */ |
York Yang | d7cba28 | 2016-03-09 10:54:26 -0800 | [diff] [blame] | 245 | |
| 246 | /* Extended ACPI Pointers */ |
| 247 | fadt->x_firmware_ctl_l = (unsigned long)facs; |
| 248 | fadt->x_firmware_ctl_h = 0x00; |
| 249 | fadt->x_dsdt_l = (unsigned long)dsdt; |
| 250 | fadt->x_dsdt_h = 0x00; |
| 251 | |
| 252 | /* PM1 Status & PM1 Enable */ |
| 253 | fadt->x_pm1a_evt_blk.space_id = ACPI_ADDRESS_SPACE_IO; |
| 254 | fadt->x_pm1a_evt_blk.bit_width = fadt->pm1_evt_len * 8; |
| 255 | fadt->x_pm1a_evt_blk.bit_offset = 0; |
| 256 | fadt->x_pm1a_evt_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS; |
| 257 | fadt->x_pm1a_evt_blk.addrl = fadt->pm1a_evt_blk; |
| 258 | fadt->x_pm1a_evt_blk.addrh = 0x00; |
| 259 | |
| 260 | fadt->x_pm1b_evt_blk.space_id = ACPI_ADDRESS_SPACE_IO; |
| 261 | fadt->x_pm1b_evt_blk.bit_width = 0; |
| 262 | fadt->x_pm1b_evt_blk.bit_offset = 0; |
| 263 | fadt->x_pm1b_evt_blk.access_size = 0; |
| 264 | fadt->x_pm1b_evt_blk.addrl = fadt->pm1b_evt_blk; |
| 265 | fadt->x_pm1b_evt_blk.addrh = 0x00; |
| 266 | |
| 267 | /* PM1 Control Registers */ |
| 268 | fadt->x_pm1a_cnt_blk.space_id = ACPI_ADDRESS_SPACE_IO; |
| 269 | fadt->x_pm1a_cnt_blk.bit_width = 16; |
| 270 | fadt->x_pm1a_cnt_blk.bit_offset = 0; |
| 271 | fadt->x_pm1a_cnt_blk.access_size = ACPI_ACCESS_SIZE_WORD_ACCESS; |
| 272 | fadt->x_pm1a_cnt_blk.addrl = fadt->pm1a_cnt_blk; |
| 273 | fadt->x_pm1a_cnt_blk.addrh = 0x00; |
| 274 | |
| 275 | fadt->x_pm1b_cnt_blk.space_id = ACPI_ADDRESS_SPACE_IO; |
| 276 | fadt->x_pm1b_cnt_blk.bit_width = 0; |
| 277 | fadt->x_pm1b_cnt_blk.bit_offset = 0; |
| 278 | fadt->x_pm1b_cnt_blk.access_size = 0; |
| 279 | fadt->x_pm1b_cnt_blk.addrl = fadt->pm1b_cnt_blk; |
| 280 | fadt->x_pm1b_cnt_blk.addrh = 0x00; |
| 281 | |
| 282 | /* PM2 Control Registers */ |
| 283 | fadt->x_pm2_cnt_blk.space_id = ACPI_ADDRESS_SPACE_IO; |
| 284 | fadt->x_pm2_cnt_blk.bit_width = 8; |
| 285 | fadt->x_pm2_cnt_blk.bit_offset = 0; |
| 286 | fadt->x_pm2_cnt_blk.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS; |
| 287 | fadt->x_pm2_cnt_blk.addrl = fadt->pm2_cnt_blk; |
| 288 | fadt->x_pm2_cnt_blk.addrh = 0x00; |
| 289 | |
| 290 | /* PM1 Timer Register */ |
| 291 | fadt->x_pm_tmr_blk.space_id = ACPI_ADDRESS_SPACE_IO; |
| 292 | fadt->x_pm_tmr_blk.bit_width = 32; |
| 293 | fadt->x_pm_tmr_blk.bit_offset = 0; |
| 294 | fadt->x_pm_tmr_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS; |
| 295 | fadt->x_pm_tmr_blk.addrl = fadt->pm_tmr_blk; |
| 296 | fadt->x_pm_tmr_blk.addrh = 0x00; |
| 297 | |
| 298 | /* General-Purpose Event Registers */ |
| 299 | fadt->x_gpe0_blk.space_id = ACPI_ADDRESS_SPACE_IO; |
| 300 | fadt->x_gpe0_blk.bit_width = 64; /* EventStatus + EventEnable */ |
| 301 | fadt->x_gpe0_blk.bit_offset = 0; |
| 302 | fadt->x_gpe0_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS; |
| 303 | fadt->x_gpe0_blk.addrl = fadt->gpe0_blk; |
| 304 | fadt->x_gpe0_blk.addrh = 0x00; |
| 305 | |
| 306 | fadt->x_gpe1_blk.space_id = ACPI_ADDRESS_SPACE_IO; |
| 307 | fadt->x_gpe1_blk.bit_width = 0; |
| 308 | fadt->x_gpe1_blk.bit_offset = 0; |
| 309 | fadt->x_gpe1_blk.access_size = 0; |
| 310 | fadt->x_gpe1_blk.addrl = fadt->gpe1_blk; |
| 311 | fadt->x_gpe1_blk.addrh = 0x00; |
York Yang | d7cba28 | 2016-03-09 10:54:26 -0800 | [diff] [blame] | 312 | } |
| 313 | |
Werner Zeh | 1cfb555 | 2016-07-27 08:22:50 +0200 | [diff] [blame] | 314 | static unsigned long acpi_fill_dmar(unsigned long current) |
| 315 | { |
| 316 | uint32_t vtbar, tmp = current; |
Kyösti Mälkki | e737755 | 2018-06-21 16:20:55 +0300 | [diff] [blame] | 317 | struct device *dev = pcidev_path_on_root(VTD_DEV_FUNC); |
Werner Zeh | 1cfb555 | 2016-07-27 08:22:50 +0200 | [diff] [blame] | 318 | uint16_t bdf, hpet_bdf[8]; |
| 319 | uint8_t i, j; |
| 320 | |
| 321 | if (!dev) |
| 322 | return current; |
| 323 | |
| 324 | vtbar = pci_read_config32(dev, VTBAR_OFFSET) & VTBAR_MASK; |
| 325 | if (!vtbar) |
| 326 | return current; |
| 327 | |
| 328 | current += acpi_create_dmar_drhd(current, |
| 329 | DRHD_INCLUDE_PCI_ALL, 0, vtbar); |
| 330 | /* The IIO I/O APIC is fixed on PCI 00:05.4 on Broadwell-DE */ |
Matt DeVillier | 7866d49 | 2018-03-29 14:59:57 +0200 | [diff] [blame] | 331 | current += acpi_create_dmar_ds_ioapic(current, |
Werner Zeh | 1cfb555 | 2016-07-27 08:22:50 +0200 | [diff] [blame] | 332 | 9, 0, 5, 4); |
| 333 | /* Get the PCI BDF for the PCH I/O APIC */ |
Kyösti Mälkki | e737755 | 2018-06-21 16:20:55 +0300 | [diff] [blame] | 334 | dev = pcidev_path_on_root(LPC_DEV_FUNC); |
Werner Zeh | 1cfb555 | 2016-07-27 08:22:50 +0200 | [diff] [blame] | 335 | bdf = pci_read_config16(dev, 0x6c); |
Matt DeVillier | 7866d49 | 2018-03-29 14:59:57 +0200 | [diff] [blame] | 336 | current += acpi_create_dmar_ds_ioapic(current, |
Werner Zeh | 1cfb555 | 2016-07-27 08:22:50 +0200 | [diff] [blame] | 337 | 8, (bdf >> 8), PCI_SLOT(bdf), PCI_FUNC(bdf)); |
| 338 | |
| 339 | /* |
| 340 | * Check if there are different PCI paths for the 8 HPET timers |
| 341 | * and add every different PCI path as a separate HPET entry. |
| 342 | * Although the DMAR specification talks about HPET block for this |
| 343 | * entry, it is possible to assign a unique PCI BDF to every single |
| 344 | * timer within a HPET block which will result in different source |
| 345 | * IDs reported by a generated MSI. |
| 346 | * In default configuration every single timer will have the same |
| 347 | * PCI BDF which will result in a single HPET entry in DMAR table. |
| 348 | * I have checked several different systems and all of them had one |
| 349 | * single entry for HPET in DMAR. |
| 350 | */ |
| 351 | memset(hpet_bdf, 0, sizeof(hpet_bdf)); |
| 352 | /* Get all unique HPET paths. */ |
| 353 | for (i = 0; i < ARRAY_SIZE(hpet_bdf); i++) { |
| 354 | bdf = pci_read_config16(dev, 0x70 + (i * 2)); |
| 355 | for (j = 0; j < i; j++) { |
| 356 | if (hpet_bdf[j] == bdf) |
| 357 | break; |
| 358 | } |
| 359 | if (j == i) |
| 360 | hpet_bdf[i] = bdf; |
| 361 | } |
| 362 | /* Create one HPET entry in DMAR for every unique HPET PCI path. */ |
| 363 | for (i = 0; i < ARRAY_SIZE(hpet_bdf); i++) { |
| 364 | if (hpet_bdf[i]) |
Matt DeVillier | 7866d49 | 2018-03-29 14:59:57 +0200 | [diff] [blame] | 365 | current += acpi_create_dmar_ds_msi_hpet(current, |
Werner Zeh | 1cfb555 | 2016-07-27 08:22:50 +0200 | [diff] [blame] | 366 | 0, (hpet_bdf[i] >> 8), PCI_SLOT(hpet_bdf[i]), |
| 367 | PCI_FUNC(hpet_bdf[i])); |
| 368 | } |
| 369 | acpi_dmar_drhd_fixup(tmp, current); |
| 370 | |
| 371 | /* Create root port ATSR capability */ |
| 372 | tmp = current; |
| 373 | current += acpi_create_dmar_atsr(current, 0, 0); |
| 374 | /* Add one entry to ATSR for each PCI root port */ |
| 375 | dev = all_devices; |
| 376 | do { |
| 377 | dev = dev_find_class(PCI_CLASS_BRIDGE_PCI << 8, dev); |
| 378 | if (dev && dev->bus->secondary == 0 && |
| 379 | PCI_SLOT(dev->path.pci.devfn) <= 3) |
Matt DeVillier | 7866d49 | 2018-03-29 14:59:57 +0200 | [diff] [blame] | 380 | current += acpi_create_dmar_ds_pci_br(current, |
Werner Zeh | 1cfb555 | 2016-07-27 08:22:50 +0200 | [diff] [blame] | 381 | dev->bus->secondary, |
| 382 | PCI_SLOT(dev->path.pci.devfn), |
| 383 | PCI_FUNC(dev->path.pci.devfn)); |
| 384 | } while (dev); |
| 385 | acpi_dmar_atsr_fixup(tmp, current); |
| 386 | |
| 387 | return current; |
| 388 | } |
| 389 | |
Werner Zeh | ca0c8e7 | 2018-09-19 08:06:54 +0200 | [diff] [blame] | 390 | unsigned long vtd_write_acpi_tables(struct device *const dev, |
Werner Zeh | 1cfb555 | 2016-07-27 08:22:50 +0200 | [diff] [blame] | 391 | unsigned long current, |
| 392 | struct acpi_rsdp *const rsdp) |
| 393 | { |
| 394 | acpi_dmar_t *const dmar = (acpi_dmar_t *)current; |
Werner Zeh | 1cfb555 | 2016-07-27 08:22:50 +0200 | [diff] [blame] | 395 | |
| 396 | /* Create DMAR table only if virtualization is enabled */ |
Werner Zeh | ca0c8e7 | 2018-09-19 08:06:54 +0200 | [diff] [blame] | 397 | if (!(pci_read_config32(dev, VTBAR_OFFSET) & VTBAR_ENABLED)) |
Werner Zeh | 1cfb555 | 2016-07-27 08:22:50 +0200 | [diff] [blame] | 398 | return current; |
| 399 | |
| 400 | printk(BIOS_DEBUG, "ACPI: * DMAR\n"); |
| 401 | acpi_create_dmar(dmar, DMAR_INTR_REMAP, acpi_fill_dmar); |
| 402 | current += dmar->header.length; |
| 403 | current = acpi_align_current(current); |
| 404 | acpi_add_table(rsdp, dmar); |
| 405 | current = acpi_align_current(current); |
| 406 | |
| 407 | return current; |
| 408 | } |
| 409 | |
York Yang | d7cba28 | 2016-03-09 10:54:26 -0800 | [diff] [blame] | 410 | static int calculate_power(int tdp, int p1_ratio, int ratio) |
| 411 | { |
| 412 | u32 m; |
| 413 | u32 power; |
| 414 | |
| 415 | /* |
| 416 | * M = ((1.1 - ((p1_ratio - ratio) * 0.00625)) / 1.1) ^ 2 |
| 417 | * |
| 418 | * Power = (ratio / p1_ratio) * m * tdp |
| 419 | */ |
| 420 | |
| 421 | m = (110000 - ((p1_ratio - ratio) * 625)) / 11; |
| 422 | m = (m * m) / 1000; |
| 423 | |
| 424 | power = ((ratio * 100000 / p1_ratio) / 100); |
| 425 | power *= (m / 100) * (tdp / 1000); |
| 426 | power /= 1000; |
| 427 | |
| 428 | return (int)power; |
| 429 | } |
| 430 | |
| 431 | static void generate_P_state_entries(int core, int cores_per_package) |
| 432 | { |
| 433 | int ratio_min, ratio_max, ratio_step; |
| 434 | int coord_type, power_max, power_unit, num_entries; |
| 435 | int ratio, power, clock, clock_max; |
| 436 | int turbo; |
| 437 | u32 control_status; |
| 438 | msr_t msr; |
| 439 | |
| 440 | /* Hardware coordination of P-states */ |
| 441 | coord_type = HW_ALL; |
| 442 | |
| 443 | /* Check for Turbo Mode */ |
| 444 | turbo = get_turbo_state() == TURBO_ENABLED; |
| 445 | |
| 446 | /* CPU attributes */ |
| 447 | msr = rdmsr(MSR_PLATFORM_INFO); |
| 448 | ratio_min = (msr.hi >> 8) & 0xff; // LFM |
| 449 | ratio_max = (msr.lo >> 8) & 0xff; // HFM |
| 450 | clock_max = (ratio_max * 100); |
| 451 | |
| 452 | /* Calculate CPU TDP in mW */ |
| 453 | msr = rdmsr(MSR_PKG_POWER_SKU_UNIT); |
| 454 | power_unit = 1 << (msr.lo & 0xf); |
| 455 | msr = rdmsr(MSR_PKG_POWER_LIMIT); |
| 456 | power_max = ((msr.lo & 0x7fff) / power_unit) * 1000; |
| 457 | |
| 458 | /* Write _PCT indicating use of FFixedHW */ |
| 459 | acpigen_write_empty_PCT(); |
| 460 | |
| 461 | /* Write _PPC starting from first supported P-state */ |
| 462 | acpigen_write_PPC(0); |
| 463 | |
| 464 | /* Write PSD indicating configured coordination type */ |
| 465 | acpigen_write_PSD_package(core, 1, coord_type); |
| 466 | |
| 467 | /* Add P-state entries in _PSS table */ |
| 468 | acpigen_write_name("_PSS"); |
| 469 | |
| 470 | /* Determine ratio points */ |
| 471 | /* Note: There should be at most 16 performance states. If Turbo Mode |
| 472 | is enabled, the Max Turbo Ratio will occupy one of these states. */ |
| 473 | ratio_step = 1; |
| 474 | num_entries = (ratio_max - ratio_min) / ratio_step; |
| 475 | while (num_entries > (15-turbo)) { |
| 476 | ratio_step <<= 1; |
| 477 | num_entries >>= 1; |
| 478 | } |
| 479 | |
| 480 | if (turbo) { |
| 481 | /* _PSS package count (with turbo) */ |
| 482 | acpigen_write_package(num_entries + 2); |
| 483 | |
| 484 | /* Get Max Turbo Ratio */ |
| 485 | msr = rdmsr(MSR_TURBO_RATIO_LIMIT); |
| 486 | ratio = msr.lo & 0xff; |
| 487 | |
| 488 | acpigen_write_PSS_package( |
| 489 | ratio * 100, /* MHz */ |
| 490 | power_max, /* mW */ |
| 491 | 10, /* lat1 */ |
| 492 | 10, /* lat2 */ |
| 493 | ratio << 8, /* control */ |
| 494 | ratio << 8); /* status */ |
| 495 | } else { |
| 496 | /* _PSS package count (without turbo) */ |
| 497 | acpigen_write_package(num_entries + 1); |
| 498 | } |
| 499 | |
| 500 | /* Generate the _PSS entries */ |
| 501 | for (ratio = ratio_min + (num_entries * ratio_step); |
| 502 | ratio >= ratio_min; ratio -= ratio_step) { |
| 503 | |
| 504 | /* Calculate power at this ratio */ |
| 505 | power = calculate_power(power_max, ratio_max, ratio); |
| 506 | clock = ratio * 100; |
| 507 | control_status = ratio << 8; |
| 508 | |
| 509 | acpigen_write_PSS_package( |
| 510 | clock, /* MHz */ |
| 511 | power, /* mW */ |
| 512 | 10, /* lat1 */ |
| 513 | 10, /* lat2 */ |
| 514 | control_status, /* control */ |
| 515 | control_status); /* status */ |
| 516 | } |
| 517 | |
| 518 | /* Fix package length */ |
| 519 | acpigen_pop_len(); |
| 520 | } |
| 521 | |
Elyes HAOUAS | 15a487a | 2018-05-27 17:58:57 +0200 | [diff] [blame] | 522 | void generate_cpu_entries(struct device *device) |
York Yang | d7cba28 | 2016-03-09 10:54:26 -0800 | [diff] [blame] | 523 | { |
| 524 | int core; |
| 525 | int pcontrol_blk = get_pmbase(), plen = 6; |
| 526 | const struct pattrs *pattrs = pattrs_get(); |
| 527 | |
| 528 | for (core = 0; core < pattrs->num_cpus; core++) { |
| 529 | if (core > 0) { |
| 530 | pcontrol_blk = 0; |
| 531 | plen = 0; |
| 532 | } |
| 533 | |
| 534 | /* Generate processor \_PR.CP0x */ |
| 535 | acpigen_write_processor(core, pcontrol_blk, plen); |
| 536 | |
| 537 | /* Generate P-state tables */ |
| 538 | generate_P_state_entries(core, pattrs->num_cpus); |
| 539 | |
| 540 | /* Generate C-state tables */ |
| 541 | acpigen_write_CST_package(cstate_map, ARRAY_SIZE(cstate_map)); |
| 542 | |
| 543 | acpigen_pop_len(); |
| 544 | } |
| 545 | } |
| 546 | |
| 547 | unsigned long acpi_madt_irq_overrides(unsigned long current) |
| 548 | { |
| 549 | int sci_irq = acpi_sci_irq(); |
| 550 | acpi_madt_irqoverride_t *irqovr; |
| 551 | uint16_t sci_flags = MP_IRQ_TRIGGER_LEVEL; |
| 552 | |
| 553 | /* INT_SRC_OVR */ |
| 554 | irqovr = (void *)current; |
| 555 | current += acpi_create_madt_irqoverride(irqovr, 0, 0, 2, 0); |
| 556 | |
| 557 | if (sci_irq >= 20) |
| 558 | sci_flags |= MP_IRQ_POLARITY_LOW; |
| 559 | else |
| 560 | sci_flags |= MP_IRQ_POLARITY_HIGH; |
| 561 | |
| 562 | irqovr = (void *)current; |
| 563 | current += acpi_create_madt_irqoverride(irqovr, 0, sci_irq, sci_irq, |
| 564 | sci_flags); |
| 565 | |
York Yang | d7cba28 | 2016-03-09 10:54:26 -0800 | [diff] [blame] | 566 | return current; |
| 567 | } |