| 1 | |
| 2 | * Copyright 2019 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 |
|
| 23 |
|
| 24 | #include <linux/sort.h>
|
| 25 | #include "amdgpu.h"
|
| 26 | #include "umc_v6_7.h"
|
| 27 | #include "amdgpu_ras_mgr.h"
|
| 28 | #define MAX_UMC_POISON_POLLING_TIME_SYNC 20
|
| 29 |
|
| 30 | #define MAX_UMC_HASH_STRING_SIZE 256
|
| 31 |
|
| 32 | static int amdgpu_umc_convert_error_address(struct amdgpu_device *adev,
|
| 33 | struct ras_err_data *err_data, uint64_t err_addr,
|
| 34 | uint32_t ch_inst, uint32_t umc_inst)
|
| 35 | {
|
| 36 | switch (amdgpu_ip_version(adev, UMC_HWIP, 0)) {
|
| 37 | case IP_VERSION(6, 7, 0):
|
| 38 | umc_v6_7_convert_error_address(adev,
|
| 39 | err_data, err_addr, ch_inst, umc_inst);
|
| 40 | break;
|
| 41 | default:
|
| 42 | dev_warn(adev->dev,
|
| 43 | "UMC address to Physical address translation is not supported\n");
|
| 44 | return AMDGPU_RAS_FAIL;
|
| 45 | }
|
| 46 |
|
| 47 | return AMDGPU_RAS_SUCCESS;
|
| 48 | }
|
| 49 |
|
| 50 | int amdgpu_umc_page_retirement_mca(struct amdgpu_device *adev,
|
| 51 | uint64_t err_addr, uint32_t ch_inst, uint32_t umc_inst)
|
| 52 | {
|
| 53 | struct ras_err_data err_data;
|
| 54 | int ret;
|
| 55 |
|
| 56 | ret = amdgpu_ras_error_data_init(&err_data);
|
| 57 | if (ret)
|
| 58 | return ret;
|
| 59 |
|
| 60 | err_data.err_addr =
|
| 61 | kzalloc_objs(struct eeprom_table_record,
|
| 62 | adev->umc.max_ras_err_cnt_per_query);
|
| 63 | if (!err_data.err_addr) {
|
| 64 | dev_warn(adev->dev,
|
| 65 | "Failed to alloc memory for umc error record in MCA notifier!\n");
|
| 66 | ret = AMDGPU_RAS_FAIL;
|
| 67 | goto out_fini_err_data;
|
| 68 | }
|
| 69 |
|
| 70 | err_data.err_addr_len = adev->umc.max_ras_err_cnt_per_query;
|
| 71 |
|
| 72 | |
| 73 | * Translate UMC channel address to Physical address
|
| 74 |
|
| 75 | ret = amdgpu_umc_convert_error_address(adev, &err_data, err_addr,
|
| 76 | ch_inst, umc_inst);
|
| 77 | if (ret)
|
| 78 | goto out_free_err_addr;
|
| 79 |
|
| 80 | if (amdgpu_bad_page_threshold != 0) {
|
| 81 | amdgpu_ras_add_bad_pages(adev, err_data.err_addr,
|
| 82 | err_data.err_addr_cnt, false);
|
| 83 | amdgpu_ras_save_bad_pages(adev, NULL);
|
| 84 | }
|
| 85 |
|
| 86 | out_free_err_addr:
|
| 87 | kfree(err_data.err_addr);
|
| 88 |
|
| 89 | out_fini_err_data:
|
| 90 | amdgpu_ras_error_data_fini(&err_data);
|
| 91 |
|
| 92 | return ret;
|
| 93 | }
|
| 94 |
|
| 95 | void amdgpu_umc_handle_bad_pages(struct amdgpu_device *adev,
|
| 96 | void *ras_error_status)
|
| 97 | {
|
| 98 | struct ras_err_data *err_data = (struct ras_err_data *)ras_error_status;
|
| 99 | struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
|
| 100 | unsigned int error_query_mode;
|
| 101 | int ret = 0;
|
| 102 | unsigned long err_count;
|
| 103 |
|
| 104 | amdgpu_ras_get_error_query_mode(adev, &error_query_mode);
|
| 105 |
|
| 106 | err_data->err_addr =
|
| 107 | kzalloc_objs(struct eeprom_table_record,
|
| 108 | adev->umc.max_ras_err_cnt_per_query);
|
| 109 |
|
| 110 | |
| 111 | * even NOMEM error is encountered
|
| 112 |
|
| 113 | if (!err_data->err_addr)
|
| 114 | dev_warn(adev->dev,
|
| 115 | "Failed to alloc memory for umc error address record!\n");
|
| 116 | else
|
| 117 | err_data->err_addr_len = adev->umc.max_ras_err_cnt_per_query;
|
| 118 |
|
| 119 | mutex_lock(&con->page_retirement_lock);
|
| 120 | ret = amdgpu_dpm_get_ecc_info(adev, (void *)&(con->umc_ecc));
|
| 121 | if (ret == -EOPNOTSUPP &&
|
| 122 | error_query_mode == AMDGPU_RAS_DIRECT_ERROR_QUERY) {
|
| 123 | if (adev->umc.ras && adev->umc.ras->ras_block.hw_ops &&
|
| 124 | adev->umc.ras->ras_block.hw_ops->query_ras_error_count)
|
| 125 | adev->umc.ras->ras_block.hw_ops->query_ras_error_count(adev,
|
| 126 | ras_error_status);
|
| 127 |
|
| 128 | if (adev->umc.ras && adev->umc.ras->ras_block.hw_ops &&
|
| 129 | adev->umc.ras->ras_block.hw_ops->query_ras_error_address &&
|
| 130 | adev->umc.max_ras_err_cnt_per_query) {
|
| 131 | err_data->err_addr =
|
| 132 | kzalloc_objs(struct eeprom_table_record,
|
| 133 | adev->umc.max_ras_err_cnt_per_query);
|
| 134 |
|
| 135 | |
| 136 | * even NOMEM error is encountered
|
| 137 |
|
| 138 | if (!err_data->err_addr)
|
| 139 | dev_warn(adev->dev,
|
| 140 | "Failed to alloc memory for umc error address record!\n");
|
| 141 | else
|
| 142 | err_data->err_addr_len =
|
| 143 | adev->umc.max_ras_err_cnt_per_query;
|
| 144 |
|
| 145 | |
| 146 | * error status
|
| 147 |
|
| 148 | adev->umc.ras->ras_block.hw_ops->query_ras_error_address(adev,
|
| 149 | ras_error_status);
|
| 150 | }
|
| 151 | } else if (error_query_mode == AMDGPU_RAS_FIRMWARE_ERROR_QUERY ||
|
| 152 | (!ret && error_query_mode == AMDGPU_RAS_DIRECT_ERROR_QUERY)) {
|
| 153 | if (adev->umc.ras &&
|
| 154 | adev->umc.ras->ecc_info_query_ras_error_count)
|
| 155 | adev->umc.ras->ecc_info_query_ras_error_count(adev,
|
| 156 | ras_error_status);
|
| 157 |
|
| 158 | if (adev->umc.ras &&
|
| 159 | adev->umc.ras->ecc_info_query_ras_error_address &&
|
| 160 | adev->umc.max_ras_err_cnt_per_query) {
|
| 161 | err_data->err_addr =
|
| 162 | kzalloc_objs(struct eeprom_table_record,
|
| 163 | adev->umc.max_ras_err_cnt_per_query);
|
| 164 |
|
| 165 | |
| 166 | * even NOMEM error is encountered
|
| 167 |
|
| 168 | if (!err_data->err_addr)
|
| 169 | dev_warn(adev->dev,
|
| 170 | "Failed to alloc memory for umc error address record!\n");
|
| 171 | else
|
| 172 | err_data->err_addr_len =
|
| 173 | adev->umc.max_ras_err_cnt_per_query;
|
| 174 |
|
| 175 | |
| 176 | * error status
|
| 177 |
|
| 178 | adev->umc.ras->ecc_info_query_ras_error_address(adev,
|
| 179 | ras_error_status);
|
| 180 | }
|
| 181 | }
|
| 182 |
|
| 183 |
|
| 184 | if (err_data->ue_count || err_data->de_count) {
|
| 185 | err_count = err_data->ue_count + err_data->de_count;
|
| 186 | if ((amdgpu_bad_page_threshold != 0) &&
|
| 187 | err_data->err_addr_cnt) {
|
| 188 | amdgpu_ras_add_bad_pages(adev, err_data->err_addr,
|
| 189 | err_data->err_addr_cnt, false);
|
| 190 | amdgpu_ras_save_bad_pages(adev, &err_count);
|
| 191 |
|
| 192 | amdgpu_dpm_send_hbm_bad_pages_num(adev,
|
| 193 | con->eeprom_control.ras_num_bad_pages);
|
| 194 |
|
| 195 | if (con->update_channel_flag == true) {
|
| 196 | amdgpu_dpm_send_hbm_bad_channel_flag(adev, con->eeprom_control.bad_channel_bitmap);
|
| 197 | con->update_channel_flag = false;
|
| 198 | }
|
| 199 | }
|
| 200 | }
|
| 201 |
|
| 202 | kfree(err_data->err_addr);
|
| 203 | err_data->err_addr = NULL;
|
| 204 |
|
| 205 | mutex_unlock(&con->page_retirement_lock);
|
| 206 | }
|
| 207 |
|
| 208 | static int amdgpu_umc_do_page_retirement(struct amdgpu_device *adev,
|
| 209 | void *ras_error_status,
|
| 210 | struct amdgpu_iv_entry *entry,
|
| 211 | uint32_t reset)
|
| 212 | {
|
| 213 | struct ras_err_data *err_data = (struct ras_err_data *)ras_error_status;
|
| 214 | struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
|
| 215 |
|
| 216 | kgd2kfd_set_sram_ecc_flag(adev->kfd.dev);
|
| 217 | amdgpu_umc_handle_bad_pages(adev, ras_error_status);
|
| 218 |
|
| 219 | if ((err_data->ue_count || err_data->de_count) &&
|
| 220 | (reset || amdgpu_ras_is_rma(adev))) {
|
| 221 | con->gpu_reset_flags |= reset;
|
| 222 | amdgpu_ras_reset_gpu(adev);
|
| 223 | }
|
| 224 |
|
| 225 | return AMDGPU_RAS_SUCCESS;
|
| 226 | }
|
| 227 |
|
| 228 | int amdgpu_umc_pasid_poison_handler(struct amdgpu_device *adev,
|
| 229 | enum amdgpu_ras_block block, uint16_t pasid,
|
| 230 | pasid_notify pasid_fn, void *data, uint32_t reset)
|
| 231 | {
|
| 232 | int ret = AMDGPU_RAS_SUCCESS;
|
| 233 |
|
| 234 | if (adev->gmc.xgmi.connected_to_cpu ||
|
| 235 | adev->gmc.is_app_apu) {
|
| 236 | if (reset) {
|
| 237 | |
| 238 | * let MCA notifier do page retirement.
|
| 239 |
|
| 240 | kgd2kfd_set_sram_ecc_flag(adev->kfd.dev);
|
| 241 | amdgpu_ras_reset_gpu(adev);
|
| 242 | }
|
| 243 | return ret;
|
| 244 | }
|
| 245 |
|
| 246 | if (!amdgpu_sriov_vf(adev)) {
|
| 247 | if (amdgpu_ip_version(adev, UMC_HWIP, 0) < IP_VERSION(12, 0, 0)) {
|
| 248 | struct ras_err_data err_data;
|
| 249 | struct ras_common_if head = {
|
| 250 | .block = AMDGPU_RAS_BLOCK__UMC,
|
| 251 | };
|
| 252 | struct ras_manager *obj = amdgpu_ras_find_obj(adev, &head);
|
| 253 |
|
| 254 | ret = amdgpu_ras_error_data_init(&err_data);
|
| 255 | if (ret)
|
| 256 | return ret;
|
| 257 |
|
| 258 | ret = amdgpu_umc_do_page_retirement(adev, &err_data, NULL, reset);
|
| 259 |
|
| 260 | if (ret == AMDGPU_RAS_SUCCESS && obj) {
|
| 261 | obj->err_data.ue_count += err_data.ue_count;
|
| 262 | obj->err_data.ce_count += err_data.ce_count;
|
| 263 | }
|
| 264 |
|
| 265 | amdgpu_ras_error_data_fini(&err_data);
|
| 266 | } else {
|
| 267 | struct ras_ih_info ih_info = {0};
|
| 268 |
|
| 269 | ih_info.block = block;
|
| 270 | ih_info.pasid = pasid;
|
| 271 | ih_info.reset = reset;
|
| 272 | ih_info.pasid_fn = pasid_fn;
|
| 273 | ih_info.data = data;
|
| 274 | amdgpu_ras_mgr_handle_consumer_interrupt(adev, &ih_info);
|
| 275 | }
|
| 276 | } else {
|
| 277 | if (adev->virt.ops && adev->virt.ops->ras_poison_handler)
|
| 278 | adev->virt.ops->ras_poison_handler(adev, block);
|
| 279 | else
|
| 280 | dev_warn(adev->dev,
|
| 281 | "No ras_poison_handler interface in SRIOV!\n");
|
| 282 | }
|
| 283 |
|
| 284 | return ret;
|
| 285 | }
|
| 286 |
|
| 287 | int amdgpu_umc_poison_handler(struct amdgpu_device *adev,
|
| 288 | enum amdgpu_ras_block block, uint32_t reset)
|
| 289 | {
|
| 290 | return amdgpu_umc_pasid_poison_handler(adev,
|
| 291 | block, 0, NULL, NULL, reset);
|
| 292 | }
|
| 293 |
|
| 294 | int amdgpu_umc_process_ras_data_cb(struct amdgpu_device *adev,
|
| 295 | void *ras_error_status,
|
| 296 | struct amdgpu_iv_entry *entry)
|
| 297 | {
|
| 298 | return amdgpu_umc_do_page_retirement(adev, ras_error_status, entry,
|
| 299 | AMDGPU_RAS_GPU_RESET_MODE1_RESET);
|
| 300 | }
|
| 301 |
|
| 302 | int amdgpu_umc_ras_sw_init(struct amdgpu_device *adev)
|
| 303 | {
|
| 304 | int err;
|
| 305 | struct amdgpu_umc_ras *ras;
|
| 306 |
|
| 307 | if (!adev->umc.ras)
|
| 308 | return 0;
|
| 309 |
|
| 310 | ras = adev->umc.ras;
|
| 311 |
|
| 312 | err = amdgpu_ras_register_ras_block(adev, &ras->ras_block);
|
| 313 | if (err) {
|
| 314 | dev_err(adev->dev, "Failed to register umc ras block!\n");
|
| 315 | return err;
|
| 316 | }
|
| 317 |
|
| 318 | strcpy(adev->umc.ras->ras_block.ras_comm.name, "umc");
|
| 319 | ras->ras_block.ras_comm.block = AMDGPU_RAS_BLOCK__UMC;
|
| 320 | ras->ras_block.ras_comm.type = AMDGPU_RAS_ERROR__MULTI_UNCORRECTABLE;
|
| 321 | adev->umc.ras_if = &ras->ras_block.ras_comm;
|
| 322 |
|
| 323 | if (!ras->ras_block.ras_late_init)
|
| 324 | ras->ras_block.ras_late_init = amdgpu_umc_ras_late_init;
|
| 325 |
|
| 326 | if (!ras->ras_block.ras_cb)
|
| 327 | ras->ras_block.ras_cb = amdgpu_umc_process_ras_data_cb;
|
| 328 |
|
| 329 | return 0;
|
| 330 | }
|
| 331 |
|
| 332 | int amdgpu_umc_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *ras_block)
|
| 333 | {
|
| 334 | int r;
|
| 335 |
|
| 336 | r = amdgpu_ras_block_late_init(adev, ras_block);
|
| 337 | if (r)
|
| 338 | return r;
|
| 339 |
|
| 340 | if (amdgpu_sriov_vf(adev))
|
| 341 | return r;
|
| 342 |
|
| 343 | if (amdgpu_ras_is_supported(adev, ras_block->block)) {
|
| 344 | r = amdgpu_irq_get(adev, &adev->gmc.ecc_irq, 0);
|
| 345 | if (r)
|
| 346 | goto late_fini;
|
| 347 | }
|
| 348 |
|
| 349 |
|
| 350 | if (adev->umc.ras &&
|
| 351 | adev->umc.ras->err_cnt_init)
|
| 352 | adev->umc.ras->err_cnt_init(adev);
|
| 353 |
|
| 354 | return 0;
|
| 355 |
|
| 356 | late_fini:
|
| 357 | amdgpu_ras_block_late_fini(adev, ras_block);
|
| 358 | return r;
|
| 359 | }
|
| 360 |
|
| 361 | int amdgpu_umc_process_ecc_irq(struct amdgpu_device *adev,
|
| 362 | struct amdgpu_irq_src *source,
|
| 363 | struct amdgpu_iv_entry *entry)
|
| 364 | {
|
| 365 | struct ras_common_if *ras_if = adev->umc.ras_if;
|
| 366 | struct ras_dispatch_if ih_data = {
|
| 367 | .entry = entry,
|
| 368 | };
|
| 369 |
|
| 370 | if (!ras_if)
|
| 371 | return 0;
|
| 372 |
|
| 373 | ih_data.head = *ras_if;
|
| 374 |
|
| 375 | amdgpu_ras_interrupt_dispatch(adev, &ih_data);
|
| 376 | return 0;
|
| 377 | }
|
| 378 |
|
| 379 | int amdgpu_umc_uniras_process_ecc_irq(struct amdgpu_device *adev,
|
| 380 | struct amdgpu_irq_src *source,
|
| 381 | struct amdgpu_iv_entry *entry)
|
| 382 | {
|
| 383 | struct ras_ih_info ih_info = {0};
|
| 384 |
|
| 385 | ih_info.block = RAS_BLOCK_ID__UMC;
|
| 386 | amdgpu_ras_mgr_dispatch_interrupt(adev, &ih_info);
|
| 387 | return 0;
|
| 388 | }
|
| 389 |
|
| 390 | int amdgpu_umc_fill_error_record(struct ras_err_data *err_data,
|
| 391 | uint64_t err_addr,
|
| 392 | uint64_t retired_page,
|
| 393 | uint32_t channel_index,
|
| 394 | uint32_t umc_inst)
|
| 395 | {
|
| 396 | struct eeprom_table_record *err_rec;
|
| 397 |
|
| 398 | if (!err_data ||
|
| 399 | !err_data->err_addr ||
|
| 400 | (err_data->err_addr_cnt >= err_data->err_addr_len))
|
| 401 | return -EINVAL;
|
| 402 |
|
| 403 | err_rec = &err_data->err_addr[err_data->err_addr_cnt];
|
| 404 |
|
| 405 | err_rec->address = err_addr;
|
| 406 |
|
| 407 | err_rec->retired_page = retired_page >> AMDGPU_GPU_PAGE_SHIFT;
|
| 408 | err_rec->ts = (uint64_t)ktime_get_real_seconds();
|
| 409 | err_rec->err_type = AMDGPU_RAS_EEPROM_ERR_NON_RECOVERABLE;
|
| 410 | err_rec->cu = 0;
|
| 411 | err_rec->mem_channel = channel_index;
|
| 412 | err_rec->mcumc_id = umc_inst;
|
| 413 |
|
| 414 | err_data->err_addr_cnt++;
|
| 415 |
|
| 416 | return 0;
|
| 417 | }
|
| 418 |
|
| 419 | static int amdgpu_umc_loop_all_aid(struct amdgpu_device *adev, umc_func func,
|
| 420 | void *data)
|
| 421 | {
|
| 422 | uint32_t umc_node_inst;
|
| 423 | uint32_t node_inst;
|
| 424 | uint32_t umc_inst;
|
| 425 | uint32_t ch_inst;
|
| 426 | int ret;
|
| 427 |
|
| 428 | |
| 429 | * This loop is done based on the following -
|
| 430 | * umc.active mask = mask of active umc instances across all nodes
|
| 431 | * umc.umc_inst_num = maximum number of umc instancess per node
|
| 432 | * umc.node_inst_num = maximum number of node instances
|
| 433 | * Channel instances are not assumed to be harvested.
|
| 434 |
|
| 435 | dev_dbg(adev->dev, "active umcs :%lx umc_inst per node: %d",
|
| 436 | adev->umc.active_mask, adev->umc.umc_inst_num);
|
| 437 | for_each_set_bit(umc_node_inst, &(adev->umc.active_mask),
|
| 438 | adev->umc.node_inst_num * adev->umc.umc_inst_num) {
|
| 439 | node_inst = umc_node_inst / adev->umc.umc_inst_num;
|
| 440 | umc_inst = umc_node_inst % adev->umc.umc_inst_num;
|
| 441 | LOOP_UMC_CH_INST(ch_inst) {
|
| 442 | dev_dbg(adev->dev,
|
| 443 | "node_inst :%d umc_inst: %d ch_inst: %d",
|
| 444 | node_inst, umc_inst, ch_inst);
|
| 445 | ret = func(adev, node_inst, umc_inst, ch_inst, data);
|
| 446 | if (ret) {
|
| 447 | dev_err(adev->dev,
|
| 448 | "Node %d umc %d ch %d func returns %d\n",
|
| 449 | node_inst, umc_inst, ch_inst, ret);
|
| 450 | return ret;
|
| 451 | }
|
| 452 | }
|
| 453 | }
|
| 454 |
|
| 455 | return 0;
|
| 456 | }
|
| 457 |
|
| 458 | int amdgpu_umc_loop_channels(struct amdgpu_device *adev,
|
| 459 | umc_func func, void *data)
|
| 460 | {
|
| 461 | uint32_t node_inst = 0;
|
| 462 | uint32_t umc_inst = 0;
|
| 463 | uint32_t ch_inst = 0;
|
| 464 | int ret = 0;
|
| 465 |
|
| 466 | if (adev->aid_mask)
|
| 467 | return amdgpu_umc_loop_all_aid(adev, func, data);
|
| 468 |
|
| 469 | if (adev->umc.node_inst_num) {
|
| 470 | LOOP_UMC_EACH_NODE_INST_AND_CH(node_inst, umc_inst, ch_inst) {
|
| 471 | ret = func(adev, node_inst, umc_inst, ch_inst, data);
|
| 472 | if (ret) {
|
| 473 | dev_err(adev->dev, "Node %d umc %d ch %d func returns %d\n",
|
| 474 | node_inst, umc_inst, ch_inst, ret);
|
| 475 | return ret;
|
| 476 | }
|
| 477 | }
|
| 478 | } else {
|
| 479 | LOOP_UMC_INST_AND_CH(umc_inst, ch_inst) {
|
| 480 | ret = func(adev, 0, umc_inst, ch_inst, data);
|
| 481 | if (ret) {
|
| 482 | dev_err(adev->dev, "Umc %d ch %d func returns %d\n",
|
| 483 | umc_inst, ch_inst, ret);
|
| 484 | return ret;
|
| 485 | }
|
| 486 | }
|
| 487 | }
|
| 488 |
|
| 489 | return 0;
|
| 490 | }
|