/* * Copyright (C) 2020 Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include static uint64_t software_sram_bottom_hpa; static uint64_t software_sram_top_hpa; /* is_sw_sram_initialized is used to tell whether Software SRAM is successfully initialized for all cores */ static volatile bool is_sw_sram_initialized = false; #ifdef CONFIG_PSRAM_ENABLED static struct rtct_entry_data_rtcm_binary *rtcm_binary = NULL; static struct acpi_table_header *acpi_rtct_tbl = NULL; static inline void rtcm_flush_binary_tlb(void) { uint64_t linear_addr, start_addr = (uint64_t)hpa2hva(rtcm_binary->address); uint64_t end_addr = start_addr + rtcm_binary->size; for (linear_addr = start_addr; linear_addr < end_addr; linear_addr += PAGE_SIZE) { invlpg(linear_addr); } } static inline void *get_rtct_entry_base() { return (void *)acpi_rtct_tbl + sizeof(*acpi_rtct_tbl); } void set_rtct_tbl(void *rtct_tbl_addr) { acpi_rtct_tbl = rtct_tbl_addr; } /* *@pre the PSRAM region is separate and never mixed with normal DRAM *@pre acpi_rtct_tbl != NULL */ static void parse_rtct(void) { uint64_t bottom_hpa = ULONG_MAX; struct rtct_entry *entry; struct rtct_entry_data_software_sram *sw_sram_entry; entry = get_rtct_entry_base(); while (((uint64_t)entry - (uint64_t)acpi_rtct_tbl) < acpi_rtct_tbl->length) { switch (entry->type) { case RTCT_ENTRY_TYPE_RTCM_BINARY: rtcm_binary = (struct rtct_entry_data_rtcm_binary *)entry->data; ASSERT((rtcm_binary->address != 0UL && rtcm_binary->size != 0U), "Invalid PTCM binary."); pr_info("found RTCM bin, in HPA %llx, size %llx", rtcm_binary->address, rtcm_binary->size); break; case RTCT_ENTRY_TYPE_SOFTWARE_SRAM: sw_sram_entry = (struct rtct_entry_data_software_sram *)entry->data; if (software_sram_top_hpa < sw_sram_entry->base + sw_sram_entry->size) { software_sram_top_hpa = sw_sram_entry->base + sw_sram_entry->size; } if (bottom_hpa > sw_sram_entry->base) { bottom_hpa = sw_sram_entry->base; } pr_info("found L%d Software SRAM, at HPA %llx, size %x", sw_sram_entry->cache_level, sw_sram_entry->base, sw_sram_entry->size); break; /* In current phase, we ignore other entries like gt_clos and wrc_close */ default: break; } /* point to next rtct entry */ entry = (struct rtct_entry *)((uint64_t)entry + entry->size); } if (bottom_hpa != ULONG_MAX) { /* Software SRAM regions are detected. */ software_sram_bottom_hpa = bottom_hpa; software_sram_top_hpa = round_page_up(software_sram_top_hpa); } } /* * Function to initialize Software SRAM. Both BSP and APs shall call this function to * make sure Software SRAM is initialized, which is required by RTCM. * BSP: * To parse RTCT and find the entry of RTCM command function * AP: * Wait until BSP has done the parsing work, then call the RTCM ABI. * * Synchronization of AP and BSP is ensured, both inside and outside RTCM. * BSP shall be the last to finish the call. */ bool init_software_sram(bool is_bsp) { bool ret = true; int32_t rtcm_ret_code; struct rtcm_header *header; rtcm_abi_func rtcm_command_func = NULL; static uint64_t init_sw_sram_cpus_mask = (1UL << BSP_CPU_ID); /* * When we shut down an RTVM, its pCPUs will be re-initialized * we must ensure init_software_sram() will only be executed at the first time when a pcpu is booted * That's why we add "!is_sw_sram_initialized" as an condition. */ if (!is_sw_sram_initialized && (acpi_rtct_tbl != NULL)) { /* TODO: We may use SMP call to flush TLB and do Software SRAM initialization on APs */ if (is_bsp) { parse_rtct(); if (rtcm_binary != NULL) { /* Clear the NX bit of PTCM area */ set_paging_x((uint64_t)hpa2hva(rtcm_binary->address), rtcm_binary->size); } bitmap_clear_lock(get_pcpu_id(), &init_sw_sram_cpus_mask); } wait_sync_change(&init_sw_sram_cpus_mask, 0UL); if (rtcm_binary != NULL) { header = hpa2hva(rtcm_binary->address); pr_info("rtcm_bin_address:%llx, rtcm magic:%x, rtcm version:%x", rtcm_binary->address, header->magic, header->version); ASSERT(header->magic == RTCM_MAGIC, "Incorrect RTCM magic!"); /* Flush the TLB, so that BSP/AP can execute the RTCM ABI */ rtcm_flush_binary_tlb(); rtcm_command_func = (rtcm_abi_func)(hpa2hva(rtcm_binary->address) + header->command_offset); pr_info("rtcm command function is found at %llx", rtcm_command_func); rtcm_ret_code = rtcm_command_func(RTCM_CMD_INIT_SOFTWARE_SRAM, get_rtct_entry_base()); pr_info("rtcm initialization return %d", rtcm_ret_code); /* return 0 for success, -1 for failure */ ASSERT(rtcm_ret_code == 0); if (is_bsp) { /* Restore the NX bit of RTCM area in page table */ set_paging_nx((uint64_t)hpa2hva(rtcm_binary->address), rtcm_binary->size); } bitmap_set_lock(get_pcpu_id(), &init_sw_sram_cpus_mask); wait_sync_change(&init_sw_sram_cpus_mask, ALL_CPUS_MASK); /* Flush the TLB on BSP and all APs to restore the NX for Software SRAM area */ rtcm_flush_binary_tlb(); if (is_bsp) { is_sw_sram_initialized = true; pr_info("BSP Software SRAM has been initialized, base_hpa:0x%lx, top_hpa:0x%lx.\n", software_sram_bottom_hpa, software_sram_top_hpa); } ret = disable_host_monitor_wait(); } } return ret; } #else void set_rtct_tbl(__unused void *rtct_tbl_addr) { } bool init_software_sram(__unused bool is_bsp) { return true; } #endif /* @pre called after 'init_software_sram()' done. */ bool is_software_sram_enabled(void) { return is_sw_sram_initialized; } uint64_t get_software_sram_base(void) { return software_sram_bottom_hpa; } uint64_t get_software_sram_size(void) { return (software_sram_top_hpa - software_sram_bottom_hpa); }