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

kv_smc.c (5116B)


      1/*
      2 * Copyright 2013 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 "amdgpu.h"
     26#include "cikd.h"
     27#include "kv_dpm.h"
     28
     29#include "smu/smu_7_0_0_d.h"
     30#include "smu/smu_7_0_0_sh_mask.h"
     31
     32int amdgpu_kv_notify_message_to_smu(struct amdgpu_device *adev, u32 id)
     33{
     34	u32 i;
     35	u32 tmp = 0;
     36
     37	WREG32(mmSMC_MESSAGE_0, id & SMC_MESSAGE_0__SMC_MSG_MASK);
     38
     39	for (i = 0; i < adev->usec_timeout; i++) {
     40		if ((RREG32(mmSMC_RESP_0) & SMC_RESP_0__SMC_RESP_MASK) != 0)
     41			break;
     42		udelay(1);
     43	}
     44	tmp = RREG32(mmSMC_RESP_0) & SMC_RESP_0__SMC_RESP_MASK;
     45
     46	if (tmp != 1) {
     47		if (tmp == 0xFF)
     48			return -EINVAL;
     49		else if (tmp == 0xFE)
     50			return -EINVAL;
     51	}
     52
     53	return 0;
     54}
     55
     56int amdgpu_kv_dpm_get_enable_mask(struct amdgpu_device *adev, u32 *enable_mask)
     57{
     58	int ret;
     59
     60	ret = amdgpu_kv_notify_message_to_smu(adev, PPSMC_MSG_SCLKDPM_GetEnabledMask);
     61
     62	if (ret == 0)
     63		*enable_mask = RREG32_SMC(ixSMC_SYSCON_MSG_ARG_0);
     64
     65	return ret;
     66}
     67
     68int amdgpu_kv_send_msg_to_smc_with_parameter(struct amdgpu_device *adev,
     69				      PPSMC_Msg msg, u32 parameter)
     70{
     71
     72	WREG32(mmSMC_MSG_ARG_0, parameter);
     73
     74	return amdgpu_kv_notify_message_to_smu(adev, msg);
     75}
     76
     77static int kv_set_smc_sram_address(struct amdgpu_device *adev,
     78				   u32 smc_address, u32 limit)
     79{
     80	if (smc_address & 3)
     81		return -EINVAL;
     82	if ((smc_address + 3) > limit)
     83		return -EINVAL;
     84
     85	WREG32(mmSMC_IND_INDEX_0, smc_address);
     86	WREG32_P(mmSMC_IND_ACCESS_CNTL, 0,
     87			~SMC_IND_ACCESS_CNTL__AUTO_INCREMENT_IND_0_MASK);
     88
     89	return 0;
     90}
     91
     92int amdgpu_kv_read_smc_sram_dword(struct amdgpu_device *adev, u32 smc_address,
     93			   u32 *value, u32 limit)
     94{
     95	int ret;
     96
     97	ret = kv_set_smc_sram_address(adev, smc_address, limit);
     98	if (ret)
     99		return ret;
    100
    101	*value = RREG32(mmSMC_IND_DATA_0);
    102	return 0;
    103}
    104
    105int amdgpu_kv_smc_dpm_enable(struct amdgpu_device *adev, bool enable)
    106{
    107	if (enable)
    108		return amdgpu_kv_notify_message_to_smu(adev, PPSMC_MSG_DPM_Enable);
    109	else
    110		return amdgpu_kv_notify_message_to_smu(adev, PPSMC_MSG_DPM_Disable);
    111}
    112
    113int amdgpu_kv_smc_bapm_enable(struct amdgpu_device *adev, bool enable)
    114{
    115	if (enable)
    116		return amdgpu_kv_notify_message_to_smu(adev, PPSMC_MSG_EnableBAPM);
    117	else
    118		return amdgpu_kv_notify_message_to_smu(adev, PPSMC_MSG_DisableBAPM);
    119}
    120
    121int amdgpu_kv_copy_bytes_to_smc(struct amdgpu_device *adev,
    122			 u32 smc_start_address,
    123			 const u8 *src, u32 byte_count, u32 limit)
    124{
    125	int ret;
    126	u32 data, original_data, addr, extra_shift, t_byte, count, mask;
    127
    128	if ((smc_start_address + byte_count) > limit)
    129		return -EINVAL;
    130
    131	addr = smc_start_address;
    132	t_byte = addr & 3;
    133
    134	/* RMW for the initial bytes */
    135	if  (t_byte != 0) {
    136		addr -= t_byte;
    137
    138		ret = kv_set_smc_sram_address(adev, addr, limit);
    139		if (ret)
    140			return ret;
    141
    142		original_data = RREG32(mmSMC_IND_DATA_0);
    143
    144		data = 0;
    145		mask = 0;
    146		count = 4;
    147		while (count > 0) {
    148			if (t_byte > 0) {
    149				mask = (mask << 8) | 0xff;
    150				t_byte--;
    151			} else if (byte_count > 0) {
    152				data = (data << 8) + *src++;
    153				byte_count--;
    154				mask <<= 8;
    155			} else {
    156				data <<= 8;
    157				mask = (mask << 8) | 0xff;
    158			}
    159			count--;
    160		}
    161
    162		data |= original_data & mask;
    163
    164		ret = kv_set_smc_sram_address(adev, addr, limit);
    165		if (ret)
    166			return ret;
    167
    168		WREG32(mmSMC_IND_DATA_0, data);
    169
    170		addr += 4;
    171	}
    172
    173	while (byte_count >= 4) {
    174		/* SMC address space is BE */
    175		data = (src[0] << 24) + (src[1] << 16) + (src[2] << 8) + src[3];
    176
    177		ret = kv_set_smc_sram_address(adev, addr, limit);
    178		if (ret)
    179			return ret;
    180
    181		WREG32(mmSMC_IND_DATA_0, data);
    182
    183		src += 4;
    184		byte_count -= 4;
    185		addr += 4;
    186	}
    187
    188	/* RMW for the final bytes */
    189	if (byte_count > 0) {
    190		data = 0;
    191
    192		ret = kv_set_smc_sram_address(adev, addr, limit);
    193		if (ret)
    194			return ret;
    195
    196		original_data = RREG32(mmSMC_IND_DATA_0);
    197
    198		extra_shift = 8 * (4 - byte_count);
    199
    200		while (byte_count > 0) {
    201			/* SMC address space is BE */
    202			data = (data << 8) + *src++;
    203			byte_count--;
    204		}
    205
    206		data <<= extra_shift;
    207
    208		data |= (original_data & ~((~0UL) << extra_shift));
    209
    210		ret = kv_set_smc_sram_address(adev, addr, limit);
    211		if (ret)
    212			return ret;
    213
    214		WREG32(mmSMC_IND_DATA_0, data);
    215	}
    216	return 0;
    217}
    218