|
44 | 44 | vf2pf_info->ucode_info[ucode].version = ver; \ |
45 | 45 | } while (0) |
46 | 46 |
|
| 47 | +#define mmRCC_CONFIG_MEMSIZE 0xde3 |
| 48 | + |
| 49 | +const char *amdgpu_virt_dynamic_crit_table_name[] = { |
| 50 | + "IP DISCOVERY", |
| 51 | + "VBIOS IMG", |
| 52 | + "RAS TELEMETRY", |
| 53 | + "DATA EXCHANGE", |
| 54 | + "BAD PAGE INFO", |
| 55 | + "INIT HEADER", |
| 56 | + "LAST", |
| 57 | +}; |
| 58 | + |
47 | 59 | bool amdgpu_virt_mmio_blocked(struct amdgpu_device *adev) |
48 | 60 | { |
49 | 61 | /* By now all MMIO pages except mailbox are blocked */ |
@@ -843,6 +855,168 @@ static void amdgpu_virt_init_ras(struct amdgpu_device *adev) |
843 | 855 | adev->virt.ras.cper_rptr = 0; |
844 | 856 | } |
845 | 857 |
|
| 858 | +static uint8_t amdgpu_virt_crit_region_calc_checksum(uint8_t *buf_start, uint8_t *buf_end) |
| 859 | +{ |
| 860 | + uint32_t sum = 0; |
| 861 | + |
| 862 | + if (buf_start >= buf_end) |
| 863 | + return 0; |
| 864 | + |
| 865 | + for (; buf_start < buf_end; buf_start++) |
| 866 | + sum += buf_start[0]; |
| 867 | + |
| 868 | + return 0xffffffff - sum; |
| 869 | +} |
| 870 | + |
| 871 | +int amdgpu_virt_init_critical_region(struct amdgpu_device *adev) |
| 872 | +{ |
| 873 | + struct amd_sriov_msg_init_data_header *init_data_hdr = NULL; |
| 874 | + uint32_t init_hdr_offset = adev->virt.init_data_header.offset; |
| 875 | + uint32_t init_hdr_size = adev->virt.init_data_header.size_kb << 10; |
| 876 | + uint64_t vram_size; |
| 877 | + int r = 0; |
| 878 | + uint8_t checksum = 0; |
| 879 | + |
| 880 | + /* Skip below init if critical region version != v2 */ |
| 881 | + if (adev->virt.req_init_data_ver != GPU_CRIT_REGION_V2) |
| 882 | + return 0; |
| 883 | + |
| 884 | + if (init_hdr_offset < 0) { |
| 885 | + dev_err(adev->dev, "Invalid init header offset\n"); |
| 886 | + return -EINVAL; |
| 887 | + } |
| 888 | + |
| 889 | + vram_size = RREG32(mmRCC_CONFIG_MEMSIZE); |
| 890 | + if (!vram_size || vram_size == U32_MAX) |
| 891 | + return -EINVAL; |
| 892 | + vram_size <<= 20; |
| 893 | + |
| 894 | + if ((init_hdr_offset + init_hdr_size) > vram_size) { |
| 895 | + dev_err(adev->dev, "init_data_header exceeds VRAM size, exiting\n"); |
| 896 | + return -EINVAL; |
| 897 | + } |
| 898 | + |
| 899 | + /* Allocate for init_data_hdr */ |
| 900 | + init_data_hdr = kzalloc(sizeof(struct amd_sriov_msg_init_data_header), GFP_KERNEL); |
| 901 | + if (!init_data_hdr) |
| 902 | + return -ENOMEM; |
| 903 | + |
| 904 | + amdgpu_device_vram_access(adev, (uint64_t)init_hdr_offset, (uint32_t *)init_data_hdr, |
| 905 | + sizeof(struct amd_sriov_msg_init_data_header), false); |
| 906 | + |
| 907 | + /* Table validation */ |
| 908 | + if (strncmp(init_data_hdr->signature, |
| 909 | + AMDGPU_SRIOV_CRIT_DATA_SIGNATURE, |
| 910 | + AMDGPU_SRIOV_CRIT_DATA_SIG_LEN) != 0) { |
| 911 | + dev_err(adev->dev, "Invalid init data signature: %.4s\n", |
| 912 | + init_data_hdr->signature); |
| 913 | + r = -EINVAL; |
| 914 | + goto out; |
| 915 | + } |
| 916 | + |
| 917 | + checksum = amdgpu_virt_crit_region_calc_checksum( |
| 918 | + (uint8_t *)&init_data_hdr->initdata_offset, |
| 919 | + (uint8_t *)init_data_hdr + |
| 920 | + sizeof(struct amd_sriov_msg_init_data_header)); |
| 921 | + if (checksum != init_data_hdr->checksum) { |
| 922 | + dev_err(adev->dev, "Found unmatching checksum from calculation 0x%x and init_data 0x%x\n", |
| 923 | + checksum, init_data_hdr->checksum); |
| 924 | + r = -EINVAL; |
| 925 | + goto out; |
| 926 | + } |
| 927 | + |
| 928 | + memset(&adev->virt.crit_regn, 0, sizeof(adev->virt.crit_regn)); |
| 929 | + memset(adev->virt.crit_regn_tbl, 0, sizeof(adev->virt.crit_regn_tbl)); |
| 930 | + |
| 931 | + adev->virt.crit_regn.offset = init_data_hdr->initdata_offset; |
| 932 | + adev->virt.crit_regn.size_kb = init_data_hdr->initdata_size_in_kb; |
| 933 | + |
| 934 | + /* Validation and initialization for each table entry */ |
| 935 | + if (IS_SRIOV_CRIT_REGN_ENTRY_VALID(init_data_hdr, AMD_SRIOV_MSG_IPD_TABLE_ID)) { |
| 936 | + if (!init_data_hdr->ip_discovery_size_in_kb || |
| 937 | + init_data_hdr->ip_discovery_size_in_kb > DISCOVERY_TMR_SIZE) { |
| 938 | + dev_err(adev->dev, "Invalid %s size: 0x%x\n", |
| 939 | + amdgpu_virt_dynamic_crit_table_name[AMD_SRIOV_MSG_IPD_TABLE_ID], |
| 940 | + init_data_hdr->ip_discovery_size_in_kb); |
| 941 | + r = -EINVAL; |
| 942 | + goto out; |
| 943 | + } |
| 944 | + |
| 945 | + adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_IPD_TABLE_ID].offset = |
| 946 | + init_data_hdr->ip_discovery_offset; |
| 947 | + adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_IPD_TABLE_ID].size_kb = |
| 948 | + init_data_hdr->ip_discovery_size_in_kb; |
| 949 | + } |
| 950 | + |
| 951 | + if (IS_SRIOV_CRIT_REGN_ENTRY_VALID(init_data_hdr, AMD_SRIOV_MSG_VBIOS_IMG_TABLE_ID)) { |
| 952 | + if (!init_data_hdr->vbios_img_size_in_kb) { |
| 953 | + dev_err(adev->dev, "Invalid %s size: 0x%x\n", |
| 954 | + amdgpu_virt_dynamic_crit_table_name[AMD_SRIOV_MSG_VBIOS_IMG_TABLE_ID], |
| 955 | + init_data_hdr->vbios_img_size_in_kb); |
| 956 | + r = -EINVAL; |
| 957 | + goto out; |
| 958 | + } |
| 959 | + |
| 960 | + adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_VBIOS_IMG_TABLE_ID].offset = |
| 961 | + init_data_hdr->vbios_img_offset; |
| 962 | + adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_VBIOS_IMG_TABLE_ID].size_kb = |
| 963 | + init_data_hdr->vbios_img_size_in_kb; |
| 964 | + } |
| 965 | + |
| 966 | + if (IS_SRIOV_CRIT_REGN_ENTRY_VALID(init_data_hdr, AMD_SRIOV_MSG_RAS_TELEMETRY_TABLE_ID)) { |
| 967 | + if (!init_data_hdr->ras_tele_info_size_in_kb) { |
| 968 | + dev_err(adev->dev, "Invalid %s size: 0x%x\n", |
| 969 | + amdgpu_virt_dynamic_crit_table_name[AMD_SRIOV_MSG_RAS_TELEMETRY_TABLE_ID], |
| 970 | + init_data_hdr->ras_tele_info_size_in_kb); |
| 971 | + r = -EINVAL; |
| 972 | + goto out; |
| 973 | + } |
| 974 | + |
| 975 | + adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_RAS_TELEMETRY_TABLE_ID].offset = |
| 976 | + init_data_hdr->ras_tele_info_offset; |
| 977 | + adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_RAS_TELEMETRY_TABLE_ID].size_kb = |
| 978 | + init_data_hdr->ras_tele_info_size_in_kb; |
| 979 | + } |
| 980 | + |
| 981 | + if (IS_SRIOV_CRIT_REGN_ENTRY_VALID(init_data_hdr, AMD_SRIOV_MSG_DATAEXCHANGE_TABLE_ID)) { |
| 982 | + if (!init_data_hdr->dataexchange_size_in_kb) { |
| 983 | + dev_err(adev->dev, "Invalid %s size: 0x%x\n", |
| 984 | + amdgpu_virt_dynamic_crit_table_name[AMD_SRIOV_MSG_DATAEXCHANGE_TABLE_ID], |
| 985 | + init_data_hdr->dataexchange_size_in_kb); |
| 986 | + r = -EINVAL; |
| 987 | + goto out; |
| 988 | + } |
| 989 | + |
| 990 | + adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_DATAEXCHANGE_TABLE_ID].offset = |
| 991 | + init_data_hdr->dataexchange_offset; |
| 992 | + adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_DATAEXCHANGE_TABLE_ID].size_kb = |
| 993 | + init_data_hdr->dataexchange_size_in_kb; |
| 994 | + } |
| 995 | + |
| 996 | + if (IS_SRIOV_CRIT_REGN_ENTRY_VALID(init_data_hdr, AMD_SRIOV_MSG_BAD_PAGE_INFO_TABLE_ID)) { |
| 997 | + if (!init_data_hdr->bad_page_size_in_kb) { |
| 998 | + dev_err(adev->dev, "Invalid %s size: 0x%x\n", |
| 999 | + amdgpu_virt_dynamic_crit_table_name[AMD_SRIOV_MSG_BAD_PAGE_INFO_TABLE_ID], |
| 1000 | + init_data_hdr->bad_page_size_in_kb); |
| 1001 | + r = -EINVAL; |
| 1002 | + goto out; |
| 1003 | + } |
| 1004 | + |
| 1005 | + adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_BAD_PAGE_INFO_TABLE_ID].offset = |
| 1006 | + init_data_hdr->bad_page_info_offset; |
| 1007 | + adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_BAD_PAGE_INFO_TABLE_ID].size_kb = |
| 1008 | + init_data_hdr->bad_page_size_in_kb; |
| 1009 | + } |
| 1010 | + |
| 1011 | + adev->virt.is_dynamic_crit_regn_enabled = true; |
| 1012 | + |
| 1013 | +out: |
| 1014 | + kfree(init_data_hdr); |
| 1015 | + init_data_hdr = NULL; |
| 1016 | + |
| 1017 | + return r; |
| 1018 | +} |
| 1019 | + |
846 | 1020 | void amdgpu_virt_init(struct amdgpu_device *adev) |
847 | 1021 | { |
848 | 1022 | bool is_sriov = false; |
|
0 commit comments