162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci/* 462306a36Sopenharmony_ci * Copyright 2022 HabanaLabs, Ltd. 562306a36Sopenharmony_ci * All Rights Reserved. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "habanalabs.h" 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#define VCMD_CONTROL_OFFSET 0x40 /* SWREG16 */ 1162306a36Sopenharmony_ci#define VCMD_IRQ_STATUS_OFFSET 0x44 /* SWREG17 */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#define VCMD_IRQ_STATUS_ENDCMD_MASK 0x1 1462306a36Sopenharmony_ci#define VCMD_IRQ_STATUS_BUSERR_MASK 0x2 1562306a36Sopenharmony_ci#define VCMD_IRQ_STATUS_TIMEOUT_MASK 0x4 1662306a36Sopenharmony_ci#define VCMD_IRQ_STATUS_CMDERR_MASK 0x8 1762306a36Sopenharmony_ci#define VCMD_IRQ_STATUS_ABORT_MASK 0x10 1862306a36Sopenharmony_ci#define VCMD_IRQ_STATUS_RESET_MASK 0x20 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistatic void dec_print_abnrm_intr_source(struct hl_device *hdev, u32 irq_status) 2162306a36Sopenharmony_ci{ 2262306a36Sopenharmony_ci const char *format = "abnormal interrupt source:%s%s%s%s%s%s\n"; 2362306a36Sopenharmony_ci char *intr_source[6] = {"Unknown", "", "", "", "", ""}; 2462306a36Sopenharmony_ci int i = 0; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci if (!irq_status) 2762306a36Sopenharmony_ci return; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci if (irq_status & VCMD_IRQ_STATUS_ENDCMD_MASK) 3062306a36Sopenharmony_ci intr_source[i++] = " ENDCMD"; 3162306a36Sopenharmony_ci if (irq_status & VCMD_IRQ_STATUS_BUSERR_MASK) 3262306a36Sopenharmony_ci intr_source[i++] = " BUSERR"; 3362306a36Sopenharmony_ci if (irq_status & VCMD_IRQ_STATUS_TIMEOUT_MASK) 3462306a36Sopenharmony_ci intr_source[i++] = " TIMEOUT"; 3562306a36Sopenharmony_ci if (irq_status & VCMD_IRQ_STATUS_CMDERR_MASK) 3662306a36Sopenharmony_ci intr_source[i++] = " CMDERR"; 3762306a36Sopenharmony_ci if (irq_status & VCMD_IRQ_STATUS_ABORT_MASK) 3862306a36Sopenharmony_ci intr_source[i++] = " ABORT"; 3962306a36Sopenharmony_ci if (irq_status & VCMD_IRQ_STATUS_RESET_MASK) 4062306a36Sopenharmony_ci intr_source[i++] = " RESET"; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci dev_err(hdev->dev, format, intr_source[0], intr_source[1], 4362306a36Sopenharmony_ci intr_source[2], intr_source[3], intr_source[4], intr_source[5]); 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic void dec_abnrm_intr_work(struct work_struct *work) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci struct hl_dec *dec = container_of(work, struct hl_dec, abnrm_intr_work); 4962306a36Sopenharmony_ci struct hl_device *hdev = dec->hdev; 5062306a36Sopenharmony_ci u32 irq_status, event_mask = 0; 5162306a36Sopenharmony_ci bool reset_required = false; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci irq_status = RREG32(dec->base_addr + VCMD_IRQ_STATUS_OFFSET); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci dev_err(hdev->dev, "Decoder abnormal interrupt %#x, core %d\n", irq_status, dec->core_id); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci dec_print_abnrm_intr_source(hdev, irq_status); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci /* Clear the interrupt */ 6062306a36Sopenharmony_ci WREG32(dec->base_addr + VCMD_IRQ_STATUS_OFFSET, irq_status); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci /* Flush the interrupt clear */ 6362306a36Sopenharmony_ci RREG32(dec->base_addr + VCMD_IRQ_STATUS_OFFSET); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if (irq_status & VCMD_IRQ_STATUS_TIMEOUT_MASK) { 6662306a36Sopenharmony_ci reset_required = true; 6762306a36Sopenharmony_ci event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR; 6862306a36Sopenharmony_ci } 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci if (irq_status & VCMD_IRQ_STATUS_CMDERR_MASK) 7162306a36Sopenharmony_ci event_mask |= HL_NOTIFIER_EVENT_UNDEFINED_OPCODE; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci if (irq_status & (VCMD_IRQ_STATUS_ENDCMD_MASK | 7462306a36Sopenharmony_ci VCMD_IRQ_STATUS_BUSERR_MASK | 7562306a36Sopenharmony_ci VCMD_IRQ_STATUS_ABORT_MASK)) 7662306a36Sopenharmony_ci event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci if (reset_required) { 7962306a36Sopenharmony_ci event_mask |= HL_NOTIFIER_EVENT_DEVICE_RESET; 8062306a36Sopenharmony_ci hl_device_cond_reset(hdev, 0, event_mask); 8162306a36Sopenharmony_ci } else if (event_mask) { 8262306a36Sopenharmony_ci hl_notifier_event_send_all(hdev, event_mask); 8362306a36Sopenharmony_ci } 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_civoid hl_dec_fini(struct hl_device *hdev) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci kfree(hdev->dec); 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ciint hl_dec_init(struct hl_device *hdev) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci struct asic_fixed_properties *prop = &hdev->asic_prop; 9462306a36Sopenharmony_ci struct hl_dec *dec; 9562306a36Sopenharmony_ci int rc, j; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci /* if max core is 0, nothing to do*/ 9862306a36Sopenharmony_ci if (!prop->max_dec) 9962306a36Sopenharmony_ci return 0; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci hdev->dec = kcalloc(prop->max_dec, sizeof(struct hl_dec), GFP_KERNEL); 10262306a36Sopenharmony_ci if (!hdev->dec) 10362306a36Sopenharmony_ci return -ENOMEM; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci for (j = 0 ; j < prop->max_dec ; j++) { 10662306a36Sopenharmony_ci dec = hdev->dec + j; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci dec->hdev = hdev; 10962306a36Sopenharmony_ci INIT_WORK(&dec->abnrm_intr_work, dec_abnrm_intr_work); 11062306a36Sopenharmony_ci dec->core_id = j; 11162306a36Sopenharmony_ci dec->base_addr = hdev->asic_funcs->get_dec_base_addr(hdev, j); 11262306a36Sopenharmony_ci if (!dec->base_addr) { 11362306a36Sopenharmony_ci dev_err(hdev->dev, "Invalid base address of decoder %d\n", j); 11462306a36Sopenharmony_ci rc = -EINVAL; 11562306a36Sopenharmony_ci goto err_dec_fini; 11662306a36Sopenharmony_ci } 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci return 0; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cierr_dec_fini: 12262306a36Sopenharmony_ci hl_dec_fini(hdev); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci return rc; 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_civoid hl_dec_ctx_fini(struct hl_ctx *ctx) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci struct hl_device *hdev = ctx->hdev; 13062306a36Sopenharmony_ci struct asic_fixed_properties *prop = &hdev->asic_prop; 13162306a36Sopenharmony_ci struct hl_dec *dec; 13262306a36Sopenharmony_ci int j; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci for (j = 0 ; j < prop->max_dec ; j++) { 13562306a36Sopenharmony_ci if (!!(prop->decoder_enabled_mask & BIT(j))) { 13662306a36Sopenharmony_ci dec = hdev->dec + j; 13762306a36Sopenharmony_ci /* Stop the decoder */ 13862306a36Sopenharmony_ci WREG32(dec->base_addr + VCMD_CONTROL_OFFSET, 0); 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci} 142