cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

si_smc.c (6610B)


      1/*
      2 * Copyright 2011 Advanced Micro Devices, Inc.
      3 *
      4 * Permission is hereby granted, free of charge, to any person obtaining a
      5 * copy of this software and associated documentation files (the "Software"),
      6 * to deal in the Software without restriction, including without limitation
      7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8 * and/or sell copies of the Software, and to permit persons to whom the
      9 * Software is furnished to do so, subject to the following conditions:
     10 *
     11 * The above copyright notice and this permission notice shall be included in
     12 * all copies or substantial portions of the Software.
     13 *
     14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
     18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     20 * OTHER DEALINGS IN THE SOFTWARE.
     21 *
     22 * Authors: Alex Deucher
     23 */
     24
     25#include <linux/firmware.h>
     26
     27#include "amdgpu.h"
     28#include "sid.h"
     29#include "ppsmc.h"
     30#include "amdgpu_ucode.h"
     31#include "sislands_smc.h"
     32
     33static int si_set_smc_sram_address(struct amdgpu_device *adev,
     34				   u32 smc_address, u32 limit)
     35{
     36	if (smc_address & 3)
     37		return -EINVAL;
     38	if ((smc_address + 3) > limit)
     39		return -EINVAL;
     40
     41	WREG32(SMC_IND_INDEX_0, smc_address);
     42	WREG32_P(SMC_IND_ACCESS_CNTL, 0, ~AUTO_INCREMENT_IND_0);
     43
     44	return 0;
     45}
     46
     47int amdgpu_si_copy_bytes_to_smc(struct amdgpu_device *adev,
     48				u32 smc_start_address,
     49				const u8 *src, u32 byte_count, u32 limit)
     50{
     51	unsigned long flags;
     52	int ret = 0;
     53	u32 data, original_data, addr, extra_shift;
     54
     55	if (smc_start_address & 3)
     56		return -EINVAL;
     57	if ((smc_start_address + byte_count) > limit)
     58		return -EINVAL;
     59
     60	addr = smc_start_address;
     61
     62	spin_lock_irqsave(&adev->smc_idx_lock, flags);
     63	while (byte_count >= 4) {
     64		/* SMC address space is BE */
     65		data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
     66
     67		ret = si_set_smc_sram_address(adev, addr, limit);
     68		if (ret)
     69			goto done;
     70
     71		WREG32(SMC_IND_DATA_0, data);
     72
     73		src += 4;
     74		byte_count -= 4;
     75		addr += 4;
     76	}
     77
     78	/* RMW for the final bytes */
     79	if (byte_count > 0) {
     80		data = 0;
     81
     82		ret = si_set_smc_sram_address(adev, addr, limit);
     83		if (ret)
     84			goto done;
     85
     86		original_data = RREG32(SMC_IND_DATA_0);
     87		extra_shift = 8 * (4 - byte_count);
     88
     89		while (byte_count > 0) {
     90			/* SMC address space is BE */
     91			data = (data << 8) + *src++;
     92			byte_count--;
     93		}
     94
     95		data <<= extra_shift;
     96		data |= (original_data & ~((~0UL) << extra_shift));
     97
     98		ret = si_set_smc_sram_address(adev, addr, limit);
     99		if (ret)
    100			goto done;
    101
    102		WREG32(SMC_IND_DATA_0, data);
    103	}
    104
    105done:
    106	spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
    107
    108	return ret;
    109}
    110
    111void amdgpu_si_start_smc(struct amdgpu_device *adev)
    112{
    113	u32 tmp = RREG32_SMC(SMC_SYSCON_RESET_CNTL);
    114
    115	tmp &= ~RST_REG;
    116
    117	WREG32_SMC(SMC_SYSCON_RESET_CNTL, tmp);
    118}
    119
    120void amdgpu_si_reset_smc(struct amdgpu_device *adev)
    121{
    122	u32 tmp;
    123
    124	RREG32(CB_CGTT_SCLK_CTRL);
    125	RREG32(CB_CGTT_SCLK_CTRL);
    126	RREG32(CB_CGTT_SCLK_CTRL);
    127	RREG32(CB_CGTT_SCLK_CTRL);
    128
    129	tmp = RREG32_SMC(SMC_SYSCON_RESET_CNTL) |
    130	      RST_REG;
    131	WREG32_SMC(SMC_SYSCON_RESET_CNTL, tmp);
    132}
    133
    134int amdgpu_si_program_jump_on_start(struct amdgpu_device *adev)
    135{
    136	static const u8 data[] = { 0x0E, 0x00, 0x40, 0x40 };
    137
    138	return amdgpu_si_copy_bytes_to_smc(adev, 0x0, data, 4, sizeof(data)+1);
    139}
    140
    141void amdgpu_si_smc_clock(struct amdgpu_device *adev, bool enable)
    142{
    143	u32 tmp = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0);
    144
    145	if (enable)
    146		tmp &= ~CK_DISABLE;
    147	else
    148		tmp |= CK_DISABLE;
    149
    150	WREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0, tmp);
    151}
    152
    153bool amdgpu_si_is_smc_running(struct amdgpu_device *adev)
    154{
    155	u32 rst = RREG32_SMC(SMC_SYSCON_RESET_CNTL);
    156	u32 clk = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0);
    157
    158	if (!(rst & RST_REG) && !(clk & CK_DISABLE))
    159		return true;
    160
    161	return false;
    162}
    163
    164PPSMC_Result amdgpu_si_send_msg_to_smc(struct amdgpu_device *adev,
    165				       PPSMC_Msg msg)
    166{
    167	u32 tmp;
    168	int i;
    169
    170	if (!amdgpu_si_is_smc_running(adev))
    171		return PPSMC_Result_Failed;
    172
    173	WREG32(SMC_MESSAGE_0, msg);
    174
    175	for (i = 0; i < adev->usec_timeout; i++) {
    176		tmp = RREG32(SMC_RESP_0);
    177		if (tmp != 0)
    178			break;
    179		udelay(1);
    180	}
    181
    182	return (PPSMC_Result)RREG32(SMC_RESP_0);
    183}
    184
    185PPSMC_Result amdgpu_si_wait_for_smc_inactive(struct amdgpu_device *adev)
    186{
    187	u32 tmp;
    188	int i;
    189
    190	if (!amdgpu_si_is_smc_running(adev))
    191		return PPSMC_Result_OK;
    192
    193	for (i = 0; i < adev->usec_timeout; i++) {
    194		tmp = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0);
    195		if ((tmp & CKEN) == 0)
    196			break;
    197		udelay(1);
    198	}
    199
    200	return PPSMC_Result_OK;
    201}
    202
    203int amdgpu_si_load_smc_ucode(struct amdgpu_device *adev, u32 limit)
    204{
    205	const struct smc_firmware_header_v1_0 *hdr;
    206	unsigned long flags;
    207	u32 ucode_start_address;
    208	u32 ucode_size;
    209	const u8 *src;
    210	u32 data;
    211
    212	if (!adev->pm.fw)
    213		return -EINVAL;
    214
    215	hdr = (const struct smc_firmware_header_v1_0 *)adev->pm.fw->data;
    216
    217	amdgpu_ucode_print_smc_hdr(&hdr->header);
    218
    219	adev->pm.fw_version = le32_to_cpu(hdr->header.ucode_version);
    220	ucode_start_address = le32_to_cpu(hdr->ucode_start_addr);
    221	ucode_size = le32_to_cpu(hdr->header.ucode_size_bytes);
    222	src = (const u8 *)
    223		(adev->pm.fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes));
    224	if (ucode_size & 3)
    225		return -EINVAL;
    226
    227	spin_lock_irqsave(&adev->smc_idx_lock, flags);
    228	WREG32(SMC_IND_INDEX_0, ucode_start_address);
    229	WREG32_P(SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, ~AUTO_INCREMENT_IND_0);
    230	while (ucode_size >= 4) {
    231		/* SMC address space is BE */
    232		data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
    233
    234		WREG32(SMC_IND_DATA_0, data);
    235
    236		src += 4;
    237		ucode_size -= 4;
    238	}
    239	WREG32_P(SMC_IND_ACCESS_CNTL, 0, ~AUTO_INCREMENT_IND_0);
    240	spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
    241
    242	return 0;
    243}
    244
    245int amdgpu_si_read_smc_sram_dword(struct amdgpu_device *adev, u32 smc_address,
    246				  u32 *value, u32 limit)
    247{
    248	unsigned long flags;
    249	int ret;
    250
    251	spin_lock_irqsave(&adev->smc_idx_lock, flags);
    252	ret = si_set_smc_sram_address(adev, smc_address, limit);
    253	if (ret == 0)
    254		*value = RREG32(SMC_IND_DATA_0);
    255	spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
    256
    257	return ret;
    258}
    259
    260int amdgpu_si_write_smc_sram_dword(struct amdgpu_device *adev, u32 smc_address,
    261				   u32 value, u32 limit)
    262{
    263	unsigned long flags;
    264	int ret;
    265
    266	spin_lock_irqsave(&adev->smc_idx_lock, flags);
    267	ret = si_set_smc_sram_address(adev, smc_address, limit);
    268	if (ret == 0)
    269		WREG32(SMC_IND_DATA_0, value);
    270	spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
    271
    272	return ret;
    273}