#include "gaudiP.h"
#include "../include/hw_ip/mmu/mmu_general.h"
#include "../include/hw_ip/mmu/mmu_v1_1.h"
#include "../include/gaudi/gaudi_masks.h"
#include "../include/gaudi/gaudi_fw_if.h"
#include "../include/gaudi/gaudi_reg_map.h"
#include "../include/gaudi/gaudi_async_ids_map_extended.h"
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/firmware.h>
#include <linux/hwmon.h>
#include <linux/iommu.h>
#include <linux/seq_file.h>
#define GAUDI_BOOT_FIT_FILE "habanalabs/gaudi/gaudi-boot-fit.itb"
#define GAUDI_LINUX_FW_FILE "habanalabs/gaudi/gaudi-fit.itb"
#define GAUDI_TPC_FW_FILE "habanalabs/gaudi/gaudi_tpc.bin"
#define GAUDI_DMA_POOL_BLK_SIZE 0x100 /* 256 bytes */
#define GAUDI_RESET_TIMEOUT_MSEC 2000 /* 2000ms */
#define GAUDI_RESET_WAIT_MSEC 1 /* 1ms */
#define GAUDI_CPU_RESET_WAIT_MSEC 200 /* 200ms */
#define GAUDI_TEST_QUEUE_WAIT_USEC 100000 /* 100ms */
#define GAUDI_PLDM_RESET_WAIT_MSEC 1000 /* 1s */
#define GAUDI_PLDM_HRESET_TIMEOUT_MSEC 20000 /* 20s */
#define GAUDI_PLDM_TEST_QUEUE_WAIT_USEC 1000000 /* 1s */
#define GAUDI_PLDM_MMU_TIMEOUT_USEC (MMU_CONFIG_TIMEOUT_USEC * 100)
#define GAUDI_PLDM_QMAN0_TIMEOUT_USEC (HL_DEVICE_TIMEOUT_USEC * 30)
#define GAUDI_PLDM_TPC_KERNEL_WAIT_USEC (HL_DEVICE_TIMEOUT_USEC * 30)
#define GAUDI_BOOT_FIT_REQ_TIMEOUT_USEC 4000000 /* 4s */
#define GAUDI_MSG_TO_CPU_TIMEOUT_USEC 4000000 /* 4s */
#define GAUDI_WAIT_FOR_BL_TIMEOUT_USEC 15000000 /* 15s */
#define GAUDI_QMAN0_FENCE_VAL 0x72E91AB9
#define GAUDI_MAX_STRING_LEN 20
#define GAUDI_CB_POOL_CB_CNT 512
#define GAUDI_CB_POOL_CB_SIZE 0x20000 /* 128KB */
#define GAUDI_ALLOC_CPU_MEM_RETRY_CNT 3
#define GAUDI_NUM_OF_TPC_INTR_CAUSE 20
#define GAUDI_NUM_OF_QM_ERR_CAUSE 16
#define GAUDI_NUM_OF_QM_ARB_ERR_CAUSE 3
#define GAUDI_ARB_WDT_TIMEOUT 0xEE6b27FF /* 8 seconds */
#define HBM_SCRUBBING_TIMEOUT_US 1000000 /* 1s */
#define BIN_REG_STRING_SIZE sizeof("0b10101010101010101010101010101010")
#define MONITOR_SOB_STRING_SIZE 256
static u32 gaudi_stream_master[GAUDI_STREAM_MASTER_ARR_SIZE] = {
GAUDI_QUEUE_ID_DMA_0_0,
GAUDI_QUEUE_ID_DMA_0_1,
GAUDI_QUEUE_ID_DMA_0_2,
GAUDI_QUEUE_ID_DMA_0_3,
GAUDI_QUEUE_ID_DMA_1_0,
GAUDI_QUEUE_ID_DMA_1_1,
GAUDI_QUEUE_ID_DMA_1_2,
GAUDI_QUEUE_ID_DMA_1_3
};
static const u8 gaudi_dma_assignment[GAUDI_DMA_MAX] = {
[GAUDI_PCI_DMA_1] = GAUDI_ENGINE_ID_DMA_0,
[GAUDI_PCI_DMA_2] = GAUDI_ENGINE_ID_DMA_1,
[GAUDI_HBM_DMA_1] = GAUDI_ENGINE_ID_DMA_2,
[GAUDI_HBM_DMA_2] = GAUDI_ENGINE_ID_DMA_3,
[GAUDI_HBM_DMA_3] = GAUDI_ENGINE_ID_DMA_4,
[GAUDI_HBM_DMA_4] = GAUDI_ENGINE_ID_DMA_5,
[GAUDI_HBM_DMA_5] = GAUDI_ENGINE_ID_DMA_6,
[GAUDI_HBM_DMA_6] = GAUDI_ENGINE_ID_DMA_7
};
static const u8 gaudi_cq_assignment[NUMBER_OF_CMPLT_QUEUES] = {
[0] = GAUDI_QUEUE_ID_DMA_0_0,
[1] = GAUDI_QUEUE_ID_DMA_0_1,
[2] = GAUDI_QUEUE_ID_DMA_0_2,
[3] = GAUDI_QUEUE_ID_DMA_0_3,
[4] = GAUDI_QUEUE_ID_DMA_1_0,
[5] = GAUDI_QUEUE_ID_DMA_1_1,
[6] = GAUDI_QUEUE_ID_DMA_1_2,
[7] = GAUDI_QUEUE_ID_DMA_1_3,
};
static const u16 gaudi_packet_sizes[MAX_PACKET_ID] = {
[PACKET_WREG_32] = sizeof(struct packet_wreg32),
[PACKET_WREG_BULK] = sizeof(struct packet_wreg_bulk),
[PACKET_MSG_LONG] = sizeof(struct packet_msg_long),
[PACKET_MSG_SHORT] = sizeof(struct packet_msg_short),
[PACKET_CP_DMA] = sizeof(struct packet_cp_dma),
[PACKET_REPEAT] = sizeof(struct packet_repeat),
[PACKET_MSG_PROT] = sizeof(struct packet_msg_prot),
[PACKET_FENCE] = sizeof(struct packet_fence),
[PACKET_LIN_DMA] = sizeof(struct packet_lin_dma),
[PACKET_NOP] = sizeof(struct packet_nop),
[PACKET_STOP] = sizeof(struct packet_stop),
[PACKET_ARB_POINT] = sizeof(struct packet_arb_point),
[PACKET_WAIT] = sizeof(struct packet_wait),
[PACKET_LOAD_AND_EXE] = sizeof(struct packet_load_and_exe)
};
static inline bool validate_packet_id(enum packet_id id)
{
switch (id) {
case PACKET_WREG_32:
case PACKET_WREG_BULK:
case PACKET_MSG_LONG:
case PACKET_MSG_SHORT:
case PACKET_CP_DMA:
case PACKET_REPEAT:
case PACKET_MSG_PROT:
case PACKET_FENCE:
case PACKET_LIN_DMA:
case PACKET_NOP:
case PACKET_STOP:
case PACKET_ARB_POINT:
case PACKET_WAIT:
case PACKET_LOAD_AND_EXE:
return true;
default:
return false;
}
}
static const char * const
gaudi_tpc_interrupts_cause[GAUDI_NUM_OF_TPC_INTR_CAUSE] = {
"tpc_address_exceed_slm",
"tpc_div_by_0",
"tpc_spu_mac_overflow",
"tpc_spu_addsub_overflow",
"tpc_spu_abs_overflow",
"tpc_spu_fp_dst_nan_inf",
"tpc_spu_fp_dst_denorm",
"tpc_vpu_mac_overflow",
"tpc_vpu_addsub_overflow",
"tpc_vpu_abs_overflow",
"tpc_vpu_fp_dst_nan_inf",
"tpc_vpu_fp_dst_denorm",
"tpc_assertions",
"tpc_illegal_instruction",
"tpc_pc_wrap_around",
"tpc_qm_sw_err",
"tpc_hbw_rresp_err",
"tpc_hbw_bresp_err",
"tpc_lbw_rresp_err",
"tpc_lbw_bresp_err"
};
static const char * const
gaudi_qman_error_cause[GAUDI_NUM_OF_QM_ERR_CAUSE] = {
"PQ AXI HBW error",
"CQ AXI HBW error",
"CP AXI HBW error",
"CP error due to undefined OPCODE",
"CP encountered STOP OPCODE",
"CP AXI LBW error",
"CP WRREG32 or WRBULK returned error",
"N/A",
"FENCE 0 inc over max value and clipped",
"FENCE 1 inc over max value and clipped",
"FENCE 2 inc over max value and clipped",
"FENCE 3 inc over max value and clipped",
"FENCE 0 dec under min value and clipped",
"FENCE 1 dec under min value and clipped",
"FENCE 2 dec under min value and clipped",
"FENCE 3 dec under min value and clipped"
};
static const char * const
gaudi_qman_arb_error_cause[GAUDI_NUM_OF_QM_ARB_ERR_CAUSE] = {
"Choice push while full error",
"Choice Q watchdog error",
"MSG AXI LBW returned with error"
};
static enum hl_queue_type gaudi_queue_type[GAUDI_QUEUE_ID_SIZE] = {
QUEUE_TYPE_EXT,
QUEUE_TYPE_EXT,
QUEUE_TYPE_EXT,
QUEUE_TYPE_EXT,
QUEUE_TYPE_EXT,
QUEUE_TYPE_EXT,
QUEUE_TYPE_EXT,
QUEUE_TYPE_EXT,
QUEUE_TYPE_CPU,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
QUEUE_TYPE_INT,
};
static struct hl_hw_obj_name_entry gaudi_so_id_to_str[] = {
{ .id = 0, .name = "SYNC_OBJ_DMA_DOWN_FEEDBACK" },
{ .id = 1, .name = "SYNC_OBJ_DMA_UP_FEEDBACK" },
{ .id = 2, .name = "SYNC_OBJ_DMA_STATIC_DRAM_SRAM_FEEDBACK" },
{ .id = 3, .name = "SYNC_OBJ_DMA_SRAM_DRAM_FEEDBACK" },
{ .id = 4, .name = "SYNC_OBJ_FIRST_COMPUTE_FINISH" },
{ .id = 5, .name = "SYNC_OBJ_HOST_DRAM_DONE" },
{ .id = 6, .name = "SYNC_OBJ_DBG_CTR_DEPRECATED" },
{ .id = 7, .name = "SYNC_OBJ_DMA_ACTIVATIONS_DRAM_SRAM_FEEDBACK" },
{ .id = 8, .name = "SYNC_OBJ_ENGINE_SEM_MME_0" },
{ .id = 9, .name = "SYNC_OBJ_ENGINE_SEM_MME_1" },
{ .id = 10, .name = "SYNC_OBJ_ENGINE_SEM_TPC_0" },
{ .id = 11, .name = "SYNC_OBJ_ENGINE_SEM_TPC_1" },
{ .id = 12, .name = "SYNC_OBJ_ENGINE_SEM_TPC_2" },
{ .id = 13, .name = "SYNC_OBJ_ENGINE_SEM_TPC_3" },
{ .id = 14, .name = "SYNC_OBJ_ENGINE_SEM_TPC_4" },
{ .id = 15, .name = "SYNC_OBJ_ENGINE_SEM_TPC_5" },
{ .id = 16, .name = "SYNC_OBJ_ENGINE_SEM_TPC_6" },
{ .id = 17, .name = "SYNC_OBJ_ENGINE_SEM_TPC_7" },
{ .id = 18, .name = "SYNC_OBJ_ENGINE_SEM_DMA_1" },
{ .id = 19, .name = "SYNC_OBJ_ENGINE_SEM_DMA_2" },
{ .id = 20, .name = "SYNC_OBJ_ENGINE_SEM_DMA_3" },
{ .id = 21, .name = "SYNC_OBJ_ENGINE_SEM_DMA_4" },
{ .id = 22, .name = "SYNC_OBJ_ENGINE_SEM_DMA_5" },
{ .id = 23, .name = "SYNC_OBJ_ENGINE_SEM_DMA_6" },
{ .id = 24, .name = "SYNC_OBJ_ENGINE_SEM_DMA_7" },
{ .id = 25, .name = "SYNC_OBJ_DBG_CTR_0" },
{ .id = 26, .name = "SYNC_OBJ_DBG_CTR_1" },
};
static struct hl_hw_obj_name_entry gaudi_monitor_id_to_str[] = {
{ .id = 200, .name = "MON_OBJ_DMA_DOWN_FEEDBACK_RESET" },
{ .id = 201, .name = "MON_OBJ_DMA_UP_FEEDBACK_RESET" },
{ .id = 203, .name = "MON_OBJ_DRAM_TO_SRAM_QUEUE_FENCE" },
{ .id = 204, .name = "MON_OBJ_TPC_0_CLK_GATE" },
{ .id = 205, .name = "MON_OBJ_TPC_1_CLK_GATE" },
{ .id = 206, .name = "MON_OBJ_TPC_2_CLK_GATE" },
{ .id = 207, .name = "MON_OBJ_TPC_3_CLK_GATE" },
{ .id = 208, .name = "MON_OBJ_TPC_4_CLK_GATE" },
{ .id = 209, .name = "MON_OBJ_TPC_5_CLK_GATE" },
{ .id = 210, .name = "MON_OBJ_TPC_6_CLK_GATE" },
{ .id = 211, .name = "MON_OBJ_TPC_7_CLK_GATE" },
};
static s64 gaudi_state_dump_specs_props[] = {
[SP_SYNC_OBJ_BASE_ADDR] = mmSYNC_MNGR_E_N_SYNC_MNGR_OBJS_SOB_OBJ_0,
[SP_NEXT_SYNC_OBJ_ADDR] = NEXT_SYNC_OBJ_ADDR_INTERVAL,
[SP_SYNC_OBJ_AMOUNT] = NUM_OF_SOB_IN_BLOCK,
[SP_MON_OBJ_WR_ADDR_LOW] =
mmSYNC_MNGR_E_N_SYNC_MNGR_OBJS_MON_PAY_ADDRL_0,
[SP_MON_OBJ_WR_ADDR_HIGH] =
mmSYNC_MNGR_E_N_SYNC_MNGR_OBJS_MON_PAY_ADDRH_0,
[SP_MON_OBJ_WR_DATA] = mmSYNC_MNGR_E_N_SYNC_MNGR_OBJS_MON_PAY_DATA_0,
[SP_MON_OBJ_ARM_DATA] = mmSYNC_MNGR_E_N_SYNC_MNGR_OBJS_MON_ARM_0,
[SP_MON_OBJ_STATUS] = mmSYNC_MNGR_E_N_SYNC_MNGR_OBJS_MON_STATUS_0,
[SP_MONITORS_AMOUNT] = NUM_OF_MONITORS_IN_BLOCK,
[SP_TPC0_CMDQ] = mmTPC0_QM_GLBL_CFG0,
[SP_TPC0_CFG_SO] = mmTPC0_CFG_QM_SYNC_OBJECT_ADDR,
[SP_NEXT_TPC] = mmTPC1_QM_GLBL_CFG0 - mmTPC0_QM_GLBL_CFG0,
[SP_MME_CMDQ] = mmMME0_QM_GLBL_CFG0,
[SP_MME_CFG_SO] = mmMME0_CTRL_ARCH_DESC_SYNC_OBJECT_ADDR_LOW_LOCAL,
[SP_NEXT_MME] = mmMME2_QM_GLBL_CFG0 - mmMME0_QM_GLBL_CFG0,
[SP_DMA_CMDQ] = mmDMA0_QM_GLBL_CFG0,
[SP_DMA_CFG_SO] = mmDMA0_CORE_WR_COMP_ADDR_LO,
[SP_DMA_QUEUES_OFFSET] = mmDMA1_QM_GLBL_CFG0 - mmDMA0_QM_GLBL_CFG0,
[SP_NUM_OF_MME_ENGINES] = NUM_OF_MME_ENGINES,
[SP_SUB_MME_ENG_NUM] = NUM_OF_MME_SUB_ENGINES,
[SP_NUM_OF_DMA_ENGINES] = NUM_OF_DMA_ENGINES,
[SP_NUM_OF_TPC_ENGINES] = NUM_OF_TPC_ENGINES,
[SP_ENGINE_NUM_OF_QUEUES] = NUM_OF_QUEUES,
[SP_ENGINE_NUM_OF_STREAMS] = NUM_OF_STREAMS,
[SP_ENGINE_NUM_OF_FENCES] = NUM_OF_FENCES,
[SP_FENCE0_CNT_OFFSET] =
mmDMA0_QM_CP_FENCE0_CNT_0 - mmDMA0_QM_GLBL_CFG0,
[SP_FENCE0_RDATA_OFFSET] =
mmDMA0_QM_CP_FENCE0_RDATA_0 - mmDMA0_QM_GLBL_CFG0,
[SP_CP_STS_OFFSET] = mmDMA0_QM_CP_STS_0 - mmDMA0_QM_GLBL_CFG0,
[SP_NUM_CORES] = 1,
};
static const int gaudi_queue_id_to_engine_id[] = {
[GAUDI_QUEUE_ID_DMA_0_0...GAUDI_QUEUE_ID_DMA_0_3] = GAUDI_ENGINE_ID_DMA_0,
[GAUDI_QUEUE_ID_DMA_1_0...GAUDI_QUEUE_ID_DMA_1_3] = GAUDI_ENGINE_ID_DMA_1,
[GAUDI_QUEUE_ID_CPU_PQ] = GAUDI_ENGINE_ID_SIZE,
[GAUDI_QUEUE_ID_DMA_2_0...GAUDI_QUEUE_ID_DMA_2_3] = GAUDI_ENGINE_ID_DMA_2,
[GAUDI_QUEUE_ID_DMA_3_0...GAUDI_QUEUE_ID_DMA_3_3] = GAUDI_ENGINE_ID_DMA_3,
[GAUDI_QUEUE_ID_DMA_4_0...GAUDI_QUEUE_ID_DMA_4_3] = GAUDI_ENGINE_ID_DMA_4,
[GAUDI_QUEUE_ID_DMA_5_0...GAUDI_QUEUE_ID_DMA_5_3] = GAUDI_ENGINE_ID_DMA_5,
[GAUDI_QUEUE_ID_DMA_6_0...GAUDI_QUEUE_ID_DMA_6_3] = GAUDI_ENGINE_ID_DMA_6,
[GAUDI_QUEUE_ID_DMA_7_0...GAUDI_QUEUE_ID_DMA_7_3] = GAUDI_ENGINE_ID_DMA_7,
[GAUDI_QUEUE_ID_MME_0_0...GAUDI_QUEUE_ID_MME_0_3] = GAUDI_ENGINE_ID_MME_0,
[GAUDI_QUEUE_ID_MME_1_0...GAUDI_QUEUE_ID_MME_1_3] = GAUDI_ENGINE_ID_MME_2,
[GAUDI_QUEUE_ID_TPC_0_0...GAUDI_QUEUE_ID_TPC_0_3] = GAUDI_ENGINE_ID_TPC_0,
[GAUDI_QUEUE_ID_TPC_1_0...GAUDI_QUEUE_ID_TPC_1_3] = GAUDI_ENGINE_ID_TPC_1,
[GAUDI_QUEUE_ID_TPC_2_0...GAUDI_QUEUE_ID_TPC_2_3] = GAUDI_ENGINE_ID_TPC_2,
[GAUDI_QUEUE_ID_TPC_3_0...GAUDI_QUEUE_ID_TPC_3_3] = GAUDI_ENGINE_ID_TPC_3,
[GAUDI_QUEUE_ID_TPC_4_0...GAUDI_QUEUE_ID_TPC_4_3] = GAUDI_ENGINE_ID_TPC_4,
[GAUDI_QUEUE_ID_TPC_5_0...GAUDI_QUEUE_ID_TPC_5_3] = GAUDI_ENGINE_ID_TPC_5,
[GAUDI_QUEUE_ID_TPC_6_0...GAUDI_QUEUE_ID_TPC_6_3] = GAUDI_ENGINE_ID_TPC_6,
[GAUDI_QUEUE_ID_TPC_7_0...GAUDI_QUEUE_ID_TPC_7_3] = GAUDI_ENGINE_ID_TPC_7,
[GAUDI_QUEUE_ID_NIC_0_0...GAUDI_QUEUE_ID_NIC_0_3] = GAUDI_ENGINE_ID_NIC_0,
[GAUDI_QUEUE_ID_NIC_1_0...GAUDI_QUEUE_ID_NIC_1_3] = GAUDI_ENGINE_ID_NIC_1,
[GAUDI_QUEUE_ID_NIC_2_0...GAUDI_QUEUE_ID_NIC_2_3] = GAUDI_ENGINE_ID_NIC_2,
[GAUDI_QUEUE_ID_NIC_3_0...GAUDI_QUEUE_ID_NIC_3_3] = GAUDI_ENGINE_ID_NIC_3,
[GAUDI_QUEUE_ID_NIC_4_0...GAUDI_QUEUE_ID_NIC_4_3] = GAUDI_ENGINE_ID_NIC_4,
[GAUDI_QUEUE_ID_NIC_5_0...GAUDI_QUEUE_ID_NIC_5_3] = GAUDI_ENGINE_ID_NIC_5,
[GAUDI_QUEUE_ID_NIC_6_0...GAUDI_QUEUE_ID_NIC_6_3] = GAUDI_ENGINE_ID_NIC_6,
[GAUDI_QUEUE_ID_NIC_7_0...GAUDI_QUEUE_ID_NIC_7_3] = GAUDI_ENGINE_ID_NIC_7,
[GAUDI_QUEUE_ID_NIC_8_0...GAUDI_QUEUE_ID_NIC_8_3] = GAUDI_ENGINE_ID_NIC_8,
[GAUDI_QUEUE_ID_NIC_9_0...GAUDI_QUEUE_ID_NIC_9_3] = GAUDI_ENGINE_ID_NIC_9,
};
static const char * const gaudi_sync_manager_names[] = {
"SYNC_MGR_E_N",
"SYNC_MGR_W_N",
"SYNC_MGR_E_S",
"SYNC_MGR_W_S",
NULL
};
struct ecc_info_extract_params {
u64 block_address;
u32 num_memories;
bool derr;
};
static int gaudi_mmu_update_asid_hop0_addr(struct hl_device *hdev, u32 asid,
u64 phys_addr);
static int gaudi_send_job_on_qman0(struct hl_device *hdev,
struct hl_cs_job *job);
static int gaudi_memset_device_memory(struct hl_device *hdev, u64 addr,
u32 size, u64 val);
static int gaudi_memset_registers(struct hl_device *hdev, u64 reg_base,
u32 num_regs, u32 val);
static int gaudi_run_tpc_kernel(struct hl_device *hdev, u64 tpc_kernel,
u32 tpc_id);
static int gaudi_mmu_clear_pgt_range(struct hl_device *hdev);
static int gaudi_cpucp_info_get(struct hl_device *hdev);
static void gaudi_disable_clock_gating(struct hl_device *hdev);
static void gaudi_mmu_prepare(struct hl_device *hdev, u32 asid);
static u32 gaudi_gen_signal_cb(struct hl_device *hdev, void *data, u16 sob_id,
u32 size, bool eb);
static u32 gaudi_gen_wait_cb(struct hl_device *hdev,
struct hl_gen_wait_properties *prop);
static inline enum hl_collective_mode
get_collective_mode(struct hl_device *hdev, u32 queue_id)
{
if (gaudi_queue_type[queue_id] == QUEUE_TYPE_EXT)
return HL_COLLECTIVE_MASTER;
if (queue_id >= GAUDI_QUEUE_ID_DMA_5_0 &&
queue_id <= GAUDI_QUEUE_ID_DMA_5_3)
return HL_COLLECTIVE_SLAVE;
if (queue_id >= GAUDI_QUEUE_ID_TPC_7_0 &&
queue_id <= GAUDI_QUEUE_ID_TPC_7_3)
return HL_COLLECTIVE_SLAVE;
if (queue_id >= GAUDI_QUEUE_ID_NIC_0_0 &&
queue_id <= GAUDI_QUEUE_ID_NIC_9_3)
return HL_COLLECTIVE_SLAVE;
return HL_COLLECTIVE_NOT_SUPPORTED;
}
static inline void set_default_power_values(struct hl_device *hdev)
{
struct asic_fixed_properties *prop = &hdev->asic_prop;
if (hdev->card_type == cpucp_card_type_pmc) {
prop->max_power_default = MAX_POWER_DEFAULT_PMC;
if (prop->fw_security_enabled)
prop->dc_power_default = DC_POWER_DEFAULT_PMC_SEC;
else
prop->dc_power_default = DC_POWER_DEFAULT_PMC;
} else {
prop->max_power_default = MAX_POWER_DEFAULT_PCI;
prop->dc_power_default = DC_POWER_DEFAULT_PCI;
}
}
static int gaudi_set_fixed_properties(struct hl_device *hdev)
{
struct asic_fixed_properties *prop = &hdev->asic_prop;
u32 num_sync_stream_queues = 0;
int i;
prop->max_queues = GAUDI_QUEUE_ID_SIZE;
prop->hw_queues_props = kcalloc(prop->max_queues,
sizeof(struct hw_queue_properties),
GFP_KERNEL);
if (!prop->hw_queues_props)
return -ENOMEM;
for (i = 0 ; i < prop->max_queues ; i++) {
if (gaudi_queue_type[i] == QUEUE_TYPE_EXT) {
prop->hw_queues_props[i].type = QUEUE_TYPE_EXT;
prop->hw_queues_props[i].driver_only = 0;
prop->hw_queues_props[i].supports_sync_stream = 1;
prop->hw_queues_props[i].cb_alloc_flags =
CB_ALLOC_KERNEL;
num_sync_stream_queues++;
} else if (gaudi_queue_type[i] == QUEUE_TYPE_CPU) {
prop->hw_queues_props[i].type = QUEUE_TYPE_CPU;
prop->hw_queues_props[i].driver_only = 1;
prop->hw_queues_props[i].supports_sync_stream = 0;
prop->hw_queues_props[i].cb_alloc_flags =
CB_ALLOC_KERNEL;
} else if (gaudi_queue_type[i] == QUEUE_TYPE_INT) {
prop->hw_queues_props[i].type = QUEUE_TYPE_INT;
prop->hw_queues_props[i].driver_only = 0;
prop->hw_queues_props[i].supports_sync_stream = 0;
prop->hw_queues_props[i].cb_alloc_flags =
CB_ALLOC_USER;
}
prop->hw_queues_props[i].collective_mode =
get_collective_mode(hdev, i);
}
prop->cache_line_size = DEVICE_CACHE_LINE_SIZE;
prop->cfg_base_address = CFG_BASE;
prop->device_dma_offset_for_host_access = HOST_PHYS_BASE;
prop->host_base_address = HOST_PHYS_BASE;
prop->host_end_address = prop->host_base_address + HOST_PHYS_SIZE;
prop->completion_queues_count = NUMBER_OF_CMPLT_QUEUES;
prop->completion_mode = HL_COMPLETION_MODE_JOB;
prop->collective_first_sob = 0;
prop->collective_first_mon = 0;
prop->sync_stream_first_sob =
ALIGN(NUMBER_OF_SOBS_IN_GRP, HL_MAX_SOBS_PER_MONITOR)
* QMAN_STREAMS * HL_RSVD_SOBS;
prop->sync_stream_first_mon =
(NUMBER_OF_COLLECTIVE_QUEUES * QMAN_STREAMS) +
(NUMBER_OF_EXT_HW_QUEUES * 2);
prop->dram_base_address = DRAM_PHYS_BASE;
prop->dram_size = GAUDI_HBM_SIZE_32GB;
prop->dram_end_address = prop->dram_base_address + prop->dram_size;
prop->dram_user_base_address = DRAM_BASE_ADDR_USER;
prop->sram_base_address = SRAM_BASE_ADDR;
prop->sram_size = SRAM_SIZE;
prop->sram_end_address = prop->sram_base_address + prop->sram_size;
prop->sram_user_base_address =
prop->sram_base_address + SRAM_USER_BASE_OFFSET;
prop->mmu_cache_mng_addr = MMU_CACHE_MNG_ADDR;
prop->mmu_cache_mng_size = MMU_CACHE_MNG_SIZE;
prop->mmu_pgt_addr = MMU_PAGE_TABLES_ADDR;
if (hdev->pldm)
prop->mmu_pgt_size = 0x800000;
else
prop->mmu_pgt_size = MMU_PAGE_TABLES_SIZE;
prop->mmu_pte_size = HL_PTE_SIZE;
prop->mmu_hop_table_size = HOP_TABLE_SIZE_512_PTE;
prop->mmu_hop0_tables_total_size = HOP0_512_PTE_TABLES_TOTAL_SIZE;
prop->dram_page_size = PAGE_SIZE_2MB;
prop->device_mem_alloc_default_page_size = prop->dram_page_size;
prop->dram_supports_virtual_memory = false;
prop->pmmu.hop_shifts[MMU_HOP0] = MMU_V1_1_HOP0_SHIFT;
prop->pmmu.hop_shifts[MMU_HOP1] = MMU_V1_1_HOP1_SHIFT;
prop->pmmu.hop_shifts[MMU_HOP2] = MMU_V1_1_HOP2_SHIFT;
prop->pmmu.hop_shifts[MMU_HOP3] = MMU_V1_1_HOP3_SHIFT;
prop->pmmu.hop_shifts[MMU_HOP4] = MMU_V1_1_HOP4_SHIFT;
prop->pmmu.hop_masks[MMU_HOP0] = MMU_V1_1_HOP0_MASK;
prop->pmmu.hop_masks[MMU_HOP1] = MMU_V1_1_HOP1_MASK;
prop->pmmu.hop_masks[MMU_HOP2] = MMU_V1_1_HOP2_MASK;
prop->pmmu.hop_masks[MMU_HOP3] = MMU_V1_1_HOP3_MASK;
prop->pmmu.hop_masks[MMU_HOP4] = MMU_V1_1_HOP4_MASK;
prop->pmmu.start_addr = VA_HOST_SPACE_START;
prop->pmmu.end_addr =
(VA_HOST_SPACE_START + VA_HOST_SPACE_SIZE / 2) - 1;
prop->pmmu.page_size = PAGE_SIZE_4KB;
prop->pmmu.num_hops = MMU_ARCH_5_HOPS;
prop->pmmu.last_mask = LAST_MASK;
prop->pmmu.hop_table_size = prop->mmu_hop_table_size;
prop->pmmu.hop0_tables_total_size = prop->mmu_hop0_tables_total_size;
memcpy(&prop->pmmu_huge, &prop->pmmu, sizeof(prop->pmmu));
prop->pmmu_huge.page_size = PAGE_SIZE_2MB;
memcpy(&prop->dmmu, &prop->pmmu, sizeof(prop->pmmu));
prop->dmmu.start_addr = (VA_HOST_SPACE_START + VA_HOST_SPACE_SIZE / 2);
prop->dmmu.end_addr = VA_HOST_SPACE_END;
prop->dmmu.page_size = PAGE_SIZE_2MB;
prop->cfg_size = CFG_SIZE;
prop->max_asid = MAX_ASID;
prop->num_of_events = GAUDI_EVENT_SIZE;
prop->max_num_of_engines = GAUDI_ENGINE_ID_SIZE;
prop->tpc_enabled_mask = TPC_ENABLED_MASK;
set_default_power_values(hdev);
prop->cb_pool_cb_cnt = GAUDI_CB_POOL_CB_CNT;
prop->cb_pool_cb_size = GAUDI_CB_POOL_CB_SIZE;
prop->pcie_dbi_base_address = mmPCIE_DBI_BASE;
prop->pcie_aux_dbi_reg_addr = CFG_BASE + mmPCIE_AUX_DBI;
strncpy(prop->cpucp_info.card_name, GAUDI_DEFAULT_CARD_NAME,
CARD_NAME_MAX_LEN);
prop->max_pending_cs = GAUDI_MAX_PENDING_CS;
prop->first_available_user_sob[HL_GAUDI_WS_DCORE] =
prop->sync_stream_first_sob +
(num_sync_stream_queues * HL_RSVD_SOBS);
prop->first_available_user_mon[HL_GAUDI_WS_DCORE] =
prop->sync_stream_first_mon +
(num_sync_stream_queues * HL_RSVD_MONS);
prop->first_available_user_interrupt = USHRT_MAX;
prop->tpc_interrupt_id = USHRT_MAX;
prop->eq_interrupt_id = 0;
for (i = 0 ; i < HL_MAX_DCORES ; i++)
prop->first_available_cq[i] = USHRT_MAX;
prop->fw_cpu_boot_dev_sts0_valid = false;
prop->fw_cpu_boot_dev_sts1_valid = false;
prop->hard_reset_done_by_fw = false;
prop->gic_interrupts_enable = true;
prop->server_type = HL_SERVER_TYPE_UNKNOWN;
prop->clk_pll_index = HL_GAUDI_MME_PLL;
prop->max_freq_value = GAUDI_MAX_CLK_FREQ;
prop->use_get_power_for_reset_history = true;
prop->configurable_stop_on_err = true;
prop->set_max_power_on_device_init = true;
prop->dma_mask = 48;
prop->hbw_flush_reg = mmPCIE_WRAP_RR_ELBI_RD_SEC_REG_CTRL;
return 0;
}
static int gaudi_pci_bars_map(struct hl_device *hdev)
{
static const char * const name[] = {"SRAM", "CFG", "HBM"};
bool is_wc[3] = {false, false, true};
int rc;
rc = hl_pci_bars_map(hdev, name, is_wc);
if (rc)
return rc;
hdev->rmmio = hdev->pcie_bar[CFG_BAR_ID] +
(CFG_BASE - SPI_FLASH_BASE_ADDR);
return 0;
}
static u64 gaudi_set_hbm_bar_base(struct hl_device *hdev, u64 addr)
{
struct gaudi_device *gaudi = hdev->asic_specific;
struct hl_inbound_pci_region pci_region;
u64 old_addr = addr;
int rc;
if ((gaudi) && (gaudi->hbm_bar_cur_addr == addr))
return old_addr;
if (hdev->asic_prop.iatu_done_by_fw)
return U64_MAX;
pci_region.mode = PCI_BAR_MATCH_MODE;
pci_region.bar = HBM_BAR_ID;
pci_region.addr = addr;
rc = hl_pci_set_inbound_region(hdev, 2, &pci_region);
if (rc)
return U64_MAX;
if (gaudi) {
old_addr = gaudi->hbm_bar_cur_addr;
gaudi->hbm_bar_cur_addr = addr;
}
return old_addr;
}
static int gaudi_init_iatu(struct hl_device *hdev)
{
struct hl_inbound_pci_region inbound_region;
struct hl_outbound_pci_region outbound_region;
int rc;
if (hdev->asic_prop.iatu_done_by_fw)
return 0;
inbound_region.mode = PCI_BAR_MATCH_MODE;
inbound_region.bar = SRAM_BAR_ID;
inbound_region.addr = SRAM_BASE_ADDR;
rc = hl_pci_set_inbound_region(hdev, 0, &inbound_region);
if (rc)
goto done;
inbound_region.mode = PCI_BAR_MATCH_MODE;
inbound_region.bar = CFG_BAR_ID;
inbound_region.addr = SPI_FLASH_BASE_ADDR;
rc = hl_pci_set_inbound_region(hdev, 1, &inbound_region);
if (rc)
goto done;
inbound_region.mode = PCI_BAR_MATCH_MODE;
inbound_region.bar = HBM_BAR_ID;
inbound_region.addr = DRAM_PHYS_BASE;
rc = hl_pci_set_inbound_region(hdev, 2, &inbound_region);
if (rc)
goto done;
outbound_region.addr = HOST_PHYS_BASE;
outbound_region.size = HOST_PHYS_SIZE;
rc = hl_pci_set_outbound_region(hdev, &outbound_region);
done:
return rc;
}
static enum hl_device_hw_state gaudi_get_hw_state(struct hl_device *hdev)
{
return RREG32(mmHW_STATE);
}
static int gaudi_early_init(struct hl_device *hdev)
{
struct asic_fixed_properties *prop = &hdev->asic_prop;
struct pci_dev *pdev = hdev->pdev;
resource_size_t pci_bar_size;
u32 fw_boot_status;
int rc;
rc = gaudi_set_fixed_properties(hdev);
if (rc) {
dev_err(hdev->dev, "Failed setting fixed properties\n");
return rc;
}
pci_bar_size = pci_resource_len(pdev, SRAM_BAR_ID);
if (pci_bar_size != SRAM_BAR_SIZE) {
dev_err(hdev->dev, "Not " HL_NAME "? BAR %d size %pa, expecting %llu\n",
SRAM_BAR_ID, &pci_bar_size, SRAM_BAR_SIZE);
rc = -ENODEV;
goto free_queue_props;
}
pci_bar_size = pci_resource_len(pdev, CFG_BAR_ID);
if (pci_bar_size != CFG_BAR_SIZE) {
dev_err(hdev->dev, "Not " HL_NAME "? BAR %d size %pa, expecting %llu\n",
CFG_BAR_ID, &pci_bar_size, CFG_BAR_SIZE);
rc = -ENODEV;
goto free_queue_props;
}
prop->dram_pci_bar_size = pci_resource_len(pdev, HBM_BAR_ID);
hdev->dram_pci_bar_start = pci_resource_start(pdev, HBM_BAR_ID);
if (hdev->asic_prop.fw_security_enabled) {
hdev->asic_prop.iatu_done_by_fw = true;
hdev->asic_prop.gic_interrupts_enable = false;
goto pci_init;
}
rc = hl_pci_elbi_read(hdev, CFG_BASE + mmCPU_BOOT_DEV_STS0,
&fw_boot_status);
if (rc)
goto free_queue_props;
if ((fw_boot_status & CPU_BOOT_DEV_STS0_ENABLED) &&
(fw_boot_status & CPU_BOOT_DEV_STS0_FW_IATU_CONF_EN))
hdev->asic_prop.iatu_done_by_fw = true;
pci_init:
rc = hl_pci_init(hdev);
if (rc)
goto free_queue_props;
rc = hl_fw_read_preboot_status(hdev);
if (rc) {
if (hdev->reset_on_preboot_fail)
hdev->asic_funcs->hw_fini(hdev, true, false);
goto pci_fini;
}
if (gaudi_get_hw_state(hdev) == HL_DEVICE_HW_STATE_DIRTY) {
dev_dbg(hdev->dev, "H/W state is dirty, must reset before initializing\n");
rc = hdev->asic_funcs->hw_fini(hdev, true, false);
if (rc) {
dev_err(hdev->dev, "failed to reset HW in dirty state (%d)\n", rc);
goto pci_fini;
}
}
return 0;
pci_fini:
hl_pci_fini(hdev);
free_queue_props:
kfree(hdev->asic_prop.hw_queues_props);
return rc;
}
static int gaudi_early_fini(struct hl_device *hdev)
{
kfree(hdev->asic_prop.hw_queues_props);
hl_pci_fini(hdev);
return 0;
}
static int gaudi_fetch_psoc_frequency(struct hl_device *hdev)
{
u32 nr = 0, nf = 0, od = 0, div_fctr = 0, pll_clk, div_sel;
struct asic_fixed_properties *prop = &hdev->asic_prop;
u16 pll_freq_arr[HL_PLL_NUM_OUTPUTS], freq;
int rc;
if ((hdev->fw_components & FW_TYPE_LINUX) &&
(prop->fw_app_cpu_boot_dev_sts0 & CPU_BOOT_DEV_STS0_PLL_INFO_EN)) {
struct gaudi_device *gaudi = hdev->asic_specific;
if (!(gaudi->hw_cap_initialized & HW_CAP_CPU_Q))
return 0;
rc = hl_fw_cpucp_pll_info_get(hdev, HL_GAUDI_CPU_PLL, pll_freq_arr);
if (rc)
return rc;
freq = pll_freq_arr[2];
} else {
div_fctr = RREG32(mmPSOC_CPU_PLL_DIV_FACTOR_2);
div_sel = RREG32(mmPSOC_CPU_PLL_DIV_SEL_2);
nr = RREG32(mmPSOC_CPU_PLL_NR);
nf = RREG32(mmPSOC_CPU_PLL_NF);
od = RREG32(mmPSOC_CPU_PLL_OD);
if (div_sel == DIV_SEL_REF_CLK ||
div_sel == DIV_SEL_DIVIDED_REF) {
if (div_sel == DIV_SEL_REF_CLK)
freq = PLL_REF_CLK;
else
freq = PLL_REF_CLK / (div_fctr + 1);
} else if (div_sel == DIV_SEL_PLL_CLK ||
div_sel == DIV_SEL_DIVIDED_PLL) {
pll_clk = PLL_REF_CLK * (nf + 1) /
((nr + 1) * (od + 1));
if (div_sel == DIV_SEL_PLL_CLK)
freq = pll_clk;
else
freq = pll_clk / (div_fctr + 1);
} else {
dev_warn(hdev->dev, "Received invalid div select value: %#x", div_sel);
freq = 0;
}
}
prop->psoc_timestamp_frequency = freq;
prop->psoc_pci_pll_nr = nr;
prop->psoc_pci_pll_nf = nf;
prop->psoc_pci_pll_od = od;
prop->psoc_pci_pll_div_factor = div_fctr;
return 0;
}
static int _gaudi_init_tpc_mem(struct hl_device *hdev,
dma_addr_t tpc_kernel_src_addr, u32 tpc_kernel_size)
{
struct asic_fixed_properties *prop = &hdev->asic_prop;
struct packet_lin_dma *init_tpc_mem_pkt;
struct hl_cs_job *job;
struct hl_cb *cb;
u64 dst_addr;
u32 cb_size, ctl;
u8 tpc_id;
int rc;
cb = hl_cb_kernel_create(hdev, PAGE_SIZE, false);
if (!cb)
return -EFAULT;
init_tpc_mem_pkt = cb->kernel_address;
cb_size = sizeof(*init_tpc_mem_pkt);
memset(init_tpc_mem_pkt, 0, cb_size);
init_tpc_mem_pkt->tsize = cpu_to_le32(tpc_kernel_size);
ctl = FIELD_PREP(GAUDI_PKT_CTL_OPCODE_MASK, PACKET_LIN_DMA);
ctl |= FIELD_PREP(GAUDI_PKT_LIN_DMA_CTL_LIN_MASK, 1);
ctl |= FIELD_PREP(GAUDI_PKT_CTL_RB_MASK, 1);
ctl |= FIELD_PREP(GAUDI_PKT_CTL_MB_MASK, 1);
init_tpc_mem_pkt->ctl = cpu_to_le32(ctl);
init_tpc_mem_pkt->src_addr = cpu_to_le64(tpc_kernel_src_addr);
dst_addr = FIELD_PREP(GAUDI_PKT_LIN_DMA_DST_ADDR_MASK,
round_up(prop->sram_user_base_address, SZ_8K));
init_tpc_mem_pkt->dst_addr |= cpu_to_le64(dst_addr);
job = hl_cs_allocate_job(hdev, QUEUE_TYPE_EXT, true);
if (!job) {
dev_err(hdev->dev, "Failed to allocate a new job\n");
rc = -ENOMEM;
goto release_cb;
}
job->id = 0;
job->user_cb = cb;
atomic_inc(&job->user_cb->cs_cnt);
job->user_cb_size = cb_size;
job->hw_queue_id = GAUDI_QUEUE_ID_DMA_0_0;
job->patched_cb = job->user_cb;
job->job_cb_size = job->user_cb_size + sizeof(struct packet_msg_prot);
hl_debugfs_add_job(hdev, job);
rc = gaudi_send_job_on_qman0(hdev, job);
if (rc)
goto free_job;
for (tpc_id = 0 ; tpc_id < TPC_NUMBER_OF_ENGINES ; tpc_id++) {
rc = gaudi_run_tpc_kernel(hdev, dst_addr, tpc_id);
if (rc)
break;
}
free_job:
hl_userptr_delete_list(hdev, &job->userptr_list);
hl_debugfs_remove_job(hdev, job);
kfree(job);
atomic_dec(&cb->cs_cnt);
release_cb:
hl_cb_put(cb);
hl_cb_destroy(&hdev->kernel_mem_mgr, cb->buf->handle);
return rc;
}
static int gaudi_init_tpc_mem(struct hl_device *hdev)
{
const struct firmware *fw;
size_t fw_size;
void *cpu_addr;
dma_addr_t dma_handle;
int rc, count = 5;
again:
rc = request_firmware(&fw, GAUDI_TPC_FW_FILE, hdev->dev);
if (rc == -EINTR && count-- > 0) {
msleep(50);
goto again;
}
if (rc) {
dev_err(hdev->dev, "Failed to load firmware file %s\n",
GAUDI_TPC_FW_FILE);
goto out;
}
fw_size = fw->size;
cpu_addr = hl_asic_dma_alloc_coherent(hdev, fw_size, &dma_handle, GFP_KERNEL | __GFP_ZERO);
if (!cpu_addr) {
dev_err(hdev->dev,
"Failed to allocate %zu of dma memory for TPC kernel\n",
fw_size);
rc = -ENOMEM;
goto out;
}
memcpy(cpu_addr, fw->data, fw_size);
rc = _gaudi_init_tpc_mem(hdev, dma_handle, fw_size);
hl_asic_dma_free_coherent(hdev, fw->size, cpu_addr, dma_handle);
out:
release_firmware(fw);
return rc;
}
static void gaudi_collective_map_sobs(struct hl_device *hdev, u32 stream)
{
struct gaudi_device *gaudi = hdev->asic_specific;
struct gaudi_collective_properties *prop = &gaudi->collective_props;
struct hl_hw_queue *q;
u32 i, sob_id, sob_group_id, queue_id;
sob_group_id =
stream * HL_RSVD_SOBS + prop->curr_sob_group_idx[stream];
sob_id = prop->hw_sob_group[sob_group_id].base_sob_id;
queue_id = GAUDI_QUEUE_ID_NIC_0_0 + stream;
for (i = 0 ; i < NIC_NUMBER_OF_ENGINES ; i++) {
q = &hdev->kernel_queues[queue_id + (4 * i)];
q->sync_stream_prop.collective_sob_id = sob_id + i;
}
queue_id = GAUDI_QUEUE_ID_DMA_5_0 + stream;
q = &hdev->kernel_queues[queue_id];
q->sync_stream_prop.collective_sob_id =
sob_id + NIC_NUMBER_OF_ENGINES;
queue_id = GAUDI_QUEUE_ID_TPC_7_0 + stream;
q = &hdev->kernel_queues[queue_id];
q->sync_stream_prop.collective_sob_id =
sob_id + NIC_NUMBER_OF_ENGINES;
}
static void gaudi_sob_group_hw_reset(struct kref *ref)
{
struct gaudi_hw_sob_group *hw_sob_group =
container_of(ref, struct gaudi_hw_sob_group, kref);
struct hl_device *hdev = hw_sob_group->hdev;
int i;
for (i = 0 ; i < NUMBER_OF_SOBS_IN_GRP ; i++)
WREG32((mmSYNC_MNGR_W_S_SYNC_MNGR_OBJS_SOB_OBJ_0 +
(hw_sob_group->base_sob_id * 4) + (i * 4)), 0);
kref_init(&hw_sob_group->kref);
}
static void gaudi_sob_group_reset_error(struct kref *ref)
{
struct gaudi_hw_sob_group *hw_sob_group =
container_of(ref, struct gaudi_hw_sob_group, kref);
struct hl_device *hdev = hw_sob_group->hdev;
dev_crit(hdev->dev,
"SOB release shouldn't be called here, base_sob_id: %d\n",
hw_sob_group->base_sob_id);
}
static void gaudi_collective_mstr_sob_mask_set(struct gaudi_device *gaudi)
{
struct gaudi_collective_properties *prop;
int i;
prop = &gaudi->collective_props;
memset(prop->mstr_sob_mask, 0, sizeof(prop->mstr_sob_mask));
for (i = 0 ; i < NIC_NUMBER_OF_ENGINES ; i++)
if (gaudi->hw_cap_initialized & BIT(HW_CAP_NIC_SHIFT + i))
prop->mstr_sob_mask[i / HL_MAX_SOBS_PER_MONITOR] |=
BIT(i % HL_MAX_SOBS_PER_MONITOR);
prop->mstr_sob_mask[i / HL_MAX_SOBS_PER_MONITOR] |=
BIT(i % HL_MAX_SOBS_PER_MONITOR);
}
static int gaudi_collective_init(struct hl_device *hdev)
{
u32 i, sob_id, reserved_sobs_per_group;
struct gaudi_collective_properties *prop;
struct gaudi_device *gaudi;
gaudi = hdev->asic_specific;
prop = &gaudi->collective_props;
sob_id = hdev->asic_prop.collective_first_sob;
reserved_sobs_per_group =
ALIGN(NUMBER_OF_SOBS_IN_GRP, HL_MAX_SOBS_PER_MONITOR);
for (i = 0 ; i < NUM_SOB_GROUPS; i++) {
prop->hw_sob_group[i].hdev = hdev;
prop->hw_sob_group[i].base_sob_id = sob_id;
sob_id += reserved_sobs_per_group;
gaudi_sob_group_hw_reset(&prop->hw_sob_group[i].kref);
}
for (i = 0 ; i < QMAN_STREAMS; i++) {
prop->next_sob_group_val[i] = 1;
prop->curr_sob_group_idx[i] = 0;
gaudi_collective_map_sobs(hdev, i);
}
gaudi_collective_mstr_sob_mask_set(gaudi);
return 0;
}
static void gaudi_reset_sob_group(struct hl_device *hdev, u16 sob_group)
{
struct gaudi_device *gaudi = hdev->asic_specific;
struct gaudi_collective_properties *cprop = &gaudi->collective_props;
kref_put(&cprop->hw_sob_group[sob_group].kref,
gaudi_sob_group_hw_reset);
}
static void gaudi_collective_master_init_job(struct hl_device *hdev,
struct hl_cs_job *job, u32 stream, u32 sob_group_offset)
{
u32 master_sob_base, master_monitor, queue_id, cb_size = 0;
struct gaudi_collective_properties *cprop;
struct hl_gen_wait_properties wait_prop;
struct hl_sync_stream_properties *prop;
struct gaudi_device *gaudi;
gaudi = hdev->asic_specific;
cprop = &gaudi->collective_props;
queue_id = job->hw_queue_id;
prop = &hdev->kernel_queues[queue_id].sync_stream_prop;
master_sob_base =
cprop->hw_sob_group[sob_group_offset].base_sob_id;
master_monitor = prop->collective_mstr_mon_id[0];
cprop->hw_sob_group[sob_group_offset].queue_id = queue_id;
dev_dbg(hdev->dev,
"Generate master wait CBs, sob %d (mask %#x), val:0x%x, mon %u, q %d\n",
master_sob_base, cprop->mstr_sob_mask[0],
cprop->next_sob_group_val[stream],
master_monitor, queue_id);
wait_prop.data = (void *) job->patched_cb;
wait_prop.sob_base = master_sob_base;
wait_prop.sob_mask = cprop->mstr_sob_mask[0];
wait_prop.sob_val = cprop->next_sob_group_val[stream];
wait_prop.mon_id = master_monitor;
wait_prop.q_idx = queue_id;
wait_prop.size = cb_size;
cb_size += gaudi_gen_wait_cb(hdev, &wait_prop);
master_sob_base += HL_MAX_SOBS_PER_MONITOR;
master_monitor = prop->collective_mstr_mon_id[1];
dev_dbg(hdev->dev,
"Generate master wait CBs, sob %d (mask %#x), val:0x%x, mon %u, q %d\n",
master_sob_base, cprop->mstr_sob_mask[1],
cprop->next_sob_group_val[stream],
master_monitor, queue_id);
wait_prop.sob_base = master_sob_base;
wait_prop.sob_mask = cprop->mstr_sob_mask[1];
wait_prop.mon_id = master_monitor;
wait_prop.size = cb_size;
cb_size += gaudi_gen_wait_cb(hdev, &wait_prop);
}
static void gaudi_collective_slave_init_job(struct hl_device *hdev,
struct hl_cs_job *job, struct hl_cs_compl *cs_cmpl)
{
struct hl_gen_wait_properties wait_prop;
struct hl_sync_stream_properties *prop;
u32 queue_id, cb_size = 0;
queue_id = job->hw_queue_id;
prop = &hdev->kernel_queues[queue_id].sync_stream_prop;
if (job->cs->encaps_signals) {
hl_hw_queue_encaps_sig_set_sob_info(hdev, job->cs, job,
cs_cmpl);
dev_dbg(hdev->dev, "collective wait: Sequence %llu found, sob_id: %u, wait for sob_val: %u\n",
job->cs->sequence,
cs_cmpl->hw_sob->sob_id,
cs_cmpl->sob_val);
}
wait_prop.data = (void *) job->user_cb;
wait_prop.sob_base = cs_cmpl->hw_sob->sob_id;
wait_prop.sob_mask = 0x1;
wait_prop.sob_val = cs_cmpl->sob_val;
wait_prop.mon_id = prop->collective_slave_mon_id;
wait_prop.q_idx = queue_id;
wait_prop.size = cb_size;
dev_dbg(hdev->dev,
"Generate slave wait CB, sob %d, val:%x, mon %d, q %d\n",
cs_cmpl->hw_sob->sob_id, cs_cmpl->sob_val,
prop->collective_slave_mon_id, queue_id);
cb_size += gaudi_gen_wait_cb(hdev, &wait_prop);
dev_dbg(hdev->dev,
"generate signal CB, sob_id: %d, sob val: 1, q_idx: %d\n",
prop->collective_sob_id, queue_id);
cb_size += gaudi_gen_signal_cb(hdev, job->user_cb,
prop->collective_sob_id, cb_size, false);
}
static int gaudi_collective_wait_init_cs(struct hl_cs *cs)
{
struct hl_cs_compl *signal_cs_cmpl =
container_of(cs->signal_fence, struct hl_cs_compl, base_fence);
struct hl_cs_compl *cs_cmpl =
container_of(cs->fence, struct hl_cs_compl, base_fence);
struct hl_cs_encaps_sig_handle *handle = cs->encaps_sig_hdl;
struct gaudi_collective_properties *cprop;
u32 stream, queue_id, sob_group_offset;
struct gaudi_device *gaudi;
struct hl_device *hdev;
struct hl_cs_job *job;
struct hl_ctx *ctx;
ctx = cs->ctx;
hdev = ctx->hdev;
gaudi = hdev->asic_specific;
cprop = &gaudi->collective_props;
if (cs->encaps_signals) {
cs_cmpl->hw_sob = handle->hw_sob;
cs_cmpl->sob_val = 0;
} else {
cs_cmpl->hw_sob = signal_cs_cmpl->hw_sob;
cs_cmpl->sob_val = signal_cs_cmpl->sob_val;
}
spin_lock(&signal_cs_cmpl->lock);
if (completion_done(&cs->signal_fence->completion)) {
spin_unlock(&signal_cs_cmpl->lock);
return -EINVAL;
}
kref_get(&cs_cmpl->hw_sob->kref);
spin_unlock(&signal_cs_cmpl->lock);
job = list_first_entry(&cs->job_list, struct hl_cs_job, cs_node);
stream = job->hw_queue_id % 4;
sob_group_offset =
stream * HL_RSVD_SOBS + cprop->curr_sob_group_idx[stream];
list_for_each_entry(job, &cs->job_list, cs_node) {
queue_id = job->hw_queue_id;
if (hdev->kernel_queues[queue_id].collective_mode ==
HL_COLLECTIVE_MASTER)
gaudi_collective_master_init_job(hdev, job, stream,
sob_group_offset);
else
gaudi_collective_slave_init_job(hdev, job, cs_cmpl);
}
cs_cmpl->sob_group = sob_group_offset;
kref_get(&cprop->hw_sob_group[sob_group_offset].kref);
cprop->next_sob_group_val[stream]++;
if (cprop->next_sob_group_val[stream] == HL_MAX_SOB_VAL) {
kref_put(&cprop->hw_sob_group[sob_group_offset].kref,
gaudi_sob_group_reset_error);
cprop->next_sob_group_val[stream] = 1;
cprop->curr_sob_group_idx[stream] =
(cprop->curr_sob_group_idx[stream] + 1) &
(HL_RSVD_SOBS - 1);
gaudi_collective_map_sobs(hdev, stream);
dev_dbg(hdev->dev, "switched to SOB group %d, stream: %d\n",
cprop->curr_sob_group_idx[stream], stream);
}
mb();
hl_fence_put(cs->signal_fence);
cs->signal_fence = NULL;
return 0;
}
static u32 gaudi_get_patched_cb_extra_size(u32 user_cb_size)
{
u32 cacheline_end, additional_commands;
cacheline_end = round_up(user_cb_size, DEVICE_CACHE_LINE_SIZE);
additional_commands = sizeof(struct packet_msg_prot) * 2;
if (user_cb_size + additional_commands > cacheline_end)
return cacheline_end - user_cb_size + additional_commands;
else
return additional_commands;
}
static int gaudi_collective_wait_create_job(struct hl_device *hdev,
struct hl_ctx *ctx, struct hl_cs *cs,
enum hl_collective_mode mode, u32 queue_id, u32 wait_queue_id,
u32 encaps_signal_offset)
{
struct hw_queue_properties *hw_queue_prop;
struct hl_cs_counters_atomic *cntr;
struct hl_cs_job *job;
struct hl_cb *cb;
u32 cb_size;
bool patched_cb;
cntr = &hdev->aggregated_cs_counters;
if (mode == HL_COLLECTIVE_MASTER) {
cb_size = sizeof(struct packet_msg_short) * 8 +
sizeof(struct packet_fence) * 2 +
sizeof(struct packet_msg_prot) * 2;
patched_cb = true;
} else {
cb_size = sizeof(struct packet_msg_short) * 5 +
sizeof(struct packet_fence);
patched_cb = false;
}
hw_queue_prop = &hdev->asic_prop.hw_queues_props[queue_id];
job = hl_cs_allocate_job(hdev, hw_queue_prop->type, true);
if (!job) {
atomic64_inc(&ctx->cs_counters.out_of_mem_drop_cnt);
atomic64_inc(&cntr->out_of_mem_drop_cnt);
dev_err(hdev->dev, "Failed to allocate a new job\n");
return -ENOMEM;
}
cb = hl_cb_kernel_create(hdev, cb_size, !patched_cb);
if (!cb) {
atomic64_inc(&ctx->cs_counters.out_of_mem_drop_cnt);
atomic64_inc(&cntr->out_of_mem_drop_cnt);
kfree(job);
return -EFAULT;
}
job->id = 0;
job->cs = cs;
job->user_cb = cb;
atomic_inc(&job->user_cb->cs_cnt);
job->user_cb_size = cb_size;
job->hw_queue_id = queue_id;
if (cs->encaps_signals)
job->encaps_sig_wait_offset = encaps_signal_offset;
if (patched_cb)
job->patched_cb = job->user_cb;
else
job->patched_cb = NULL;
job->job_cb_size = job->user_cb_size;
hl_cb_destroy(&hdev->kernel_mem_mgr, cb->buf->handle);
if (hw_queue_prop->type == QUEUE_TYPE_EXT)
cs_get(cs);
cs->jobs_in_queue_cnt[job->hw_queue_id]++;
list_add_tail(&job->cs_node, &cs->job_list);
hl_debugfs_add_job(hdev, job);
return 0;
}
static int gaudi_collective_wait_create_jobs(struct hl_device *hdev,
struct hl_ctx *ctx, struct hl_cs *cs,
u32 wait_queue_id, u32 collective_engine_id,
u32 encaps_signal_offset)
{
struct gaudi_device *gaudi = hdev->asic_specific;
struct hw_queue_properties *hw_queue_prop;
u32 queue_id, collective_queue, num_jobs;
u32 stream, nic_queue, nic_idx = 0;
bool skip;
int i, rc = 0;
hw_queue_prop = &hdev->asic_prop.hw_queues_props[wait_queue_id];
if (!(hw_queue_prop->collective_mode == HL_COLLECTIVE_MASTER)) {
dev_err(hdev->dev,
"Queue %d is not configured as collective master\n",
wait_queue_id);
return -EINVAL;
}
if (collective_engine_id != GAUDI_ENGINE_ID_DMA_5 &&
collective_engine_id != GAUDI_ENGINE_ID_TPC_7) {
dev_err(hdev->dev,
"Collective wait does not support engine %u\n",
collective_engine_id);
return -EINVAL;
}
stream = wait_queue_id % 4;
if (collective_engine_id == GAUDI_ENGINE_ID_DMA_5)
collective_queue = GAUDI_QUEUE_ID_DMA_5_0 + stream;
else
collective_queue = GAUDI_QUEUE_ID_TPC_7_0 + stream;
num_jobs = NUMBER_OF_SOBS_IN_GRP + 1;
nic_queue = GAUDI_QUEUE_ID_NIC_0_0 + stream;
for (i = 0 ; i < num_jobs ; i++) {
if (i == 0) {
queue_id = wait_queue_id;
rc = gaudi_collective_wait_create_job(hdev, ctx, cs,
HL_COLLECTIVE_MASTER, queue_id,
wait_queue_id, encaps_signal_offset);
} else {
if (nic_idx < NIC_NUMBER_OF_ENGINES) {
if (gaudi->hw_cap_initialized &
BIT(HW_CAP_NIC_SHIFT + nic_idx))
skip = false;
else
skip = true;
queue_id = nic_queue;
nic_queue += 4;
nic_idx++;
if (skip)
continue;
} else {
queue_id = collective_queue;
}
rc = gaudi_collective_wait_create_job(hdev, ctx, cs,
HL_COLLECTIVE_SLAVE, queue_id,
wait_queue_id, encaps_signal_offset);
}
if (rc)
return rc;
}
return rc;
}
static int gaudi_late_init(struct hl_device *hdev)
{
struct gaudi_device *gaudi = hdev->asic_specific;
int rc;
rc = gaudi->cpucp_info_get(hdev);
if (rc) {
dev_err(hdev->dev, "Failed to get cpucp info\n");
return rc;
}
if ((hdev->card_type == cpucp_card_type_pci) &&
(hdev->nic_ports_mask & 0x3)) {
dev_info(hdev->dev,
"PCI card detected, only 8 ports are enabled\n");
hdev->nic_ports_mask &= ~0x3;
WREG32(mmNIC0_QM0_GLBL_CFG1, NIC0_QM0_GLBL_CFG1_PQF_STOP_MASK |
NIC0_QM0_GLBL_CFG1_CQF_STOP_MASK |
NIC0_QM0_GLBL_CFG1_CP_STOP_MASK);
WREG32(mmNIC0_QM1_GLBL_CFG1, NIC0_QM0_GLBL_CFG1_PQF_STOP_MASK |
NIC0_QM0_GLBL_CFG1_CQF_STOP_MASK |
NIC0_QM0_GLBL_CFG1_CP_STOP_MASK);
WREG32(mmNIC0_QM0_GLBL_CFG0, 0);
WREG32(mmNIC0_QM1_GLBL_CFG0, 0);
gaudi->hw_cap_initialized &= ~(HW_CAP_NIC0 | HW_CAP_NIC1);
}
rc = hl_fw_send_pci_access_msg(hdev, CPUCP_PACKET_ENABLE_PCI_ACCESS, 0x0);
if (rc) {
dev_err(hdev->dev, "Failed to enable PCI access from CPU\n");
return rc;
}
rc = hdev->asic_funcs->scrub_device_mem(hdev);
if (rc)
goto disable_pci_access;
rc = gaudi_fetch_psoc_frequency(hdev);
if (rc) {
dev_err(hdev->dev, "Failed to fetch psoc frequency\n");
goto disable_pci_access;
}
rc = gaudi_mmu_clear_pgt_range(hdev);
if (rc) {
dev_err(hdev->dev, "Failed to clear MMU page tables range\n");
goto disable_pci_access;
}
rc = gaudi_init_tpc_mem(hdev);
if (rc) {
dev_err(hdev->dev, "Failed to initialize TPC memories\n");
goto disable_pci_access;
}
rc = gaudi_collective_init(hdev);
if (rc) {
dev_err(hdev->dev, "Failed to init collective\n");
goto disable_pci_access;
}
gaudi_mmu_prepare(hdev, 1);
hl_fw_set_pll_profile(hdev);
return 0;
disable_pci_access:
hl_fw_send_pci_access_msg(hdev, CPUCP_PACKET_DISABLE_PCI_ACCESS, 0x0);
return rc;
}
static void gaudi_late_fini(struct hl_device *hdev)
{
hl_hwmon_release_resources(hdev);
}
static int gaudi_alloc_cpu_accessible_dma_mem(struct hl_device *hdev)
{
dma_addr_t dma_addr_arr[GAUDI_ALLOC_CPU_MEM_RETRY_CNT] = {}, end_addr;
void *virt_addr_arr[GAUDI_ALLOC_CPU_MEM_RETRY_CNT] = {};
int i, j, rc = 0;
for (i = 0 ; i < GAUDI_ALLOC_CPU_MEM_RETRY_CNT ; i++) {
virt_addr_arr[i] = hl_asic_dma_alloc_coherent(hdev, HL_CPU_ACCESSIBLE_MEM_SIZE,
&dma_addr_arr[i],
GFP_KERNEL | __GFP_ZERO);
if (!virt_addr_arr[i]) {
rc = -ENOMEM;
goto free_dma_mem_arr;
}
end_addr = dma_addr_arr[i] + HL_CPU_ACCESSIBLE_MEM_SIZE - 1;
if (GAUDI_CPU_PCI_MSB_ADDR(dma_addr_arr[i]) ==
GAUDI_CPU_PCI_MSB_ADDR(end_addr))
break;
}
if (i == GAUDI_ALLOC_CPU_MEM_RETRY_CNT) {
dev_err(hdev->dev,
"MSB of CPU accessible DMA memory are not identical in all range\n");
rc = -EFAULT;
goto free_dma_mem_arr;
}
hdev->cpu_accessible_dma_mem = virt_addr_arr[i];
hdev->cpu_accessible_dma_address = dma_addr_arr[i];
hdev->cpu_pci_msb_addr =
GAUDI_CPU_PCI_MSB_ADDR(hdev->cpu_accessible_dma_address);
if (!hdev->asic_prop.fw_security_enabled)
GAUDI_PCI_TO_CPU_ADDR(hdev->cpu_accessible_dma_address);
free_dma_mem_arr:
for (j = 0 ; j < i ; j++)
hl_asic_dma_free_coherent(hdev, HL_CPU_ACCESSIBLE_MEM_SIZE, virt_addr_arr[j],
dma_addr_arr[j]);
return rc;
}
static void gaudi_free_internal_qmans_pq_mem(struct hl_device *hdev)
{
struct gaudi_device *gaudi = hdev->asic_specific;
struct gaudi_internal_qman_info *q;
u32 i;
for (i = 0 ; i < GAUDI_QUEUE_ID_SIZE ; i++) {
q = &gaudi->internal_qmans[i];
if (!q->pq_kernel_addr)
continue;
hl_asic_dma_free_coherent(hdev, q->pq_size, q->pq_kernel_addr, q->pq_dma_addr);
}
}
static int gaudi_alloc_internal_qmans_pq_mem(struct hl_device *hdev)
{
struct gaudi_device *gaudi = hdev->asic_specific;
struct gaudi_internal_qman_info *q;
int rc, i;
for (i = 0 ; i < GAUDI_QUEUE_ID_SIZE ; i++) {
if (gaudi_queue_type[i] != QUEUE_TYPE_INT)
continue;
q = &gaudi->internal_qmans[i];
switch (i) {
case GAUDI_QUEUE_ID_DMA_2_0 ... GAUDI_QUEUE_ID_DMA_7_3:
q->pq_size = HBM_DMA_QMAN_SIZE_IN_BYTES;
break;
case GAUDI_QUEUE_ID_MME_0_0 ... GAUDI_QUEUE_ID_MME_1_3:
q->pq_size = MME_QMAN_SIZE_IN_BYTES;
break;
case GAUDI_QUEUE_ID_TPC_0_0 ... GAUDI_QUEUE_ID_TPC_7_3:
q->pq_size = TPC_QMAN_SIZE_IN_BYTES;
break;
case GAUDI_QUEUE_ID_NIC_0_0 ... GAUDI_QUEUE_ID_NIC_9_3:
q->pq_size = NIC_QMAN_SIZE_IN_BYTES;
break;
default:
dev_err(hdev->dev, "Bad internal queue index %d", i);
rc = -EINVAL;
goto free_internal_qmans_pq_mem;
}
q->pq_kernel_addr = hl_asic_dma_alloc_coherent(hdev, q->pq_size, &q->pq_dma_addr,
GFP_KERNEL | __GFP_ZERO);
if (!q->pq_kernel_addr) {
rc = -ENOMEM;
goto free_internal_qmans_pq_mem;
}
}
return 0;
free_internal_qmans_pq_mem:
gaudi_free_internal_qmans_pq_mem(hdev);
return rc;
}
static void gaudi_set_pci_memory_regions(struct hl_device *hdev)
{
struct asic_fixed_properties *prop = &hdev->asic_prop;
struct pci_mem_region *region;
region = &hdev->pci_mem_region[PCI_REGION_CFG];
region->region_base = CFG_BASE;
region->region_size = CFG_SIZE;
region->offset_in_bar = CFG_BASE - SPI_FLASH_BASE_ADDR;
region->bar_size = CFG_BAR_SIZE;
region->bar_id = CFG_BAR_ID;
region->used = 1;
region = &hdev->pci_mem_region[PCI_REGION_SRAM];
region->region_base = SRAM_BASE_ADDR;
region->region_size = SRAM_SIZE;
region->offset_in_bar = 0;
region->bar_size = SRAM_BAR_SIZE;
region->bar_id = SRAM_BAR_ID;
region->used = 1;
region = &hdev->pci_mem_region[PCI_REGION_DRAM];
region->region_base = DRAM_PHYS_BASE;
region->region_size = hdev->asic_prop.dram_size;
region->offset_in_bar = 0;
region->bar_size = prop->dram_pci_bar_size;
region->bar_id = HBM_BAR_ID;
region->used = 1;
region = &hdev->pci_mem_region[PCI_REGION_SP_SRAM];
region->region_base = PSOC_SCRATCHPAD_ADDR;
region->region_size = PSOC_SCRATCHPAD_SIZE;
region->offset_in_bar = PSOC_SCRATCHPAD_ADDR - SPI_FLASH_BASE_ADDR;
region->bar_size = CFG_BAR_SIZE;
region->bar_id = CFG_BAR_ID;
region->used = 1;
}
static int gaudi_sw_init(struct hl_device *hdev)
{
struct gaudi_device *gaudi;
u32 i, event_id = 0;
int rc;
gaudi = kzalloc(sizeof(*gaudi), GFP_KERNEL);
if (!gaudi)
return -ENOMEM;
for (i = 0 ; i < ARRAY_SIZE(gaudi_irq_map_table) ; i++) {
if (gaudi_irq_map_table[i].valid) {
if (event_id == GAUDI_EVENT_SIZE) {
dev_err(hdev->dev,
"Event array exceeds the limit of %u events\n",
GAUDI_EVENT_SIZE);
rc = -EINVAL;
goto free_gaudi_device;
}
gaudi->events[event_id++] =
gaudi_irq_map_table[i].fc_id;
}
}
gaudi->cpucp_info_get = gaudi_cpucp_info_get;
hdev->asic_specific = gaudi;
hdev->dma_pool = dma_pool_create(dev_name(hdev->dev),
&hdev->pdev->dev, GAUDI_DMA_POOL_BLK_SIZE, 8, 0);
if (!hdev->dma_pool) {
dev_err(hdev->dev, "failed to create DMA pool\n");
rc = -ENOMEM;
goto free_gaudi_device;
}
rc = gaudi_alloc_cpu_accessible_dma_mem(hdev);
if (rc)
goto free_dma_pool;
hdev->cpu_accessible_dma_pool = gen_pool_create(ilog2(32), -1);
if (!hdev->cpu_accessible_dma_pool) {
dev_err(hdev->dev,
"Failed to create CPU accessible DMA pool\n");
rc = -ENOMEM;
goto free_cpu_dma_mem;
}
rc = gen_pool_add(hdev->cpu_accessible_dma_pool,
(uintptr_t) hdev->cpu_accessible_dma_mem,
HL_CPU_ACCESSIBLE_MEM_SIZE, -1);
if (rc) {
dev_err(hdev->dev,
"Failed to add memory to CPU accessible DMA pool\n");
rc = -EFAULT;
goto free_cpu_accessible_dma_pool;
}
rc = gaudi_alloc_internal_qmans_pq_mem(hdev);
if (rc)
goto free_cpu_accessible_dma_pool;
spin_lock_init(&gaudi->hw_queues_lock);
hdev->supports_sync_stream = true;
hdev->supports_coresight = true;
hdev->supports_staged_submission = true;
hdev->supports_wait_for_multi_cs = true;
hdev->asic_funcs->set_pci_memory_regions(hdev);
hdev->stream_master_qid_arr =
hdev->asic_funcs->get_stream_master_qid_arr();
hdev->stream_master_qid_arr_size = GAUDI_STREAM_MASTER_ARR_SIZE;
return 0;
free_cpu_accessible_dma_pool:
gen_pool_destroy(hdev->cpu_accessible_dma_pool);
free_cpu_dma_mem:
if (!hdev->asic_prop.fw_security_enabled)
GAUDI_CPU_TO_PCI_ADDR(hdev->cpu_accessible_dma_address,
hdev->cpu_pci_msb_addr);
hl_asic_dma_free_coherent(hdev, HL_CPU_ACCESSIBLE_MEM_SIZE, hdev->cpu_accessible_dma_mem,
hdev->cpu_accessible_dma_address);
free_dma_pool:
dma_pool_destroy(hdev->dma_pool);
free_gaudi_device:
kfree(gaudi);
return rc;
}
static int gaudi_sw_fini(struct hl_device *hdev)
{
struct gaudi_device *gaudi = hdev->asic_specific;
gaudi_free_internal_qmans_pq_mem(hdev);
gen_pool_destroy(hdev->cpu_accessible_dma_pool);
if (!hdev->asic_prop.fw_security_enabled)
GAUDI_CPU_TO_PCI_ADDR(hdev->cpu_accessible_dma_address,
hdev->cpu_pci_msb_addr);
hl_asic_dma_free_coherent(hdev, HL_CPU_ACCESSIBLE_MEM_SIZE, hdev->cpu_accessible_dma_mem,
hdev->cpu_accessible_dma_address);
dma_pool_destroy(hdev->dma_pool);
kfree(gaudi);
return 0;
}
static irqreturn_t gaudi_irq_handler_single(int irq, void *arg)
{
struct hl_device *hdev = arg;
int i;
if (hdev->disabled)
return IRQ_HANDLED;
for (i = 0 ; i < hdev->asic_prop.completion_queues_count ; i++)
hl_irq_handler_cq(irq, &hdev->completion_queue[i]);
hl_irq_handler_eq(irq, &hdev->event_queue);
return IRQ_HANDLED;
}
static int gaudi_pci_irq_vector(struct hl_device *hdev, unsigned int nr,
bool cpu_eq)
{
int msi_vec;
if ((nr != GAUDI_EVENT_QUEUE_MSI_IDX) && (cpu_eq))
dev_crit(hdev->dev, "CPU EQ must use IRQ %d\n",
GAUDI_EVENT_QUEUE_MSI_IDX);
msi_vec = ((nr < GAUDI_EVENT_QUEUE_MSI_IDX) || (cpu_eq)) ? nr :
(nr + NIC_NUMBER_OF_ENGINES + 1);
return pci_irq_vector(hdev->pdev, msi_vec);
}
static int gaudi_enable_msi_single(struct hl_device *hdev)
{
int rc, irq;
dev_dbg(hdev->dev, "Working in single MSI IRQ mode\n");
irq = gaudi_pci_irq_vector(hdev, 0, false);
rc = request_irq(irq, gaudi_irq_handler_single, 0,
"gaudi single msi", hdev);
if (rc)
dev_err(hdev->dev,
"Failed to request single MSI IRQ\n");
return rc;
}
static int gaudi_enable_msi(struct hl_device *hdev)
{
struct gaudi_device *gaudi = hdev->asic_specific;
int rc;
if (gaudi->hw_cap_initialized & HW_CAP_MSI)
return 0;
rc = pci_alloc_irq_vectors(hdev->pdev, 1, 1, PCI_IRQ_MSI);
if (rc < 0) {
dev_err(hdev->dev, "MSI: Failed to enable support %d\n", rc);
return rc;
}
rc = gaudi_enable_msi_single(hdev);
if (rc)
goto free_pci_irq_vectors;
gaudi->hw_cap_initialized |= HW_CAP_MSI;
return 0;
free_pci_irq_vectors:
pci_free_irq_vectors(hdev->pdev);
return rc;
}
static void gaudi_sync_irqs(struct hl_device *hdev)
{
struct gaudi_device *gaudi = hdev->asic_specific;
if (!(gaudi->hw_cap_initialized & HW_CAP_MSI))
return;
synchronize_irq(gaudi_pci_irq_vector(hdev, 0, false));
}
static void gaudi_disable_msi(struct hl_device *hdev)
{
struct gaudi_device *gaudi = hdev->asic_specific;
if (!(gaudi->hw_cap_initialized & HW_CAP_MSI))
return;
gaudi_sync_irqs(hdev);
free_irq(gaudi_pci_irq_vector(hdev, 0, false), hdev);
pci_free_irq_vectors(hdev->pdev);
gaudi->hw_cap_initialized &= ~HW_CAP_MSI;
}
static void gaudi_init_scrambler_sram(struct hl_device *hdev)
{
struct gaudi_device *gaudi = hdev->asic_specific;
if (hdev->asic_prop.fw_security_enabled)
return;
if (hdev->asic_prop.fw_app_cpu_boot_dev_sts0 &
CPU_BOOT_DEV_STS0_SRAM_SCR_EN)
return;
if (gaudi->hw_cap_initialized & HW_CAP_SRAM_SCRAMBLER)
return;
WREG32(mmNIF_RTR_CTRL_0_SCRAM_SRAM_EN,
1 << IF_RTR_CTRL_SCRAM_SRAM_EN_VAL_SHIFT);
WREG32(mmNIF_RTR_CTRL_1_SCRAM_SRAM_EN,
1 << IF_RTR_CTRL_SCRAM_SRAM_EN_VAL_SHIFT);
WREG32(mmNIF_RTR_CTRL_2_SCRAM_SRAM_EN,
1 << IF_RTR_CTRL_SCRAM_SRAM_EN_VAL_SHIFT);
WREG32(mmNIF_RTR_CTRL_3_SCRAM_SRAM_EN,
1 << IF_RTR_CTRL_SCRAM_SRAM_EN_VAL_SHIFT);
WREG32(mmNIF_RTR_CTRL_4_SCRAM_SRAM_EN,
1 << IF_RTR_CTRL_SCRAM_SRAM_EN_VAL_SHIFT);
WREG32(mmNIF_RTR_CTRL_5_SCRAM_SRAM_EN,
1 << IF_RTR_CTRL_SCRAM_SRAM_EN_VAL_SHIFT);
WREG32(mmNIF_RTR_CTRL_6_SCRAM_SRAM_EN,
1 << IF_RTR_CTRL_SCRAM_SRAM_EN_VAL_SHIFT);
WREG32(mmNIF_RTR_CTRL_7_SCRAM_SRAM_EN,
1 << IF_RTR_CTRL_SCRAM_SRAM_EN_VAL_SHIFT);
WREG32(mmSIF_RTR_CTRL_0_SCRAM_SRAM_EN,
1 << IF_RTR_CTRL_SCRAM_SRAM_EN_VAL_SHIFT);
WREG32(mmSIF_RTR_CTRL_1_SCRAM_SRAM_EN,
1 << IF_RTR_CTRL_SCRAM_SRAM_EN_VAL_SHIFT);
WREG32(mmSIF_RTR_CTRL_2_SCRAM_SRAM_EN,
1 << IF_RTR_CTRL_SCRAM_SRAM_EN_VAL_SHIFT);
WREG32(mmSIF_RTR_CTRL_3_SCRAM_SRAM_EN,
1 << IF_RTR_CTRL_SCRAM_SRAM_EN_VAL_SHIFT);
WREG32(mmSIF_RTR_CTRL_4_SCRAM_SRAM_EN,
1 << IF_RTR_CTRL_SCRAM_SRAM_EN_VAL_SHIFT);
WREG32(mmSIF_RTR_CTRL_5_SCRAM_SRAM_EN,
1 << IF_RTR_CTRL_SCRAM_SRAM_EN_VAL_SHIFT);
WREG32(mmSIF_RTR_CTRL_6_SCRAM_SRAM_EN,
1 << IF_RTR_CTRL_SCRAM_SRAM_EN_VAL_SHIFT);
WREG32(mmSIF_RTR_CTRL_7_SCRAM_SRAM_EN,
1 << IF_RTR_CTRL_SCRAM_SRAM_EN_VAL_SHIFT);
WREG32(mmDMA_IF_E_N_DOWN_CH0_SCRAM_SRAM_EN,
1 << DMA_IF_DOWN_CHX_SCRAM_SRAM_EN_VAL_SHIFT);
WREG32(mmDMA_IF_E_N_DOWN_CH1_SCRAM_SRAM_EN,
1 << DMA_IF_DOWN_CHX_SCRAM_SRAM_EN_VAL_SHIFT);
WREG32(mmDMA_IF_E_S_DOWN_CH0_SCRAM_SRAM_EN,
1 << DMA_IF_DOWN_CHX_SCRAM_SRAM_EN_VAL_SHIFT);
WREG32(mmDMA_IF_E_S_DOWN_CH1_SCRAM_SRAM_EN,
1 << DMA_IF_DOWN_CHX_SCRAM_SRAM_EN_VAL_SHIFT);
WREG32(mmDMA_IF_W_N_DOWN_CH0_SCRAM_SRAM_EN,
1 << DMA_IF_DOWN_CHX_SCRAM_SRAM_EN_VAL_SHIFT);
WREG32(mmDMA_IF_W_N_DOWN_CH1_SCRAM_SRAM_EN,
1 << DMA_IF_DOWN_CHX_SCRAM_SRAM_EN_VAL_SHIFT);
WREG32(mmDMA_IF_W_S_DOWN_CH0_SCRAM_SRAM_EN,
1 << DMA_IF_DOWN_CHX_SCRAM_SRAM_EN_VAL_SHIFT);
WREG32(mmDMA_IF_W_S_DOWN_CH1_SCRAM_SRAM_EN,
1 << DMA_IF_DOWN_CHX_SCRAM_SRAM_EN_VAL_SHIFT);
gaudi->hw_cap_initialized |= HW_CAP_SRAM_SCRAMBLER;
}
static void gaudi_init_scrambler_hbm(struct hl_device *hdev)
{
struct gaudi_device *gaudi = hdev->asic_specific;
if (hdev->asic_prop.fw_security_enabled)
return;
if (hdev->asic_prop.fw_bootfit_cpu_boot_dev_sts0 &
CPU_BOOT_DEV_STS0_DRAM_SCR_EN)
return;
if (gaudi->hw_cap_initialized & HW_CAP_HBM_SCRAMBLER)
return;
WREG32(mmNIF_RTR_CTRL_0_SCRAM_HBM_EN,
1 << IF_RTR_CTRL_SCRAM_HBM_EN_VAL_SHIFT);
WREG32(mmNIF_RTR_CTRL_1_SCRAM_HBM_EN,
1 << IF_RTR_CTRL_SCRAM_HBM_EN_VAL_SHIFT);
WREG32(mmNIF_RTR_CTRL_2_SCRAM_HBM_EN,
1 << IF_RTR_CTRL_SCRAM_HBM_EN_VAL_SHIFT);
WREG32(mmNIF_RTR_CTRL_3_SCRAM_HBM_EN,
1 << IF_RTR_CTRL_SCRAM_HBM_EN_VAL_SHIFT);
WREG32(mmNIF_RTR_CTRL_4_SCRAM_HBM_EN,
1 << IF_RTR_CTRL_SCRAM_HBM_EN_VAL_SHIFT);
WREG32(mmNIF_RTR_CTRL_5_SCRAM_HBM_EN,
1 << IF_RTR_CTRL_SCRAM_HBM_EN_VAL_SHIFT);
WREG32(mmNIF_RTR_CTRL_6_SCRAM_HBM_EN,
1 << IF_RTR_CTRL_SCRAM_HBM_EN_VAL_SHIFT);
WREG32(mmNIF_RTR_CTRL_7_SCRAM_HBM_EN,
1 << IF_RTR_CTRL_SCRAM_HBM_EN_VAL_SHIFT);
WREG32(mmSIF_RTR_CTRL_0_SCRAM_HBM_EN,
1 << IF_RTR_CTRL_SCRAM_HBM_EN_VAL_SHIFT);
WREG32(mmSIF_RTR_CTRL_1_SCRAM_HBM_EN,
1 << IF_RTR_CTRL_SCRAM_HBM_EN_VAL_SHIFT);
WREG32(mmSIF_RTR_CTRL_2_SCRAM_HBM_EN,
1 << IF_RTR_CTRL_SCRAM_HBM_EN_VAL_SHIFT);
WREG32(mmSIF_RTR_CTRL_3_SCRAM_HBM_EN,
1 << IF_RTR_CTRL_SCRAM_HBM_EN_VAL_SHIFT);
WREG32(mmSIF_RTR_CTRL_4_SCRAM_HBM_EN,
1 << IF_RTR_CTRL_SCRAM_HBM_EN_VAL_SHIFT);
WREG32(mmSIF_RTR_CTRL_5_SCRAM_HBM_EN,
1 << IF_RTR_CTRL_SCRAM_HBM_EN_VAL_SHIFT);
WREG32(mmSIF_RTR_CTRL_6_SCRAM_HBM_EN,
1 << IF_RTR_CTRL_SCRAM_HBM_EN_VAL_SHIFT);
WREG32(mmSIF_RTR_CTRL_7_SCRAM_HBM_EN,
1 << IF_RTR_CTRL_SCRAM_HBM_EN_VAL_SHIFT);
WREG32(mmDMA_IF_E_N_DOWN_CH0_SCRAM_HBM_EN,
1 << DMA_IF_DOWN_CHX_SCRAM_HBM_EN_VAL_SHIFT);
WREG32(mmDMA_IF_E_N_DOWN_CH1_SCRAM_HBM_EN,
1 << DMA_IF_DOWN_CHX_SCRAM_HBM_EN_VAL_SHIFT);
WREG32(mmDMA_IF_E_S_DOWN_CH0_SCRAM_HBM_EN,
1 << DMA_IF_DOWN_CHX_SCRAM_HBM_EN_VAL_SHIFT);
WREG32(mmDMA_IF_E_S_DOWN_CH1_SCRAM_HBM_EN,
1 << DMA_IF_DOWN_CHX_SCRAM_HBM_EN_VAL_SHIFT);
WREG32(mmDMA_IF_W_N_DOWN_CH0_SCRAM_HBM_EN,
1 << DMA_IF_DOWN_CHX_SCRAM_HBM_EN_VAL_SHIFT);
WREG32(mmDMA_IF_W_N_DOWN_CH1_SCRAM_HBM_EN,
1 << DMA_IF_DOWN_CHX_SCRAM_HBM_EN_VAL_SHIFT);
WREG32(mmDMA_IF_W_S_DOWN_CH0_SCRAM_HBM_EN,
1 << DMA_IF_DOWN_CHX_SCRAM_HBM_EN_VAL_SHIFT);
WREG32(mmDMA_IF_W_S_DOWN_CH1_SCRAM_HBM_EN,
1 << DMA_IF_DOWN_CHX_SCRAM_HBM_EN_VAL_SHIFT);
gaudi->hw_cap_initialized |= HW_CAP_HBM_SCRAMBLER;
}
static void gaudi_init_e2e(struct hl_device *hdev)
{
if (hdev->asic_prop.fw_security_enabled)
return;
if (hdev->asic_prop.fw_bootfit_cpu_boot_dev_sts0 &
CPU_BOOT_DEV_STS0_E2E_CRED_EN)
return;
WREG32(mmSIF_RTR_CTRL_0_E2E_HBM_WR_SIZE, 247 >> 3);
WREG32(mmSIF_RTR_CTRL_0_E2E_HBM_RD_SIZE, 785 >> 3);
WREG32(mmSIF_RTR_CTRL_0_E2E_PCI_WR_SIZE, 49);
WREG32(mmSIF_RTR_CTRL_0_E2E_PCI_RD_SIZE, 101);
WREG32(mmSIF_RTR_CTRL_1_E2E_HBM_WR_SIZE, 275 >> 3);
WREG32(mmSIF_RTR_CTRL_1_E2E_HBM_RD_SIZE, 614 >> 3);
WREG32(mmSIF_RTR_CTRL_1_E2E_PCI_WR_SIZE, 1);
WREG32(mmSIF_RTR_CTRL_1_E2E_PCI_RD_SIZE, 39);
WREG32(mmSIF_RTR_CTRL_2_E2E_HBM_WR_SIZE, 1);
WREG32(mmSIF_RTR_CTRL_2_E2E_HBM_RD_SIZE, 1);
WREG32(mmSIF_RTR_CTRL_2_E2E_PCI_WR_SIZE, 1);
WREG32(mmSIF_RTR_CTRL_2_E2E_PCI_RD_SIZE, 32);
WREG32(mmSIF_RTR_CTRL_3_E2E_HBM_WR_SIZE, 176 >> 3);
WREG32(mmSIF_RTR_CTRL_3_E2E_HBM_RD_SIZE, 32 >> 3);
WREG32(mmSIF_RTR_CTRL_3_E2E_PCI_WR_SIZE, 19);
WREG32(mmSIF_RTR_CTRL_3_E2E_PCI_RD_SIZE, 32);
WREG32(mmSIF_RTR_CTRL_4_E2E_HBM_WR_SIZE, 176 >> 3);
WREG32(mmSIF_RTR_CTRL_4_E2E_HBM_RD_SIZE, 32 >> 3);
WREG32(mmSIF_RTR_CTRL_4_E2E_PCI_WR_SIZE, 19);
WREG32(mmSIF_RTR_CTRL_4_E2E_PCI_RD_SIZE, 32);
WREG32(mmSIF_RTR_CTRL_5_E2E_HBM_WR_SIZE, 1);
WREG32(mmSIF_RTR_CTRL_5_E2E_HBM_RD_SIZE, 1);
WREG32(mmSIF_RTR_CTRL_5_E2E_PCI_WR_SIZE, 1);
WREG32(mmSIF_RTR_CTRL_5_E2E_PCI_RD_SIZE, 32);
WREG32(mmSIF_RTR_CTRL_6_E2E_HBM_WR_SIZE, 275 >> 3);
WREG32(mmSIF_RTR_CTRL_6_E2E_HBM_RD_SIZE, 614 >> 3);
WREG32(mmSIF_RTR_CTRL_6_E2E_PCI_WR_SIZE, 1);
WREG32(mmSIF_RTR_CTRL_6_E2E_PCI_RD_SIZE, 39);
WREG32(mmSIF_RTR_CTRL_7_E2E_HBM_WR_SIZE, 297 >> 3);
WREG32(mmSIF_RTR_CTRL_7_E2E_HBM_RD_SIZE, 908 >> 3);
WREG32(mmSIF_RTR_CTRL_7_E2E_PCI_WR_SIZE, 19);
WREG32(mmSIF_RTR_CTRL_7_E2E_PCI_RD_SIZE, 19);
WREG32(mmNIF_RTR_CTRL_0_E2E_HBM_WR_SIZE, 318 >> 3);
WREG32(mmNIF_RTR_CTRL_0_E2E_HBM_RD_SIZE, 956 >> 3);
WREG32(mmNIF_RTR_CTRL_0_E2E_PCI_WR_SIZE, 79);
WREG32(mmNIF_RTR_CTRL_0_E2E_PCI_RD_SIZE, 163);
WREG32(mmNIF_RTR_CTRL_1_E2E_HBM_WR_SIZE, 275 >> 3);
WREG32(mmNIF_RTR_CTRL_1_E2E_HBM_RD_SIZE, 614 >> 3);
WREG32(mmNIF_RTR_CTRL_1_E2E_PCI_WR_SIZE, 1);
WREG32(mmNIF_RTR_CTRL_1_E2E_PCI_RD_SIZE, 39);
WREG32(mmNIF_RTR_CTRL_2_E2E_HBM_WR_SIZE, 1);
WREG32(mmNIF_RTR_CTRL_2_E2E_HBM_RD_SIZE, 1);
WREG32(mmNIF_RTR_CTRL_2_E2E_PCI_WR_SIZE, 1);
WREG32(mmNIF_RTR_CTRL_2_E2E_PCI_RD_SIZE, 32);
WREG32(mmNIF_RTR_CTRL_3_E2E_HBM_WR_SIZE, 176 >> 3);
WREG32(mmNIF_RTR_CTRL_3_E2E_HBM_RD_SIZE, 32 >> 3);
WREG32(mmNIF_RTR_CTRL_3_E2E_PCI_WR_SIZE, 19);
WREG32(mmNIF_RTR_CTRL_3_E2E_PCI_RD_SIZE, 32);
WREG32(mmNIF_RTR_CTRL_4_E2E_HBM_WR_SIZE, 176 >> 3);
WREG32(mmNIF_RTR_CTRL_4_E2E_HBM_RD_SIZE, 32 >> 3);
WREG32(mmNIF_RTR_CTRL_4_E2E_PCI_WR_SIZE, 19);
WREG32(mmNIF_RTR_CTRL_4_E2E_PCI_RD_SIZE, 32);
WREG32(mmNIF_RTR_CTRL_5_E2E_HBM_WR_SIZE, 1);
WREG32(mmNIF_RTR_CTRL_5_E2E_HBM_RD_SIZE, 1);
WREG32(mmNIF_RTR_CTRL_5_E2E_PCI_WR_SIZE, 1);
WREG32(mmNIF_RTR_CTRL_5_E2E_PCI_RD_SIZE, 32);
WREG32(mmNIF_RTR_CTRL_6_E2E_HBM_WR_SIZE, 275 >> 3);
WREG32(mmNIF_RTR_CTRL_6_E2E_HBM_RD_SIZE, 614 >> 3);
WREG32(mmNIF_RTR_CTRL_6_E2E_PCI_WR_SIZE, 1);
WREG32(mmNIF_RTR_CTRL_6_E2E_PCI_RD_SIZE, 39);
WREG32(mmNIF_RTR_CTRL_7_E2E_HBM_WR_SIZE, 318 >> 3);
WREG32(mmNIF_RTR_CTRL_7_E2E_HBM_RD_SIZE, 956 >> 3);
WREG32(mmNIF_RTR_CTRL_7_E2E_PCI_WR_SIZE, 79);
WREG32(mmNIF_RTR_CTRL_7_E2E_PCI_RD_SIZE, 79);
WREG32(mmDMA_IF_E_N_DOWN_CH0_E2E_HBM_WR_SIZE, 344 >> 3);
WREG32(mmDMA_IF_E_N_DOWN_CH0_E2E_HBM_RD_SIZE, 1000 >> 3);
WREG32(mmDMA_IF_E_N_DOWN_CH0_E2E_PCI_WR_SIZE, 162);
WREG32(mmDMA_IF_E_N_DOWN_CH0_E2E_PCI_RD_SIZE, 338);
WREG32(mmDMA_IF_E_N_DOWN_CH1_E2E_HBM_WR_SIZE, 344 >> 3);
WREG32(mmDMA_IF_E_N_DOWN_CH1_E2E_HBM_RD_SIZE, 1000 >> 3);
WREG32(mmDMA_IF_E_N_DOWN_CH1_E2E_PCI_WR_SIZE, 162);
WREG32(mmDMA_IF_E_N_DOWN_CH1_E2E_PCI_RD_SIZE, 338);
WREG32(mmDMA_IF_E_S_DOWN_CH0_E2E_HBM_WR_SIZE, 344 >> 3);
WREG32(mmDMA_IF_E_S_DOWN_CH0_E2E_HBM_RD_SIZE, 1000 >> 3);
WREG32(mmDMA_IF_E_S_DOWN_CH0_E2E_PCI_WR_SIZE, 162);
WREG32(mmDMA_IF_E_S_DOWN_CH0_E2E_PCI_RD_SIZE, 338);
WREG32(mmDMA_IF_E_S_DOWN_CH1_E2E_HBM_WR_SIZE, 344 >> 3);
WREG32(mmDMA_IF_E_S_DOWN_CH1_E2E_HBM_RD_SIZE, 1000 >> 3);
WREG32(mmDMA_IF_E_S_DOWN_CH1_E2E_PCI_WR_SIZE, 162);
WREG32(mmDMA_IF_E_S_DOWN_CH1_E2E_PCI_RD_SIZE, 338);
WREG32(mmDMA_IF_W_N_DOWN_CH0_E2E_HBM_WR_SIZE, 344 >> 3);
WREG32(mmDMA_IF_W_N_DOWN_CH0_E2E_HBM_RD_SIZE, 1000 >> 3);
WREG32(mmDMA_IF_W_N_DOWN_CH0_E2E_PCI_WR_SIZE, 162);
WREG32(mmDMA_IF_W_N_DOWN_CH0_E2E_PCI_RD_SIZE, 338);
WREG32(mmDMA_IF_W_N_DOWN_CH1_E2E_HBM_WR_SIZE, 344 >> 3);
WREG32(mmDMA_IF_W_N_DOWN_CH1_E2E_HBM_RD_SIZE, 1000 >> 3);
WREG32(mmDMA_IF_W_N_DOWN_CH1_E2E_PCI_WR_SIZE, 162);
WREG32(mmDMA_IF_W_N_DOWN_CH1_E2E_PCI_RD_SIZE, 338);
WREG32(mmDMA_IF_W_S_DOWN_CH0_E2E_HBM_WR_SIZE, 344 >> 3);
WREG32(mmDMA_IF_W_S_DOWN_CH0_E2E_HBM_RD_SIZE, 1000 >> 3);
WREG32(mmDMA_IF_W_S_DOWN_CH0_E2E_PCI_WR_SIZE, 162);
WREG32(mmDMA_IF_W_S_DOWN_CH0_E2E_PCI_RD_SIZE, 338);
WREG32(mmDMA_IF_W_S_DOWN_CH1_E2E_HBM_WR_SIZE, 344 >> 3);
WREG32(mmDMA_IF_W_S_DOWN_CH1_E2E_HBM_RD_SIZE, 1000 >> 3);
WREG32(mmDMA_IF_W_S_DOWN_CH1_E2E_PCI_WR_SIZE, 162);
WREG32(mmDMA_IF_W_S_DOWN_CH1_E2E_PCI_RD_SIZE, 338);
WREG32(mmSIF_RTR_CTRL_0_E2E_HBM_EN,
1 << IF_RTR_CTRL_E2E_HBM_EN_VAL_SHIFT);
WREG32(mmSIF_RTR_CTRL_0_E2E_PCI_EN,
1 << IF_RTR_CTRL_E2E_PCI_EN_VAL_SHIFT);
WREG32(mmSIF_RTR_CTRL_1_E2E_HBM_EN,
1 << IF_RTR_CTRL_E2E_HBM_EN_VAL_SHIFT);
WREG32(mmSIF_RTR_CTRL_1_E2E_PCI_EN,
1 << IF_RTR_CTRL_E2E_PCI_EN_VAL_SHIFT);
WREG32(mmSIF_RTR_CTRL_2_E2E_HBM_EN,
1 << IF_RTR_CTRL_E2E_HBM_EN_VAL_SHIFT);
WREG32(mmSIF_RTR_CTRL_2_E2E_PCI_EN,
1 << IF_RTR_CTRL_E2E_PCI_EN_VAL_SHIFT);
WREG32(mmSIF_RTR_CTRL_3_E2E_HBM_EN,
1 << IF_RTR_CTRL_E2E_HBM_EN_VAL_SHIFT);
WREG32(mmSIF_RTR_CTRL_3_E2E_PCI_EN,
1 << IF_RTR_CTRL_E2E_PCI_EN_VAL_SHIFT);
WREG32(mmSIF_RTR_CTRL_4_E2E_HBM_EN,
1 << IF_RTR_CTRL_E2E_HBM_EN_VAL_SHIFT);
WREG32(mmSIF_RTR_CTRL_4_E2E_PCI_EN,
1 << IF_RTR_CTRL_E2E_PCI_EN_VAL_SHIFT);
WREG32(mmSIF_RTR_CTRL_5_E2E_HBM_EN,
1 << IF_RTR_CTRL_E2E_HBM_EN_VAL_SHIFT);
WREG32(mmSIF_RTR_CTRL_5_E2E_PCI_EN,
1 << IF_RTR_CTRL_E2E_PCI_EN_VAL_SHIFT);
WREG32(mmSIF_RTR_CTRL_6_E2E_HBM_EN,
1 << IF_RTR_CTRL_E2E_HBM_EN_VAL_SHIFT);
WREG32(mmSIF_RTR_CTRL_6_E2E_PCI_EN,
1 << IF_RTR_CTRL_E2E_PCI_EN_VAL_SHIFT);
WREG32(mmSIF_RTR_CTRL_7_E2E_HBM_EN,
1 << IF_RTR_CTRL_E2E_HBM_EN_VAL_SHIFT);
WREG32(mmSIF_RTR_CTRL_7_E2E_PCI_EN,
1 << IF_RTR_CTRL_E2E_PCI_EN_VAL_SHIFT);
WREG32(mmNIF_RTR_CTRL_0_E2E_HBM_EN,
1 << IF_RTR_CTRL_E2E_HBM_EN_VAL_SHIFT);
WREG32(mmNIF_RTR_CTRL_0_E2E_PCI_EN,
1 << IF_RTR_CTRL_E2E_PCI_EN_VAL_SHIFT);
WREG32(mmNIF_RTR_CTRL_1_E2E_HBM_EN,
1 << IF_RTR_CTRL_E2E_HBM_EN_VAL_SHIFT);
WREG32(mmNIF_RTR_CTRL_1_E2E_PCI_EN,
1 << IF_RTR_CTRL_E2E_PCI_EN_VAL_SHIFT);
WREG32(mmNIF_RTR_CTRL_2_E2E_HBM_EN,
1 << IF_RTR_CTRL_E2E_HBM_EN_VAL_SHIFT);
WREG32(mmNIF_RTR_CTRL_2_E2E_PCI_EN,
1 << IF_RTR_CTRL_E2E_PCI_EN_VAL_SHIFT);
WREG32(mmNIF_RTR_CTRL_3_E2E_HBM_EN,
1 << IF_RTR_CTRL_E2E_HBM_EN_VAL_SHIFT);
WREG32(mmNIF_RTR_CTRL_3_E2E_PCI_EN,
1 << IF_RTR_CTRL_E2E_PCI_EN_VAL_SHIFT);
WREG32(mmNIF_RTR_CTRL_4_E2E_HBM_EN,
1 << IF_RTR_CTRL_E2E_HBM_EN_VAL_SHIFT);
WREG32(mmNIF_RTR_CTRL_4_E2E_PCI_EN,
1 << IF_RTR_CTRL_E2E_PCI_EN_VAL_SHIFT);
WREG32(mmNIF_RTR_CTRL_5_E2E_HBM_EN,
1 << IF_RTR_CTRL_E2E_HBM_EN_VAL_SHIFT);
WREG32(mmNIF_RTR_CTRL_5_E2E_PCI_EN,
1 << IF_RTR_CTRL_E2E_PCI_EN_VAL_SHIFT);
WREG32(mmNIF_RTR_CTRL_6_E2E_HBM_EN,
1 << IF_RTR_CTRL_E2E_HBM_EN_VAL_SHIFT);
WREG32(mmNIF_RTR_CTRL_6_E2E_PCI_EN,
1 << IF_RTR_CTRL_E2E_PCI_EN_VAL_SHIFT);
WREG32(mmNIF_RTR_CTRL_7_E2E_HBM_EN,
1 << IF_RTR_CTRL_E2E_HBM_EN_VAL_SHIFT);
WREG32(mmNIF_RTR_CTRL_7_E2E_PCI_EN,
1 << IF_RTR_CTRL_E2E_PCI_EN_VAL_SHIFT);
WREG32(mmDMA_IF_E_N_DOWN_CH0_E2E_HBM_EN,
1 << DMA_IF_DOWN_CHX_E2E_HBM_EN_VAL_SHIFT);
WREG32(mmDMA_IF_E_N_DOWN_CH0_E2E_PCI_EN,
1 << DMA_IF_DOWN_CHX_E2E_PCI_EN_VAL_SHIFT);
WREG32(mmDMA_IF_E_N_DOWN_CH1_E2E_HBM_EN,
1 << DMA_IF_DOWN_CHX_E2E_HBM_EN_VAL_SHIFT);
WREG32(mmDMA_IF_E_N_DOWN_CH1_E2E_PCI_EN,
1 << DMA_IF_DOWN_CHX_E2E_PCI_EN_VAL_SHIFT);
WREG32(mmDMA_IF_E_S_DOWN_CH0_E2E_HBM_EN,
1 << DMA_IF_DOWN_CHX_E2E_HBM_EN_VAL_SHIFT);
WREG32(mmDMA_IF_E_S_DOWN_CH0_E2E_PCI_EN,
1 << DMA_IF_DOWN_CHX_E2E_PCI_EN_VAL_SHIFT);
WREG32(mmDMA_IF_E_S_DOWN_CH1_E2E_HBM_EN,
1 << DMA_IF_DOWN_CHX_E2E_HBM_EN_VAL_SHIFT);
WREG32(mmDMA_IF_E_S_DOWN_CH1_E2E_PCI_EN,
1 << DMA_IF_DOWN_CHX_E2E_PCI_EN_VAL_SHIFT);
WREG32(mmDMA_IF_W_N_DOWN_CH0_E2E_HBM_EN,
1 << DMA_IF_DOWN_CHX_E2E_HBM_EN_VAL_SHIFT);
WREG32(mmDMA_IF_W_N_DOWN_CH0_E2E_PCI_EN,
1 << DMA_IF_DOWN_CHX_E2E_PCI_EN_VAL_SHIFT);
WREG32(mmDMA_IF_W_N_DOWN_CH1_E2E_HBM_EN,
1 << DMA_IF_DOWN_CHX_E2E_HBM_EN_VAL_SHIFT);
WREG32(mmDMA_IF_W_N_DOWN_CH1_E2E_PCI_EN,
1 << DMA_IF_DOWN_CHX_E2E_PCI_EN_VAL_SHIFT);
WREG32(mmDMA_IF_W_S_DOWN_CH0_E2E_HBM_EN,
1 << DMA_IF_DOWN_CHX_E2E_HBM_EN_VAL_SHIFT);
WREG32(mmDMA_IF_W_S_DOWN_CH0_E2E_PCI_EN,
1 << DMA_IF_DOWN_CHX_E2E_PCI_EN_VAL_SHIFT);
WREG32(mmDMA_IF_W_S_DOWN_CH1_E2E_HBM_EN,
1 << DMA_IF_DOWN_CHX_E2E_HBM_EN_VAL_SHIFT);
WREG32(mmDMA_IF_W_S_DOWN_CH1_E2E_PCI_EN,
1 << DMA_IF_DOWN_CHX_E2E_PCI_EN_VAL_SHIFT);
}
static void gaudi_init_hbm_cred(struct hl_device *hdev)
{
u32 hbm0_wr, hbm1_wr, hbm0_rd, hbm1_rd;
if (hdev->asic_prop.fw_security_enabled)
return;
if (hdev->asic_prop.fw_bootfit_cpu_boot_dev_sts0 &
CPU_BOOT_DEV_STS0_HBM_CRED_EN)
return;
hbm0_wr = 0x33333333;
hbm0_rd = 0x77777777;
hbm1_wr = 0x55555555;
hbm1_rd = 0xDDDDDDDD;
WREG32(mmDMA_IF_E_N_HBM0_WR_CRED_CNT, hbm0_wr);
WREG32(mmDMA_IF_E_N_HBM1_WR_CRED_CNT, hbm1_wr);
WREG32(mmDMA_IF_E_N_HBM0_RD_CRED_CNT, hbm0_rd);
WREG32(mmDMA_IF_E_N_HBM1_RD_CRED_CNT, hbm1_rd);
WREG32(mmDMA_IF_E_S_HBM0_WR_CRED_CNT, hbm0_wr);
WREG32(mmDMA_IF_E_S_HBM1_WR_CRED_CNT, hbm1_wr);
WREG32(mmDMA_IF_E_S_HBM0_RD_CRED_CNT, hbm0_rd);
WREG32(mmDMA_IF_E_S_HBM1_RD_CRED_CNT, hbm1_rd);
WREG32(mmDMA_IF_W_N_HBM0_WR_CRED_CNT, hbm0_wr);
WREG32(mmDMA_IF_W_N_HBM1_WR_CRED_CNT, hbm1_wr);
WREG32(mmDMA_IF_W_N_HBM0_RD_CRED_CNT, hbm0_rd);
WREG32(mmDMA_IF_W_N_HBM1_RD_CRED_CNT, hbm1_rd);
WREG32(mmDMA_IF_W_S_HBM0_WR_CRED_CNT, hbm0_wr);
WREG32(mmDMA_IF_W_S_HBM1_WR_CRED_CNT, hbm1_wr);
WREG32(mmDMA_IF_W_S_HBM0_RD_CRED_CNT, hbm0_rd);
WREG32(mmDMA_IF_W_S_HBM1_RD_CRED_CNT, hbm1_rd);
WREG32(mmDMA_IF_E_N_HBM_CRED_EN_0,
(1 << DMA_IF_HBM_CRED_EN_READ_CREDIT_EN_SHIFT) |
(1 << DMA_IF_HBM_CRED_EN_WRITE_CREDIT_EN_SHIFT));
WREG32(mmDMA_IF_E_S_HBM_CRED_EN_0,
(1 << DMA_IF_HBM_CRED_EN_READ_CREDIT_EN_SHIFT) |
(1 << DMA_IF_HBM_CRED_EN_WRITE_CREDIT_EN_SHIFT));
WREG32(mmDMA_IF_W_N_HBM_CRED_EN_0,
(1 << DMA_IF_HBM_CRED_EN_READ_CREDIT_EN_SHIFT) |
(1 << DMA_IF_HBM_CRED_EN_WRITE_CREDIT_EN_SHIFT));
WREG32(mmDMA_IF_W_S_HBM_CRED_EN_0,
(1 << DMA_IF_HBM_CRED_EN_READ_CREDIT_EN_SHIFT) |
(1 << DMA_IF_HBM_CRED_EN_WRITE_CREDIT_EN_SHIFT));
WREG32(mmDMA_IF_E_N_HBM_CRED_EN_1,
(1 << DMA_IF_HBM_CRED_EN_READ_CREDIT_EN_SHIFT) |
(1 << DMA_IF_HBM_CRED_EN_WRITE_CREDIT_EN_SHIFT));
WREG32(mmDMA_IF_E_S_HBM_CRED_EN_1,
(1 << DMA_IF_HBM_CRED_EN_READ_CREDIT_EN_SHIFT) |
(1 << DMA_IF_HBM_CRED_EN_WRITE_CREDIT_EN_SHIFT));
WREG32(mmDMA_IF_W_N_HBM_CRED_EN_1,
(1 << DMA_IF_HBM_CRED_EN_READ_CREDIT_EN_SHIFT) |
(1 << DMA_IF_HBM_CRED_EN_WRITE_CREDIT_EN_SHIFT));
WREG32(mmDMA_IF_W_S_HBM_CRED_EN_1,
(1 << DMA_IF_HBM_CRED_EN_READ_CREDIT_EN_SHIFT) |
(1 << DMA_IF_HBM_CRED_EN_WRITE_CREDIT_EN_SHIFT));
}
static void gaudi_init_golden_registers(struct hl_device *hdev)
{
u32 tpc_offset;
int tpc_id, i;
gaudi_init_e2e(hdev);
gaudi_init_hbm_cred(hdev);
for (tpc_id = 0, tpc_offset = 0;
tpc_id < TPC_NUMBER_OF_ENGINES;
tpc_id++, tpc_offset += TPC_CFG_OFFSET) {
WREG32(mmTPC0_CFG_TPC_INTR_MASK + tpc_offset, 0x8FFE);
WREG32_FIELD(TPC0_CFG_MSS_CONFIG, tpc_offset,
ICACHE_FETCH_LINE_NUM, 2);
}
for (i = 0 ; i < 128 ; i += 8)
writeq(0, hdev->pcie_bar[SRAM_BAR_ID] + i);
WREG32(mmMME0_CTRL_EUS_ROLLUP_CNT_ADD, 3);
WREG32(mmMME1_CTRL_EUS_ROLLUP_CNT_ADD, 3);
WREG32(mmMME2_CTRL_EUS_ROLLUP_CNT_ADD, 3);
WREG32(mmMME3_CTRL_EUS_ROLLUP_CNT_ADD, 3);
}
static void gaudi_init_pci_dma_qman(struct hl_device *hdev, int dma_id,
int qman_id, dma_addr_t qman_pq_addr)
{
struct cpu_dyn_regs *dyn_regs =
&hdev->fw_loader.dynamic_loader.comm_desc.cpu_dyn_regs;
u32 mtr_base_en_lo, mtr_base_en_hi, mtr_base_ws_lo, mtr_base_ws_hi;
u32 so_base_en_lo, so_base_en_hi, so_base_ws_lo, so_base_ws_hi;
u32 q_off, dma_qm_offset;
u32 dma_qm_err_cfg, irq_handler_offset;
dma_qm_offset = dma_id * DMA_QMAN_OFFSET;
mtr_base_en_lo = lower_32_bits(CFG_BASE +
mmSYNC_MNGR_E_N_SYNC_MNGR_OBJS_MON_PAY_ADDRL_0);
mtr_base_en_hi = upper_32_bits(CFG_BASE +
mmSYNC_MNGR_E_N_SYNC_MNGR_OBJS_MON_PAY_ADDRL_0);
so_base_en_lo = lower_32_bits(CFG_BASE +
mmSYNC_MNGR_E_N_SYNC_MNGR_OBJS_SOB_OBJ_0);
so_base_en_hi = upper_32_bits(CFG_BASE +
mmSYNC_MNGR_E_N_SYNC_MNGR_OBJS_SOB_OBJ_0);
mtr_base_ws_lo = lower_32_bits(CFG_BASE +
mmSYNC_MNGR_W_S_SYNC_MNGR_OBJS_MON_PAY_ADDRL_0);
mtr_base_ws_hi = upper_32_bits(CFG_BASE +
mmSYNC_MNGR_W_S_SYNC_MNGR_OBJS_MON_PAY_ADDRL_0);
so_base_ws_lo = lower_32_bits(CFG_BASE +
mmSYNC_MNGR_W_S_SYNC_MNGR_OBJS_SOB_OBJ_0);
so_base_ws_hi = upper_32_bits(CFG_BASE +
mmSYNC_MNGR_W_S_SYNC_MNGR_OBJS_SOB_OBJ_0);
q_off = dma_qm_offset + qman_id * 4;
WREG32(mmDMA0_QM_PQ_BASE_LO_0 + q_off, lower_32_bits(qman_pq_addr));
WREG32(mmDMA0_QM_PQ_BASE_HI_0 + q_off, upper_32_bits(qman_pq_addr));
WREG32(mmDMA0_QM_PQ_SIZE_0 + q_off, ilog2(HL_QUEUE_LENGTH));
WREG32(mmDMA0_QM_PQ_PI_0 + q_off, 0);
WREG32(mmDMA0_QM_PQ_CI_0 + q_off, 0);
WREG32(mmDMA0_QM_CP_LDMA_TSIZE_OFFSET_0 + q_off, QMAN_LDMA_SIZE_OFFSET);
WREG32(mmDMA0_QM_CP_LDMA_SRC_BASE_LO_OFFSET_0 + q_off,
QMAN_LDMA_SRC_OFFSET);
WREG32(mmDMA0_QM_CP_LDMA_DST_BASE_LO_OFFSET_0 + q_off,
QMAN_LDMA_DST_OFFSET);
WREG32(mmDMA0_QM_CP_MSG_BASE0_ADDR_LO_0 + q_off, mtr_base_en_lo);
WREG32(mmDMA0_QM_CP_MSG_BASE0_ADDR_HI_0 + q_off, mtr_base_en_hi);
WREG32(mmDMA0_QM_CP_MSG_BASE1_ADDR_LO_0 + q_off, so_base_en_lo);
WREG32(mmDMA0_QM_CP_MSG_BASE1_ADDR_HI_0 + q_off, so_base_en_hi);
WREG32(mmDMA0_QM_CP_MSG_BASE2_ADDR_LO_0 + q_off, mtr_base_ws_lo);
WREG32(mmDMA0_QM_CP_MSG_BASE2_ADDR_HI_0 + q_off, mtr_base_ws_hi);
WREG32(mmDMA0_QM_CP_MSG_BASE3_ADDR_LO_0 + q_off, so_base_ws_lo);
WREG32(mmDMA0_QM_CP_MSG_BASE3_ADDR_HI_0 + q_off, so_base_ws_hi);
WREG32(mmDMA0_QM_CP_BARRIER_CFG_0 + q_off, 0x100);
if (qman_id == 0) {
irq_handler_offset = hdev->asic_prop.gic_interrupts_enable ?
mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR :
le32_to_cpu(dyn_regs->gic_dma_qm_irq_ctrl);
dma_qm_err_cfg = PCI_DMA_QMAN_GLBL_ERR_CFG_MSG_EN_MASK;
if (hdev->stop_on_err)
dma_qm_err_cfg |=
PCI_DMA_QMAN_GLBL_ERR_CFG_STOP_ON_ERR_EN_MASK;
WREG32(mmDMA0_QM_GLBL_ERR_CFG + dma_qm_offset, dma_qm_err_cfg);
WREG32(mmDMA0_QM_GLBL_ERR_ADDR_LO + dma_qm_offset,
lower_32_bits(CFG_BASE + irq_handler_offset));
WREG32(mmDMA0_QM_GLBL_ERR_ADDR_HI + dma_qm_offset,
upper_32_bits(CFG_BASE + irq_handler_offset));
WREG32(mmDMA0_QM_GLBL_ERR_WDATA + dma_qm_offset,
gaudi_irq_map_table[GAUDI_EVENT_DMA0_QM].cpu_id +
dma_id);
WREG32(mmDMA0_QM_ARB_ERR_MSG_EN + dma_qm_offset,
QM_ARB_ERR_MSG_EN_MASK);
WREG32(mmDMA0_QM_ARB_SLV_CHOISE_WDT + dma_qm_offset, GAUDI_ARB_WDT_TIMEOUT);
WREG32(mmDMA0_QM_GLBL_PROT + dma_qm_offset,
QMAN_EXTERNAL_MAKE_TRUSTED);
WREG32(mmDMA0_QM_GLBL_CFG1 + dma_qm_offset, 0);
}
}
static void gaudi_init_dma_core(struct hl_device *hdev, int dma_id)
{
struct cpu_dyn_regs *dyn_regs =
&hdev->fw_loader.dynamic_loader.comm_desc.cpu_dyn_regs;
u32 dma_err_cfg = 1 << DMA0_CORE_ERR_CFG_ERR_MSG_EN_SHIFT;
u32 dma_offset = dma_id * DMA_CORE_OFFSET;
u32 irq_handler_offset;
WREG32(mmDMA0_CORE_RD_MAX_OUTSTAND + dma_offset, 0);
WREG32(mmDMA0_CORE_RD_MAX_SIZE + dma_offset, 0);
WREG32(mmDMA0_CORE_LBW_MAX_OUTSTAND + dma_offset, 15);
if (hdev->stop_on_err)
dma_err_cfg |= 1 << DMA0_CORE_ERR_CFG_STOP_ON_ERR_SHIFT;
WREG32(mmDMA0_CORE_ERR_CFG + dma_offset, dma_err_cfg);
irq_handler_offset = hdev->asic_prop.gic_interrupts_enable ?
mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR :
le32_to_cpu(dyn_regs->gic_dma_core_irq_ctrl);
WREG32(mmDMA0_CORE_ERRMSG_ADDR_LO + dma_offset,
lower_32_bits(CFG_BASE + irq_handler_offset));
WREG32(mmDMA0_CORE_ERRMSG_ADDR_HI + dma_offset,
upper_32_bits(CFG_BASE + irq_handler_offset));
WREG32(mmDMA0_CORE_ERRMSG_WDATA + dma_offset,
gaudi_irq_map_table[GAUDI_EVENT_DMA0_CORE].cpu_id + dma_id);
WREG32(mmDMA0_CORE_PROT + dma_offset,
1 << DMA0_CORE_PROT_ERR_VAL_SHIFT);
WREG32(mmDMA0_CORE_SECURE_PROPS + dma_offset,
1 << DMA0_CORE_SECURE_PROPS_MMBP_SHIFT);
WREG32(mmDMA0_CORE_CFG_0 + dma_offset, 1 << DMA0_CORE_CFG_0_EN_SHIFT);
}
static void gaudi_enable_qman(struct hl_device *hdev, int dma_id,
u32 enable_mask)
{
u32 dma_qm_offset = dma_id * DMA_QMAN_OFFSET;
WREG32(mmDMA0_QM_GLBL_CFG0 + dma_qm_offset, enable_mask);
}
static void gaudi_init_pci_dma_qmans(struct hl_device *hdev)
{
struct gaudi_device *gaudi = hdev->asic_specific;
struct hl_hw_queue *q;
int i, j, dma_id, cpu_skip, nic_skip, cq_id = 0, q_idx, msi_vec = 0;
if (gaudi->hw_cap_initialized & HW_CAP_PCI_DMA)
return;
for (i = 0 ; i < PCI_DMA_NUMBER_OF_CHNLS ; i++) {
dma_id = gaudi_dma_assignment[i];
if (dma_id > 1) {
cpu_skip = 1;
nic_skip = NIC_NUMBER_OF_ENGINES;
} else {
cpu_skip = 0;
nic_skip = 0;
}
for (j = 0 ; j < QMAN_STREAMS ; j++) {
q_idx = 4 * dma_id + j + cpu_skip;
q = &hdev->kernel_queues[q_idx];
q->cq_id = cq_id++;
q->msi_vec = nic_skip + cpu_skip + msi_vec++;
gaudi_init_pci_dma_qman(hdev, dma_id, j,
q->bus_address);
}
gaudi_init_dma_core(hdev, dma_id);
gaudi_enable_qman(hdev, dma_id, PCI_DMA_QMAN_ENABLE);
}
gaudi->hw_cap_initialized |= HW_CAP_PCI_DMA;
}
static void gaudi_init_hbm_dma_qman(struct hl_device *hdev, int dma_id,
int qman_id, u64 qman_base_addr)
{
struct cpu_dyn_regs *dyn_regs =
&hdev->fw_loader.dynamic_loader.comm_desc.cpu_dyn_regs;
u32 mtr_base_en_lo, mtr_base_en_hi, mtr_base_ws_lo, mtr_base_ws_hi;
u32 so_base_en_lo, so_base_en_hi, so_base_ws_lo, so_base_ws_hi;
u32 dma_qm_err_cfg, irq_handler_offset;
u32 q_off, dma_qm_offset;
dma_qm_offset = dma_id * DMA_QMAN_OFFSET;
mtr_base_en_lo = lower_32_bits(CFG_BASE +
mmSYNC_MNGR_E_N_SYNC_MNGR_OBJS_MON_PAY_ADDRL_0);
mtr_base_en_hi = upper_32_bits(CFG_BASE +
mmSYNC_MNGR_E_N_SYNC_MNGR_OBJS_MON_PAY_ADDRL_0);
so_base_en_lo = lower_32_bits(CFG_BASE +
mmSYNC_MNGR_E_N_SYNC_MNGR_OBJS_SOB_OBJ_0);
so_base_en_hi = upper_32_bits(CFG_BASE +
mmSYNC_MNGR_E_N_SYNC_MNGR_OBJS_SOB_OBJ_0);
mtr_base_ws_lo = lower_32_bits(CFG_BASE +
mmSYNC_MNGR_W_S_SYNC_MNGR_OBJS_MON_PAY_ADDRL_0);
mtr_base_ws_hi = upper_32_bits(CFG_BASE +
mmSYNC_MNGR_W_S_SYNC_MNGR_OBJS_MON_PAY_ADDRL_0);
so_base_ws_lo = lower_32_bits(CFG_BASE +
mmSYNC_MNGR_W_S_SYNC_MNGR_OBJS_SOB_OBJ_0);
so_base_ws_hi = upper_32_bits(CFG_BASE +
mmSYNC_MNGR_W_S_SYNC_MNGR_OBJS_SOB_OBJ_0);
q_off = dma_qm_offset + qman_id * 4;
if (qman_id < 4) {
WREG32(mmDMA0_QM_PQ_BASE_LO_0 + q_off,
lower_32_bits(qman_base_addr));
WREG32(mmDMA0_QM_PQ_BASE_HI_0 + q_off,
upper_32_bits(qman_base_addr));
WREG32(mmDMA0_QM_PQ_SIZE_0 + q_off, ilog2(HBM_DMA_QMAN_LENGTH));
WREG32(mmDMA0_QM_PQ_PI_0 + q_off, 0);
WREG32(mmDMA0_QM_PQ_CI_0 + q_off, 0);
WREG32(mmDMA0_QM_CP_LDMA_TSIZE_OFFSET_0 + q_off,
QMAN_CPDMA_SIZE_OFFSET);
WREG32(mmDMA0_QM_CP_LDMA_SRC_BASE_LO_OFFSET_0 + q_off,
QMAN_CPDMA_SRC_OFFSET);
WREG32(mmDMA0_QM_CP_LDMA_DST_BASE_LO_OFFSET_0 + q_off,
QMAN_CPDMA_DST_OFFSET);
} else {
irq_handler_offset = hdev->asic_prop.gic_interrupts_enable ?
mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR :
le32_to_cpu(dyn_regs->gic_dma_qm_irq_ctrl);
WREG32(mmDMA0_QM_CP_LDMA_TSIZE_OFFSET_0 + q_off,
QMAN_LDMA_SIZE_OFFSET);
WREG32(mmDMA0_QM_CP_LDMA_SRC_BASE_LO_OFFSET_0 + q_off,
QMAN_LDMA_SRC_OFFSET);
WREG32(mmDMA0_QM_CP_LDMA_DST_BASE_LO_OFFSET_0 + q_off,
QMAN_LDMA_DST_OFFSET);
dma_qm_err_cfg = HBM_DMA_QMAN_GLBL_ERR_CFG_MSG_EN_MASK;
if (hdev->stop_on_err)
dma_qm_err_cfg |=
HBM_DMA_QMAN_GLBL_ERR_CFG_STOP_ON_ERR_EN_MASK;
WREG32(mmDMA0_QM_GLBL_ERR_CFG + dma_qm_offset, dma_qm_err_cfg);
WREG32(mmDMA0_QM_GLBL_ERR_ADDR_LO + dma_qm_offset,
lower_32_bits(CFG_BASE + irq_handler_offset));
WREG32(mmDMA0_QM_GLBL_ERR_ADDR_HI + dma_qm_offset,
upper_32_bits(CFG_BASE + irq_handler_offset));
WREG32(mmDMA0_QM_GLBL_ERR_WDATA + dma_qm_offset,
gaudi_irq_map_table[GAUDI_EVENT_DMA0_QM].cpu_id +
dma_id);
WREG32(mmDMA0_QM_ARB_ERR_MSG_EN + dma_qm_offset,
QM_ARB_ERR_MSG_EN_MASK);
WREG32(mmDMA0_QM_ARB_SLV_CHOISE_WDT + dma_qm_offset, GAUDI_ARB_WDT_TIMEOUT);
WREG32(mmDMA0_QM_GLBL_CFG1 + dma_qm_offset, 0);
WREG32(mmDMA0_QM_GLBL_PROT + dma_qm_offset,
QMAN_INTERNAL_MAKE_TRUSTED);
}
WREG32(mmDMA0_QM_CP_MSG_BASE0_ADDR_LO_0 + q_off, mtr_base_en_lo);
WREG32(mmDMA0_QM_CP_MSG_BASE0_ADDR_HI_0 + q_off, mtr_base_en_hi);
WREG32(mmDMA0_QM_CP_MSG_BASE1_ADDR_LO_0 + q_off, so_base_en_lo);
WREG32(mmDMA0_QM_CP_MSG_BASE1_ADDR_HI_0 + q_off, so_base_en_hi);
if (gaudi_dma_assignment[dma_id] == GAUDI_ENGINE_ID_DMA_5) {
WREG32(mmDMA0_QM_CP_MSG_BASE2_ADDR_LO_0 + q_off,
mtr_base_ws_lo);
WREG32(mmDMA0_QM_CP_MSG_BASE2_ADDR_HI_0 + q_off,
mtr_base_ws_hi);
WREG32(mmDMA0_QM_CP_MSG_BASE3_ADDR_LO_0 + q_off,
so_base_ws_lo);
WREG32(mmDMA0_QM_CP_MSG_BASE3_ADDR_HI_0 + q_off,
so_base_ws_hi);
}
}
static void gaudi_init_hbm_dma_qmans(struct hl_device *hdev)
{
struct gaudi_device *gaudi = hdev->asic_specific;
struct gaudi_internal_qman_info *q;
u64 qman_base_addr;
int i, j, dma_id, internal_q_index;
if (gaudi->hw_cap_initialized & HW_CAP_HBM_DMA)
return;
for (i = 0 ; i < HBM_DMA_NUMBER_OF_CHNLS ; i++) {
dma_id = gaudi_dma_assignment[GAUDI_HBM_DMA_1 + i];
for (j = 0 ; j < QMAN_STREAMS ; j++) {
internal_q_index = dma_id * QMAN_STREAMS + j + 1;
q = &gaudi->internal_qmans[internal_q_index];
qman_base_addr = (u64) q->pq_dma_addr;
gaudi_init_hbm_dma_qman(hdev, dma_id, j,
qman_base_addr);
}
gaudi_init_hbm_dma_qman(hdev, dma_id, 4, 0);
gaudi_init_dma_core(hdev, dma_id);
gaudi_enable_qman(hdev, dma_id, HBM_DMA_QMAN_ENABLE);
}
gaudi->hw_cap_initialized |= HW_CAP_HBM_DMA;
}
static void gaudi_init_mme_qman(struct hl_device *hdev, u32 mme_offset,
int qman_id, u64 qman_base_addr)
{
struct cpu_dyn_regs *dyn_regs =
&hdev->fw_loader.dynamic_loader.comm_desc.cpu_dyn_regs;
u32 mtr_base_lo, mtr_base_hi;
u32 so_base_lo, so_base_hi;
u32 irq_handler_offset;
u32 q_off, mme_id;
u32 mme_qm_err_cfg;
mtr_base_lo = lower_32_bits(CFG_BASE +
mmSYNC_MNGR_E_N_SYNC_MNGR_OBJS_MON_PAY_ADDRL_0);
mtr_base_hi = upper_32_bits(CFG_BASE +
mmSYNC_MNGR_E_N_SYNC_MNGR_OBJS_MON_PAY_ADDRL_0);
so_base_lo = lower_32_bits(CFG_BASE +
mmSYNC_MNGR_E_N_SYNC_MNGR_OBJS_SOB_OBJ_0);
so_base_hi = upper_32_bits(CFG_BASE +
mmSYNC_MNGR_E_N_SYNC_MNGR_OBJS_SOB_OBJ_0);
q_off = mme_offset + qman_id * 4;
if (qman_id < 4) {
WREG32(mmMME0_QM_PQ_BASE_LO_0 + q_off,
lower_32_bits(qman_base_addr));
WREG32(mmMME0_QM_PQ_BASE_HI_0 + q_off,
upper_32_bits(qman_base_addr));
WREG32(mmMME0_QM_PQ_SIZE_0 + q_off, ilog2(MME_QMAN_LENGTH));
WREG32(mmMME0_QM_PQ_PI_0 + q_off, 0);
WREG32(mmMME0_QM_PQ_CI_0 + q_off, 0);
WREG32(mmMME0_QM_CP_LDMA_TSIZE_OFFSET_0 + q_off,
QMAN_CPDMA_SIZE_OFFSET);
WREG32(mmMME0_QM_CP_LDMA_SRC_BASE_LO_OFFSET_0 + q_off,
QMAN_CPDMA_SRC_OFFSET);
WREG32(mmMME0_QM_CP_LDMA_DST_BASE_LO_OFFSET_0 + q_off,
QMAN_CPDMA_DST_OFFSET);
} else {
irq_handler_offset = hdev->asic_prop.gic_interrupts_enable ?
mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR :
le32_to_cpu(dyn_regs->gic_mme_qm_irq_ctrl);
WREG32(mmMME0_QM_CP_LDMA_TSIZE_OFFSET_0 + q_off,
QMAN_LDMA_SIZE_OFFSET);
WREG32(mmMME0_QM_CP_LDMA_SRC_BASE_LO_OFFSET_0 + q_off,
QMAN_LDMA_SRC_OFFSET);
WREG32(mmMME0_QM_CP_LDMA_DST_BASE_LO_OFFSET_0 + q_off,
QMAN_LDMA_DST_OFFSET);
mme_id = mme_offset /
(mmMME1_QM_GLBL_CFG0 - mmMME0_QM_GLBL_CFG0) / 2;
mme_qm_err_cfg = MME_QMAN_GLBL_ERR_CFG_MSG_EN_MASK;
if (hdev->stop_on_err)
mme_qm_err_cfg |=
MME_QMAN_GLBL_ERR_CFG_STOP_ON_ERR_EN_MASK;
WREG32(mmMME0_QM_GLBL_ERR_CFG + mme_offset, mme_qm_err_cfg);
WREG32(mmMME0_QM_GLBL_ERR_ADDR_LO + mme_offset,
lower_32_bits(CFG_BASE + irq_handler_offset));
WREG32(mmMME0_QM_GLBL_ERR_ADDR_HI + mme_offset,
upper_32_bits(CFG_BASE + irq_handler_offset));
WREG32(mmMME0_QM_GLBL_ERR_WDATA + mme_offset,
gaudi_irq_map_table[GAUDI_EVENT_MME0_QM].cpu_id +
mme_id);
WREG32(mmMME0_QM_ARB_ERR_MSG_EN + mme_offset,
QM_ARB_ERR_MSG_EN_MASK);
WREG32(mmMME0_QM_ARB_SLV_CHOISE_WDT + mme_offset, GAUDI_ARB_WDT_TIMEOUT);
WREG32(mmMME0_QM_GLBL_CFG1 + mme_offset, 0);
WREG32(mmMME0_QM_GLBL_PROT + mme_offset,
QMAN_INTERNAL_MAKE_TRUSTED);
}
WREG32(mmMME0_QM_CP_MSG_BASE0_ADDR_LO_0 + q_off, mtr_base_lo);
WREG32(mmMME0_QM_CP_MSG_BASE0_ADDR_HI_0 + q_off, mtr_base_hi);
WREG32(mmMME0_QM_CP_MSG_BASE1_ADDR_LO_0 + q_off, so_base_lo);
WREG32(mmMME0_QM_CP_MSG_BASE1_ADDR_HI_0 + q_off, so_base_hi);
}
static void gaudi_init_mme_qmans(struct hl_device *hdev)
{
struct gaudi_device *gaudi = hdev->asic_specific;
struct gaudi_internal_qman_info *q;
u64 qman_base_addr;
u32 mme_offset;
int i, internal_q_index;
if (gaudi->hw_cap_initialized & HW_CAP_MME)
return;
mme_offset = mmMME2_QM_GLBL_CFG0 - mmMME0_QM_GLBL_CFG0;
for (i = 0 ; i < MME_NUMBER_OF_QMANS ; i++) {
internal_q_index = GAUDI_QUEUE_ID_MME_0_0 + i;
q = &gaudi->internal_qmans[internal_q_index];
qman_base_addr = (u64) q->pq_dma_addr;
gaudi_init_mme_qman(hdev, mme_offset, (i & 0x3),
qman_base_addr);
if (i == 3)
mme_offset = 0;
}
mme_offset = mmMME2_QM_GLBL_CFG0 - mmMME0_QM_GLBL_CFG0;
gaudi_init_mme_qman(hdev, mme_offset, 4, 0);
gaudi_init_mme_qman(hdev, 0, 4, 0);
WREG32(mmMME2_QM_GLBL_CFG0, QMAN_MME_ENABLE);
WREG32(mmMME0_QM_GLBL_CFG0, QMAN_MME_ENABLE);
gaudi->hw_cap_initialized |= HW_CAP_MME;
}
static void gaudi_init_tpc_qman(struct hl_device *hdev, u32 tpc_offset,
int qman_id, u64 qman_base_addr)
{
struct cpu_dyn_regs *dyn_regs =
&hdev->fw_loader.dynamic_loader.comm_desc.cpu_dyn_regs;
u32 mtr_base_en_lo, mtr_base_en_hi, mtr_base_ws_lo, mtr_base_ws_hi;
u32 so_base_en_lo, so_base_en_hi, so_base_ws_lo, so_base_ws_hi;
u32 tpc_qm_err_cfg, irq_handler_offset;
u32 q_off, tpc_id;
mtr_base_en_lo = lower_32_bits(CFG_BASE +
mmSYNC_MNGR_E_N_SYNC_MNGR_OBJS_MON_PAY_ADDRL_0);
mtr_base_en_hi = upper_32_bits(CFG_BASE +
mmSYNC_MNGR_E_N_SYNC_MNGR_OBJS_MON_PAY_ADDRL_0);
so_base_en_lo = lower_32_bits(CFG_BASE +
mmSYNC_MNGR_E_N_SYNC_MNGR_OBJS_SOB_OBJ_0);
so_base_en_hi = upper_32_bits(CFG_BASE +
mmSYNC_MNGR_E_N_SYNC_MNGR_OBJS_SOB_OBJ_0);
mtr_base_ws_lo = lower_32_bits(CFG_BASE +
mmSYNC_MNGR_W_S_SYNC_MNGR_OBJS_MON_PAY_ADDRL_0);
mtr_base_ws_hi = upper_32_bits(CFG_BASE +
mmSYNC_MNGR_W_S_SYNC_MNGR_OBJS_MON_PAY_ADDRL_0);
so_base_ws_lo = lower_32_bits(CFG_BASE +
mmSYNC_MNGR_W_S_SYNC_MNGR_OBJS_SOB_OBJ_0);
so_base_ws_hi = upper_32_bits(CFG_BASE +
mmSYNC_MNGR_W_S_SYNC_MNGR_OBJS_SOB_OBJ_0);
q_off = tpc_offset + qman_id * 4;
tpc_id = tpc_offset /
(mmTPC1_QM_GLBL_CFG0 - mmTPC0_QM_GLBL_CFG0);
if (qman_id < 4) {
WREG32(mmTPC0_QM_PQ_BASE_LO_0 + q_off,
lower_32_bits(qman_base_addr));
WREG32(mmTPC0_QM_PQ_BASE_HI_0 + q_off,
upper_32_bits(qman_base_addr));
WREG32(mmTPC0_QM_PQ_SIZE_0 + q_off, ilog2(TPC_QMAN_LENGTH));
WREG32(mmTPC0_QM_PQ_PI_0 + q_off, 0);
WREG32(mmTPC0_QM_PQ_CI_0 + q_off, 0);
WREG32(mmTPC0_QM_CP_LDMA_TSIZE_OFFSET_0 + q_off,
QMAN_CPDMA_SIZE_OFFSET);
WREG32(mmTPC0_QM_CP_LDMA_SRC_BASE_LO_OFFSET_0 + q_off,
QMAN_CPDMA_SRC_OFFSET);
WREG32(mmTPC0_QM_CP_LDMA_DST_BASE_LO_OFFSET_0 + q_off,
QMAN_CPDMA_DST_OFFSET);
} else {
irq_handler_offset = hdev->asic_prop.gic_interrupts_enable ?
mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR :
le32_to_cpu(dyn_regs->gic_tpc_qm_irq_ctrl);
WREG32(mmTPC0_QM_CP_LDMA_TSIZE_OFFSET_0 + q_off,
QMAN_LDMA_SIZE_OFFSET);
WREG32(mmTPC0_QM_CP_LDMA_SRC_BASE_LO_OFFSET_0 + q_off,
QMAN_LDMA_SRC_OFFSET);
WREG32(mmTPC0_QM_CP_LDMA_DST_BASE_LO_OFFSET_0 + q_off,
QMAN_LDMA_DST_OFFSET);
tpc_qm_err_cfg = TPC_QMAN_GLBL_ERR_CFG_MSG_EN_MASK;
if (hdev->stop_on_err)
tpc_qm_err_cfg |=
TPC_QMAN_GLBL_ERR_CFG_STOP_ON_ERR_EN_MASK;
WREG32(mmTPC0_QM_GLBL_ERR_CFG + tpc_offset, tpc_qm_err_cfg);
WREG32(mmTPC0_QM_GLBL_ERR_ADDR_LO + tpc_offset,
lower_32_bits(CFG_BASE + irq_handler_offset));
WREG32(mmTPC0_QM_GLBL_ERR_ADDR_HI + tpc_offset,
upper_32_bits(CFG_BASE + irq_handler_offset));
WREG32(mmTPC0_QM_GLBL_ERR_WDATA + tpc_offset,
gaudi_irq_map_table[GAUDI_EVENT_TPC0_QM].cpu_id +
tpc_id);
WREG32(mmTPC0_QM_ARB_ERR_MSG_EN + tpc_offset,
QM_ARB_ERR_MSG_EN_MASK);
WREG32(mmTPC0_QM_ARB_SLV_CHOISE_WDT + tpc_offset, GAUDI_ARB_WDT_TIMEOUT);
WREG32(mmTPC0_QM_GLBL_CFG1 + tpc_offset, 0);
WREG32(mmTPC0_QM_GLBL_PROT + tpc_offset,
QMAN_INTERNAL_MAKE_TRUSTED);
}
WREG32(mmTPC0_QM_CP_MSG_BASE0_ADDR_LO_0 + q_off, mtr_base_en_lo);
WREG32(mmTPC0_QM_CP_MSG_BASE0_ADDR_HI_0 + q_off, mtr_base_en_hi);
WREG32(mmTPC0_QM_CP_MSG_BASE1_ADDR_LO_0 + q_off, so_base_en_lo);
WREG32(mmTPC0_QM_CP_MSG_BASE1_ADDR_HI_0 + q_off, so_base_en_hi);
if (tpc_id == 6) {
WREG32(mmTPC0_QM_CP_MSG_BASE2_ADDR_LO_0 + q_off,
mtr_base_ws_lo);
WREG32(mmTPC0_QM_CP_MSG_BASE2_ADDR_HI_0 + q_off,
mtr_base_ws_hi);
WREG32(mmTPC0_QM_CP_MSG_BASE3_ADDR_LO_0 + q_off,
so_base_ws_lo);
WREG32(mmTPC0_QM_CP_MSG_BASE3_ADDR_HI_0 + q_off,
so_base_ws_hi);
}
}
static void gaudi_init_tpc_qmans(struct hl_device *hdev)
{
struct gaudi_device *gaudi = hdev->asic_specific;
struct gaudi_internal_qman_info *q;
u64 qman_base_addr;
u32 so_base_hi, tpc_offset = 0;
u32 tpc_delta = mmTPC1_CFG_SM_BASE_ADDRESS_HIGH -
mmTPC0_CFG_SM_BASE_ADDRESS_HIGH;
int i, tpc_id, internal_q_index;
if (gaudi->hw_cap_initialized & HW_CAP_TPC_MASK)
return;
so_base_hi = upper_32_bits(CFG_BASE +
mmSYNC_MNGR_E_N_SYNC_MNGR_OBJS_SOB_OBJ_0);
for (tpc_id = 0 ; tpc_id < TPC_NUMBER_OF_ENGINES ; tpc_id++) {
for (i = 0 ; i < QMAN_STREAMS ; i++) {
internal_q_index = GAUDI_QUEUE_ID_TPC_0_0 +
tpc_id * QMAN_STREAMS + i;
q = &gaudi->internal_qmans[internal_q_index];
qman_base_addr = (u64) q->pq_dma_addr;
gaudi_init_tpc_qman(hdev, tpc_offset, i,
qman_base_addr);
if (i == 3) {
gaudi_init_tpc_qman(hdev, tpc_offset, 4, 0);
WREG32(mmTPC0_QM_GLBL_CFG0 + tpc_offset,
QMAN_TPC_ENABLE);
}
}
WREG32(mmTPC0_CFG_SM_BASE_ADDRESS_HIGH + tpc_id * tpc_delta,
so_base_hi);
tpc_offset += mmTPC1_QM_GLBL_CFG0 - mmTPC0_QM_GLBL_CFG0;
gaudi->hw_cap_initialized |=
FIELD_PREP(HW_CAP_TPC_MASK, 1 << tpc_id);
}
}
static void gaudi_init_nic_qman(struct hl_device *hdev, u32 nic_offset,
int qman_id, u64 qman_base_addr, int nic_id)
{
struct cpu_dyn_regs *dyn_regs =
&hdev->fw_loader.dynamic_loader.comm_desc.cpu_dyn_regs;
u32 mtr_base_en_lo, mtr_base_en_hi, mtr_base_ws_lo, mtr_base_ws_hi;
u32 so_base_en_lo, so_base_en_hi, so_base_ws_lo, so_base_ws_hi;
u32 nic_qm_err_cfg, irq_handler_offset;
u32 q_off;
mtr_base_en_lo = lower_32_bits((CFG_BASE & U32_MAX) +
mmSYNC_MNGR_E_N_SYNC_MNGR_OBJS_MON_PAY_ADDRL_0);
mtr_base_en_hi = upper_32_bits(CFG_BASE +
mmSYNC_MNGR_E_N_SYNC_MNGR_OBJS_MON_PAY_ADDRL_0);
so_base_en_lo = lower_32_bits((CFG_BASE & U32_MAX) +
mmSYNC_MNGR_E_N_SYNC_MNGR_OBJS_SOB_OBJ_0);
so_base_en_hi = upper_32_bits(CFG_BASE +
mmSYNC_MNGR_E_N_SYNC_MNGR_OBJS_SOB_OBJ_0);
mtr_base_ws_lo = lower_32_bits((CFG_BASE & U32_MAX) +
mmSYNC_MNGR_W_S_SYNC_MNGR_OBJS_MON_PAY_ADDRL_0);
mtr_base_ws_hi = upper_32_bits(CFG_BASE +
mmSYNC_MNGR_W_S_SYNC_MNGR_OBJS_MON_PAY_ADDRL_0);
so_base_ws_lo = lower_32_bits((CFG_BASE & U32_MAX) +
mmSYNC_MNGR_W_S_SYNC_MNGR_OBJS_SOB_OBJ_0);
so_base_ws_hi = upper_32_bits(CFG_BASE +
mmSYNC_MNGR_W_S_SYNC_MNGR_OBJS_SOB_OBJ_0);
q_off = nic_offset + qman_id * 4;
WREG32(mmNIC0_QM0_PQ_BASE_LO_0 + q_off, lower_32_bits(qman_base_addr));
WREG32(mmNIC0_QM0_PQ_BASE_HI_0 + q_off, upper_32_bits(qman_base_addr));
WREG32(mmNIC0_QM0_PQ_SIZE_0 + q_off, ilog2(NIC_QMAN_LENGTH));
WREG32(mmNIC0_QM0_PQ_PI_0 + q_off, 0);
WREG32(mmNIC0_QM0_PQ_CI_0 + q_off, 0);
WREG32(mmNIC0_QM0_CP_LDMA_TSIZE_OFFSET_0 + q_off,
QMAN_LDMA_SIZE_OFFSET);
WREG32(mmNIC0_QM0_CP_LDMA_SRC_BASE_LO_OFFSET_0 + q_off,
QMAN_LDMA_SRC_OFFSET);
WREG32(mmNIC0_QM0_CP_LDMA_DST_BASE_LO_OFFSET_0 + q_off,
QMAN_LDMA_DST_OFFSET);
WREG32(mmNIC0_QM0_CP_MSG_BASE0_ADDR_LO_0 + q_off, mtr_base_en_lo);
WREG32(mmNIC0_QM0_CP_MSG_BASE0_ADDR_HI_0 + q_off, mtr_base_en_hi);
WREG32(mmNIC0_QM0_CP_MSG_BASE1_ADDR_LO_0 + q_off, so_base_en_lo);
WREG32(mmNIC0_QM0_CP_MSG_BASE1_ADDR_HI_0 + q_off, so_base_en_hi);
WREG32(mmNIC0_QM0_CP_MSG_BASE2_ADDR_LO_0 + q_off, mtr_base_ws_lo);
WREG32(mmNIC0_QM0_CP_MSG_BASE2_ADDR_HI_0 + q_off, mtr_base_ws_hi);
WREG32(mmNIC0_QM0_CP_MSG_BASE3_ADDR_LO_0 + q_off, so_base_ws_lo);
WREG32(mmNIC0_QM0_CP_MSG_BASE3_ADDR_HI_0 + q_off, so_base_ws_hi);
if (qman_id == 0) {
irq_handler_offset = hdev->asic_prop.gic_interrupts_enable ?
mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR :
le32_to_cpu(dyn_regs->gic_nic_qm_irq_ctrl);
nic_qm_err_cfg = NIC_QMAN_GLBL_ERR_CFG_MSG_EN_MASK;
if (hdev->stop_on_err)
nic_qm_err_cfg |=
NIC_QMAN_GLBL_ERR_CFG_STOP_ON_ERR_EN_MASK;
WREG32(mmNIC0_QM0_GLBL_ERR_CFG + nic_offset, nic_qm_err_cfg);
WREG32(mmNIC0_QM0_GLBL_ERR_ADDR_LO + nic_offset,
lower_32_bits(CFG_BASE + irq_handler_offset));
WREG32(mmNIC0_QM0_GLBL_ERR_ADDR_HI + nic_offset,
upper_32_bits(CFG_BASE + irq_handler_offset));
WREG32(mmNIC0_QM0_GLBL_ERR_WDATA + nic_offset,
gaudi_irq_map_table[GAUDI_EVENT_NIC0_QM0].cpu_id +
nic_id);
WREG32(mmNIC0_QM0_ARB_ERR_MSG_EN + nic_offset,
QM_ARB_ERR_MSG_EN_MASK);
WREG32(mmNIC0_QM0_ARB_SLV_CHOISE_WDT + nic_offset, GAUDI_ARB_WDT_TIMEOUT);
WREG32(mmNIC0_QM0_GLBL_CFG1 + nic_offset, 0);
WREG32(mmNIC0_QM0_GLBL_PROT + nic_offset,
QMAN_INTERNAL_MAKE_TRUSTED);
}
}
static void gaudi_init_nic_qmans(struct hl_device *hdev)
{
struct gaudi_device *gaudi = hdev->asic_specific;
struct gaudi_internal_qman_info *q;
u64 qman_base_addr;
u32 nic_offset = 0;
u32 nic_delta_between_qmans =
mmNIC0_QM1_GLBL_CFG0 - mmNIC0_QM0_GLBL_CFG0;
u32 nic_delta_between_nics =
mmNIC1_QM0_GLBL_CFG0 - mmNIC0_QM0_GLBL_CFG0;
int i, nic_id, internal_q_index;
if (!hdev->nic_ports_mask)
return;
if (gaudi->hw_cap_initialized & HW_CAP_NIC_MASK)
return;
dev_dbg(hdev->dev, "Initializing NIC QMANs\n");
for (nic_id = 0 ; nic_id < NIC_NUMBER_OF_ENGINES ; nic_id++) {
if (!(hdev->nic_ports_mask & (1 << nic_id))) {
nic_offset += nic_delta_between_qmans;
if (nic_id & 1) {
nic_offset -= (nic_delta_between_qmans * 2);
nic_offset += nic_delta_between_nics;
}
continue;
}
for (i = 0 ; i < QMAN_STREAMS ; i++) {
internal_q_index = GAUDI_QUEUE_ID_NIC_0_0 +
nic_id * QMAN_STREAMS + i;
q = &gaudi->internal_qmans[internal_q_index];
qman_base_addr = (u64) q->pq_dma_addr;
gaudi_init_nic_qman(hdev, nic_offset, (i & 0x3),
qman_base_addr, nic_id);
}
WREG32(mmNIC0_QM0_GLBL_CFG0 + nic_offset, NIC_QMAN_ENABLE);
nic_offset += nic_delta_between_qmans;
if (nic_id & 1) {
nic_offset -= (nic_delta_between_qmans * 2);
nic_offset += nic_delta_between_nics;
}
gaudi->hw_cap_initialized |= 1 << (HW_CAP_NIC_SHIFT + nic_id);
}
}
static void gaudi_disable_pci_dma_qmans(struct hl_device *hdev)
{
struct gaudi_device *gaudi = hdev->asic_specific;
if (!(gaudi->hw_cap_initialized & HW_CAP_PCI_DMA))
return;
WREG32(mmDMA0_QM_GLBL_CFG0, 0);
WREG32(mmDMA1_QM_GLBL_CFG0, 0);
WREG32(mmDMA5_QM_GLBL_CFG0, 0);
}
static void gaudi_disable_hbm_dma_qmans(struct hl_device *hdev)
{
struct gaudi_device *gaudi = hdev->asic_specific;
if (!(gaudi->hw_cap_initialized & HW_CAP_HBM_DMA))
return;
WREG32(mmDMA2_QM_GLBL_CFG0, 0);
WREG32(mmDMA3_QM_GLBL_CFG0, 0);
WREG32(mmDMA4_QM_GLBL_CFG0, 0);
WREG32(mmDMA6_QM_GLBL_CFG0, 0);
WREG32(mmDMA7_QM_GLBL_CFG0, 0);
}
static void gaudi_disable_mme_qmans(struct hl_device *hdev)
{
struct gaudi_device *gaudi = hdev->asic_specific;
if (!(gaudi->hw_cap_initialized & HW_CAP_MME))
return;
WREG32(mmMME2_QM_GLBL_CFG0, 0);
WREG32(mmMME0_QM_GLBL_CFG0, 0);
}
static void gaudi_disable_tpc_qmans(struct hl_device *hdev)
{
struct gaudi_device *gaudi = hdev->asic_specific;
u32 tpc_offset = 0;
int tpc_id;
if (!(gaudi->hw_cap_initialized & HW_CAP_TPC_MASK))
return;
for (tpc_id = 0 ; tpc_id < TPC_NUMBER_OF_ENGINES ; tpc_id++) {
WREG32(mmTPC0_QM_GLBL_CFG0 + tpc_offset, 0);
tpc_offset += mmTPC1_QM_GLBL_CFG0 - mmTPC0_QM_GLBL_CFG0;
}
}
static void gaudi_disable_nic_qmans(struct hl_device *hdev)
{
struct gaudi_device *gaudi = hdev->asic_specific;
u32 nic_mask, nic_offset = 0;
u32 nic_delta_between_qmans =
mmNIC0_QM1_GLBL_CFG0 - mmNIC0_QM0_GLBL_CFG0;
u32 nic_delta_between_nics =
mmNIC1_QM0_GLBL_CFG0 - mmNIC0_QM0_GLBL_CFG0;
int nic_id;
for (nic_id = 0 ; nic_id < NIC_NUMBER_OF_ENGINES ; nic_id++) {
nic_mask = 1 << (HW_CAP_NIC_SHIFT + nic_id);
if (gaudi->hw_cap_initialized & nic_mask)
WREG32(mmNIC0_QM0_GLBL_CFG0 + nic_offset, 0);
nic_offset += nic_delta_between_qmans;
if (nic_id & 1) {
nic_offset -= (nic_delta_between_qmans * 2);
nic_offset += nic_delta_between_nics;
}
}
}
static void gaudi_stop_pci_dma_qmans(struct hl_device *hdev)
{
struct gaudi_device *gaudi = hdev->asic_specific;
if (!(gaudi->hw_cap_initialized & HW_CAP_PCI_DMA))
return;
WREG32(mmDMA0_QM_GLBL_CFG1, 0xF << DMA0_QM_GLBL_CFG1_CP_STOP_SHIFT);
WREG32(mmDMA1_QM_GLBL_CFG1, 0xF << DMA0_QM_GLBL_CFG1_CP_STOP_SHIFT);
WREG32(mmDMA5_QM_GLBL_CFG1, 0xF << DMA0_QM_GLBL_CFG1_CP_STOP_SHIFT);
}
static void gaudi_stop_hbm_dma_qmans(struct hl_device *hdev)
{
struct gaudi_device *gaudi = hdev->asic_specific;
if (!(gaudi->hw_cap_initialized & HW_CAP_HBM_DMA))
return;
WREG32(mmDMA2_QM_GLBL_CFG1, 0x1F << DMA0_QM_GLBL_CFG1_CP_STOP_SHIFT);
WREG32(mmDMA3_QM_GLBL_CFG1, 0x1F << DMA0_QM_GLBL_CFG1_CP_STOP_SHIFT);
WREG32(mmDMA4_QM_GLBL_CFG1, 0x1F << DMA0_QM_GLBL_CFG1_CP_STOP_SHIFT);
WREG32(mmDMA6_QM_GLBL_CFG1, 0x1F << DMA0_QM_GLBL_CFG1_CP_STOP_SHIFT);
WREG32(mmDMA7_QM_GLBL_CFG1, 0x1F << DMA0_QM_GLBL_CFG1_CP_STOP_SHIFT);
}
static void gaudi_stop_mme_qmans(struct hl_device *hdev)
{
struct gaudi_device *gaudi = hdev->asic_specific;
if (!(gaudi->hw_cap_initialized & HW_CAP_MME))
return;
WREG32(mmMME2_QM_GLBL_CFG1, 0x1F << MME0_QM_GLBL_CFG1_CP_STOP_SHIFT);
WREG32(mmMME0_QM_GLBL_CFG1, 0x1F << MME0_QM_GLBL_CFG1_CP_STOP_SHIFT);
}
static void gaudi_stop_tpc_qmans(struct hl_device *hdev)
{
struct gaudi_device *gaudi = hdev->asic_specific;
if (!(gaudi->hw_cap_initialized & HW_CAP_TPC_MASK))
return;
WREG32(mmTPC0_QM_GLBL_CFG1, 0x1F << TPC0_QM_GLBL_CFG1_CP_STOP_SHIFT);
WREG32(mmTPC1_QM_GLBL_CFG1, 0x1F << TPC0_QM_GLBL_CFG1_CP_STOP_SHIFT);
WREG32(mmTPC2_QM_GLBL_CFG1, 0x1F << TPC0_QM_GLBL_CFG1_CP_STOP_SHIFT);
WREG32(mmTPC3_QM_GLBL_CFG1, 0x1F << TPC0_QM_GLBL_CFG1_CP_STOP_SHIFT);
WREG32(mmTPC4_QM_GLBL_CFG1, 0x1F << TPC0_QM_GLBL_CFG1_CP_STOP_SHIFT);
WREG32(mmTPC5_QM_GLBL_CFG1, 0x1F << TPC0_QM_GLBL_CFG1_CP_STOP_SHIFT);
WREG32(mmTPC6_QM_GLBL_CFG1, 0x1F << TPC0_QM_GLBL_CFG1_CP_STOP_SHIFT);
WREG32(mmTPC7_QM_GLBL_CFG1, 0x1F << TPC0_QM_GLBL_CFG1_CP_STOP_SHIFT);
}
static void gaudi_stop_nic_qmans(struct hl_device *hdev)
{
struct gaudi_device *gaudi = hdev->asic_specific;
if (gaudi->hw_cap_initialized & HW_CAP_NIC0)
WREG32(mmNIC0_QM0_GLBL_CFG1,
NIC0_QM0_GLBL_CFG1_PQF_STOP_MASK |
NIC0_QM0_GLBL_CFG1_CQF_STOP_MASK |
NIC0_QM0_GLBL_CFG1_CP_STOP_MASK);
if (gaudi->hw_cap_initialized & HW_CAP_NIC1)
WREG32(mmNIC0_QM1_GLBL_CFG1,
NIC0_QM0_GLBL_CFG1_PQF_STOP_MASK |
NIC0_QM0_GLBL_CFG1_CQF_STOP_MASK |
NIC0_QM0_GLBL_CFG1_CP_STOP_MASK);
if (gaudi->hw_cap_initialized & HW_CAP_NIC2)
WREG32(mmNIC1_QM0_GLBL_CFG1,
NIC0_QM0_GLBL_CFG1_PQF_STOP_MASK |
NIC0_QM0_GLBL_CFG1_CQF_STOP_MASK |
NIC0_QM0_GLBL_CFG1_CP_STOP_MASK);
if (gaudi->hw_cap_initialized & HW_CAP_NIC3)
WREG32(mmNIC1_QM1_GLBL_CFG1,
NIC0_QM0_GLBL_CFG1_PQF_STOP_MASK |
NIC0_QM0_GLBL_CFG1_CQF_STOP_MASK |
NIC0_QM0_GLBL_CFG1_CP_STOP_MASK);
if (gaudi->hw_cap_initialized & HW_CAP_NIC4)
WREG32(mmNIC2_QM0_GLBL_CFG1,
NIC0_QM0_GLBL_CFG1_PQF_STOP_MASK |
NIC0_QM0_GLBL_CFG1_CQF_STOP_MASK |
NIC0_QM0_GLBL_CFG1_CP_STOP_MASK);
if (gaudi->hw_cap_initialized & HW_CAP_NIC5)
WREG32(mmNIC2_QM1_GLBL_CFG1,
NIC0_QM0_GLBL_CFG1_PQF_STOP_MASK |
NIC0_QM0_GLBL_CFG1_CQF_STOP_MASK |
NIC0_QM0_GLBL_CFG1_CP_STOP_MASK);
if (gaudi->hw_cap_initialized & HW_CAP_NIC6)
WREG32(mmNIC3_QM0_GLBL_CFG1,
NIC0_QM0_GLBL_CFG1_PQF_STOP_MASK |
NIC0_QM0_GLBL_CFG1_CQF_STOP_MASK |
NIC0_QM0_GLBL_CFG1_CP_STOP_MASK);
if (gaudi->hw_cap_initialized & HW_CAP_NIC7)
WREG32(mmNIC3_QM1_GLBL_CFG1,
NIC0_QM0_GLBL_CFG1_PQF_STOP_MASK |
NIC0_QM0_GLBL_CFG1_CQF_STOP_MASK |
NIC0_QM0_GLBL_CFG1_CP_STOP_MASK);
if (gaudi->hw_cap_initialized & HW_CAP_NIC8)
WREG32(mmNIC4_QM0_GLBL_CFG1,
NIC0_QM0_GLBL_CFG1_PQF_STOP_MASK |
NIC0_QM0_GLBL_CFG1_CQF_STOP_MASK |
NIC0_QM0_GLBL_CFG1_CP_STOP_MASK);
if (gaudi->hw_cap_initialized & HW_CAP_NIC9)
WREG32(mmNIC4_QM1_GLBL_CFG1,
NIC0_QM0_GLBL_CFG1_PQF_STOP_MASK |
NIC0_QM0_GLBL_CFG1_CQF_STOP_MASK |
NIC0_QM0_GLBL_CFG1_CP_STOP_MASK);
}
static void gaudi_pci_dma_stall(struct hl_device *hdev)
{
struct gaudi_device *gaudi = hdev->asic_specific;
if (!(gaudi->hw_cap_initialized & HW_CAP_PCI_DMA))
return;
WREG32(mmDMA0_CORE_CFG_1, 1 << DMA0_CORE_CFG_1_HALT_SHIFT);
WREG32(mmDMA1_CORE_CFG_1, 1 << DMA0_CORE_CFG_1_HALT_SHIFT);
WREG32(mmDMA5_CORE_CFG_1, 1 << DMA0_CORE_CFG_1_HALT_SHIFT);
}
static void gaudi_hbm_dma_stall(struct hl_device *hdev)
{
struct gaudi_device *gaudi = hdev->asic_specific;
if (!(gaudi->hw_cap_initialized & HW_CAP_HBM_DMA))
return;
WREG32(mmDMA2_CORE_CFG_1, 1 << DMA0_CORE_CFG_1_HALT_SHIFT);
WREG32(mmDMA3_CORE_CFG_1, 1 << DMA0_CORE_CFG_1_HALT_SHIFT);
WREG32(mmDMA4_CORE_CFG_1, 1 << DMA0_CORE_CFG_1_HALT_SHIFT);
WREG32(mmDMA6_CORE_CFG_1, 1 << DMA0_CORE_CFG_1_HALT_SHIFT);
WREG32(mmDMA7_CORE_CFG_1, 1 << DMA0_CORE_CFG_1_HALT_SHIFT);
}
static void gaudi_mme_stall(struct hl_device *hdev)
{
struct gaudi_device *gaudi = hdev->asic_specific;
if (!(gaudi->hw_cap_initialized & HW_CAP_MME))
return;
WREG32(mmMME0_ACC_ACC_STALL, 1 << MME_ACC_ACC_STALL_R_SHIFT);
WREG32(mmMME0_ACC_ACC_STALL, 1 << MME_ACC_ACC_STALL_R_SHIFT);
WREG32(mmMME0_SBAB_SB_STALL, 1 << MME_SBAB_SB_STALL_R_SHIFT);
WREG32(mmMME0_SBAB_SB_STALL, 1 << MME_SBAB_SB_STALL_R_SHIFT);
WREG32(mmMME1_ACC_ACC_STALL, 1 << MME_ACC_ACC_STALL_R_SHIFT);
WREG32(mmMME1_ACC_ACC_STALL, 1 << MME_ACC_ACC_STALL_R_SHIFT);
WREG32(mmMME1_SBAB_SB_STALL, 1 << MME_SBAB_SB_STALL_R_SHIFT);
WREG32(mmMME1_SBAB_SB_STALL, 1 << MME_SBAB_SB_STALL_R_SHIFT);
WREG32(mmMME2_ACC_ACC_STALL, 1 << MME_ACC_ACC_STALL_R_SHIFT);
WREG32(mmMME2_ACC_ACC_STALL, 1 << MME_ACC_ACC_STALL_R_SHIFT);
WREG32(mmMME2_SBAB_SB_STALL, 1 << MME_SBAB_SB_STALL_R_SHIFT);
WREG32(mmMME2_SBAB_SB_STALL, 1 << MME_SBAB_SB_STALL_R_SHIFT);
WREG32(mmMME3_ACC_ACC_STALL, 1 << MME_ACC_ACC_STALL_R_SHIFT);
WREG32(mmMME3_ACC_ACC_STALL, 1 << MME_ACC_ACC_STALL_R_SHIFT);
WREG32(mmMME3_SBAB_SB_STALL, 1 << MME_SBAB_SB_STALL_R_SHIFT);
WREG32(mmMME3_SBAB_SB_STALL, 1 << MME_SBAB_SB_STALL_R_SHIFT);
}
static void gaudi_tpc_stall(struct hl_device *hdev)
{
struct gaudi_device *gaudi = hdev->asic_specific;
if (!(gaudi->hw_cap_initialized & HW_CAP_TPC_MASK))
return;
WREG32(mmTPC0_CFG_TPC_STALL, 1 << TPC0_CFG_TPC_STALL_V_SHIFT);
WREG32(mmTPC1_CFG_TPC_STALL, 1 << TPC0_CFG_TPC_STALL_V_SHIFT);
WREG32(mmTPC2_CFG_TPC_STALL, 1 << TPC0_CFG_TPC_STALL_V_SHIFT);
WREG32(mmTPC3_CFG_TPC_STALL, 1 << TPC0_CFG_TPC_STALL_V_SHIFT);
WREG32(mmTPC4_CFG_TPC_STALL, 1 << TPC0_CFG_TPC_STALL_V_SHIFT);
WREG32(mmTPC5_CFG_TPC_STALL, 1 << TPC0_CFG_TPC_STALL_V_SHIFT);
WREG32(mmTPC6_CFG_TPC_STALL, 1 << TPC0_CFG_TPC_STALL_V_SHIFT);
WREG32(mmTPC7_CFG_TPC_STALL, 1 << TPC0_CFG_TPC_STALL_V_SHIFT);
}
static void gaudi_disable_clock_gating(struct hl_device *hdev)
{
u32 qman_offset;
int i;
if (hdev->asic_prop.fw_security_enabled)
return;
for (i = 0, qman_offset = 0 ; i < DMA_NUMBER_OF_CHANNELS ; i++) {
WREG32(mmDMA0_QM_CGM_CFG + qman_offset, 0);
WREG32(mmDMA0_QM_CGM_CFG1 + qman_offset, 0);
qman_offset += (mmDMA1_QM_CGM_CFG - mmDMA0_QM_CGM_CFG);
}
WREG32(mmMME0_QM_CGM_CFG, 0);
WREG32(mmMME0_QM_CGM_CFG1, 0);
WREG32(mmMME2_QM_CGM_CFG, 0);
WREG32(mmMME2_QM_CGM_CFG1, 0);
for (i = 0, qman_offset = 0 ; i < TPC_NUMBER_OF_ENGINES ; i++) {
WREG32(mmTPC0_QM_CGM_CFG + qman_offset, 0);
WREG32(mmTPC0_QM_CGM_CFG1 + qman_offset, 0);
qman_offset += (mmTPC1_QM_CGM_CFG - mmTPC0_QM_CGM_CFG);
}
}
static void gaudi_enable_timestamp(struct hl_device *hdev)
{
WREG32(mmPSOC_TIMESTAMP_BASE - CFG_BASE, 0);
WREG32(mmPSOC_TIMESTAMP_BASE - CFG_BASE + 0xC, 0);
WREG32(mmPSOC_TIMESTAMP_BASE - CFG_BASE + 0x8, 0);
WREG32(mmPSOC_TIMESTAMP_BASE - CFG_BASE, 1);
}
static void gaudi_disable_timestamp(struct hl_device *hdev)
{
WREG32(mmPSOC_TIMESTAMP_BASE - CFG_BASE, 0);
}
static void gaudi_halt_engines(struct hl_device *hdev, bool hard_reset, bool fw_reset)
{
u32 wait_timeout_ms;
if (hdev->pldm)
wait_timeout_ms = GAUDI_PLDM_RESET_WAIT_MSEC;
else
wait_timeout_ms = GAUDI_RESET_WAIT_MSEC;
if (fw_reset)
goto skip_engines;
gaudi_stop_nic_qmans(hdev);
gaudi_stop_mme_qmans(hdev);
gaudi_stop_tpc_qmans(hdev);
gaudi_stop_hbm_dma_qmans(hdev);
gaudi_stop_pci_dma_qmans(hdev);
msleep(wait_timeout_ms);
gaudi_pci_dma_stall(hdev);
gaudi_hbm_dma_stall(hdev);
gaudi_tpc_stall(hdev);
gaudi_mme_stall(hdev);
msleep(wait_timeout_ms);
gaudi_disable_nic_qmans(hdev);
gaudi_disable_mme_qmans(hdev);
gaudi_disable_tpc_qmans(hdev);
gaudi_disable_hbm_dma_qmans(hdev);
gaudi_disable_pci_dma_qmans(hdev);
gaudi_disable_timestamp(hdev);
skip_engines:
gaudi_disable_msi(hdev);
}
static int gaudi_mmu_init(struct hl_device *hdev)
{
struct asic_fixed_properties *prop = &hdev->asic_prop;
struct gaudi_device *gaudi = hdev->asic_specific;
u64 hop0_addr;
int rc, i;
if (gaudi->hw_cap_initialized & HW_CAP_MMU)
return 0;
for (i = 0 ; i < prop->max_asid ; i++) {
hop0_addr = prop->mmu_pgt_addr +
(i * prop->mmu_hop_table_size);
rc = gaudi_mmu_update_asid_hop0_addr(hdev, i, hop0_addr);
if (rc) {
dev_err(hdev->dev,
"failed to set hop0 addr for asid %d\n", i);
return rc;
}
}
WREG32(mmSTLB_CACHE_INV_BASE_39_8, prop->mmu_cache_mng_addr >> 8);
WREG32(mmSTLB_CACHE_INV_BASE_49_40, prop->mmu_cache_mng_addr >> 40);
WREG32(mmSTLB_MEM_CACHE_INVALIDATION, 1);
rc = hl_mmu_invalidate_cache(hdev, true, 0);
if (rc)
return rc;
WREG32(mmMMU_UP_MMU_ENABLE, 1);
WREG32(mmMMU_UP_SPI_MASK, 0xF);
WREG32(mmSTLB_HOP_CONFIGURATION, 0x30440);
gaudi->mmu_cache_inv_pi = 1;
gaudi->hw_cap_initialized |= HW_CAP_MMU;
return 0;
}
static int gaudi_load_firmware_to_device(struct hl_device *hdev)
{
void __iomem *dst;
dst = hdev->pcie_bar[HBM_BAR_ID] + LINUX_FW_OFFSET;
return hl_fw_load_fw_to_device(hdev, GAUDI_LINUX_FW_FILE, dst, 0, 0);
}
static int gaudi_load_boot_fit_to_device(struct hl_device *hdev)
{
void __iomem *dst;
dst = hdev->pcie_bar[SRAM_BAR_ID] + BOOT_FIT_SRAM_OFFSET;
return hl_fw_load_fw_to_device(hdev, GAUDI_BOOT_FIT_FILE, dst, 0, 0);
}
static void gaudi_init_dynamic_firmware_loader(struct hl_device *hdev)
{
struct dynamic_fw_load_mgr *dynamic_loader;
struct cpu_dyn_regs *dyn_regs;
dynamic_loader = &hdev->fw_loader.dynamic_loader;
dyn_regs = &dynamic_loader->comm_desc.cpu_dyn_regs;
dyn_regs->kmd_msg_to_cpu =
cpu_to_le32(mmPSOC_GLOBAL_CONF_KMD_MSG_TO_CPU);
dyn_regs->cpu_cmd_status_to_host =
cpu_to_le32(mmCPU_CMD_STATUS_TO_HOST);
dynamic_loader->wait_for_bl_timeout = GAUDI_WAIT_FOR_BL_TIMEOUT_USEC;
}
static void gaudi_init_static_firmware_loader(struct hl_device *hdev)
{
struct static_fw_load_mgr *static_loader;
static_loader = &hdev->fw_loader.static_loader;
static_loader->preboot_version_max_off = SRAM_SIZE - VERSION_MAX_LEN;
static_loader->boot_fit_version_max_off = SRAM_SIZE - VERSION_MAX_LEN;
static_loader->kmd_msg_to_cpu_reg = mmPSOC_GLOBAL_CONF_KMD_MSG_TO_CPU;
static_loader->cpu_cmd_status_to_host_reg = mmCPU_CMD_STATUS_TO_HOST;
static_loader->cpu_boot_status_reg = mmPSOC_GLOBAL_CONF_CPU_BOOT_STATUS;
static_loader->cpu_boot_dev_status0_reg = mmCPU_BOOT_DEV_STS0;
static_loader->cpu_boot_dev_status1_reg = mmCPU_BOOT_DEV_STS1;
static_loader->boot_err0_reg = mmCPU_BOOT_ERR0;
static_loader->boot_err1_reg = mmCPU_BOOT_ERR1;
static_loader->preboot_version_offset_reg = mmPREBOOT_VER_OFFSET;
static_loader->boot_fit_version_offset_reg = mmUBOOT_VER_OFFSET;
static_loader->sram_offset_mask = ~(lower_32_bits(SRAM_BASE_ADDR));
static_loader->cpu_reset_wait_msec = hdev->pldm ?
GAUDI_PLDM_RESET_WAIT_MSEC :
GAUDI_CPU_RESET_WAIT_MSEC;
}
static void gaudi_init_firmware_preload_params(struct hl_device *hdev)
{
struct pre_fw_load_props *pre_fw_load = &hdev->fw_loader.pre_fw_load;
pre_fw_load->cpu_boot_status_reg = mmPSOC_GLOBAL_CONF_CPU_BOOT_STATUS;
pre_fw_load->sts_boot_dev_sts0_reg = mmCPU_BOOT_DEV_STS0;
pre_fw_load->sts_boot_dev_sts1_reg = mmCPU_BOOT_DEV_STS1;
pre_fw_load->boot_err0_reg = mmCPU_BOOT_ERR0;
pre_fw_load->boot_err1_reg = mmCPU_BOOT_ERR1;
pre_fw_load->wait_for_preboot_timeout = GAUDI_BOOT_FIT_REQ_TIMEOUT_USEC;
}
static void gaudi_init_firmware_loader(struct hl_device *hdev)
{
struct asic_fixed_properties *prop = &hdev->asic_prop;
struct fw_load_mgr *fw_loader = &hdev->fw_loader;
fw_loader->fw_comp_loaded = FW_TYPE_NONE;
fw_loader->boot_fit_img.image_name = GAUDI_BOOT_FIT_FILE;
fw_loader->linux_img.image_name = GAUDI_LINUX_FW_FILE;
fw_loader->cpu_timeout = GAUDI_CPU_TIMEOUT_USEC;
fw_loader->boot_fit_timeout = GAUDI_BOOT_FIT_REQ_TIMEOUT_USEC;
fw_loader->skip_bmc = !hdev->bmc_enable;
fw_loader->sram_bar_id = SRAM_BAR_ID;
fw_loader->dram_bar_id = HBM_BAR_ID;
if (prop->dynamic_fw_load)
gaudi_init_dynamic_firmware_loader(hdev);
else
gaudi_init_static_firmware_loader(hdev);
}
static int gaudi_init_cpu(struct hl_device *hdev)
{
struct gaudi_device *gaudi = hdev->asic_specific;
int rc;
if (!(hdev->fw_components & FW_TYPE_PREBOOT_CPU))
return 0;
if (gaudi->hw_cap_initialized & HW_CAP_CPU)
return 0;
if (!hdev->asic_prop.fw_security_enabled)
WREG32(mmCPU_IF_CPU_MSB_ADDR, hdev->cpu_pci_msb_addr);
rc = hl_fw_init_cpu(hdev);
if (rc)
return rc;
gaudi->hw_cap_initialized |= HW_CAP_CPU;
return 0;
}
static int gaudi_init_cpu_queues(struct hl_device *hdev, u32 cpu_timeout)
{
struct cpu_dyn_regs *dyn_regs =
&hdev->fw_loader.dynamic_loader.comm_desc.cpu_dyn_regs;
struct asic_fixed_properties *prop = &hdev->asic_prop;
struct gaudi_device *gaudi = hdev->asic_specific;
u32 status, irq_handler_offset;
struct hl_eq *eq;
struct hl_hw_queue *cpu_pq =
&hdev->kernel_queues[GAUDI_QUEUE_ID_CPU_PQ];
int err;
if (!hdev->cpu_queues_enable)
return 0;
if (gaudi->hw_cap_initialized & HW_CAP_CPU_Q)
return 0;
eq = &hdev->event_queue;
WREG32(mmCPU_IF_PQ_BASE_ADDR_LOW, lower_32_bits(cpu_pq->bus_address));
WREG32(mmCPU_IF_PQ_BASE_ADDR_HIGH, upper_32_bits(cpu_pq->bus_address));
WREG32(mmCPU_IF_EQ_BASE_ADDR_LOW, lower_32_bits(eq->bus_address));
WREG32(mmCPU_IF_EQ_BASE_ADDR_HIGH, upper_32_bits(eq->bus_address));
WREG32(mmCPU_IF_CQ_BASE_ADDR_LOW,
lower_32_bits(hdev->cpu_accessible_dma_address));
WREG32(mmCPU_IF_CQ_BASE_ADDR_HIGH,
upper_32_bits(hdev->cpu_accessible_dma_address));
WREG32(mmCPU_IF_PQ_LENGTH, HL_QUEUE_SIZE_IN_BYTES);
WREG32(mmCPU_IF_EQ_LENGTH, HL_EQ_SIZE_IN_BYTES);
WREG32(mmCPU_IF_CQ_LENGTH, HL_CPU_ACCESSIBLE_MEM_SIZE);
WREG32(mmCPU_IF_EQ_RD_OFFS, 0);
WREG32(mmCPU_IF_PF_PQ_PI, 0);
WREG32(mmCPU_IF_QUEUE_INIT, PQ_INIT_STATUS_READY_FOR_CP_SINGLE_MSI);
irq_handler_offset = prop->gic_interrupts_enable ?
mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR :
le32_to_cpu(dyn_regs->gic_host_pi_upd_irq);
WREG32(irq_handler_offset,
gaudi_irq_map_table[GAUDI_EVENT_PI_UPDATE].cpu_id);
err = hl_poll_timeout(
hdev,
mmCPU_IF_QUEUE_INIT,
status,
(status == PQ_INIT_STATUS_READY_FOR_HOST),
1000,
cpu_timeout);
if (err) {
dev_err(hdev->dev,
"Failed to communicate with Device CPU (CPU-CP timeout)\n");
return -EIO;
}
if (prop->fw_cpu_boot_dev_sts0_valid)
prop->fw_app_cpu_boot_dev_sts0 = RREG32(mmCPU_BOOT_DEV_STS0);
if (prop->fw_cpu_boot_dev_sts1_valid)
prop->fw_app_cpu_boot_dev_sts1 = RREG32(mmCPU_BOOT_DEV_STS1);
gaudi->hw_cap_initialized |= HW_CAP_CPU_Q;
return 0;
}
static void gaudi_pre_hw_init(struct hl_device *hdev)
{
RREG32(mmHW_STATE);
if (!hdev->asic_prop.fw_security_enabled) {
WREG32(mmPCIE_WRAP_LBW_PROT_OVR,
(PCIE_WRAP_LBW_PROT_OVR_RD_EN_MASK |
PCIE_WRAP_LBW_PROT_OVR_WR_EN_MASK));
RREG32(mmPCIE_WRAP_LBW_PROT_OVR);
}
WREG32(mmHW_STATE, HL_DEVICE_HW_STATE_DIRTY);
}
static int gaudi_hw_init(struct hl_device *hdev)
{
struct gaudi_device *gaudi = hdev->asic_specific;
int rc;
gaudi_pre_hw_init(hdev);
if (hdev->asic_prop.iatu_done_by_fw)
gaudi->hbm_bar_cur_addr = DRAM_PHYS_BASE;
if (gaudi_set_hbm_bar_base(hdev, DRAM_PHYS_BASE) == U64_MAX) {
dev_err(hdev->dev,
"failed to map HBM bar to DRAM base address\n");
return -EIO;
}
rc = gaudi_init_cpu(hdev);
if (rc) {
dev_err(hdev->dev, "failed to initialize CPU\n");
return rc;
}
gaudi_disable_clock_gating(hdev);
gaudi_init_scrambler_sram(hdev);
gaudi_init_scrambler_hbm(hdev);
gaudi_init_golden_registers(hdev);
rc = gaudi_mmu_init(hdev);
if (rc)
return rc;
gaudi_init_security(hdev);
gaudi_init_pci_dma_qmans(hdev);
gaudi_init_hbm_dma_qmans(hdev);
gaudi_init_mme_qmans(hdev);
gaudi_init_tpc_qmans(hdev);
gaudi_init_nic_qmans(hdev);
gaudi_enable_timestamp(hdev);
rc = gaudi_enable_msi(hdev);
if (rc)
goto disable_queues;
rc = gaudi_init_cpu_queues(hdev, GAUDI_CPU_TIMEOUT_USEC);
if (rc) {
dev_err(hdev->dev, "failed to initialize CPU H/W queues %d\n",
rc);
goto disable_msi;
}
RREG32(mmHW_STATE);
return 0;
disable_msi:
gaudi_disable_msi(hdev);
disable_queues:
gaudi_disable_mme_qmans(hdev);
gaudi_disable_pci_dma_qmans(hdev);
return rc;
}
static int gaudi_hw_fini(struct hl_device *hdev, bool hard_reset, bool fw_reset)
{
struct cpu_dyn_regs *dyn_regs =
&hdev->fw_loader.dynamic_loader.comm_desc.cpu_dyn_regs;
u32 status, reset_timeout_ms, cpu_timeout_ms, irq_handler_offset;
struct gaudi_device *gaudi = hdev->asic_specific;
bool driver_performs_reset;
if (!hard_reset) {
dev_err(hdev->dev, "GAUDI doesn't support soft-reset\n");
return 0;
}
if (hdev->pldm) {
reset_timeout_ms = GAUDI_PLDM_HRESET_TIMEOUT_MSEC;
cpu_timeout_ms = GAUDI_PLDM_RESET_WAIT_MSEC;
} else {
reset_timeout_ms = GAUDI_RESET_TIMEOUT_MSEC;
cpu_timeout_ms = GAUDI_CPU_RESET_WAIT_MSEC;
}
if (fw_reset) {
dev_dbg(hdev->dev,
"Firmware performs HARD reset, going to wait %dms\n",
reset_timeout_ms);
goto skip_reset;
}
driver_performs_reset = !!(!hdev->asic_prop.fw_security_enabled &&
!hdev->asic_prop.hard_reset_done_by_fw);
if (driver_performs_reset)
WREG32(mmPCIE_AUX_FLR_CTRL, (PCIE_AUX_FLR_CTRL_HW_CTRL_MASK |
PCIE_AUX_FLR_CTRL_INT_MASK_MASK));
if (hdev->fw_loader.fw_comp_loaded & FW_TYPE_LINUX) {
irq_handler_offset = hdev->asic_prop.gic_interrupts_enable ?
mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR :
le32_to_cpu(dyn_regs->gic_host_halt_irq);
WREG32(irq_handler_offset,
gaudi_irq_map_table[GAUDI_EVENT_HALT_MACHINE].cpu_id);
if (hdev->reset_info.curr_reset_cause == HL_RESET_CAUSE_HEARTBEAT) {
if (hdev->asic_prop.hard_reset_done_by_fw)
hl_fw_ask_hard_reset_without_linux(hdev);
else
hl_fw_ask_halt_machine_without_linux(hdev);
}
} else {
if (hdev->asic_prop.hard_reset_done_by_fw)
hl_fw_ask_hard_reset_without_linux(hdev);
else
hl_fw_ask_halt_machine_without_linux(hdev);
}
if (driver_performs_reset) {
WREG32(mmPSOC_GLOBAL_CONF_SOFT_RST_CFG_H,
(CFG_RST_H_DMA_MASK |
CFG_RST_H_MME_MASK |
CFG_RST_H_SM_MASK |
CFG_RST_H_TPC_7_MASK));
WREG32(mmPSOC_GLOBAL_CONF_SOFT_RST_CFG_L, CFG_RST_L_TPC_MASK);
WREG32(mmPSOC_GLOBAL_CONF_SW_ALL_RST_CFG_H,
(CFG_RST_H_HBM_MASK |
CFG_RST_H_TPC_7_MASK |
CFG_RST_H_NIC_MASK |
CFG_RST_H_SM_MASK |
CFG_RST_H_DMA_MASK |
CFG_RST_H_MME_MASK |
CFG_RST_H_CPU_MASK |
CFG_RST_H_MMU_MASK));
WREG32(mmPSOC_GLOBAL_CONF_SW_ALL_RST_CFG_L,
(CFG_RST_L_IF_MASK |
CFG_RST_L_PSOC_MASK |
CFG_RST_L_TPC_MASK));
msleep(cpu_timeout_ms);
WREG32(mmPREBOOT_PCIE_EN, LKD_HARD_RESET_MAGIC);
WREG32(mmPSOC_GLOBAL_CONF_BOOT_SEQ_RE_START, 1);
WREG32(mmPSOC_GLOBAL_CONF_SW_ALL_RST,
1 << PSOC_GLOBAL_CONF_SW_ALL_RST_IND_SHIFT);
dev_dbg(hdev->dev,
"Issued HARD reset command, going to wait %dms\n",
reset_timeout_ms);
} else {
dev_dbg(hdev->dev,
"Firmware performs HARD reset, going to wait %dms\n",
reset_timeout_ms);
}
skip_reset:
msleep(reset_timeout_ms);
status = RREG32(mmPSOC_GLOBAL_CONF_BTM_FSM);
if (status & PSOC_GLOBAL_CONF_BTM_FSM_STATE_MASK) {
dev_err(hdev->dev, "Timeout while waiting for device to reset 0x%x\n", status);
return -ETIMEDOUT;
}
if (gaudi) {
gaudi->hw_cap_initialized &= ~(HW_CAP_CPU | HW_CAP_CPU_Q | HW_CAP_HBM |
HW_CAP_PCI_DMA | HW_CAP_MME | HW_CAP_TPC_MASK |
HW_CAP_HBM_DMA | HW_CAP_PLL | HW_CAP_NIC_MASK |
HW_CAP_MMU | HW_CAP_SRAM_SCRAMBLER |
HW_CAP_HBM_SCRAMBLER);
memset(gaudi->events_stat, 0, sizeof(gaudi->events_stat));
hdev->device_cpu_is_halted = false;
}
return 0;
}
static int gaudi_suspend(struct hl_device *hdev)
{
int rc;
rc = hl_fw_send_pci_access_msg(hdev, CPUCP_PACKET_DISABLE_PCI_ACCESS, 0x0);
if (rc)
dev_err(hdev->dev, "Failed to disable PCI access from CPU\n");
return rc;
}
static int gaudi_resume(struct hl_device *hdev)
{
return gaudi_init_iatu(hdev);
}
static int gaudi_mmap(struct hl_device *hdev, struct vm_area_struct *vma,
void *cpu_addr, dma_addr_t dma_addr, size_t size)
{
int rc;
vm_flags_set(vma, VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP |
VM_DONTCOPY | VM_NORESERVE);
rc = dma_mmap_coherent(hdev->dev, vma, cpu_addr,
(dma_addr - HOST_PHYS_BASE), size);
if (rc)
dev_err(hdev->dev, "dma_mmap_coherent error %d", rc);
return rc;
}
static void gaudi_ring_doorbell(struct hl_device *hdev, u32 hw_queue_id, u32 pi)
{
struct cpu_dyn_regs *dyn_regs =
&hdev->fw_loader.dynamic_loader.comm_desc.cpu_dyn_regs;
u32 db_reg_offset, db_value, dma_qm_offset, q_off, irq_handler_offset;
struct gaudi_device *gaudi = hdev->asic_specific;
bool invalid_queue = false;
int dma_id;
switch (hw_queue_id) {
case GAUDI_QUEUE_ID_DMA_0_0...GAUDI_QUEUE_ID_DMA_0_3:
dma_id = gaudi_dma_assignment[GAUDI_PCI_DMA_1];
dma_qm_offset = dma_id * DMA_QMAN_OFFSET;
q_off = dma_qm_offset + (hw_queue_id & 0x3) * 4;
db_reg_offset = mmDMA0_QM_PQ_PI_0 + q_off;
break;
case GAUDI_QUEUE_ID_DMA_1_0...GAUDI_QUEUE_ID_DMA_1_3:
dma_id = gaudi_dma_assignment[GAUDI_PCI_DMA_2];
dma_qm_offset = dma_id * DMA_QMAN_OFFSET;
q_off = dma_qm_offset + (hw_queue_id & 0x3) * 4;
db_reg_offset = mmDMA0_QM_PQ_PI_0 + q_off;
break;
case GAUDI_QUEUE_ID_DMA_2_0...GAUDI_QUEUE_ID_DMA_2_3:
dma_id = gaudi_dma_assignment[GAUDI_HBM_DMA_1];
dma_qm_offset = dma_id * DMA_QMAN_OFFSET;
q_off = dma_qm_offset + ((hw_queue_id - 1) & 0x3) * 4;
db_reg_offset = mmDMA0_QM_PQ_PI_0 + q_off;
break;
case GAUDI_QUEUE_ID_DMA_3_0...GAUDI_QUEUE_ID_DMA_3_3:
dma_id = gaudi_dma_assignment[GAUDI_HBM_DMA_2];
dma_qm_offset = dma_id * DMA_QMAN_OFFSET;
q_off = dma_qm_offset + ((hw_queue_id - 1) & 0x3) * 4;
db_reg_offset = mmDMA0_QM_PQ_PI_0 + q_off;
break;
case GAUDI_QUEUE_ID_DMA_4_0...GAUDI_QUEUE_ID_DMA_4_3:
dma_id = gaudi_dma_assignment[GAUDI_HBM_DMA_3];
dma_qm_offset = dma_id * DMA_QMAN_OFFSET;
q_off = dma_qm_offset + ((hw_queue_id - 1) & 0x3) * 4;
db_reg_offset = mmDMA0_QM_PQ_PI_0 + q_off;
break;
case GAUDI_QUEUE_ID_DMA_5_0...GAUDI_QUEUE_ID_DMA_5_3:
dma_id = gaudi_dma_assignment[GAUDI_HBM_DMA_4];
dma_qm_offset = dma_id * DMA_QMAN_OFFSET;
q_off = dma_qm_offset + ((hw_queue_id - 1) & 0x3) * 4;
db_reg_offset = mmDMA0_QM_PQ_PI_0 + q_off;
break;
case GAUDI_QUEUE_ID_DMA_6_0...GAUDI_QUEUE_ID_DMA_6_3:
dma_id = gaudi_dma_assignment[GAUDI_HBM_DMA_5];
dma_qm_offset = dma_id * DMA_QMAN_OFFSET;
q_off = dma_qm_offset + ((hw_queue_id - 1) & 0x3) * 4;
db_reg_offset = mmDMA0_QM_PQ_PI_0 + q_off;
break;
case GAUDI_QUEUE_ID_DMA_7_0...GAUDI_QUEUE_ID_DMA_7_3:
dma_id = gaudi_dma_assignment[GAUDI_HBM_DMA_6];
dma_qm_offset = dma_id * DMA_QMAN_OFFSET;
q_off = dma_qm_offset + ((hw_queue_id - 1) & 0x3) * 4;
db_reg_offset = mmDMA0_QM_PQ_PI_0 + q_off;
break;
case GAUDI_QUEUE_ID_CPU_PQ:
if (gaudi->hw_cap_initialized & HW_CAP_CPU_Q)
db_reg_offset = mmCPU_IF_PF_PQ_PI;
else
invalid_queue = true;
break;
case GAUDI_QUEUE_ID_MME_0_0:
db_reg_offset = mmMME2_QM_PQ_PI_0;
break;
case GAUDI_QUEUE_ID_MME_0_1:
db_reg_offset = mmMME2_QM_PQ_PI_1;
break;
case GAUDI_QUEUE_ID_MME_0_2:
db_reg_offset = mmMME2_QM_PQ_PI_2;
break;
case GAUDI_QUEUE_ID_MME_0_3:
db_reg_offset = mmMME2_QM_PQ_PI_3;
break;
case GAUDI_QUEUE_ID_MME_1_0:
db_reg_offset = mmMME0_QM_PQ_PI_0;
break;
case GAUDI_QUEUE_ID_MME_1_1:
db_reg_offset = mmMME0_QM_PQ_PI_1;
break;
case GAUDI_QUEUE_ID_MME_1_2:
db_reg_offset = mmMME0_QM_PQ_PI_2;
break;
case GAUDI_QUEUE_ID_MME_1_3:
db_reg_offset = mmMME0_QM_PQ_PI_3;
break;
case GAUDI_QUEUE_ID_TPC_0_0:
db_reg_offset = mmTPC0_QM_PQ_PI_0;
break;
case GAUDI_QUEUE_ID_TPC_0_1:
db_reg_offset = mmTPC0_QM_PQ_PI_1;
break;
case GAUDI_QUEUE_ID_TPC_0_2:
db_reg_offset = mmTPC0_QM_PQ_PI_2;
break;
case GAUDI_QUEUE_ID_TPC_0_3:
db_reg_offset = mmTPC0_QM_PQ_PI_3;
break;
case GAUDI_QUEUE_ID_TPC_1_0:
db_reg_offset = mmTPC1_QM_PQ_PI_0;
break;
case GAUDI_QUEUE_ID_TPC_1_1:
db_reg_offset = mmTPC1_QM_PQ_PI_1;
break;
case GAUDI_QUEUE_ID_TPC_1_2:
db_reg_offset = mmTPC1_QM_PQ_PI_2;
break;
case GAUDI_QUEUE_ID_TPC_1_3:
db_reg_offset = mmTPC1_QM_PQ_PI_3;
break;
case GAUDI_QUEUE_ID_TPC_2_0:
db_reg_offset = mmTPC2_QM_PQ_PI_0;
break;
case GAUDI_QUEUE_ID_TPC_2_1:
db_reg_offset = mmTPC2_QM_PQ_PI_1;
break;
case GAUDI_QUEUE_ID_TPC_2_2:
db_reg_offset = mmTPC2_QM_PQ_PI_2;
break;
case GAUDI_QUEUE_ID_TPC_2_3:
db_reg_offset = mmTPC2_QM_PQ_PI_3;
break;
case GAUDI_QUEUE_ID_TPC_3_0:
db_reg_offset = mmTPC3_QM_PQ_PI_0;
break;
case GAUDI_QUEUE_ID_TPC_3_1:
db_reg_offset = mmTPC3_QM_PQ_PI_1;
break;
case GAUDI_QUEUE_ID_TPC_3_2:
db_reg_offset = mmTPC3_QM_PQ_PI_2;
break;
case GAUDI_QUEUE_ID_TPC_3_3:
db_reg_offset = mmTPC3_QM_PQ_PI_3;
break;
case GAUDI_QUEUE_ID_TPC_4_0:
db_reg_offset = mmTPC4_QM_PQ_PI_0;
break;
case GAUDI_QUEUE_ID_TPC_4_1:
db_reg_offset = mmTPC4_QM_PQ_PI_1;
break;
case GAUDI_QUEUE_ID_TPC_4_2:
db_reg_offset = mmTPC4_QM_PQ_PI_2;
break;
case GAUDI_QUEUE_ID_TPC_4_3:
db_reg_offset = mmTPC4_QM_PQ_PI_3;
break;
case GAUDI_QUEUE_ID_TPC_5_0:
db_reg_offset = mmTPC5_QM_PQ_PI_0;
break;
case GAUDI_QUEUE_ID_TPC_5_1:
db_reg_offset = mmTPC5_QM_PQ_PI_1;
break;
case GAUDI_QUEUE_ID_TPC_5_2:
db_reg_offset = mmTPC5_QM_PQ_PI_2;
break;
case GAUDI_QUEUE_ID_TPC_5_3:
db_reg_offset = mmTPC5_QM_PQ_PI_3;
break;
case GAUDI_QUEUE_ID_TPC_6_0:
db_reg_offset = mmTPC6_QM_PQ_PI_0;
break;
case GAUDI_QUEUE_ID_TPC_6_1:
db_reg_offset = mmTPC6_QM_PQ_PI_1;
break;
case GAUDI_QUEUE_ID_TPC_6_2:
db_reg_offset = mmTPC6_QM_PQ_PI_2;
break;
case GAUDI_QUEUE_ID_TPC_6_3:
db_reg_offset = mmTPC6_QM_PQ_PI_3;
break;
case GAUDI_QUEUE_ID_TPC_7_0:
db_reg_offset = mmTPC7_QM_PQ_PI_0;
break;
case GAUDI_QUEUE_ID_TPC_7_1:
db_reg_offset = mmTPC7_QM_PQ_PI_1;
break;
case GAUDI_QUEUE_ID_TPC_7_2:
db_reg_offset = mmTPC7_QM_PQ_PI_2;
break;
case GAUDI_QUEUE_ID_TPC_7_3:
db_reg_offset = mmTPC7_QM_PQ_PI_3;
break;
case GAUDI_QUEUE_ID_NIC_0_0...GAUDI_QUEUE_ID_NIC_0_3:
if (!(gaudi->hw_cap_initialized & HW_CAP_NIC0))
invalid_queue = true;
q_off = ((hw_queue_id - 1) & 0x3) * 4;
db_reg_offset = mmNIC0_QM0_PQ_PI_0 + q_off;
break;
case GAUDI_QUEUE_ID_NIC_1_0...GAUDI_QUEUE_ID_NIC_1_3:
if (!(gaudi->hw_cap_initialized & HW_CAP_NIC1))
invalid_queue = true;
q_off = ((hw_queue_id - 1) & 0x3) * 4;
db_reg_offset = mmNIC0_QM1_PQ_PI_0 + q_off;
break;
case GAUDI_QUEUE_ID_NIC_2_0...GAUDI_QUEUE_ID_NIC_2_3:
if (!(gaudi->hw_cap_initialized & HW_CAP_NIC2))
invalid_queue = true;
q_off = ((hw_queue_id - 1) & 0x3) * 4;
db_reg_offset = mmNIC1_QM0_PQ_PI_0 + q_off;
break;
case GAUDI_QUEUE_ID_NIC_3_0...GAUDI_QUEUE_ID_NIC_3_3:
if (!(gaudi->hw_cap_initialized & HW_CAP_NIC3))
invalid_queue = true;
q_off = ((hw_queue_id - 1) & 0x3) * 4;
db_reg_offset = mmNIC1_QM1_PQ_PI_0 + q_off;
break;
case GAUDI_QUEUE_ID_NIC_4_0...GAUDI_QUEUE_ID_NIC_4_3:
if (!(gaudi->hw_cap_initialized & HW_CAP_NIC4))
invalid_queue = true;
q_off = ((hw_queue_id - 1) & 0x3) * 4;
db_reg_offset = mmNIC2_QM0_PQ_PI_0 + q_off;
break;
case GAUDI_QUEUE_ID_NIC_5_0...GAUDI_QUEUE_ID_NIC_5_3:
if (!(gaudi->hw_cap_initialized & HW_CAP_NIC5))
invalid_queue = true;
q_off = ((hw_queue_id - 1) & 0x3) * 4;
db_reg_offset = mmNIC2_QM1_PQ_PI_0 + q_off;
break;
case GAUDI_QUEUE_ID_NIC_6_0...GAUDI_QUEUE_ID_NIC_6_3:
if (!(gaudi->hw_cap_initialized & HW_CAP_NIC6))
invalid_queue = true;
q_off = ((hw_queue_id - 1) & 0x3) * 4;
db_reg_offset = mmNIC3_QM0_PQ_PI_0 + q_off;
break;
case GAUDI_QUEUE_ID_NIC_7_0...GAUDI_QUEUE_ID_NIC_7_3:
if (!(gaudi->hw_cap_initialized & HW_CAP_NIC7))
invalid_queue = true;
q_off = ((hw_queue_id - 1) & 0x3) * 4;
db_reg_offset = mmNIC3_QM1_PQ_PI_0 + q_off;
break;
case GAUDI_QUEUE_ID_NIC_8_0...GAUDI_QUEUE_ID_NIC_8_3:
if (!(gaudi->hw_cap_initialized & HW_CAP_NIC8))
invalid_queue = true;
q_off = ((hw_queue_id - 1) & 0x3) * 4;
db_reg_offset = mmNIC4_QM0_PQ_PI_0 + q_off;
break;
case GAUDI_QUEUE_ID_NIC_9_0...GAUDI_QUEUE_ID_NIC_9_3:
if (!(gaudi->hw_cap_initialized & HW_CAP_NIC9))
invalid_queue = true;
q_off = ((hw_queue_id - 1) & 0x3) * 4;
db_reg_offset = mmNIC4_QM1_PQ_PI_0 + q_off;
break;
default:
invalid_queue = true;
}
if (invalid_queue) {
dev_err(hdev->dev, "h/w queue %d is invalid. Can't set pi\n",
hw_queue_id);
return;
}
db_value = pi;
WREG32(db_reg_offset, db_value);
if (hw_queue_id == GAUDI_QUEUE_ID_CPU_PQ) {
mb();
irq_handler_offset = hdev->asic_prop.gic_interrupts_enable ?
mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR :
le32_to_cpu(dyn_regs->gic_host_pi_upd_irq);
WREG32(irq_handler_offset,
gaudi_irq_map_table[GAUDI_EVENT_PI_UPDATE].cpu_id);
}
}
static void gaudi_pqe_write(struct hl_device *hdev, __le64 *pqe,
struct hl_bd *bd)
{
__le64 *pbd = (__le64 *) bd;
pqe[0] = pbd[0];
pqe[1] = pbd[1];
}
static void *gaudi_dma_alloc_coherent(struct hl_device *hdev, size_t size,
dma_addr_t *dma_handle, gfp_t flags)
{
void *kernel_addr = dma_alloc_coherent(&hdev->pdev->dev, size,
dma_handle, flags);
if (kernel_addr)
*dma_handle += HOST_PHYS_BASE;
return kernel_addr;
}
static void gaudi_dma_free_coherent(struct hl_device *hdev, size_t size,
void *cpu_addr, dma_addr_t dma_handle)
{
dma_addr_t fixed_dma_handle = dma_handle - HOST_PHYS_BASE;
dma_free_coherent(&hdev->pdev->dev, size, cpu_addr, fixed_dma_handle);
}
static int gaudi_scrub_device_dram(struct hl_device *hdev, u64 val)
{
struct asic_fixed_properties *prop = &hdev->asic_prop;
u64 cur_addr = prop->dram_user_base_address;
u32 chunk_size, busy;
int rc, dma_id;
while (cur_addr < prop->dram_end_address) {
for (dma_id = 0 ; dma_id < DMA_NUMBER_OF_CHANNELS ; dma_id++) {
u32 dma_offset = dma_id * DMA_CORE_OFFSET;
chunk_size =
min((u64)SZ_2G, prop->dram_end_address - cur_addr);
dev_dbg(hdev->dev,
"Doing HBM scrubbing for 0x%09llx - 0x%09llx\n",
cur_addr, cur_addr + chunk_size);
WREG32(mmDMA0_CORE_SRC_BASE_LO + dma_offset,
lower_32_bits(val));
WREG32(mmDMA0_CORE_SRC_BASE_HI + dma_offset,
upper_32_bits(val));
WREG32(mmDMA0_CORE_DST_BASE_LO + dma_offset,
lower_32_bits(cur_addr));
WREG32(mmDMA0_CORE_DST_BASE_HI + dma_offset,
upper_32_bits(cur_addr));
WREG32(mmDMA0_CORE_DST_TSIZE_0 + dma_offset,
chunk_size);
WREG32(mmDMA0_CORE_COMMIT + dma_offset,
((1 << DMA0_CORE_COMMIT_LIN_SHIFT) |
(1 << DMA0_CORE_COMMIT_MEM_SET_SHIFT)));
cur_addr += chunk_size;
if (cur_addr == prop->dram_end_address)
break;
}
for (dma_id = 0 ; dma_id < DMA_NUMBER_OF_CHANNELS ; dma_id++) {
u32 dma_offset = dma_id * DMA_CORE_OFFSET;
rc = hl_poll_timeout(
hdev,
mmDMA0_CORE_STS0 + dma_offset,
busy,
((busy & DMA0_CORE_STS0_BUSY_MASK) == 0),
1000,
HBM_SCRUBBING_TIMEOUT_US);
if (rc) {
dev_err(hdev->dev,
"DMA Timeout during HBM scrubbing of DMA #%d\n",
dma_id);
return -EIO;
}
}
}
return 0;
}
static int gaudi_scrub_device_mem(struct hl_device *hdev)
{
struct asic_fixed_properties *prop = &hdev->asic_prop;
u64 wait_to_idle_time = hdev->pdev ? HBM_SCRUBBING_TIMEOUT_US :
min_t(u64, HBM_SCRUBBING_TIMEOUT_US * 10, HL_SIM_MAX_TIMEOUT_US);
u64 addr, size, val = hdev->memory_scrub_val;
ktime_t timeout;
int rc = 0;
if (!hdev->memory_scrub)
return 0;
timeout = ktime_add_us(ktime_get(), wait_to_idle_time);
while (!hdev->asic_funcs->is_device_idle(hdev, NULL, 0, NULL)) {
if (ktime_compare(ktime_get(), timeout) > 0) {
dev_err(hdev->dev, "waiting for idle timeout\n");
return -ETIMEDOUT;
}
usleep_range((1000 >> 2) + 1, 1000);
}
addr = prop->sram_user_base_address;
size = hdev->pldm ? 0x10000 : prop->sram_size - SRAM_USER_BASE_OFFSET;
dev_dbg(hdev->dev, "Scrubbing SRAM: 0x%09llx - 0x%09llx val: 0x%llx\n",
addr, addr + size, val);
rc = gaudi_memset_device_memory(hdev, addr, size, val);
if (rc) {
dev_err(hdev->dev, "Failed to clear SRAM (%d)\n", rc);
return rc;
}
rc = gaudi_scrub_device_dram(hdev, val);
if (rc) {
dev_err(hdev->dev, "Failed to clear HBM (%d)\n", rc);
return rc;
}
return 0;
}
static void *gaudi_get_int_queue_base(struct hl_device *hdev,
u32 queue_id, dma_addr_t *dma_handle,
u16 *queue_len)
{
struct gaudi_device *gaudi = hdev->asic_specific;
struct gaudi_internal_qman_info *q;
if (queue_id >= GAUDI_QUEUE_ID_SIZE ||
gaudi_queue_type[queue_id] != QUEUE_TYPE_INT) {
dev_err(hdev->dev, "Got invalid queue id %d\n", queue_id);
return NULL;
}
q = &gaudi->internal_qmans[queue_id];
*dma_handle = q->pq_dma_addr;
*queue_len = q->pq_size / QMAN_PQ_ENTRY_SIZE;
return q->pq_kernel_addr;
}
static int gaudi_send_cpu_message(struct hl_device *hdev, u32 *msg,
u16 len, u32 timeout, u64 *result)
{
struct gaudi_device *gaudi = hdev->asic_specific;
if (!(gaudi->hw_cap_initialized & HW_CAP_CPU_Q)) {
if (result)
*result = 0;
return 0;
}
if (!timeout)
timeout = GAUDI_MSG_TO_CPU_TIMEOUT_USEC;
return hl_fw_send_cpu_message(hdev, GAUDI_QUEUE_ID_CPU_PQ, msg, len,
timeout, result);
}
static int gaudi_test_queue(struct hl_device *hdev, u32 hw_queue_id)
{
struct packet_msg_prot *fence_pkt;
dma_addr_t pkt_dma_addr;
u32 fence_val, tmp, timeout_usec;
dma_addr_t fence_dma_addr;
u32 *fence_ptr;
int rc;
if (hdev->pldm)
timeout_usec = GAUDI_PLDM_TEST_QUEUE_WAIT_USEC;
else
timeout_usec = GAUDI_TEST_QUEUE_WAIT_USEC;
fence_val = GAUDI_QMAN0_FENCE_VAL;
fence_ptr = hl_asic_dma_pool_zalloc(hdev, 4, GFP_KERNEL, &fence_dma_addr);
if (!fence_ptr) {
dev_err(hdev->dev,
"Failed to allocate memory for H/W queue %d testing\n",
hw_queue_id);
return -ENOMEM;
}
*fence_ptr = 0;
fence_pkt = hl_asic_dma_pool_zalloc(hdev, sizeof(struct packet_msg_prot), GFP_KERNEL,
&pkt_dma_addr);
if (!fence_pkt) {
dev_err(hdev->dev,
"Failed to allocate packet for H/W queue %d testing\n",
hw_queue_id);
rc = -ENOMEM;
goto free_fence_ptr;
}
tmp = FIELD_PREP(GAUDI_PKT_CTL_OPCODE_MASK, PACKET_MSG_PROT);
tmp |= FIELD_PREP(GAUDI_PKT_CTL_EB_MASK, 1);
tmp |= FIELD_PREP(GAUDI_PKT_CTL_MB_MASK, 1);
fence_pkt->ctl = cpu_to_le32(tmp);
fence_pkt->value = cpu_to_le32(fence_val);
fence_pkt->addr = cpu_to_le64(fence_dma_addr);
rc = hl_hw_queue_send_cb_no_cmpl(hdev, hw_queue_id,
sizeof(struct packet_msg_prot),
pkt_dma_addr);
if (rc) {
dev_err(hdev->dev,
"Failed to send fence packet to H/W queue %d\n",
hw_queue_id);
goto free_pkt;
}
rc = hl_poll_timeout_memory(hdev, fence_ptr, tmp, (tmp == fence_val),
1000, timeout_usec, true);
hl_hw_queue_inc_ci_kernel(hdev, hw_queue_id);
if (rc == -ETIMEDOUT) {
dev_err(hdev->dev,
"H/W queue %d test failed (scratch(0x%08llX) == 0x%08X)\n",
hw_queue_id, (unsigned long long) fence_dma_addr, tmp);
rc = -EIO;
}
free_pkt:
hl_asic_dma_pool_free(hdev, (void *) fence_pkt, pkt_dma_addr);
free_fence_ptr:
hl_asic_dma_pool_free(hdev, (void *) fence_ptr, fence_dma_addr);
return rc;
}
static int gaudi_test_cpu_queue(struct hl_device *hdev)
{
struct gaudi_device *gaudi = hdev->asic_specific;
if (!(gaudi->hw_cap_initialized & HW_CAP_CPU_Q))
return 0;
return hl_fw_test_cpu_queue(hdev);
}
static int gaudi_test_queues(struct hl_device *hdev)
{
int i, rc, ret_val = 0;
for (i = 0 ; i < hdev->asic_prop.max_queues ; i++) {
if (hdev->asic_prop.hw_queues_props[i].type == QUEUE_TYPE_EXT) {
rc = gaudi_test_queue(hdev, i);
if (rc)
ret_val = -EINVAL;
}
}
rc = gaudi_test_cpu_queue(hdev);
if (rc)
ret_val = -EINVAL;
return ret_val;
}
static void *gaudi_dma_pool_zalloc(struct hl_device *hdev, size_t size,
gfp_t mem_flags, dma_addr_t *dma_handle)
{
void *kernel_addr;
if (size > GAUDI_DMA_POOL_BLK_SIZE)
return NULL;
kernel_addr = dma_pool_zalloc(hdev->dma_pool, mem_flags, dma_handle);
if (kernel_addr)
*dma_handle += HOST_PHYS_BASE;
return kernel_addr;
}
static void gaudi_dma_pool_free(struct hl_device *hdev, void *vaddr,
dma_addr_t dma_addr)
{
dma_addr_t fixed_dma_addr = dma_addr - HOST_PHYS_BASE;
dma_pool_free(hdev->dma_pool, vaddr, fixed_dma_addr);
}
static void *gaudi_cpu_accessible_dma_pool_alloc(struct hl_device *hdev,
size_t size, dma_addr_t *dma_handle)
{
return hl_fw_cpu_accessible_dma_pool_alloc(hdev, size, dma_handle);
}
static void gaudi_cpu_accessible_dma_pool_free(struct hl_device *hdev,
size_t size, void *vaddr)
{
hl_fw_cpu_accessible_dma_pool_free(hdev, size, vaddr);
}
static u32 gaudi_get_dma_desc_list_size(struct hl_device *hdev, struct sg_table *sgt)
{
struct scatterlist *sg, *sg_next_iter;
u32 count, dma_desc_cnt;
u64 len, len_next;
dma_addr_t addr, addr_next;
dma_desc_cnt = 0;
for_each_sgtable_dma_sg(sgt, sg, count) {
len = sg_dma_len(sg);
addr = sg_dma_address(sg);
if (len == 0)
break;
while ((count + 1) < sgt->nents) {
sg_next_iter = sg_next(sg);
len_next = sg_dma_len(sg_next_iter);
addr_next = sg_dma_address(sg_next_iter);
if (len_next == 0)
break;
if ((addr + len == addr_next) &&
(len + len_next <= DMA_MAX_TRANSFER_SIZE)) {
len += len_next;
count++;
sg = sg_next_iter;
} else {
break;
}
}
dma_desc_cnt++;
}
return dma_desc_cnt * sizeof(struct packet_lin_dma);
}
static int gaudi_pin_memory_before_cs(struct hl_device *hdev,
struct hl_cs_parser *parser,
struct packet_lin_dma *user_dma_pkt,
u64 addr, enum dma_data_direction dir)
{
struct hl_userptr *userptr;
int rc;
if (hl_userptr_is_pinned(hdev, addr, le32_to_cpu(user_dma_pkt->tsize),
parser->job_userptr_list, &userptr))
goto already_pinned;
userptr = kzalloc(sizeof(*userptr), GFP_KERNEL);
if (!userptr)
return -ENOMEM;
rc = hl_pin_host_memory(hdev, addr, le32_to_cpu(user_dma_pkt->tsize),
userptr);
if (rc)
goto free_userptr;
list_add_tail(&userptr->job_node, parser->job_userptr_list);
rc = hdev->asic_funcs->asic_dma_map_sgtable(hdev, userptr->sgt, dir);
if (rc) {
dev_err(hdev->dev, "failed to map sgt with DMA region\n");
goto unpin_memory;
}
userptr->dma_mapped = true;
userptr->dir = dir;
already_pinned:
parser->patched_cb_size +=
gaudi_get_dma_desc_list_size(hdev, userptr->sgt);
return 0;
unpin_memory:
list_del(&userptr->job_node);
hl_unpin_host_memory(hdev, userptr);
free_userptr:
kfree(userptr);
return rc;
}
static int gaudi_validate_dma_pkt_host(struct hl_device *hdev,
struct hl_cs_parser *parser,
struct packet_lin_dma *user_dma_pkt,
bool src_in_host)
{
enum dma_data_direction dir;
bool skip_host_mem_pin = false, user_memset;
u64 addr;
int rc = 0;
user_memset = (le32_to_cpu(user_dma_pkt->ctl) &
GAUDI_PKT_LIN_DMA_CTL_MEMSET_MASK) >>
GAUDI_PKT_LIN_DMA_CTL_MEMSET_SHIFT;
if (src_in_host) {
if (user_memset)
skip_host_mem_pin = true;
dev_dbg(hdev->dev, "DMA direction is HOST --> DEVICE\n");
dir = DMA_TO_DEVICE;
addr = le64_to_cpu(user_dma_pkt->src_addr);
} else {
dev_dbg(hdev->dev, "DMA direction is DEVICE --> HOST\n");
dir = DMA_FROM_DEVICE;
addr = (le64_to_cpu(user_dma_pkt->dst_addr) &
GAUDI_PKT_LIN_DMA_DST_ADDR_MASK) >>
GAUDI_PKT_LIN_DMA_DST_ADDR_SHIFT;
}
if (skip_host_mem_pin)
parser->patched_cb_size += sizeof(*user_dma_pkt);
else
rc = gaudi_pin_memory_before_cs(hdev, parser, user_dma_pkt,
addr, dir);
return rc;
}
static int gaudi_validate_dma_pkt_no_mmu(struct hl_device *hdev,
struct hl_cs_parser *parser,
struct packet_lin_dma *user_dma_pkt)
{
bool src_in_host = false;
u64 dst_addr = (le64_to_cpu(user_dma_pkt->dst_addr) &
GAUDI_PKT_LIN_DMA_DST_ADDR_MASK) >>
GAUDI_PKT_LIN_DMA_DST_ADDR_SHIFT;
dev_dbg(hdev->dev, "DMA packet details:\n");
dev_dbg(hdev->dev, "source == 0x%llx\n",
le64_to_cpu(user_dma_pkt->src_addr));
dev_dbg(hdev->dev, "destination == 0x%llx\n", dst_addr);
dev_dbg(hdev->dev, "size == %u\n", le32_to_cpu(user_dma_pkt->tsize));
if (!le32_to_cpu(user_dma_pkt->tsize)) {
parser->patched_cb_size += sizeof(*user_dma_pkt);
return 0;
}
if (parser->hw_queue_id <= GAUDI_QUEUE_ID_DMA_0_3)
src_in_host = true;
return gaudi_validate_dma_pkt_host(hdev, parser, user_dma_pkt,
src_in_host);
}
static int gaudi_validate_load_and_exe_pkt(struct hl_device *hdev,
struct hl_cs_parser *parser,
struct packet_load_and_exe *user_pkt)
{
u32 cfg;
cfg = le32_to_cpu(user_pkt->cfg);
if (cfg & GAUDI_PKT_LOAD_AND_EXE_CFG_DST_MASK) {
dev_err(hdev->dev,
"User not allowed to use Load and Execute\n");
return -EPERM;
}
parser->patched_cb_size += sizeof(struct packet_load_and_exe);
return 0;
}
static int gaudi_validate_cb(struct hl_device *hdev,
struct hl_cs_parser *parser, bool is_mmu)
{
u32 cb_parsed_length = 0;
int rc = 0;
parser->patched_cb_size = 0;
while (cb_parsed_length < parser->user_cb_size) {
enum packet_id pkt_id;
u16 pkt_size;
struct gaudi_packet *user_pkt;
user_pkt = parser->user_cb->kernel_address + cb_parsed_length;
pkt_id = (enum packet_id) (
(le64_to_cpu(user_pkt->header) &
PACKET_HEADER_PACKET_ID_MASK) >>
PACKET_HEADER_PACKET_ID_SHIFT);
if (!validate_packet_id(pkt_id)) {
dev_err(hdev->dev, "Invalid packet id %u\n", pkt_id);
rc = -EINVAL;
break;
}
pkt_size = gaudi_packet_sizes[pkt_id];
cb_parsed_length += pkt_size;
if (cb_parsed_length > parser->user_cb_size) {
dev_err(hdev->dev,
"packet 0x%x is out of CB boundary\n", pkt_id);
rc = -EINVAL;
break;
}
switch (pkt_id) {
case PACKET_MSG_PROT:
dev_err(hdev->dev,
"User not allowed to use MSG_PROT\n");
rc = -EPERM;
break;
case PACKET_CP_DMA:
dev_err(hdev->dev, "User not allowed to use CP_DMA\n");
rc = -EPERM;
break;
case PACKET_STOP:
dev_err(hdev->dev, "User not allowed to use STOP\n");
rc = -EPERM;
break;
case PACKET_WREG_BULK:
dev_err(hdev->dev,
"User not allowed to use WREG_BULK\n");
rc = -EPERM;
break;
case PACKET_LOAD_AND_EXE:
rc = gaudi_validate_load_and_exe_pkt(hdev, parser,
(struct packet_load_and_exe *) user_pkt);
break;
case PACKET_LIN_DMA:
parser->contains_dma_pkt = true;
if (is_mmu)
parser->patched_cb_size += pkt_size;
else
rc = gaudi_validate_dma_pkt_no_mmu(hdev, parser,
(struct packet_lin_dma *) user_pkt);
break;
case PACKET_WREG_32:
case PACKET_MSG_LONG:
case PACKET_MSG_SHORT:
case PACKET_REPEAT:
case PACKET_FENCE:
case PACKET_NOP:
case PACKET_ARB_POINT:
parser->patched_cb_size += pkt_size;
break;
default:
dev_err(hdev->dev, "Invalid packet header 0x%x\n",
pkt_id);
rc = -EINVAL;
break;
}
if (rc)
break;
}
if (parser->completion)
parser->patched_cb_size += gaudi_get_patched_cb_extra_size(
parser->patched_cb_size);
return rc;
}
static int gaudi_patch_dma_packet(struct hl_device *hdev,
struct hl_cs_parser *parser,
struct packet_lin_dma *user_dma_pkt,
struct packet_lin_dma *new_dma_pkt,
u32 *new_dma_pkt_size)
{
struct hl_userptr *userptr;
struct scatterlist *sg, *sg_next_iter;
u32 count, dma_desc_cnt, user_wrcomp_en_mask, ctl;
u64 len, len_next;
dma_addr_t dma_addr, dma_addr_next;
u64 device_memory_addr, addr;
enum dma_data_direction dir;
struct sg_table *sgt;
bool src_in_host = false;
bool skip_host_mem_pin = false;
bool user_memset;
ctl = le32_to_cpu(user_dma_pkt->ctl);
if (parser->hw_queue_id <= GAUDI_QUEUE_ID_DMA_0_3)
src_in_host = true;
user_memset = (ctl & GAUDI_PKT_LIN_DMA_CTL_MEMSET_MASK) >>
GAUDI_PKT_LIN_DMA_CTL_MEMSET_SHIFT;
if (src_in_host) {
addr = le64_to_cpu(user_dma_pkt->src_addr);
device_memory_addr = le64_to_cpu(user_dma_pkt->dst_addr);
dir = DMA_TO_DEVICE;
if (user_memset)
skip_host_mem_pin = true;
} else {
addr = le64_to_cpu(user_dma_pkt->dst_addr);
device_memory_addr = le64_to_cpu(user_dma_pkt->src_addr);
dir = DMA_FROM_DEVICE;
}
if ((!skip_host_mem_pin) &&
(!hl_userptr_is_pinned(hdev, addr,
le32_to_cpu(user_dma_pkt->tsize),
parser->job_userptr_list, &userptr))) {
dev_err(hdev->dev, "Userptr 0x%llx + 0x%x NOT mapped\n",
addr, user_dma_pkt->tsize);
return -EFAULT;
}
if ((user_memset) && (dir == DMA_TO_DEVICE)) {
memcpy(new_dma_pkt, user_dma_pkt, sizeof(*user_dma_pkt));
*new_dma_pkt_size = sizeof(*user_dma_pkt);
return 0;
}
user_wrcomp_en_mask = ctl & GAUDI_PKT_LIN_DMA_CTL_WRCOMP_EN_MASK;
sgt = userptr->sgt;
dma_desc_cnt = 0;
for_each_sgtable_dma_sg(sgt, sg, count) {
len = sg_dma_len(sg);
dma_addr = sg_dma_address(sg);
if (len == 0)
break;
while ((count + 1) < sgt->nents) {
sg_next_iter = sg_next(sg);
len_next = sg_dma_len(sg_next_iter);
dma_addr_next = sg_dma_address(sg_next_iter);
if (len_next == 0)
break;
if ((dma_addr + len == dma_addr_next) &&
(len + len_next <= DMA_MAX_TRANSFER_SIZE)) {
len += len_next;
count++;
sg = sg_next_iter;
} else {
break;
}
}
ctl = le32_to_cpu(user_dma_pkt->ctl);
if (likely(dma_desc_cnt))
ctl &= ~GAUDI_PKT_CTL_EB_MASK;
ctl &= ~GAUDI_PKT_LIN_DMA_CTL_WRCOMP_EN_MASK;
new_dma_pkt->ctl = cpu_to_le32(ctl);
new_dma_pkt->tsize = cpu_to_le32(len);
if (dir == DMA_TO_DEVICE) {
new_dma_pkt->src_addr = cpu_to_le64(dma_addr);
new_dma_pkt->dst_addr = cpu_to_le64(device_memory_addr);
} else {
new_dma_pkt->src_addr = cpu_to_le64(device_memory_addr);
new_dma_pkt->dst_addr = cpu_to_le64(dma_addr);
}
if (!user_memset)
device_memory_addr += len;
dma_desc_cnt++;
new_dma_pkt++;
}
if (!dma_desc_cnt) {
dev_err(hdev->dev,
"Error of 0 SG entries when patching DMA packet\n");
return -EFAULT;
}
new_dma_pkt--;
new_dma_pkt->ctl |= cpu_to_le32(user_wrcomp_en_mask);
*new_dma_pkt_size = dma_desc_cnt * sizeof(struct packet_lin_dma);
return 0;
}
static int gaudi_patch_cb(struct hl_device *hdev,
struct hl_cs_parser *parser)
{
u32 cb_parsed_length = 0;
u32 cb_patched_cur_length = 0;
int rc = 0;
while (cb_parsed_length < parser->user_cb_size) {
enum packet_id pkt_id;
u16 pkt_size;
u32 new_pkt_size = 0;
struct gaudi_packet *user_pkt, *kernel_pkt;
user_pkt = parser->user_cb->kernel_address + cb_parsed_length;
kernel_pkt = parser->patched_cb->kernel_address +
cb_patched_cur_length;
pkt_id = (enum packet_id) (
(le64_to_cpu(user_pkt->header) &
PACKET_HEADER_PACKET_ID_MASK) >>
PACKET_HEADER_PACKET_ID_SHIFT);
if (!validate_packet_id(pkt_id)) {
dev_err(hdev->dev, "Invalid packet id %u\n", pkt_id);
rc = -EINVAL;
break;
}
pkt_size = gaudi_packet_sizes[pkt_id];
cb_parsed_length += pkt_size;
if (cb_parsed_length > parser->user_cb_size) {
dev_err(hdev->dev,
"packet 0x%x is out of CB boundary\n", pkt_id);
rc = -EINVAL;
break;
}
switch (pkt_id) {
case PACKET_LIN_DMA:
rc = gaudi_patch_dma_packet(hdev, parser,
(struct packet_lin_dma *) user_pkt,
(struct packet_lin_dma *) kernel_pkt,
&new_pkt_size);
cb_patched_cur_length += new_pkt_size;
break;
case PACKET_MSG_PROT:
dev_err(hdev->dev,
"User not allowed to use MSG_PROT\n");
rc = -EPERM;
break;
case PACKET_CP_DMA:
dev_err(hdev->dev, "User not allowed to use CP_DMA\n");
rc = -EPERM;
break;
case PACKET_STOP:
dev_err(hdev->dev, "User not allowed to use STOP\n");
rc = -EPERM;
break;
case PACKET_WREG_32:
case PACKET_WREG_BULK:
case PACKET_MSG_LONG:
case PACKET_MSG_SHORT:
case PACKET_REPEAT:
case PACKET_FENCE:
case PACKET_NOP:
case PACKET_ARB_POINT:
case PACKET_LOAD_AND_EXE:
memcpy(kernel_pkt, user_pkt, pkt_size);
cb_patched_cur_length += pkt_size;
break;
default:
dev_err(hdev->dev, "Invalid packet header 0x%x\n",
pkt_id);
rc = -EINVAL;
break;
}
if (rc)
break;
}
return rc;
}
static int gaudi_parse_cb_mmu(struct hl_device *hdev,
struct hl_cs_parser *parser)
{
u64 handle;
u32 patched_cb_size;
struct hl_cb *user_cb;
int rc;
if (parser->completion)
parser->patched_cb_size = parser->user_cb_size +
gaudi_get_patched_cb_extra_size(parser->user_cb_size);
else
parser->patched_cb_size = parser->user_cb_size;
rc = hl_cb_create(hdev, &hdev->kernel_mem_mgr, hdev->kernel_ctx,
parser->patched_cb_size, false, false,
&handle);
if (rc) {
dev_err(hdev->dev,
"Failed to allocate patched CB for DMA CS %d\n",
rc);
return rc;
}
parser->patched_cb = hl_cb_get(&hdev->kernel_mem_mgr, handle);
if (!parser->patched_cb) {
dev_crit(hdev->dev, "DMA CB handle invalid 0x%llx\n", handle);
rc = -EFAULT;
goto out;
}
memcpy(parser->patched_cb->kernel_address,
parser->user_cb->kernel_address,
parser->user_cb_size);
patched_cb_size = parser->patched_cb_size;
user_cb = parser->user_cb;
parser->user_cb = parser->patched_cb;
rc = gaudi_validate_cb(hdev, parser, true);
parser->user_cb = user_cb;
if (rc) {
hl_cb_put(parser->patched_cb);
goto out;
}
if (patched_cb_size != parser->patched_cb_size) {
dev_err(hdev->dev, "user CB size mismatch\n");
hl_cb_put(parser->patched_cb);
rc = -EINVAL;
goto out;
}
out:
hl_cb_destroy(&hdev->kernel_mem_mgr, handle);
return rc;
}
static int gaudi_parse_cb_no_mmu(struct hl_device *hdev,
struct hl_cs_parser *parser)
{
u64 handle;
int rc;
rc = gaudi_validate_cb(hdev, parser, false);
if (rc)
goto free_userptr;
rc = hl_cb_create(hdev, &hdev->kernel_mem_mgr, hdev->kernel_ctx,
parser->patched_cb_size, false, false,
&handle);
if (rc) {
dev_err(hdev->dev,
"Failed to allocate patched CB for DMA CS %d\n", rc);
goto free_userptr;
}
parser->patched_cb = hl_cb_get(&hdev->kernel_mem_mgr, handle);
if (!parser->patched_cb) {
dev_crit(hdev->dev, "DMA CB handle invalid 0x%llx\n", handle);
rc = -EFAULT;
goto out;
}
rc = gaudi_patch_cb(hdev, parser);
if (rc)
hl_cb_put(parser->patched_cb);
out:
hl_cb_destroy(&hdev->kernel_mem_mgr, handle);
free_userptr:
if (rc)
hl_userptr_delete_list(hdev, parser->job_userptr_list);
return rc;
}
static int gaudi_parse_cb_no_ext_queue(struct hl_device *hdev,
struct hl_cs_parser *parser)
{
struct asic_fixed_properties *asic_prop = &hdev->asic_prop;
struct gaudi_device *gaudi = hdev->asic_specific;
u32 nic_queue_offset, nic_mask_q_id;
if ((parser->hw_queue_id >= GAUDI_QUEUE_ID_NIC_0_0) &&
(parser->hw_queue_id <= GAUDI_QUEUE_ID_NIC_9_3)) {
nic_queue_offset = parser->hw_queue_id - GAUDI_QUEUE_ID_NIC_0_0;
nic_mask_q_id = 1 << (HW_CAP_NIC_SHIFT + (nic_queue_offset >> 2));
if (!(gaudi->hw_cap_initialized & nic_mask_q_id)) {
dev_err(hdev->dev, "h/w queue %d is disabled\n", parser->hw_queue_id);
return -EINVAL;
}
}
if (hl_mem_area_inside_range((u64) (uintptr_t) parser->user_cb,
parser->user_cb_size,
asic_prop->sram_user_base_address,
asic_prop->sram_end_address))
return 0;
if (hl_mem_area_inside_range((u64) (uintptr_t) parser->user_cb,
parser->user_cb_size,
asic_prop->dram_user_base_address,
asic_prop->dram_end_address))
return 0;
if (hl_mem_area_inside_range((u64) (uintptr_t) parser->user_cb,
parser->user_cb_size,
asic_prop->pmmu.start_addr,
asic_prop->pmmu.end_addr))
return 0;
dev_err(hdev->dev,
"CB address 0x%px + 0x%x for internal QMAN is not valid\n",
parser->user_cb, parser->user_cb_size);
return -EFAULT;
}
static int gaudi_cs_parser(struct hl_device *hdev, struct hl_cs_parser *parser)
{
struct gaudi_device *gaudi = hdev->asic_specific;
if (parser->queue_type == QUEUE_TYPE_INT)
return gaudi_parse_cb_no_ext_queue(hdev, parser);
if (gaudi->hw_cap_initialized & HW_CAP_MMU)
return gaudi_parse_cb_mmu(hdev, parser);
else
return gaudi_parse_cb_no_mmu(hdev, parser);
}
static void gaudi_add_end_of_cb_packets(struct hl_device *hdev, void *kernel_address,
u32 len, u32 original_len, u64 cq_addr, u32 cq_val,
u32 msi_vec, bool eb)
{
struct packet_msg_prot *cq_pkt;
struct packet_nop *cq_padding;
u64 msi_addr;
u32 tmp;
cq_padding = kernel_address + original_len;
cq_pkt = kernel_address + len - (sizeof(struct packet_msg_prot) * 2);
while ((void *)cq_padding < (void *)cq_pkt) {
cq_padding->ctl = cpu_to_le32(FIELD_PREP(GAUDI_PKT_CTL_OPCODE_MASK, PACKET_NOP));
cq_padding++;
}
tmp = FIELD_PREP(GAUDI_PKT_CTL_OPCODE_MASK, PACKET_MSG_PROT);
tmp |= FIELD_PREP(GAUDI_PKT_CTL_MB_MASK, 1);
if (eb)
tmp |= FIELD_PREP(GAUDI_PKT_CTL_EB_MASK, 1);
cq_pkt->ctl = cpu_to_le32(tmp);
cq_pkt->value = cpu_to_le32(cq_val);
cq_pkt->addr = cpu_to_le64(cq_addr);
cq_pkt++;
tmp = FIELD_PREP(GAUDI_PKT_CTL_OPCODE_MASK, PACKET_MSG_PROT);
tmp |= FIELD_PREP(GAUDI_PKT_CTL_MB_MASK, 1);
cq_pkt->ctl = cpu_to_le32(tmp);
cq_pkt->value = cpu_to_le32(1);
msi_addr = hdev->pdev ? mmPCIE_CORE_MSI_REQ : mmPCIE_MSI_INTR_0 + msi_vec * 4;
cq_pkt->addr = cpu_to_le64(CFG_BASE + msi_addr);
}
static void gaudi_update_eq_ci(struct hl_device *hdev, u32 val)
{
WREG32(mmCPU_IF_EQ_RD_OFFS, val);
}
static int gaudi_memset_device_memory(struct hl_device *hdev, u64 addr,
u32 size, u64 val)
{
struct packet_lin_dma *lin_dma_pkt;
struct hl_cs_job *job;
u32 cb_size, ctl, err_cause;
struct hl_cb *cb;
int rc;
cb = hl_cb_kernel_create(hdev, PAGE_SIZE, false);
if (!cb)
return -EFAULT;
lin_dma_pkt = cb->kernel_address;
memset(lin_dma_pkt, 0, sizeof(*lin_dma_pkt));
cb_size = sizeof(*lin_dma_pkt);
ctl = FIELD_PREP(GAUDI_PKT_CTL_OPCODE_MASK, PACKET_LIN_DMA);
ctl |= FIELD_PREP(GAUDI_PKT_LIN_DMA_CTL_MEMSET_MASK, 1);
ctl |= FIELD_PREP(GAUDI_PKT_LIN_DMA_CTL_LIN_MASK, 1);
ctl |= FIELD_PREP(GAUDI_PKT_CTL_MB_MASK, 1);
ctl |= FIELD_PREP(GAUDI_PKT_CTL_RB_MASK, 1);
lin_dma_pkt->ctl = cpu_to_le32(ctl);
lin_dma_pkt->src_addr = cpu_to_le64(val);
lin_dma_pkt->dst_addr |= cpu_to_le64(addr);
lin_dma_pkt->tsize = cpu_to_le32(size);
job = hl_cs_allocate_job(hdev, QUEUE_TYPE_EXT, true);
if (!job) {
dev_err(hdev->dev, "Failed to allocate a new job\n");
rc = -ENOMEM;
goto release_cb;
}
err_cause = RREG32(mmDMA0_CORE_ERR_CAUSE);
if (err_cause && !hdev->init_done) {
dev_dbg(hdev->dev,
"Clearing DMA0 engine from errors (cause 0x%x)\n",
err_cause);
WREG32(mmDMA0_CORE_ERR_CAUSE, err_cause);
}
job->id = 0;
job->user_cb = cb;
atomic_inc(&job->user_cb->cs_cnt);
job->user_cb_size = cb_size;
job->hw_queue_id = GAUDI_QUEUE_ID_DMA_0_0;
job->patched_cb = job->user_cb;
job->job_cb_size = job->user_cb_size + sizeof(struct packet_msg_prot);
hl_debugfs_add_job(hdev, job);
rc = gaudi_send_job_on_qman0(hdev, job);
hl_debugfs_remove_job(hdev, job);
kfree(job);
atomic_dec(&cb->cs_cnt);
err_cause = RREG32(mmDMA0_CORE_ERR_CAUSE);
if (err_cause) {
dev_err(hdev->dev, "DMA Failed, cause 0x%x\n", err_cause);
rc = -EIO;
if (!hdev->init_done) {
dev_dbg(hdev->dev,
"Clearing DMA0 engine from errors (cause 0x%x)\n",
err_cause);
WREG32(mmDMA0_CORE_ERR_CAUSE, err_cause);
}
}
release_cb:
hl_cb_put(cb);
hl_cb_destroy(&hdev->kernel_mem_mgr, cb->buf->handle);
return rc;
}
static int gaudi_memset_registers(struct hl_device *hdev, u64 reg_base,
u32 num_regs, u32 val)
{
struct packet_msg_long *pkt;
struct hl_cs_job *job;
u32 cb_size, ctl;
struct hl_cb *cb;
int i, rc;
cb_size = (sizeof(*pkt) * num_regs) + sizeof(struct packet_msg_prot);
if (cb_size > SZ_2M) {
dev_err(hdev->dev, "CB size must be smaller than %uMB", SZ_2M);
return -ENOMEM;
}
cb = hl_cb_kernel_create(hdev, cb_size, false);
if (!cb)
return -EFAULT;
pkt = cb->kernel_address;
ctl = FIELD_PREP(GAUDI_PKT_LONG_CTL_OP_MASK, 0);
ctl |= FIELD_PREP(GAUDI_PKT_CTL_OPCODE_MASK, PACKET_MSG_LONG);
ctl |= FIELD_PREP(GAUDI_PKT_CTL_EB_MASK, 1);
ctl |= FIELD_PREP(GAUDI_PKT_CTL_RB_MASK, 1);
ctl |= FIELD_PREP(GAUDI_PKT_CTL_MB_MASK, 1);
for (i = 0; i < num_regs ; i++, pkt++) {
pkt->ctl = cpu_to_le32(ctl);
pkt->value = cpu_to_le32(val);
pkt->addr = cpu_to_le64(reg_base + (i * 4));
}
job = hl_cs_allocate_job(hdev, QUEUE_TYPE_EXT, true);
if (!job) {
dev_err(hdev->dev, "Failed to allocate a new job\n");
rc = -ENOMEM;
goto release_cb;
}
job->id = 0;
job->user_cb = cb;
atomic_inc(&job->user_cb->cs_cnt);
job->user_cb_size = cb_size;
job->hw_queue_id = GAUDI_QUEUE_ID_DMA_0_0;
job->patched_cb = job->user_cb;
job->job_cb_size = cb_size;
hl_debugfs_add_job(hdev, job);
rc = gaudi_send_job_on_qman0(hdev, job);
hl_debugfs_remove_job(hdev, job);
kfree(job);
atomic_dec(&cb->cs_cnt);
release_cb:
hl_cb_put(cb);
hl_cb_destroy(&hdev->kernel_mem_mgr, cb->buf->handle);
return rc;
}
static int gaudi_restore_sm_registers(struct hl_device *hdev)
{
u64 base_addr;
u32 num_regs;
int rc;
base_addr = CFG_BASE + mmSYNC_MNGR_E_N_SYNC_MNGR_OBJS_SOB_OBJ_0;
num_regs = NUM_OF_SOB_IN_BLOCK;
rc = gaudi_memset_registers(hdev, base_addr, num_regs, 0);
if (rc) {
dev_err(hdev->dev, "failed resetting SM registers");
return -ENOMEM;
}
base_addr = CFG_BASE + mmSYNC_MNGR_E_S_SYNC_MNGR_OBJS_SOB_OBJ_0;
num_regs = NUM_OF_SOB_IN_BLOCK;
rc = gaudi_memset_registers(hdev, base_addr, num_regs, 0);
if (rc) {
dev_err(hdev->dev, "failed resetting SM registers");
return -ENOMEM;
}
base_addr = CFG_BASE + mmSYNC_MNGR_W_N_SYNC_MNGR_OBJS_SOB_OBJ_0;
num_regs = NUM_OF_SOB_IN_BLOCK;
rc = gaudi_memset_registers(hdev, base_addr, num_regs, 0);
if (rc) {
dev_err(hdev->dev, "failed resetting SM registers");
return -ENOMEM;
}
base_addr = CFG_BASE + mmSYNC_MNGR_E_N_SYNC_MNGR_OBJS_MON_STATUS_0;
num_regs = NUM_OF_MONITORS_IN_BLOCK;
rc = gaudi_memset_registers(hdev, base_addr, num_regs, 0);
if (rc) {
dev_err(hdev->dev, "failed resetting SM registers");
return -ENOMEM;
}
base_addr = CFG_BASE + mmSYNC_MNGR_E_S_SYNC_MNGR_OBJS_MON_STATUS_0;
num_regs = NUM_OF_MONITORS_IN_BLOCK;
rc = gaudi_memset_registers(hdev, base_addr, num_regs, 0);
if (rc) {
dev_err(hdev->dev, "failed resetting SM registers");
return -ENOMEM;
}
base_addr = CFG_BASE + mmSYNC_MNGR_W_N_SYNC_MNGR_OBJS_MON_STATUS_0;
num_regs = NUM_OF_MONITORS_IN_BLOCK;
rc = gaudi_memset_registers(hdev, base_addr, num_regs, 0);
if (rc) {
dev_err(hdev->dev, "failed resetting SM registers");
return -ENOMEM;
}
base_addr = CFG_BASE + mmSYNC_MNGR_W_S_SYNC_MNGR_OBJS_SOB_OBJ_0 +
(GAUDI_FIRST_AVAILABLE_W_S_SYNC_OBJECT * 4);
num_regs = NUM_OF_SOB_IN_BLOCK - GAUDI_FIRST_AVAILABLE_W_S_SYNC_OBJECT;
rc = gaudi_memset_registers(hdev, base_addr, num_regs, 0);
if (rc) {
dev_err(hdev->dev, "failed resetting SM registers");
return -ENOMEM;
}
base_addr = CFG_BASE + mmSYNC_MNGR_W_S_SYNC_MNGR_OBJS_MON_STATUS_0 +
(GAUDI_FIRST_AVAILABLE_W_S_MONITOR * 4);
num_regs = NUM_OF_MONITORS_IN_BLOCK - GAUDI_FIRST_AVAILABLE_W_S_MONITOR;
rc = gaudi_memset_registers(hdev, base_addr, num_regs, 0);
if (rc) {
dev_err(hdev->dev, "failed resetting SM registers");
return -ENOMEM;
}
return 0;
}
static void gaudi_restore_dma_registers(struct hl_device *hdev)
{
u32 sob_delta = mmSYNC_MNGR_E_N_SYNC_MNGR_OBJS_SOB_OBJ_1 -
mmSYNC_MNGR_E_N_SYNC_MNGR_OBJS_SOB_OBJ_0;
int i;
for (i = 0 ; i < DMA_NUMBER_OF_CHANNELS ; i++) {
u64 sob_addr = CFG_BASE +
mmSYNC_MNGR_E_N_SYNC_MNGR_OBJS_SOB_OBJ_0 +
(i * sob_delta);
u32 dma_offset = i * DMA_CORE_OFFSET;
WREG32(mmDMA0_CORE_WR_COMP_ADDR_LO + dma_offset,
lower_32_bits(sob_addr));
WREG32(mmDMA0_CORE_WR_COMP_ADDR_HI + dma_offset,
upper_32_bits(sob_addr));
WREG32(mmDMA0_CORE_WR_COMP_WDATA + dma_offset, 0x80000001);
if (i > 1)
WREG32(mmDMA0_CORE_WR_AWUSER_31_11 + dma_offset,
0x00000001);
}
}
static void gaudi_restore_qm_registers(struct hl_device *hdev)
{
u32 qman_offset;
int i;
for (i = 0 ; i < DMA_NUMBER_OF_CHANNELS ; i++) {
qman_offset = i * DMA_QMAN_OFFSET;
WREG32(mmDMA0_QM_ARB_CFG_0 + qman_offset, 0);
}
for (i = 0 ; i < MME_NUMBER_OF_MASTER_ENGINES ; i++) {
qman_offset = i * (mmMME2_QM_BASE - mmMME0_QM_BASE);
WREG32(mmMME0_QM_ARB_CFG_0 + qman_offset, 0);
}
for (i = 0 ; i < TPC_NUMBER_OF_ENGINES ; i++) {
qman_offset = i * TPC_QMAN_OFFSET;
WREG32(mmTPC0_QM_ARB_CFG_0 + qman_offset, 0);
}
for (i = 0 ; i < NIC_NUMBER_OF_ENGINES ; i++) {
qman_offset = (i >> 1) * NIC_MACRO_QMAN_OFFSET +
(i & 0x1) * NIC_ENGINE_QMAN_OFFSET;
WREG32(mmNIC0_QM0_ARB_CFG_0 + qman_offset, 0);
}
}
static int gaudi_restore_user_registers(struct hl_device *hdev)
{
int rc;
rc = gaudi_restore_sm_registers(hdev);
if (rc)
return rc;
gaudi_restore_dma_registers(hdev);
gaudi_restore_qm_registers(hdev);
return 0;
}
static int gaudi_context_switch(struct hl_device *hdev, u32 asid)
{
return 0;
}
static int gaudi_mmu_clear_pgt_range(struct hl_device *hdev)
{
u32 size = hdev->asic_prop.mmu_pgt_size +
hdev->asic_prop.mmu_cache_mng_size;
struct gaudi_device *gaudi = hdev->asic_specific;
u64 addr = hdev->asic_prop.mmu_pgt_addr;
if (!(gaudi->hw_cap_initialized & HW_CAP_MMU))
return 0;
return gaudi_memset_device_memory(hdev, addr, size, 0);
}
static void gaudi_restore_phase_topology(struct hl_device *hdev)
{
}
static int gaudi_dma_core_transfer(struct hl_device *hdev, int dma_id, u64 addr,
u32 size_to_dma, dma_addr_t dma_addr)
{
u32 err_cause, val;
u64 dma_offset;
int rc;
dma_offset = dma_id * DMA_CORE_OFFSET;
WREG32(mmDMA0_CORE_SRC_BASE_LO + dma_offset, lower_32_bits(addr));
WREG32(mmDMA0_CORE_SRC_BASE_HI + dma_offset, upper_32_bits(addr));
WREG32(mmDMA0_CORE_DST_BASE_LO + dma_offset, lower_32_bits(dma_addr));
WREG32(mmDMA0_CORE_DST_BASE_HI + dma_offset, upper_32_bits(dma_addr));
WREG32(mmDMA0_CORE_DST_TSIZE_0 + dma_offset, size_to_dma);
WREG32(mmDMA0_CORE_COMMIT + dma_offset,
(1 << DMA0_CORE_COMMIT_LIN_SHIFT));
rc = hl_poll_timeout(
hdev,
mmDMA0_CORE_STS0 + dma_offset,
val,
((val & DMA0_CORE_STS0_BUSY_MASK) == 0),
0,
1000000);
if (rc) {
dev_err(hdev->dev,
"DMA %d timed-out during reading of 0x%llx\n",
dma_id, addr);
return -EIO;
}
err_cause = RREG32(mmDMA0_CORE_ERR_CAUSE + dma_offset);
if (err_cause) {
dev_err(hdev->dev, "DMA Failed, cause 0x%x\n", err_cause);
dev_dbg(hdev->dev,
"Clearing DMA0 engine from errors (cause 0x%x)\n",
err_cause);
WREG32(mmDMA0_CORE_ERR_CAUSE + dma_offset, err_cause);
return -EIO;
}
return 0;
}
static int gaudi_debugfs_read_dma(struct hl_device *hdev, u64 addr, u32 size,
void *blob_addr)
{
u32 dma_core_sts0, err_cause, cfg1, size_left, pos, size_to_dma;
u32 qm_glbl_sts0, qm_cgm_sts;
u64 dma_offset, qm_offset;
dma_addr_t dma_addr;
void *kernel_addr;
bool is_eng_idle;
int rc = 0, dma_id;
kernel_addr = hl_asic_dma_alloc_coherent(hdev, SZ_2M, &dma_addr, GFP_KERNEL | __GFP_ZERO);
if (!kernel_addr)
return -ENOMEM;
hdev->asic_funcs->hw_queues_lock(hdev);
dma_id = gaudi_dma_assignment[GAUDI_PCI_DMA_1];
dma_offset = dma_id * DMA_CORE_OFFSET;
qm_offset = dma_id * DMA_QMAN_OFFSET;
dma_core_sts0 = RREG32(mmDMA0_CORE_STS0 + dma_offset);
qm_glbl_sts0 = RREG32(mmDMA0_QM_GLBL_STS0 + qm_offset);
qm_cgm_sts = RREG32(mmDMA0_QM_CGM_STS + qm_offset);
is_eng_idle = IS_QM_IDLE(qm_glbl_sts0, qm_cgm_sts) &&
IS_DMA_IDLE(dma_core_sts0);
if (!is_eng_idle) {
dma_id = gaudi_dma_assignment[GAUDI_PCI_DMA_2];
dma_offset = dma_id * DMA_CORE_OFFSET;
qm_offset = dma_id * DMA_QMAN_OFFSET;
dma_core_sts0 = RREG32(mmDMA0_CORE_STS0 + dma_offset);
qm_glbl_sts0 = RREG32(mmDMA0_QM_GLBL_STS0 + qm_offset);
qm_cgm_sts = RREG32(mmDMA0_QM_CGM_STS + qm_offset);
is_eng_idle = IS_QM_IDLE(qm_glbl_sts0, qm_cgm_sts) &&
IS_DMA_IDLE(dma_core_sts0);
if (!is_eng_idle) {
dev_err_ratelimited(hdev->dev,
"Can't read via DMA because it is BUSY\n");
rc = -EAGAIN;
goto out;
}
}
cfg1 = RREG32(mmDMA0_QM_GLBL_CFG1 + qm_offset);
WREG32(mmDMA0_QM_GLBL_CFG1 + qm_offset,
0xF << DMA0_QM_GLBL_CFG1_CP_STOP_SHIFT);
WREG32_OR(mmDMA0_CORE_PROT + dma_offset, BIT(DMA0_CORE_PROT_VAL_SHIFT));
err_cause = RREG32(mmDMA0_CORE_ERR_CAUSE + dma_offset);
if (err_cause) {
dev_dbg(hdev->dev,
"Clearing DMA0 engine from errors (cause 0x%x)\n",
err_cause);
WREG32(mmDMA0_CORE_ERR_CAUSE + dma_offset, err_cause);
}
pos = 0;
size_left = size;
size_to_dma = SZ_2M;
while (size_left > 0) {
if (size_left < SZ_2M)
size_to_dma = size_left;
rc = gaudi_dma_core_transfer(hdev, dma_id, addr, size_to_dma,
dma_addr);
if (rc)
break;
memcpy(blob_addr + pos, kernel_addr, size_to_dma);
if (size_left <= SZ_2M)
break;
pos += SZ_2M;
addr += SZ_2M;
size_left -= SZ_2M;
}
WREG32_AND(mmDMA0_CORE_PROT + dma_offset,
~BIT(DMA0_CORE_PROT_VAL_SHIFT));
WREG32(mmDMA0_QM_GLBL_CFG1 + qm_offset, cfg1);
out:
hdev->asic_funcs->hw_queues_unlock(hdev);
hl_asic_dma_free_coherent(hdev, SZ_2M, kernel_addr, dma_addr);
return rc;
}
static u64 gaudi_read_pte(struct hl_device *hdev, u64 addr)
{
struct gaudi_device *gaudi = hdev->asic_specific;
if (hdev->reset_info.hard_reset_pending)
return U64_MAX;
return readq(hdev->pcie_bar[HBM_BAR_ID] +
(addr - gaudi->hbm_bar_cur_addr));
}
static void gaudi_write_pte(struct hl_device *hdev, u64 addr, u64 val)
{
struct gaudi_device *gaudi = hdev->asic_specific;
if (hdev->reset_info.hard_reset_pending)
return;
writeq(val, hdev->pcie_bar[HBM_BAR_ID] +
(addr - gaudi->hbm_bar_cur_addr));
}
void gaudi_mmu_prepare_reg(struct hl_device *hdev, u64 reg, u32 asid)
{
WREG32_AND(reg, ~0x7FF);
WREG32_OR(reg, asid);
}
static void gaudi_mmu_prepare(struct hl_device *hdev, u32 asid)
{
struct gaudi_device *gaudi = hdev->asic_specific;
if (!(gaudi->hw_cap_initialized & HW_CAP_MMU))
return;
if (asid & ~DMA0_QM_GLBL_NON_SECURE_PROPS_0_ASID_MASK) {
dev_crit(hdev->dev, "asid %u is too big\n", asid);
return;
}
gaudi_mmu_prepare_reg(hdev, mmDMA0_QM_GLBL_NON_SECURE_PROPS_0, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA0_QM_GLBL_NON_SECURE_PROPS_1, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA0_QM_GLBL_NON_SECURE_PROPS_2, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA0_QM_GLBL_NON_SECURE_PROPS_3, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA0_QM_GLBL_NON_SECURE_PROPS_4, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA1_QM_GLBL_NON_SECURE_PROPS_0, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA1_QM_GLBL_NON_SECURE_PROPS_1, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA1_QM_GLBL_NON_SECURE_PROPS_2, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA1_QM_GLBL_NON_SECURE_PROPS_3, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA1_QM_GLBL_NON_SECURE_PROPS_4, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA2_QM_GLBL_NON_SECURE_PROPS_0, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA2_QM_GLBL_NON_SECURE_PROPS_1, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA2_QM_GLBL_NON_SECURE_PROPS_2, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA2_QM_GLBL_NON_SECURE_PROPS_3, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA2_QM_GLBL_NON_SECURE_PROPS_4, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA3_QM_GLBL_NON_SECURE_PROPS_0, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA3_QM_GLBL_NON_SECURE_PROPS_1, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA3_QM_GLBL_NON_SECURE_PROPS_2, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA3_QM_GLBL_NON_SECURE_PROPS_3, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA3_QM_GLBL_NON_SECURE_PROPS_4, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA4_QM_GLBL_NON_SECURE_PROPS_0, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA4_QM_GLBL_NON_SECURE_PROPS_1, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA4_QM_GLBL_NON_SECURE_PROPS_2, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA4_QM_GLBL_NON_SECURE_PROPS_3, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA4_QM_GLBL_NON_SECURE_PROPS_4, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA5_QM_GLBL_NON_SECURE_PROPS_0, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA5_QM_GLBL_NON_SECURE_PROPS_1, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA5_QM_GLBL_NON_SECURE_PROPS_2, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA5_QM_GLBL_NON_SECURE_PROPS_3, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA5_QM_GLBL_NON_SECURE_PROPS_4, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA6_QM_GLBL_NON_SECURE_PROPS_0, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA6_QM_GLBL_NON_SECURE_PROPS_1, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA6_QM_GLBL_NON_SECURE_PROPS_2, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA6_QM_GLBL_NON_SECURE_PROPS_3, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA6_QM_GLBL_NON_SECURE_PROPS_4, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA7_QM_GLBL_NON_SECURE_PROPS_0, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA7_QM_GLBL_NON_SECURE_PROPS_1, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA7_QM_GLBL_NON_SECURE_PROPS_2, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA7_QM_GLBL_NON_SECURE_PROPS_3, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA7_QM_GLBL_NON_SECURE_PROPS_4, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA0_CORE_NON_SECURE_PROPS, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA1_CORE_NON_SECURE_PROPS, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA2_CORE_NON_SECURE_PROPS, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA3_CORE_NON_SECURE_PROPS, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA4_CORE_NON_SECURE_PROPS, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA5_CORE_NON_SECURE_PROPS, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA6_CORE_NON_SECURE_PROPS, asid);
gaudi_mmu_prepare_reg(hdev, mmDMA7_CORE_NON_SECURE_PROPS, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC0_QM_GLBL_NON_SECURE_PROPS_0, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC0_QM_GLBL_NON_SECURE_PROPS_1, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC0_QM_GLBL_NON_SECURE_PROPS_2, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC0_QM_GLBL_NON_SECURE_PROPS_3, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC0_QM_GLBL_NON_SECURE_PROPS_4, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC0_CFG_ARUSER_LO, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC0_CFG_AWUSER_LO, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC1_QM_GLBL_NON_SECURE_PROPS_0, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC1_QM_GLBL_NON_SECURE_PROPS_1, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC1_QM_GLBL_NON_SECURE_PROPS_2, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC1_QM_GLBL_NON_SECURE_PROPS_3, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC1_QM_GLBL_NON_SECURE_PROPS_4, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC1_CFG_ARUSER_LO, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC1_CFG_AWUSER_LO, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC2_QM_GLBL_NON_SECURE_PROPS_0, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC2_QM_GLBL_NON_SECURE_PROPS_1, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC2_QM_GLBL_NON_SECURE_PROPS_2, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC2_QM_GLBL_NON_SECURE_PROPS_3, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC2_QM_GLBL_NON_SECURE_PROPS_4, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC2_CFG_ARUSER_LO, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC2_CFG_AWUSER_LO, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC3_QM_GLBL_NON_SECURE_PROPS_0, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC3_QM_GLBL_NON_SECURE_PROPS_1, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC3_QM_GLBL_NON_SECURE_PROPS_2, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC3_QM_GLBL_NON_SECURE_PROPS_3, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC3_QM_GLBL_NON_SECURE_PROPS_4, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC3_CFG_ARUSER_LO, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC3_CFG_AWUSER_LO, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC4_QM_GLBL_NON_SECURE_PROPS_0, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC4_QM_GLBL_NON_SECURE_PROPS_1, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC4_QM_GLBL_NON_SECURE_PROPS_2, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC4_QM_GLBL_NON_SECURE_PROPS_3, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC4_QM_GLBL_NON_SECURE_PROPS_4, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC4_CFG_ARUSER_LO, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC4_CFG_AWUSER_LO, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC5_QM_GLBL_NON_SECURE_PROPS_0, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC5_QM_GLBL_NON_SECURE_PROPS_1, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC5_QM_GLBL_NON_SECURE_PROPS_2, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC5_QM_GLBL_NON_SECURE_PROPS_3, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC5_QM_GLBL_NON_SECURE_PROPS_4, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC5_CFG_ARUSER_LO, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC5_CFG_AWUSER_LO, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC6_QM_GLBL_NON_SECURE_PROPS_0, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC6_QM_GLBL_NON_SECURE_PROPS_1, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC6_QM_GLBL_NON_SECURE_PROPS_2, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC6_QM_GLBL_NON_SECURE_PROPS_3, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC6_QM_GLBL_NON_SECURE_PROPS_4, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC6_CFG_ARUSER_LO, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC6_CFG_AWUSER_LO, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC7_QM_GLBL_NON_SECURE_PROPS_0, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC7_QM_GLBL_NON_SECURE_PROPS_1, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC7_QM_GLBL_NON_SECURE_PROPS_2, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC7_QM_GLBL_NON_SECURE_PROPS_3, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC7_QM_GLBL_NON_SECURE_PROPS_4, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC7_CFG_ARUSER_LO, asid);
gaudi_mmu_prepare_reg(hdev, mmTPC7_CFG_AWUSER_LO, asid);
gaudi_mmu_prepare_reg(hdev, mmMME0_QM_GLBL_NON_SECURE_PROPS_0, asid);
gaudi_mmu_prepare_reg(hdev, mmMME0_QM_GLBL_NON_SECURE_PROPS_1, asid);
gaudi_mmu_prepare_reg(hdev, mmMME0_QM_GLBL_NON_SECURE_PROPS_2, asid);
gaudi_mmu_prepare_reg(hdev, mmMME0_QM_GLBL_NON_SECURE_PROPS_3, asid);
gaudi_mmu_prepare_reg(hdev, mmMME0_QM_GLBL_NON_SECURE_PROPS_4, asid);
gaudi_mmu_prepare_reg(hdev, mmMME2_QM_GLBL_NON_SECURE_PROPS_0, asid);
gaudi_mmu_prepare_reg(hdev, mmMME2_QM_GLBL_NON_SECURE_PROPS_1, asid);
gaudi_mmu_prepare_reg(hdev, mmMME2_QM_GLBL_NON_SECURE_PROPS_2, asid);
gaudi_mmu_prepare_reg(hdev, mmMME2_QM_GLBL_NON_SECURE_PROPS_3, asid);
gaudi_mmu_prepare_reg(hdev, mmMME2_QM_GLBL_NON_SECURE_PROPS_4, asid);
gaudi_mmu_prepare_reg(hdev, mmMME0_SBAB_ARUSER0, asid);
gaudi_mmu_prepare_reg(hdev, mmMME0_SBAB_ARUSER1, asid);
gaudi_mmu_prepare_reg(hdev, mmMME1_SBAB_ARUSER0, asid);
gaudi_mmu_prepare_reg(hdev, mmMME1_SBAB_ARUSER1, asid);
gaudi_mmu_prepare_reg(hdev, mmMME2_SBAB_ARUSER0, asid);
gaudi_mmu_prepare_reg(hdev, mmMME2_SBAB_ARUSER1, asid);
gaudi_mmu_prepare_reg(hdev, mmMME3_SBAB_ARUSER0, asid);
gaudi_mmu_prepare_reg(hdev, mmMME3_SBAB_ARUSER1, asid);
gaudi_mmu_prepare_reg(hdev, mmMME0_ACC_WBC, asid);
gaudi_mmu_prepare_reg(hdev, mmMME1_ACC_WBC, asid);
gaudi_mmu_prepare_reg(hdev, mmMME2_ACC_WBC, asid);
gaudi_mmu_prepare_reg(hdev, mmMME3_ACC_WBC, asid);
if (gaudi->hw_cap_initialized & HW_CAP_NIC0) {
gaudi_mmu_prepare_reg(hdev, mmNIC0_QM0_GLBL_NON_SECURE_PROPS_0,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC0_QM0_GLBL_NON_SECURE_PROPS_1,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC0_QM0_GLBL_NON_SECURE_PROPS_2,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC0_QM0_GLBL_NON_SECURE_PROPS_3,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC0_QM0_GLBL_NON_SECURE_PROPS_4,
asid);
}
if (gaudi->hw_cap_initialized & HW_CAP_NIC1) {
gaudi_mmu_prepare_reg(hdev, mmNIC0_QM1_GLBL_NON_SECURE_PROPS_0,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC0_QM1_GLBL_NON_SECURE_PROPS_1,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC0_QM1_GLBL_NON_SECURE_PROPS_2,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC0_QM1_GLBL_NON_SECURE_PROPS_3,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC0_QM1_GLBL_NON_SECURE_PROPS_4,
asid);
}
if (gaudi->hw_cap_initialized & HW_CAP_NIC2) {
gaudi_mmu_prepare_reg(hdev, mmNIC1_QM0_GLBL_NON_SECURE_PROPS_0,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC1_QM0_GLBL_NON_SECURE_PROPS_1,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC1_QM0_GLBL_NON_SECURE_PROPS_2,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC1_QM0_GLBL_NON_SECURE_PROPS_3,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC1_QM0_GLBL_NON_SECURE_PROPS_4,
asid);
}
if (gaudi->hw_cap_initialized & HW_CAP_NIC3) {
gaudi_mmu_prepare_reg(hdev, mmNIC1_QM1_GLBL_NON_SECURE_PROPS_0,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC1_QM1_GLBL_NON_SECURE_PROPS_1,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC1_QM1_GLBL_NON_SECURE_PROPS_2,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC1_QM1_GLBL_NON_SECURE_PROPS_3,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC1_QM1_GLBL_NON_SECURE_PROPS_4,
asid);
}
if (gaudi->hw_cap_initialized & HW_CAP_NIC4) {
gaudi_mmu_prepare_reg(hdev, mmNIC2_QM0_GLBL_NON_SECURE_PROPS_0,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC2_QM0_GLBL_NON_SECURE_PROPS_1,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC2_QM0_GLBL_NON_SECURE_PROPS_2,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC2_QM0_GLBL_NON_SECURE_PROPS_3,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC2_QM0_GLBL_NON_SECURE_PROPS_4,
asid);
}
if (gaudi->hw_cap_initialized & HW_CAP_NIC5) {
gaudi_mmu_prepare_reg(hdev, mmNIC2_QM1_GLBL_NON_SECURE_PROPS_0,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC2_QM1_GLBL_NON_SECURE_PROPS_1,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC2_QM1_GLBL_NON_SECURE_PROPS_2,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC2_QM1_GLBL_NON_SECURE_PROPS_3,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC2_QM1_GLBL_NON_SECURE_PROPS_4,
asid);
}
if (gaudi->hw_cap_initialized & HW_CAP_NIC6) {
gaudi_mmu_prepare_reg(hdev, mmNIC3_QM0_GLBL_NON_SECURE_PROPS_0,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC3_QM0_GLBL_NON_SECURE_PROPS_1,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC3_QM0_GLBL_NON_SECURE_PROPS_2,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC3_QM0_GLBL_NON_SECURE_PROPS_3,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC3_QM0_GLBL_NON_SECURE_PROPS_4,
asid);
}
if (gaudi->hw_cap_initialized & HW_CAP_NIC7) {
gaudi_mmu_prepare_reg(hdev, mmNIC3_QM1_GLBL_NON_SECURE_PROPS_0,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC3_QM1_GLBL_NON_SECURE_PROPS_1,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC3_QM1_GLBL_NON_SECURE_PROPS_2,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC3_QM1_GLBL_NON_SECURE_PROPS_3,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC3_QM1_GLBL_NON_SECURE_PROPS_4,
asid);
}
if (gaudi->hw_cap_initialized & HW_CAP_NIC8) {
gaudi_mmu_prepare_reg(hdev, mmNIC4_QM0_GLBL_NON_SECURE_PROPS_0,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC4_QM0_GLBL_NON_SECURE_PROPS_1,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC4_QM0_GLBL_NON_SECURE_PROPS_2,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC4_QM0_GLBL_NON_SECURE_PROPS_3,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC4_QM0_GLBL_NON_SECURE_PROPS_4,
asid);
}
if (gaudi->hw_cap_initialized & HW_CAP_NIC9) {
gaudi_mmu_prepare_reg(hdev, mmNIC4_QM1_GLBL_NON_SECURE_PROPS_0,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC4_QM1_GLBL_NON_SECURE_PROPS_1,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC4_QM1_GLBL_NON_SECURE_PROPS_2,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC4_QM1_GLBL_NON_SECURE_PROPS_3,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC4_QM1_GLBL_NON_SECURE_PROPS_4,
asid);
}
gaudi_mmu_prepare_reg(hdev, mmPSOC_GLOBAL_CONF_TRACE_ARUSER, asid);
gaudi_mmu_prepare_reg(hdev, mmPSOC_GLOBAL_CONF_TRACE_AWUSER, asid);
}
static int gaudi_send_job_on_qman0(struct hl_device *hdev,
struct hl_cs_job *job)
{
struct packet_msg_prot *fence_pkt;
u32 *fence_ptr;
dma_addr_t fence_dma_addr;
struct hl_cb *cb;
u32 tmp, timeout, dma_offset;
int rc;
if (hdev->pldm)
timeout = GAUDI_PLDM_QMAN0_TIMEOUT_USEC;
else
timeout = HL_DEVICE_TIMEOUT_USEC;
fence_ptr = hl_asic_dma_pool_zalloc(hdev, 4, GFP_KERNEL, &fence_dma_addr);
if (!fence_ptr) {
dev_err(hdev->dev,
"Failed to allocate fence memory for QMAN0\n");
return -ENOMEM;
}
cb = job->patched_cb;
fence_pkt = cb->kernel_address +
job->job_cb_size - sizeof(struct packet_msg_prot);
tmp = FIELD_PREP(GAUDI_PKT_CTL_OPCODE_MASK, PACKET_MSG_PROT);
tmp |= FIELD_PREP(GAUDI_PKT_CTL_EB_MASK, 1);
tmp |= FIELD_PREP(GAUDI_PKT_CTL_MB_MASK, 1);
fence_pkt->ctl = cpu_to_le32(tmp);
fence_pkt->value = cpu_to_le32(GAUDI_QMAN0_FENCE_VAL);
fence_pkt->addr = cpu_to_le64(fence_dma_addr);
dma_offset = gaudi_dma_assignment[GAUDI_PCI_DMA_1] * DMA_CORE_OFFSET;
WREG32(mmDMA0_CORE_PROT + dma_offset,
BIT(DMA0_CORE_PROT_ERR_VAL_SHIFT) | BIT(DMA0_CORE_PROT_VAL_SHIFT));
rc = hl_hw_queue_send_cb_no_cmpl(hdev, GAUDI_QUEUE_ID_DMA_0_0,
job->job_cb_size, cb->bus_address);
if (rc) {
dev_err(hdev->dev, "Failed to send CB on QMAN0, %d\n", rc);
goto free_fence_ptr;
}
rc = hl_poll_timeout_memory(hdev, fence_ptr, tmp,
(tmp == GAUDI_QMAN0_FENCE_VAL), 1000,
timeout, true);
hl_hw_queue_inc_ci_kernel(hdev, GAUDI_QUEUE_ID_DMA_0_0);
if (rc == -ETIMEDOUT) {
dev_err(hdev->dev, "QMAN0 Job timeout (0x%x)\n", tmp);
goto free_fence_ptr;
}
free_fence_ptr:
WREG32(mmDMA0_CORE_PROT + dma_offset, BIT(DMA0_CORE_PROT_ERR_VAL_SHIFT));
hl_asic_dma_pool_free(hdev, (void *) fence_ptr, fence_dma_addr);
return rc;
}
static void gaudi_get_event_desc(u16 event_type, char *desc, size_t size)
{
if (event_type >= GAUDI_EVENT_SIZE)
goto event_not_supported;
if (!gaudi_irq_map_table[event_type].valid)
goto event_not_supported;
snprintf(desc, size, gaudi_irq_map_table[event_type].name);
return;
event_not_supported:
snprintf(desc, size, "N/A");
}
static const char *gaudi_get_razwi_initiator_dma_name(struct hl_device *hdev, u32 x_y,
bool is_write, u16 *engine_id_1,
u16 *engine_id_2)
{
u32 dma_id[2], dma_offset, err_cause[2], mask, i;
mask = is_write ? DMA0_CORE_ERR_CAUSE_HBW_WR_ERR_MASK :
DMA0_CORE_ERR_CAUSE_HBW_RD_ERR_MASK;
switch (x_y) {
case RAZWI_INITIATOR_ID_X_Y_DMA_IF_W_S_0:
case RAZWI_INITIATOR_ID_X_Y_DMA_IF_W_S_1:
dma_id[0] = 0;
dma_id[1] = 2;
break;
case RAZWI_INITIATOR_ID_X_Y_DMA_IF_E_S_0:
case RAZWI_INITIATOR_ID_X_Y_DMA_IF_E_S_1:
dma_id[0] = 1;
dma_id[1] = 3;
break;
case RAZWI_INITIATOR_ID_X_Y_DMA_IF_W_N_0:
case RAZWI_INITIATOR_ID_X_Y_DMA_IF_W_N_1:
dma_id[0] = 4;
dma_id[1] = 6;
break;
case RAZWI_INITIATOR_ID_X_Y_DMA_IF_E_N_0:
case RAZWI_INITIATOR_ID_X_Y_DMA_IF_E_N_1:
dma_id[0] = 5;
dma_id[1] = 7;
break;
default:
goto unknown_initiator;
}
for (i = 0 ; i < 2 ; i++) {
dma_offset = dma_id[i] * DMA_CORE_OFFSET;
err_cause[i] = RREG32(mmDMA0_CORE_ERR_CAUSE + dma_offset);
}
switch (x_y) {
case RAZWI_INITIATOR_ID_X_Y_DMA_IF_W_S_0:
case RAZWI_INITIATOR_ID_X_Y_DMA_IF_W_S_1:
if ((err_cause[0] & mask) && !(err_cause[1] & mask)) {
*engine_id_1 = GAUDI_ENGINE_ID_DMA_0;
return "DMA0";
} else if (!(err_cause[0] & mask) && (err_cause[1] & mask)) {
*engine_id_1 = GAUDI_ENGINE_ID_DMA_2;
return "DMA2";
} else {
*engine_id_1 = GAUDI_ENGINE_ID_DMA_0;
*engine_id_2 = GAUDI_ENGINE_ID_DMA_2;
return "DMA0 or DMA2";
}
case RAZWI_INITIATOR_ID_X_Y_DMA_IF_E_S_0:
case RAZWI_INITIATOR_ID_X_Y_DMA_IF_E_S_1:
if ((err_cause[0] & mask) && !(err_cause[1] & mask)) {
*engine_id_1 = GAUDI_ENGINE_ID_DMA_1;
return "DMA1";
} else if (!(err_cause[0] & mask) && (err_cause[1] & mask)) {
*engine_id_1 = GAUDI_ENGINE_ID_DMA_3;
return "DMA3";
} else {
*engine_id_1 = GAUDI_ENGINE_ID_DMA_1;
*engine_id_2 = GAUDI_ENGINE_ID_DMA_3;
return "DMA1 or DMA3";
}
case RAZWI_INITIATOR_ID_X_Y_DMA_IF_W_N_0:
case RAZWI_INITIATOR_ID_X_Y_DMA_IF_W_N_1:
if ((err_cause[0] & mask) && !(err_cause[1] & mask)) {
*engine_id_1 = GAUDI_ENGINE_ID_DMA_4;
return "DMA4";
} else if (!(err_cause[0] & mask) && (err_cause[1] & mask)) {
*engine_id_1 = GAUDI_ENGINE_ID_DMA_6;
return "DMA6";
} else {
*engine_id_1 = GAUDI_ENGINE_ID_DMA_4;
*engine_id_2 = GAUDI_ENGINE_ID_DMA_6;
return "DMA4 or DMA6";
}
case RAZWI_INITIATOR_ID_X_Y_DMA_IF_E_N_0:
case RAZWI_INITIATOR_ID_X_Y_DMA_IF_E_N_1:
if ((err_cause[0] & mask) && !(err_cause[1] & mask)) {
*engine_id_1 = GAUDI_ENGINE_ID_DMA_5;
return "DMA5";
} else if (!(err_cause[0] & mask) && (err_cause[1] & mask)) {
*engine_id_1 = GAUDI_ENGINE_ID_DMA_7;
return "DMA7";
} else {
*engine_id_1 = GAUDI_ENGINE_ID_DMA_5;
*engine_id_2 = GAUDI_ENGINE_ID_DMA_7;
return "DMA5 or DMA7";
}
}
unknown_initiator:
return "unknown initiator";
}
static const char *gaudi_get_razwi_initiator_name(struct hl_device *hdev, bool is_write,
u16 *engine_id_1, u16 *engine_id_2)
{
u32 val, x_y, axi_id;
val = is_write ? RREG32(mmMMU_UP_RAZWI_WRITE_ID) :
RREG32(mmMMU_UP_RAZWI_READ_ID);
x_y = val & ((RAZWI_INITIATOR_Y_MASK << RAZWI_INITIATOR_Y_SHIFT) |
(RAZWI_INITIATOR_X_MASK << RAZWI_INITIATOR_X_SHIFT));
axi_id = val & (RAZWI_INITIATOR_AXI_ID_MASK <<
RAZWI_INITIATOR_AXI_ID_SHIFT);
switch (x_y) {
case RAZWI_INITIATOR_ID_X_Y_TPC0_NIC0:
if (axi_id == RAZWI_INITIATOR_ID_AXI_ID(AXI_ID_TPC)) {
*engine_id_1 = GAUDI_ENGINE_ID_TPC_0;
return "TPC0";
}
if (axi_id == RAZWI_INITIATOR_ID_AXI_ID(AXI_ID_NIC)) {
*engine_id_1 = GAUDI_ENGINE_ID_NIC_0;
return "NIC0";
}
break;
case RAZWI_INITIATOR_ID_X_Y_TPC1:
*engine_id_1 = GAUDI_ENGINE_ID_TPC_1;
return "TPC1";
case RAZWI_INITIATOR_ID_X_Y_MME0_0:
case RAZWI_INITIATOR_ID_X_Y_MME0_1:
*engine_id_1 = GAUDI_ENGINE_ID_MME_0;
return "MME0";
case RAZWI_INITIATOR_ID_X_Y_MME1_0:
case RAZWI_INITIATOR_ID_X_Y_MME1_1:
*engine_id_1 = GAUDI_ENGINE_ID_MME_1;
return "MME1";
case RAZWI_INITIATOR_ID_X_Y_TPC2:
*engine_id_1 = GAUDI_ENGINE_ID_TPC_2;
return "TPC2";
case RAZWI_INITIATOR_ID_X_Y_TPC3_PCI_CPU_PSOC:
if (axi_id == RAZWI_INITIATOR_ID_AXI_ID(AXI_ID_TPC)) {
*engine_id_1 = GAUDI_ENGINE_ID_TPC_3;
return "TPC3";
}
if (axi_id == RAZWI_INITIATOR_ID_AXI_ID(AXI_ID_PCI))
return "PCI";
if (axi_id == RAZWI_INITIATOR_ID_AXI_ID(AXI_ID_CPU))
return "CPU";
if (axi_id == RAZWI_INITIATOR_ID_AXI_ID(AXI_ID_PSOC))
return "PSOC";
break;
case RAZWI_INITIATOR_ID_X_Y_DMA_IF_W_S_0:
case RAZWI_INITIATOR_ID_X_Y_DMA_IF_W_S_1:
case RAZWI_INITIATOR_ID_X_Y_DMA_IF_E_S_0:
case RAZWI_INITIATOR_ID_X_Y_DMA_IF_E_S_1:
case RAZWI_INITIATOR_ID_X_Y_DMA_IF_W_N_0:
case RAZWI_INITIATOR_ID_X_Y_DMA_IF_W_N_1:
case RAZWI_INITIATOR_ID_X_Y_DMA_IF_E_N_0:
case RAZWI_INITIATOR_ID_X_Y_DMA_IF_E_N_1:
return gaudi_get_razwi_initiator_dma_name(hdev, x_y, is_write,
engine_id_1, engine_id_2);
case RAZWI_INITIATOR_ID_X_Y_TPC4_NIC1_NIC2:
if (axi_id == RAZWI_INITIATOR_ID_AXI_ID(AXI_ID_TPC)) {
*engine_id_1 = GAUDI_ENGINE_ID_TPC_4;
return "TPC4";
}
if (axi_id == RAZWI_INITIATOR_ID_AXI_ID(AXI_ID_NIC)) {
*engine_id_1 = GAUDI_ENGINE_ID_NIC_1;
return "NIC1";
}
if (axi_id == RAZWI_INITIATOR_ID_AXI_ID(AXI_ID_NIC_FT)) {
*engine_id_1 = GAUDI_ENGINE_ID_NIC_2;
return "NIC2";
}
break;
case RAZWI_INITIATOR_ID_X_Y_TPC5:
*engine_id_1 = GAUDI_ENGINE_ID_TPC_5;
return "TPC5";
case RAZWI_INITIATOR_ID_X_Y_MME2_0:
case RAZWI_INITIATOR_ID_X_Y_MME2_1:
*engine_id_1 = GAUDI_ENGINE_ID_MME_2;
return "MME2";
case RAZWI_INITIATOR_ID_X_Y_MME3_0:
case RAZWI_INITIATOR_ID_X_Y_MME3_1:
*engine_id_1 = GAUDI_ENGINE_ID_MME_3;
return "MME3";
case RAZWI_INITIATOR_ID_X_Y_TPC6:
*engine_id_1 = GAUDI_ENGINE_ID_TPC_6;
return "TPC6";
case RAZWI_INITIATOR_ID_X_Y_TPC7_NIC4_NIC5:
if (axi_id == RAZWI_INITIATOR_ID_AXI_ID(AXI_ID_TPC)) {
*engine_id_1 = GAUDI_ENGINE_ID_TPC_7;
return "TPC7";
}
if (axi_id == RAZWI_INITIATOR_ID_AXI_ID(AXI_ID_NIC)) {
*engine_id_1 = GAUDI_ENGINE_ID_NIC_4;
return "NIC4";
}
if (axi_id == RAZWI_INITIATOR_ID_AXI_ID(AXI_ID_NIC_FT)) {
*engine_id_1 = GAUDI_ENGINE_ID_NIC_5;
return "NIC5";
}
break;
default:
break;
}
dev_err(hdev->dev,
"Unknown RAZWI initiator ID 0x%x [Y=%d, X=%d, AXI_ID=%d]\n",
val,
(val >> RAZWI_INITIATOR_Y_SHIFT) & RAZWI_INITIATOR_Y_MASK,
(val >> RAZWI_INITIATOR_X_SHIFT) & RAZWI_INITIATOR_X_MASK,
(val >> RAZWI_INITIATOR_AXI_ID_SHIFT) &
RAZWI_INITIATOR_AXI_ID_MASK);
return "unknown initiator";
}
static void gaudi_print_and_get_razwi_info(struct hl_device *hdev, u16 *engine_id_1,
u16 *engine_id_2, bool *is_read, bool *is_write)
{
if (RREG32(mmMMU_UP_RAZWI_WRITE_VLD)) {
dev_err_ratelimited(hdev->dev,
"RAZWI event caused by illegal write of %s\n",
gaudi_get_razwi_initiator_name(hdev, true, engine_id_1, engine_id_2));
WREG32(mmMMU_UP_RAZWI_WRITE_VLD, 0);
*is_write = true;
}
if (RREG32(mmMMU_UP_RAZWI_READ_VLD)) {
dev_err_ratelimited(hdev->dev,
"RAZWI event caused by illegal read of %s\n",
gaudi_get_razwi_initiator_name(hdev, false, engine_id_1, engine_id_2));
WREG32(mmMMU_UP_RAZWI_READ_VLD, 0);
*is_read = true;
}
}
static void gaudi_print_and_get_mmu_error_info(struct hl_device *hdev, u64 *addr, u64 *event_mask)
{
struct gaudi_device *gaudi = hdev->asic_specific;
u32 val;
if (!(gaudi->hw_cap_initialized & HW_CAP_MMU))
return;
val = RREG32(mmMMU_UP_PAGE_ERROR_CAPTURE);
if (val & MMU_UP_PAGE_ERROR_CAPTURE_ENTRY_VALID_MASK) {
*addr = val & MMU_UP_PAGE_ERROR_CAPTURE_VA_49_32_MASK;
*addr <<= 32;
*addr |= RREG32(mmMMU_UP_PAGE_ERROR_CAPTURE_VA);
dev_err_ratelimited(hdev->dev, "MMU page fault on va 0x%llx\n", *addr);
hl_handle_page_fault(hdev, *addr, 0, true, event_mask);
WREG32(mmMMU_UP_PAGE_ERROR_CAPTURE, 0);
}
val = RREG32(mmMMU_UP_ACCESS_ERROR_CAPTURE);
if (val & MMU_UP_ACCESS_ERROR_CAPTURE_ENTRY_VALID_MASK) {
*addr = val & MMU_UP_ACCESS_ERROR_CAPTURE_VA_49_32_MASK;
*addr <<= 32;
*addr |= RREG32(mmMMU_UP_ACCESS_ERROR_CAPTURE_VA);
dev_err_ratelimited(hdev->dev, "MMU access error on va 0x%llx\n", *addr);
WREG32(mmMMU_UP_ACCESS_ERROR_CAPTURE, 0);
}
}
static int gaudi_extract_ecc_info(struct hl_device *hdev,
struct ecc_info_extract_params *params, u64 *ecc_address,
u64 *ecc_syndrom, u8 *memory_wrapper_idx)
{
u32 i, num_mem_regs, reg, err_bit;
u64 err_addr, err_word = 0;
num_mem_regs = params->num_memories / 32 +
((params->num_memories % 32) ? 1 : 0);
if (params->block_address >= CFG_BASE)
params->block_address -= CFG_BASE;
if (params->derr)
err_addr = params->block_address + GAUDI_ECC_DERR0_OFFSET;
else
err_addr = params->block_address + GAUDI_ECC_SERR0_OFFSET;
*memory_wrapper_idx = 0xFF;
for (i = 0 ; i < num_mem_regs ; i++) {
err_addr += i * 4;
err_word = RREG32(err_addr);
if (err_word) {
err_bit = __ffs(err_word);
*memory_wrapper_idx = err_bit + (32 * i);
break;
}
}
if (*memory_wrapper_idx == 0xFF) {
dev_err(hdev->dev, "ECC error information cannot be found\n");
return -EINVAL;
}
WREG32(params->block_address + GAUDI_ECC_MEM_SEL_OFFSET,
*memory_wrapper_idx);
*ecc_address =
RREG32(params->block_address + GAUDI_ECC_ADDRESS_OFFSET);
*ecc_syndrom =
RREG32(params->block_address + GAUDI_ECC_SYNDROME_OFFSET);
reg = RREG32(params->block_address + GAUDI_ECC_MEM_INFO_CLR_OFFSET);
if (params->derr)
reg |= FIELD_PREP(GAUDI_ECC_MEM_INFO_CLR_DERR_MASK, 1);
else
reg |= FIELD_PREP(GAUDI_ECC_MEM_INFO_CLR_SERR_MASK, 1);
WREG32(params->block_address + GAUDI_ECC_MEM_INFO_CLR_OFFSET, reg);
return 0;
}
static inline u32 gaudi_queue_idx_dec(u32 idx, u32 q_len)
{
u32 mask = q_len - 1;
return (idx + q_len - 1) & mask;
}
static void gaudi_handle_sw_config_stream_data(struct hl_device *hdev, u32 stream,
u64 qman_base, u64 event_mask)
{
u64 cq_ptr_lo, cq_ptr_hi, cq_tsize, cq_ptr;
u32 cq_ptr_lo_off, size;
cq_ptr_lo_off = mmTPC0_QM_CQ_PTR_LO_1 - mmTPC0_QM_CQ_PTR_LO_0;
cq_ptr_lo = qman_base + (mmTPC0_QM_CQ_PTR_LO_0 - mmTPC0_QM_BASE) +
stream * cq_ptr_lo_off;
cq_ptr_hi = cq_ptr_lo +
(mmTPC0_QM_CQ_PTR_HI_0 - mmTPC0_QM_CQ_PTR_LO_0);
cq_tsize = cq_ptr_lo +
(mmTPC0_QM_CQ_TSIZE_0 - mmTPC0_QM_CQ_PTR_LO_0);
cq_ptr = (((u64) RREG32(cq_ptr_hi)) << 32) | RREG32(cq_ptr_lo);
size = RREG32(cq_tsize);
dev_info(hdev->dev, "stop on err: stream: %u, addr: %#llx, size: %u\n",
stream, cq_ptr, size);
if (event_mask & HL_NOTIFIER_EVENT_UNDEFINED_OPCODE) {
hdev->captured_err_info.undef_opcode.cq_addr = cq_ptr;
hdev->captured_err_info.undef_opcode.cq_size = size;
hdev->captured_err_info.undef_opcode.stream_id = stream;
}
}
static void gaudi_handle_last_pqes_on_err(struct hl_device *hdev, u32 qid_base,
u32 stream, u64 qman_base,
u64 event_mask,
bool pr_sw_conf)
{
u32 ci, qm_ci_stream_off, queue_len;
struct hl_hw_queue *q;
u64 pq_ci, addr[PQ_FETCHER_CACHE_SIZE];
int i;
q = &hdev->kernel_queues[qid_base + stream];
qm_ci_stream_off = mmTPC0_QM_PQ_CI_1 - mmTPC0_QM_PQ_CI_0;
pq_ci = qman_base + (mmTPC0_QM_PQ_CI_0 - mmTPC0_QM_BASE) +
stream * qm_ci_stream_off;
queue_len = (q->queue_type == QUEUE_TYPE_INT) ?
q->int_queue_len : HL_QUEUE_LENGTH;
hdev->asic_funcs->hw_queues_lock(hdev);
if (pr_sw_conf)
gaudi_handle_sw_config_stream_data(hdev, stream, qman_base, event_mask);
ci = RREG32(pq_ci);
ci = gaudi_queue_idx_dec(ci, queue_len);
memset(addr, 0, sizeof(addr));
for (i = 0; i < PQ_FETCHER_CACHE_SIZE; i++) {
struct hl_bd *bd;
u32 len;
bd = q->kernel_address;
bd += ci;
len = le32_to_cpu(bd->len);
if (!len)
break;
addr[i] = le64_to_cpu(bd->ptr);
dev_info(hdev->dev, "stop on err PQE(stream %u): ci: %u, addr: %#llx, size: %u\n",
stream, ci, addr[i], len);
ci = gaudi_queue_idx_dec(ci, queue_len);
}
if (event_mask & HL_NOTIFIER_EVENT_UNDEFINED_OPCODE) {
struct undefined_opcode_info *undef_opcode = &hdev->captured_err_info.undef_opcode;
u32 arr_idx = undef_opcode->cb_addr_streams_len;
if (arr_idx == 0) {
undef_opcode->timestamp = ktime_get();
undef_opcode->engine_id = gaudi_queue_id_to_engine_id[qid_base];
}
memcpy(undef_opcode->cb_addr_streams[arr_idx], addr, sizeof(addr));
undef_opcode->cb_addr_streams_len++;
}
hdev->asic_funcs->hw_queues_unlock(hdev);
}
static void handle_qman_data_on_err(struct hl_device *hdev, u32 qid_base,
u32 stream, u64 qman_base, u64 event_mask)
{
u32 i;
if (stream != QMAN_STREAMS) {
gaudi_handle_last_pqes_on_err(hdev, qid_base, stream,
qman_base, event_mask, true);
return;
}
gaudi_handle_sw_config_stream_data(hdev, stream, qman_base, event_mask);
for (i = 0; i < QMAN_STREAMS; i++)
gaudi_handle_last_pqes_on_err(hdev, qid_base, i,
qman_base, event_mask, false);
}
static void gaudi_handle_qman_err_generic(struct hl_device *hdev,
const char *qm_name,
u64 qman_base,
u32 qid_base,
u64 *event_mask)
{
u32 i, j, glbl_sts_val, arb_err_val, glbl_sts_clr_val;
u64 glbl_sts_addr, arb_err_addr;
char reg_desc[32];
glbl_sts_addr = qman_base + (mmTPC0_QM_GLBL_STS1_0 - mmTPC0_QM_BASE);
arb_err_addr = qman_base + (mmTPC0_QM_ARB_ERR_CAUSE - mmTPC0_QM_BASE);
for (i = 0 ; i < QMAN_STREAMS + 1 ; i++) {
glbl_sts_clr_val = 0;
glbl_sts_val = RREG32(glbl_sts_addr + 4 * i);
if (!glbl_sts_val)
continue;
if (i == QMAN_STREAMS)
snprintf(reg_desc, ARRAY_SIZE(reg_desc), "LowerCP");
else
snprintf(reg_desc, ARRAY_SIZE(reg_desc), "stream%u", i);
for (j = 0 ; j < GAUDI_NUM_OF_QM_ERR_CAUSE ; j++) {
if (glbl_sts_val & BIT(j)) {
dev_err_ratelimited(hdev->dev,
"%s %s. err cause: %s\n",
qm_name, reg_desc,
gaudi_qman_error_cause[j]);
glbl_sts_clr_val |= BIT(j);
}
}
if (glbl_sts_val & TPC0_QM_GLBL_STS1_CP_UNDEF_CMD_ERR_MASK &&
hdev->captured_err_info.undef_opcode.write_enable) {
memset(&hdev->captured_err_info.undef_opcode, 0,
sizeof(hdev->captured_err_info.undef_opcode));
hdev->captured_err_info.undef_opcode.write_enable = false;
*event_mask |= HL_NOTIFIER_EVENT_UNDEFINED_OPCODE;
}
if (!hdev->stop_on_err)
WREG32(glbl_sts_addr + 4 * i, glbl_sts_clr_val);
else
handle_qman_data_on_err(hdev, qid_base, i, qman_base, *event_mask);
}
arb_err_val = RREG32(arb_err_addr);
if (!arb_err_val)
return;
for (j = 0 ; j < GAUDI_NUM_OF_QM_ARB_ERR_CAUSE ; j++) {
if (arb_err_val & BIT(j)) {
dev_err_ratelimited(hdev->dev,
"%s ARB_ERR. err cause: %s\n",
qm_name,
gaudi_qman_arb_error_cause[j]);
}
}
}
static void gaudi_print_sm_sei_info(struct hl_device *hdev, u16 event_type,
struct hl_eq_sm_sei_data *sei_data)
{
u32 index = event_type - GAUDI_EVENT_DMA_IF_SEI_0;
index = (index ^ 0x3) & 0x3;
switch (sei_data->sei_cause) {
case SM_SEI_SO_OVERFLOW:
dev_err_ratelimited(hdev->dev,
"%s SEI Error: SOB Group %u overflow/underflow",
gaudi_sync_manager_names[index],
le32_to_cpu(sei_data->sei_log));
break;
case SM_SEI_LBW_4B_UNALIGNED:
dev_err_ratelimited(hdev->dev,
"%s SEI Error: Unaligned 4B LBW access, monitor agent address low - %#x",
gaudi_sync_manager_names[index],
le32_to_cpu(sei_data->sei_log));
break;
case SM_SEI_AXI_RESPONSE_ERR:
dev_err_ratelimited(hdev->dev,
"%s SEI Error: AXI ID %u response error",
gaudi_sync_manager_names[index],
le32_to_cpu(sei_data->sei_log));
break;
default:
dev_err_ratelimited(hdev->dev, "Unknown SM SEI cause %u",
le32_to_cpu(sei_data->sei_log));
break;
}
}
static void gaudi_handle_ecc_event(struct hl_device *hdev, u16 event_type,
struct hl_eq_ecc_data *ecc_data)
{
struct ecc_info_extract_params params;
u64 ecc_address = 0, ecc_syndrom = 0;
u8 index, memory_wrapper_idx = 0;
bool extract_info_from_fw;
int rc;
if (hdev->asic_prop.fw_security_enabled) {
extract_info_from_fw = true;
goto extract_ecc_info;
}
switch (event_type) {
case GAUDI_EVENT_PCIE_CORE_SERR ... GAUDI_EVENT_PCIE_PHY_DERR:
case GAUDI_EVENT_DMA0_SERR_ECC ... GAUDI_EVENT_MMU_DERR:
extract_info_from_fw = true;
break;
case GAUDI_EVENT_TPC0_SERR ... GAUDI_EVENT_TPC7_SERR:
index = event_type - GAUDI_EVENT_TPC0_SERR;
params.block_address = mmTPC0_CFG_BASE + index * TPC_CFG_OFFSET;
params.num_memories = 90;
params.derr = false;
extract_info_from_fw = false;
break;
case GAUDI_EVENT_TPC0_DERR ... GAUDI_EVENT_TPC7_DERR:
index = event_type - GAUDI_EVENT_TPC0_DERR;
params.block_address =
mmTPC0_CFG_BASE + index * TPC_CFG_OFFSET;
params.num_memories = 90;
params.derr = true;
extract_info_from_fw = false;
break;
case GAUDI_EVENT_MME0_ACC_SERR:
case GAUDI_EVENT_MME1_ACC_SERR:
case GAUDI_EVENT_MME2_ACC_SERR:
case GAUDI_EVENT_MME3_ACC_SERR:
index = (event_type - GAUDI_EVENT_MME0_ACC_SERR) / 4;
params.block_address = mmMME0_ACC_BASE + index * MME_ACC_OFFSET;
params.num_memories = 128;
params.derr = false;
extract_info_from_fw = false;
break;
case GAUDI_EVENT_MME0_ACC_DERR:
case GAUDI_EVENT_MME1_ACC_DERR:
case GAUDI_EVENT_MME2_ACC_DERR:
case GAUDI_EVENT_MME3_ACC_DERR:
index = (event_type - GAUDI_EVENT_MME0_ACC_DERR) / 4;
params.block_address = mmMME0_ACC_BASE + index * MME_ACC_OFFSET;
params.num_memories = 128;
params.derr = true;
extract_info_from_fw = false;
break;
case GAUDI_EVENT_MME0_SBAB_SERR:
case GAUDI_EVENT_MME1_SBAB_SERR:
case GAUDI_EVENT_MME2_SBAB_SERR:
case GAUDI_EVENT_MME3_SBAB_SERR:
index = (event_type - GAUDI_EVENT_MME0_SBAB_SERR) / 4;
params.block_address =
mmMME0_SBAB_BASE + index * MME_ACC_OFFSET;
params.num_memories = 33;
params.derr = false;
extract_info_from_fw = false;
break;
case GAUDI_EVENT_MME0_SBAB_DERR:
case GAUDI_EVENT_MME1_SBAB_DERR:
case GAUDI_EVENT_MME2_SBAB_DERR:
case GAUDI_EVENT_MME3_SBAB_DERR:
index = (event_type - GAUDI_EVENT_MME0_SBAB_DERR) / 4;
params.block_address =
mmMME0_SBAB_BASE + index * MME_ACC_OFFSET;
params.num_memories = 33;
params.derr = true;
extract_info_from_fw = false;
break;
default:
return;
}
extract_ecc_info:
if (extract_info_from_fw) {
ecc_address = le64_to_cpu(ecc_data->ecc_address);
ecc_syndrom = le64_to_cpu(ecc_data->ecc_syndrom);
memory_wrapper_idx = ecc_data->memory_wrapper_idx;
} else {
rc = gaudi_extract_ecc_info(hdev, ¶ms, &ecc_address,
&ecc_syndrom, &memory_wrapper_idx);
if (rc)
return;
}
dev_err(hdev->dev,
"ECC error detected. address: %#llx. Syndrom: %#llx. block id %u\n",
ecc_address, ecc_syndrom, memory_wrapper_idx);
}
static void gaudi_handle_qman_err(struct hl_device *hdev, u16 event_type, u64 *event_mask)
{
u64 qman_base;
char desc[32];
u32 qid_base;
u8 index;
switch (event_type) {
case GAUDI_EVENT_TPC0_QM ... GAUDI_EVENT_TPC7_QM:
index = event_type - GAUDI_EVENT_TPC0_QM;
qid_base = GAUDI_QUEUE_ID_TPC_0_0 + index * QMAN_STREAMS;
qman_base = mmTPC0_QM_BASE + index * TPC_QMAN_OFFSET;
snprintf(desc, ARRAY_SIZE(desc), "%s%d", "TPC_QM", index);
break;
case GAUDI_EVENT_MME0_QM ... GAUDI_EVENT_MME2_QM:
if (event_type == GAUDI_EVENT_MME0_QM) {
index = 0;
qid_base = GAUDI_QUEUE_ID_MME_0_0;
} else {
index = 2;
qid_base = GAUDI_QUEUE_ID_MME_1_0;
}
qman_base = mmMME0_QM_BASE + index * MME_QMAN_OFFSET;
snprintf(desc, ARRAY_SIZE(desc), "%s%d", "MME_QM", index);
break;
case GAUDI_EVENT_DMA0_QM ... GAUDI_EVENT_DMA7_QM:
index = event_type - GAUDI_EVENT_DMA0_QM;
qid_base = GAUDI_QUEUE_ID_DMA_0_0 + index * QMAN_STREAMS;
if (index > 1)
qid_base++;
qman_base = mmDMA0_QM_BASE + index * DMA_QMAN_OFFSET;
snprintf(desc, ARRAY_SIZE(desc), "%s%d", "DMA_QM", index);
break;
case GAUDI_EVENT_NIC0_QM0:
qid_base = GAUDI_QUEUE_ID_NIC_0_0;
qman_base = mmNIC0_QM0_BASE;
snprintf(desc, ARRAY_SIZE(desc), "NIC0_QM0");
break;
case GAUDI_EVENT_NIC0_QM1:
qid_base = GAUDI_QUEUE_ID_NIC_1_0;
qman_base = mmNIC0_QM1_BASE;
snprintf(desc, ARRAY_SIZE(desc), "NIC0_QM1");
break;
case GAUDI_EVENT_NIC1_QM0:
qid_base = GAUDI_QUEUE_ID_NIC_2_0;
qman_base = mmNIC1_QM0_BASE;
snprintf(desc, ARRAY_SIZE(desc), "NIC1_QM0");
break;
case GAUDI_EVENT_NIC1_QM1:
qid_base = GAUDI_QUEUE_ID_NIC_3_0;
qman_base = mmNIC1_QM1_BASE;
snprintf(desc, ARRAY_SIZE(desc), "NIC1_QM1");
break;
case GAUDI_EVENT_NIC2_QM0:
qid_base = GAUDI_QUEUE_ID_NIC_4_0;
qman_base = mmNIC2_QM0_BASE;
snprintf(desc, ARRAY_SIZE(desc), "NIC2_QM0");
break;
case GAUDI_EVENT_NIC2_QM1:
qid_base = GAUDI_QUEUE_ID_NIC_5_0;
qman_base = mmNIC2_QM1_BASE;
snprintf(desc, ARRAY_SIZE(desc), "NIC2_QM1");
break;
case GAUDI_EVENT_NIC3_QM0:
qid_base = GAUDI_QUEUE_ID_NIC_6_0;
qman_base = mmNIC3_QM0_BASE;
snprintf(desc, ARRAY_SIZE(desc), "NIC3_QM0");
break;
case GAUDI_EVENT_NIC3_QM1:
qid_base = GAUDI_QUEUE_ID_NIC_7_0;
qman_base = mmNIC3_QM1_BASE;
snprintf(desc, ARRAY_SIZE(desc), "NIC3_QM1");
break;
case GAUDI_EVENT_NIC4_QM0:
qid_base = GAUDI_QUEUE_ID_NIC_8_0;
qman_base = mmNIC4_QM0_BASE;
snprintf(desc, ARRAY_SIZE(desc), "NIC4_QM0");
break;
case GAUDI_EVENT_NIC4_QM1:
qid_base = GAUDI_QUEUE_ID_NIC_9_0;
qman_base = mmNIC4_QM1_BASE;
snprintf(desc, ARRAY_SIZE(desc), "NIC4_QM1");
break;
default:
return;
}
gaudi_handle_qman_err_generic(hdev, desc, qman_base, qid_base, event_mask);
}
static void gaudi_print_irq_info(struct hl_device *hdev, u16 event_type,
bool check_razwi, u64 *event_mask)
{
bool is_read = false, is_write = false;
u16 engine_id[2], num_of_razwi_eng = 0;
char desc[64] = "";
u64 razwi_addr = 0;
u8 razwi_flags = 0;
engine_id[0] = HL_RAZWI_NA_ENG_ID;
engine_id[1] = HL_RAZWI_NA_ENG_ID;
gaudi_get_event_desc(event_type, desc, sizeof(desc));
dev_err_ratelimited(hdev->dev, "Received H/W interrupt %d [\"%s\"]\n",
event_type, desc);
if (check_razwi) {
gaudi_print_and_get_razwi_info(hdev, &engine_id[0], &engine_id[1], &is_read,
&is_write);
gaudi_print_and_get_mmu_error_info(hdev, &razwi_addr, event_mask);
if (is_read)
razwi_flags |= HL_RAZWI_READ;
if (is_write)
razwi_flags |= HL_RAZWI_WRITE;
if (engine_id[0] != HL_RAZWI_NA_ENG_ID) {
if (engine_id[1] != HL_RAZWI_NA_ENG_ID)
num_of_razwi_eng = 2;
else
num_of_razwi_eng = 1;
}
if (razwi_flags)
hl_handle_razwi(hdev, razwi_addr, engine_id, num_of_razwi_eng,
razwi_flags, event_mask);
}
}
static void gaudi_print_out_of_sync_info(struct hl_device *hdev,
struct cpucp_pkt_sync_err *sync_err)
{
struct hl_hw_queue *q = &hdev->kernel_queues[GAUDI_QUEUE_ID_CPU_PQ];
dev_err(hdev->dev, "Out of sync with FW, FW: pi=%u, ci=%u, LKD: pi=%u, ci=%d\n",
le32_to_cpu(sync_err->pi), le32_to_cpu(sync_err->ci), q->pi, atomic_read(&q->ci));
}
static void gaudi_print_fw_alive_info(struct hl_device *hdev,
struct hl_eq_fw_alive *fw_alive)
{
dev_err(hdev->dev,
"FW alive report: severity=%s, process_id=%u, thread_id=%u, uptime=%llu seconds\n",
(fw_alive->severity == FW_ALIVE_SEVERITY_MINOR) ? "Minor" : "Critical",
le32_to_cpu(fw_alive->process_id),
le32_to_cpu(fw_alive->thread_id),
le64_to_cpu(fw_alive->uptime_seconds));
}
static void gaudi_print_nic_axi_irq_info(struct hl_device *hdev, u16 event_type,
void *data)
{
char desc[64] = "", *type;
struct eq_nic_sei_event *eq_nic_sei = data;
u16 nic_id = event_type - GAUDI_EVENT_NIC_SEI_0;
switch (eq_nic_sei->axi_error_cause) {
case RXB:
type = "RXB";
break;
case RXE:
type = "RXE";
break;
case TXS:
type = "TXS";
break;
case TXE:
type = "TXE";
break;
case QPC_RESP:
type = "QPC_RESP";
break;
case NON_AXI_ERR:
type = "NON_AXI_ERR";
break;
case TMR:
type = "TMR";
break;
default:
dev_err(hdev->dev, "unknown NIC AXI cause %d\n",
eq_nic_sei->axi_error_cause);
type = "N/A";
break;
}
snprintf(desc, sizeof(desc), "NIC%d_%s%d", nic_id, type,
eq_nic_sei->id);
dev_err_ratelimited(hdev->dev, "Received H/W interrupt %d [\"%s\"]\n",
event_type, desc);
}
static int gaudi_compute_reset_late_init(struct hl_device *hdev)
{
return -EPERM;
}
static int gaudi_hbm_read_interrupts(struct hl_device *hdev, int device,
struct hl_eq_hbm_ecc_data *hbm_ecc_data)
{
u32 base, val, val2, wr_par, rd_par, ca_par, derr, serr, type, ch;
int rc = 0;
if (hdev->asic_prop.fw_app_cpu_boot_dev_sts0 &
CPU_BOOT_DEV_STS0_HBM_ECC_EN) {
if (!hbm_ecc_data) {
dev_err(hdev->dev, "No FW ECC data");
return 0;
}
wr_par = FIELD_GET(CPUCP_PKT_HBM_ECC_INFO_WR_PAR_MASK,
le32_to_cpu(hbm_ecc_data->hbm_ecc_info));
rd_par = FIELD_GET(CPUCP_PKT_HBM_ECC_INFO_RD_PAR_MASK,
le32_to_cpu(hbm_ecc_data->hbm_ecc_info));
ca_par = FIELD_GET(CPUCP_PKT_HBM_ECC_INFO_CA_PAR_MASK,
le32_to_cpu(hbm_ecc_data->hbm_ecc_info));
derr = FIELD_GET(CPUCP_PKT_HBM_ECC_INFO_DERR_MASK,
le32_to_cpu(hbm_ecc_data->hbm_ecc_info));
serr = FIELD_GET(CPUCP_PKT_HBM_ECC_INFO_SERR_MASK,
le32_to_cpu(hbm_ecc_data->hbm_ecc_info));
type = FIELD_GET(CPUCP_PKT_HBM_ECC_INFO_TYPE_MASK,
le32_to_cpu(hbm_ecc_data->hbm_ecc_info));
ch = FIELD_GET(CPUCP_PKT_HBM_ECC_INFO_HBM_CH_MASK,
le32_to_cpu(hbm_ecc_data->hbm_ecc_info));
dev_err(hdev->dev,
"HBM%d pc%d interrupts info: WR_PAR=%d, RD_PAR=%d, CA_PAR=%d, SERR=%d, DERR=%d\n",
device, ch, wr_par, rd_par, ca_par, serr, derr);
dev_err(hdev->dev,
"HBM%d pc%d ECC info: 1ST_ERR_ADDR=0x%x, 1ST_ERR_TYPE=%d, SEC_CONT_CNT=%u, SEC_CNT=%d, DEC_CNT=%d\n",
device, ch, hbm_ecc_data->first_addr, type,
hbm_ecc_data->sec_cont_cnt, hbm_ecc_data->sec_cnt,
hbm_ecc_data->dec_cnt);
return 0;
}
if (hdev->asic_prop.fw_security_enabled) {
dev_info(hdev->dev, "Cannot access MC regs for ECC data while security is enabled\n");
return 0;
}
base = GAUDI_HBM_CFG_BASE + device * GAUDI_HBM_CFG_OFFSET;
for (ch = 0 ; ch < GAUDI_HBM_CHANNELS ; ch++) {
val = RREG32_MASK(base + ch * 0x1000 + 0x06C, 0x0000FFFF);
val = (val & 0xFF) | ((val >> 8) & 0xFF);
if (val) {
rc = -EIO;
dev_err(hdev->dev,
"HBM%d pc%d interrupts info: WR_PAR=%d, RD_PAR=%d, CA_PAR=%d, SERR=%d, DERR=%d\n",
device, ch * 2, val & 0x1, (val >> 1) & 0x1,
(val >> 2) & 0x1, (val >> 3) & 0x1,
(val >> 4) & 0x1);
val2 = RREG32(base + ch * 0x1000 + 0x060);
dev_err(hdev->dev,
"HBM%d pc%d ECC info: 1ST_ERR_ADDR=0x%x, 1ST_ERR_TYPE=%d, SEC_CONT_CNT=%d, SEC_CNT=%d, DEC_CNT=%d\n",
device, ch * 2,
RREG32(base + ch * 0x1000 + 0x064),
(val2 & 0x200) >> 9, (val2 & 0xFC00) >> 10,
(val2 & 0xFF0000) >> 16,
(val2 & 0xFF000000) >> 24);
}
val = RREG32_MASK(base + ch * 0x1000 + 0x07C, 0x0000FFFF);
val = (val & 0xFF) | ((val >> 8) & 0xFF);
if (val) {
rc = -EIO;
dev_err(hdev->dev,
"HBM%d pc%d interrupts info: WR_PAR=%d, RD_PAR=%d, CA_PAR=%d, SERR=%d, DERR=%d\n",
device, ch * 2 + 1, val & 0x1, (val >> 1) & 0x1,
(val >> 2) & 0x1, (val >> 3) & 0x1,
(val >> 4) & 0x1);
val2 = RREG32(base + ch * 0x1000 + 0x070);
dev_err(hdev->dev,
"HBM%d pc%d ECC info: 1ST_ERR_ADDR=0x%x, 1ST_ERR_TYPE=%d, SEC_CONT_CNT=%d, SEC_CNT=%d, DEC_CNT=%d\n",
device, ch * 2 + 1,
RREG32(base + ch * 0x1000 + 0x074),
(val2 & 0x200) >> 9, (val2 & 0xFC00) >> 10,
(val2 & 0xFF0000) >> 16,
(val2 & 0xFF000000) >> 24);
}
RMWREG32(base + (ch * 0x1000) + 0x060, 0x1C8, 0x1FF);
RMWREG32(base + (ch * 0x1000) + 0x070, 0x1C8, 0x1FF);
WREG32(base + (ch * 0x1000) + 0x06C, 0x1F1F);
WREG32(base + (ch * 0x1000) + 0x07C, 0x1F1F);
RMWREG32(base + (ch * 0x1000) + 0x060, 0x0, 0xF);
RMWREG32(base + (ch * 0x1000) + 0x070, 0x0, 0xF);
}
val = RREG32(base + 0x8F30);
val2 = RREG32(base + 0x8F34);
if (val | val2) {
rc = -EIO;
dev_err(hdev->dev,
"HBM %d MC SRAM SERR info: Reg 0x8F30=0x%x, Reg 0x8F34=0x%x\n",
device, val, val2);
}
val = RREG32(base + 0x8F40);
val2 = RREG32(base + 0x8F44);
if (val | val2) {
rc = -EIO;
dev_err(hdev->dev,
"HBM %d MC SRAM DERR info: Reg 0x8F40=0x%x, Reg 0x8F44=0x%x\n",
device, val, val2);
}
return rc;
}
static int gaudi_hbm_event_to_dev(u16 hbm_event_type)
{
switch (hbm_event_type) {
case GAUDI_EVENT_HBM0_SPI_0:
case GAUDI_EVENT_HBM0_SPI_1:
return 0;
case GAUDI_EVENT_HBM1_SPI_0:
case GAUDI_EVENT_HBM1_SPI_1:
return 1;
case GAUDI_EVENT_HBM2_SPI_0:
case GAUDI_EVENT_HBM2_SPI_1:
return 2;
case GAUDI_EVENT_HBM3_SPI_0:
case GAUDI_EVENT_HBM3_SPI_1:
return 3;
default:
break;
}
return 0;
}
static bool gaudi_tpc_read_interrupts(struct hl_device *hdev, u8 tpc_id,
char *interrupt_name)
{
u32 tpc_offset = tpc_id * TPC_CFG_OFFSET, tpc_interrupts_cause, i;
bool soft_reset_required = false;
tpc_interrupts_cause = RREG32(mmTPC0_CFG_TPC_INTR_CAUSE + tpc_offset) &
TPC0_CFG_TPC_INTR_CAUSE_CAUSE_MASK;
for (i = 0 ; i < GAUDI_NUM_OF_TPC_INTR_CAUSE ; i++)
if (tpc_interrupts_cause & BIT(i)) {
dev_err_ratelimited(hdev->dev,
"TPC%d_%s interrupt cause: %s\n",
tpc_id, interrupt_name,
gaudi_tpc_interrupts_cause[i]);
if (i == 15)
soft_reset_required = true;
}
WREG32(mmTPC0_CFG_TPC_INTR_CAUSE + tpc_offset, 0);
return soft_reset_required;
}
static int tpc_dec_event_to_tpc_id(u16 tpc_dec_event_type)
{
return (tpc_dec_event_type - GAUDI_EVENT_TPC0_DEC) >> 1;
}
static int tpc_krn_event_to_tpc_id(u16 tpc_dec_event_type)
{
return (tpc_dec_event_type - GAUDI_EVENT_TPC0_KRN_ERR) / 6;
}
static void gaudi_print_clk_change_info(struct hl_device *hdev, u16 event_type, u64 *event_mask)
{
ktime_t zero_time = ktime_set(0, 0);
mutex_lock(&hdev->clk_throttling.lock);
switch (event_type) {
case GAUDI_EVENT_FIX_POWER_ENV_S:
hdev->clk_throttling.current_reason |= HL_CLK_THROTTLE_POWER;
hdev->clk_throttling.aggregated_reason |= HL_CLK_THROTTLE_POWER;
hdev->clk_throttling.timestamp[HL_CLK_THROTTLE_TYPE_POWER].start = ktime_get();
hdev->clk_throttling.timestamp[HL_CLK_THROTTLE_TYPE_POWER].end = zero_time;
dev_info_ratelimited(hdev->dev,
"Clock throttling due to power consumption\n");
break;
case GAUDI_EVENT_FIX_POWER_ENV_E:
hdev->clk_throttling.current_reason &= ~HL_CLK_THROTTLE_POWER;
hdev->clk_throttling.timestamp[HL_CLK_THROTTLE_TYPE_POWER].end = ktime_get();
dev_info_ratelimited(hdev->dev,
"Power envelop is safe, back to optimal clock\n");
break;
case GAUDI_EVENT_FIX_THERMAL_ENV_S:
hdev->clk_throttling.current_reason |= HL_CLK_THROTTLE_THERMAL;
hdev->clk_throttling.aggregated_reason |= HL_CLK_THROTTLE_THERMAL;
hdev->clk_throttling.timestamp[HL_CLK_THROTTLE_TYPE_THERMAL].start = ktime_get();
hdev->clk_throttling.timestamp[HL_CLK_THROTTLE_TYPE_THERMAL].end = zero_time;
*event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
dev_info_ratelimited(hdev->dev,
"Clock throttling due to overheating\n");
break;
case GAUDI_EVENT_FIX_THERMAL_ENV_E:
hdev->clk_throttling.current_reason &= ~HL_CLK_THROTTLE_THERMAL;
hdev->clk_throttling.timestamp[HL_CLK_THROTTLE_TYPE_THERMAL].end = ktime_get();
*event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
dev_info_ratelimited(hdev->dev,
"Thermal envelop is safe, back to optimal clock\n");
break;
default:
dev_err(hdev->dev, "Received invalid clock change event %d\n",
event_type);
break;
}
mutex_unlock(&hdev->clk_throttling.lock);
}
static void gaudi_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entry)
{
struct gaudi_device *gaudi = hdev->asic_specific;
struct hl_info_fw_err_info fw_err_info;
u64 data = le64_to_cpu(eq_entry->data[0]), event_mask = 0;
u32 ctl = le32_to_cpu(eq_entry->hdr.ctl);
u32 fw_fatal_err_flag = 0, flags = 0;
u16 event_type = ((ctl & EQ_CTL_EVENT_TYPE_MASK)
>> EQ_CTL_EVENT_TYPE_SHIFT);
bool reset_required, reset_direct = false;
u8 cause;
int rc;
if (event_type >= GAUDI_EVENT_SIZE) {
dev_err(hdev->dev, "Event type %u exceeds maximum of %u",
event_type, GAUDI_EVENT_SIZE - 1);
return;
}
gaudi->events_stat[event_type]++;
gaudi->events_stat_aggregate[event_type]++;
switch (event_type) {
case GAUDI_EVENT_PCIE_CORE_DERR:
case GAUDI_EVENT_PCIE_IF_DERR:
case GAUDI_EVENT_PCIE_PHY_DERR:
case GAUDI_EVENT_TPC0_DERR ... GAUDI_EVENT_TPC7_DERR:
case GAUDI_EVENT_MME0_ACC_DERR:
case GAUDI_EVENT_MME0_SBAB_DERR:
case GAUDI_EVENT_MME1_ACC_DERR:
case GAUDI_EVENT_MME1_SBAB_DERR:
case GAUDI_EVENT_MME2_ACC_DERR:
case GAUDI_EVENT_MME2_SBAB_DERR:
case GAUDI_EVENT_MME3_ACC_DERR:
case GAUDI_EVENT_MME3_SBAB_DERR:
case GAUDI_EVENT_DMA0_DERR_ECC ... GAUDI_EVENT_DMA7_DERR_ECC:
fallthrough;
case GAUDI_EVENT_CPU_IF_ECC_DERR:
case GAUDI_EVENT_PSOC_MEM_DERR:
case GAUDI_EVENT_PSOC_CORESIGHT_DERR:
case GAUDI_EVENT_SRAM0_DERR ... GAUDI_EVENT_SRAM28_DERR:
case GAUDI_EVENT_NIC0_DERR ... GAUDI_EVENT_NIC4_DERR:
case GAUDI_EVENT_DMA_IF0_DERR ... GAUDI_EVENT_DMA_IF3_DERR:
case GAUDI_EVENT_HBM_0_DERR ... GAUDI_EVENT_HBM_3_DERR:
case GAUDI_EVENT_MMU_DERR:
case GAUDI_EVENT_NIC0_CS_DBG_DERR ... GAUDI_EVENT_NIC4_CS_DBG_DERR:
gaudi_print_irq_info(hdev, event_type, true, &event_mask);
gaudi_handle_ecc_event(hdev, event_type, &eq_entry->ecc_data);
event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR;
fw_fatal_err_flag = HL_DRV_RESET_FW_FATAL_ERR;
goto reset_device;
case GAUDI_EVENT_GIC500:
case GAUDI_EVENT_AXI_ECC:
case GAUDI_EVENT_L2_RAM_ECC:
case GAUDI_EVENT_PLL0 ... GAUDI_EVENT_PLL17:
gaudi_print_irq_info(hdev, event_type, false, &event_mask);
fw_fatal_err_flag = HL_DRV_RESET_FW_FATAL_ERR;
event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR;
goto reset_device;
case GAUDI_EVENT_HBM0_SPI_0:
case GAUDI_EVENT_HBM1_SPI_0:
case GAUDI_EVENT_HBM2_SPI_0:
case GAUDI_EVENT_HBM3_SPI_0:
gaudi_print_irq_info(hdev, event_type, false, &event_mask);
gaudi_hbm_read_interrupts(hdev,
gaudi_hbm_event_to_dev(event_type),
&eq_entry->hbm_ecc_data);
fw_fatal_err_flag = HL_DRV_RESET_FW_FATAL_ERR;
event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR;
goto reset_device;
case GAUDI_EVENT_HBM0_SPI_1:
case GAUDI_EVENT_HBM1_SPI_1:
case GAUDI_EVENT_HBM2_SPI_1:
case GAUDI_EVENT_HBM3_SPI_1:
gaudi_print_irq_info(hdev, event_type, false, &event_mask);
gaudi_hbm_read_interrupts(hdev,
gaudi_hbm_event_to_dev(event_type),
&eq_entry->hbm_ecc_data);
hl_fw_unmask_irq(hdev, event_type);
event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR;
break;
case GAUDI_EVENT_TPC0_DEC:
case GAUDI_EVENT_TPC1_DEC:
case GAUDI_EVENT_TPC2_DEC:
case GAUDI_EVENT_TPC3_DEC:
case GAUDI_EVENT_TPC4_DEC:
case GAUDI_EVENT_TPC5_DEC:
case GAUDI_EVENT_TPC6_DEC:
case GAUDI_EVENT_TPC7_DEC:
event_mask |= HL_NOTIFIER_EVENT_TPC_ASSERT;
gaudi_print_irq_info(hdev, event_type, true, &event_mask);
reset_required = gaudi_tpc_read_interrupts(hdev,
tpc_dec_event_to_tpc_id(event_type),
"AXI_SLV_DEC_Error");
event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
if (reset_required) {
dev_err(hdev->dev, "reset required due to %s\n",
gaudi_irq_map_table[event_type].name);
reset_direct = true;
goto reset_device;
} else {
hl_fw_unmask_irq(hdev, event_type);
event_mask |= HL_NOTIFIER_EVENT_DEVICE_RESET;
}
break;
case GAUDI_EVENT_TPC0_KRN_ERR:
case GAUDI_EVENT_TPC1_KRN_ERR:
case GAUDI_EVENT_TPC2_KRN_ERR:
case GAUDI_EVENT_TPC3_KRN_ERR:
case GAUDI_EVENT_TPC4_KRN_ERR:
case GAUDI_EVENT_TPC5_KRN_ERR:
case GAUDI_EVENT_TPC6_KRN_ERR:
case GAUDI_EVENT_TPC7_KRN_ERR:
gaudi_print_irq_info(hdev, event_type, true, &event_mask);
reset_required = gaudi_tpc_read_interrupts(hdev,
tpc_krn_event_to_tpc_id(event_type),
"KRN_ERR");
event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
if (reset_required) {
dev_err(hdev->dev, "reset required due to %s\n",
gaudi_irq_map_table[event_type].name);
reset_direct = true;
goto reset_device;
} else {
hl_fw_unmask_irq(hdev, event_type);
event_mask |= HL_NOTIFIER_EVENT_DEVICE_RESET;
}
break;
case GAUDI_EVENT_PCIE_CORE_SERR:
case GAUDI_EVENT_PCIE_IF_SERR:
case GAUDI_EVENT_PCIE_PHY_SERR:
case GAUDI_EVENT_TPC0_SERR ... GAUDI_EVENT_TPC7_SERR:
case GAUDI_EVENT_MME0_ACC_SERR:
case GAUDI_EVENT_MME0_SBAB_SERR:
case GAUDI_EVENT_MME1_ACC_SERR:
case GAUDI_EVENT_MME1_SBAB_SERR:
case GAUDI_EVENT_MME2_ACC_SERR:
case GAUDI_EVENT_MME2_SBAB_SERR:
case GAUDI_EVENT_MME3_ACC_SERR:
case GAUDI_EVENT_MME3_SBAB_SERR:
case GAUDI_EVENT_DMA0_SERR_ECC ... GAUDI_EVENT_DMA7_SERR_ECC:
case GAUDI_EVENT_CPU_IF_ECC_SERR:
case GAUDI_EVENT_PSOC_MEM_SERR:
case GAUDI_EVENT_PSOC_CORESIGHT_SERR:
case GAUDI_EVENT_SRAM0_SERR ... GAUDI_EVENT_SRAM28_SERR:
case GAUDI_EVENT_NIC0_SERR ... GAUDI_EVENT_NIC4_SERR:
case GAUDI_EVENT_DMA_IF0_SERR ... GAUDI_EVENT_DMA_IF3_SERR:
case GAUDI_EVENT_HBM_0_SERR ... GAUDI_EVENT_HBM_3_SERR:
fallthrough;
case GAUDI_EVENT_MMU_SERR:
gaudi_print_irq_info(hdev, event_type, true, &event_mask);
gaudi_handle_ecc_event(hdev, event_type, &eq_entry->ecc_data);
hl_fw_unmask_irq(hdev, event_type);
event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR;
break;
case GAUDI_EVENT_PCIE_DEC:
case GAUDI_EVENT_CPU_AXI_SPLITTER:
case GAUDI_EVENT_PSOC_AXI_DEC:
case GAUDI_EVENT_PSOC_PRSTN_FALL:
gaudi_print_irq_info(hdev, event_type, true, &event_mask);
hl_fw_unmask_irq(hdev, event_type);
event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR;
break;
case GAUDI_EVENT_MMU_PAGE_FAULT:
case GAUDI_EVENT_MMU_WR_PERM:
gaudi_print_irq_info(hdev, event_type, true, &event_mask);
hl_fw_unmask_irq(hdev, event_type);
event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
break;
case GAUDI_EVENT_MME0_WBC_RSP:
case GAUDI_EVENT_MME0_SBAB0_RSP:
case GAUDI_EVENT_MME1_WBC_RSP:
case GAUDI_EVENT_MME1_SBAB0_RSP:
case GAUDI_EVENT_MME2_WBC_RSP:
case GAUDI_EVENT_MME2_SBAB0_RSP:
case GAUDI_EVENT_MME3_WBC_RSP:
case GAUDI_EVENT_MME3_SBAB0_RSP:
case GAUDI_EVENT_RAZWI_OR_ADC:
case GAUDI_EVENT_MME0_QM ... GAUDI_EVENT_MME2_QM:
case GAUDI_EVENT_DMA0_QM ... GAUDI_EVENT_DMA7_QM:
fallthrough;
case GAUDI_EVENT_NIC0_QM0:
case GAUDI_EVENT_NIC0_QM1:
case GAUDI_EVENT_NIC1_QM0:
case GAUDI_EVENT_NIC1_QM1:
case GAUDI_EVENT_NIC2_QM0:
case GAUDI_EVENT_NIC2_QM1:
case GAUDI_EVENT_NIC3_QM0:
case GAUDI_EVENT_NIC3_QM1:
case GAUDI_EVENT_NIC4_QM0:
case GAUDI_EVENT_NIC4_QM1:
case GAUDI_EVENT_DMA0_CORE ... GAUDI_EVENT_DMA7_CORE:
case GAUDI_EVENT_TPC0_QM ... GAUDI_EVENT_TPC7_QM:
gaudi_print_irq_info(hdev, event_type, true, &event_mask);
gaudi_handle_qman_err(hdev, event_type, &event_mask);
hl_fw_unmask_irq(hdev, event_type);
event_mask |= (HL_NOTIFIER_EVENT_USER_ENGINE_ERR | HL_NOTIFIER_EVENT_DEVICE_RESET);
break;
case GAUDI_EVENT_RAZWI_OR_ADC_SW:
gaudi_print_irq_info(hdev, event_type, true, &event_mask);
event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
goto reset_device;
case GAUDI_EVENT_TPC0_BMON_SPMU:
case GAUDI_EVENT_TPC1_BMON_SPMU:
case GAUDI_EVENT_TPC2_BMON_SPMU:
case GAUDI_EVENT_TPC3_BMON_SPMU:
case GAUDI_EVENT_TPC4_BMON_SPMU:
case GAUDI_EVENT_TPC5_BMON_SPMU:
case GAUDI_EVENT_TPC6_BMON_SPMU:
case GAUDI_EVENT_TPC7_BMON_SPMU:
case GAUDI_EVENT_DMA_BM_CH0 ... GAUDI_EVENT_DMA_BM_CH7:
gaudi_print_irq_info(hdev, event_type, false, &event_mask);
hl_fw_unmask_irq(hdev, event_type);
event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
break;
case GAUDI_EVENT_NIC_SEI_0 ... GAUDI_EVENT_NIC_SEI_4:
gaudi_print_nic_axi_irq_info(hdev, event_type, &data);
hl_fw_unmask_irq(hdev, event_type);
event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
break;
case GAUDI_EVENT_DMA_IF_SEI_0 ... GAUDI_EVENT_DMA_IF_SEI_3:
gaudi_print_irq_info(hdev, event_type, false, &event_mask);
gaudi_print_sm_sei_info(hdev, event_type,
&eq_entry->sm_sei_data);
rc = hl_state_dump(hdev);
event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
if (rc)
dev_err(hdev->dev,
"Error during system state dump %d\n", rc);
hl_fw_unmask_irq(hdev, event_type);
break;
case GAUDI_EVENT_STATUS_NIC0_ENG0 ... GAUDI_EVENT_STATUS_NIC4_ENG1:
break;
case GAUDI_EVENT_FIX_POWER_ENV_S ... GAUDI_EVENT_FIX_THERMAL_ENV_E:
gaudi_print_clk_change_info(hdev, event_type, &event_mask);
hl_fw_unmask_irq(hdev, event_type);
break;
case GAUDI_EVENT_PSOC_GPIO_U16_0:
cause = le64_to_cpu(eq_entry->data[0]) & 0xFF;
dev_err(hdev->dev,
"Received high temp H/W interrupt %d (cause %d)\n",
event_type, cause);
event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
break;
case GAUDI_EVENT_DEV_RESET_REQ:
gaudi_print_irq_info(hdev, event_type, false, &event_mask);
event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR;
goto reset_device;
case GAUDI_EVENT_PKT_QUEUE_OUT_SYNC:
gaudi_print_irq_info(hdev, event_type, false, &event_mask);
gaudi_print_out_of_sync_info(hdev, &eq_entry->pkt_sync_err);
event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR;
goto reset_device;
case GAUDI_EVENT_FW_ALIVE_S:
gaudi_print_irq_info(hdev, event_type, false, &event_mask);
gaudi_print_fw_alive_info(hdev, &eq_entry->fw_alive);
fw_err_info.err_type = HL_INFO_FW_REPORTED_ERR;
fw_err_info.event_id = event_type;
fw_err_info.event_mask = &event_mask;
hl_handle_fw_err(hdev, &fw_err_info);
goto reset_device;
default:
dev_err(hdev->dev, "Received invalid H/W interrupt %d\n",
event_type);
break;
}
if (event_mask)
hl_notifier_event_send_all(hdev, event_mask);
return;
reset_device:
reset_required = true;
if (hdev->asic_prop.fw_security_enabled && !reset_direct) {
flags = HL_DRV_RESET_HARD | HL_DRV_RESET_BYPASS_REQ_TO_FW | fw_fatal_err_flag;
event_mask |= (HL_NOTIFIER_EVENT_DEVICE_RESET |
HL_NOTIFIER_EVENT_DEVICE_UNAVAILABLE);
} else if (hdev->hard_reset_on_fw_events) {
flags = HL_DRV_RESET_HARD | HL_DRV_RESET_DELAY | fw_fatal_err_flag;
event_mask |= HL_NOTIFIER_EVENT_DEVICE_RESET;
} else {
reset_required = false;
}
if (reset_required) {
if (event_mask & HL_NOTIFIER_EVENT_GENERAL_HW_ERR)
hl_handle_critical_hw_err(hdev, event_type, &event_mask);
hl_device_cond_reset(hdev, flags, event_mask);
} else {
hl_fw_unmask_irq(hdev, event_type);
if (event_mask)
hl_notifier_event_send_all(hdev, event_mask);
}
}
static void *gaudi_get_events_stat(struct hl_device *hdev, bool aggregate, u32 *size)
{
struct gaudi_device *gaudi = hdev->asic_specific;
if (aggregate) {
*size = (u32) sizeof(gaudi->events_stat_aggregate);
return gaudi->events_stat_aggregate;
}
*size = (u32) sizeof(gaudi->events_stat);
return gaudi->events_stat;
}
static int gaudi_mmu_invalidate_cache(struct hl_device *hdev, bool is_hard, u32 flags)
{
struct gaudi_device *gaudi = hdev->asic_specific;
u32 status, timeout_usec;
int rc;
if (!(gaudi->hw_cap_initialized & HW_CAP_MMU) ||
hdev->reset_info.hard_reset_pending)
return 0;
if (hdev->pldm)
timeout_usec = GAUDI_PLDM_MMU_TIMEOUT_USEC;
else
timeout_usec = MMU_CONFIG_TIMEOUT_USEC;
WREG32(mmSTLB_INV_PS, 3);
WREG32(mmSTLB_CACHE_INV, gaudi->mmu_cache_inv_pi++);
WREG32(mmSTLB_INV_PS, 2);
rc = hl_poll_timeout(
hdev,
mmSTLB_INV_PS,
status,
!status,
1000,
timeout_usec);
WREG32(mmSTLB_INV_SET, 0);
return rc;
}
static int gaudi_mmu_invalidate_cache_range(struct hl_device *hdev,
bool is_hard, u32 flags,
u32 asid, u64 va, u64 size)
{
return hdev->asic_funcs->mmu_invalidate_cache(hdev, is_hard, flags);
}
static int gaudi_mmu_update_asid_hop0_addr(struct hl_device *hdev, u32 asid, u64 phys_addr)
{
u32 status, timeout_usec;
int rc;
if (hdev->pldm)
timeout_usec = GAUDI_PLDM_MMU_TIMEOUT_USEC;
else
timeout_usec = MMU_CONFIG_TIMEOUT_USEC;
WREG32(MMU_ASID, asid);
WREG32(MMU_HOP0_PA43_12, phys_addr >> MMU_HOP0_PA43_12_SHIFT);
WREG32(MMU_HOP0_PA49_44, phys_addr >> MMU_HOP0_PA49_44_SHIFT);
WREG32(MMU_BUSY, 0x80000000);
rc = hl_poll_timeout(
hdev,
MMU_BUSY,
status,
!(status & 0x80000000),
1000,
timeout_usec);
if (rc) {
dev_err(hdev->dev,
"Timeout during MMU hop0 config of asid %d\n", asid);
return rc;
}
return 0;
}
static int gaudi_send_heartbeat(struct hl_device *hdev)
{
struct gaudi_device *gaudi = hdev->asic_specific;
if (!(gaudi->hw_cap_initialized & HW_CAP_CPU_Q))
return 0;
return hl_fw_send_heartbeat(hdev);
}
static int gaudi_cpucp_info_get(struct hl_device *hdev)
{
struct gaudi_device *gaudi = hdev->asic_specific;
struct asic_fixed_properties *prop = &hdev->asic_prop;
int rc;
if (!(gaudi->hw_cap_initialized & HW_CAP_CPU_Q))
return 0;
rc = hl_fw_cpucp_handshake(hdev, mmCPU_BOOT_DEV_STS0,
mmCPU_BOOT_DEV_STS1, mmCPU_BOOT_ERR0,
mmCPU_BOOT_ERR1);
if (rc)
return rc;
if (!strlen(prop->cpucp_info.card_name))
strncpy(prop->cpucp_info.card_name, GAUDI_DEFAULT_CARD_NAME,
CARD_NAME_MAX_LEN);
hdev->card_type = le32_to_cpu(hdev->asic_prop.cpucp_info.card_type);
set_default_power_values(hdev);
return 0;
}
static bool gaudi_is_device_idle(struct hl_device *hdev, u64 *mask_arr, u8 mask_len,
struct engines_data *e)
{
struct gaudi_device *gaudi = hdev->asic_specific;
const char *fmt = "%-5d%-9s%#-14x%#-12x%#x\n";
const char *mme_slave_fmt = "%-5d%-9s%-14s%-12s%#x\n";
const char *nic_fmt = "%-5d%-9s%#-14x%#x\n";
unsigned long *mask = (unsigned long *)mask_arr;
u32 qm_glbl_sts0, qm_cgm_sts, dma_core_sts0, tpc_cfg_sts, mme_arch_sts;
bool is_idle = true, is_eng_idle, is_slave;
u64 offset;
int i, dma_id, port;
if (e)
hl_engine_data_sprintf(e,
"\nDMA is_idle QM_GLBL_STS0 QM_CGM_STS DMA_CORE_STS0\n"
"--- ------- ------------ ---------- -------------\n");
for (i = 0 ; i < DMA_NUMBER_OF_CHNLS ; i++) {
dma_id = gaudi_dma_assignment[i];
offset = dma_id * DMA_QMAN_OFFSET;
qm_glbl_sts0 = RREG32(mmDMA0_QM_GLBL_STS0 + offset);
qm_cgm_sts = RREG32(mmDMA0_QM_CGM_STS + offset);
dma_core_sts0 = RREG32(mmDMA0_CORE_STS0 + offset);
is_eng_idle = IS_QM_IDLE(qm_glbl_sts0, qm_cgm_sts) &&
IS_DMA_IDLE(dma_core_sts0);
is_idle &= is_eng_idle;
if (mask && !is_eng_idle)
set_bit(GAUDI_ENGINE_ID_DMA_0 + dma_id, mask);
if (e)
hl_engine_data_sprintf(e, fmt, dma_id,
is_eng_idle ? "Y" : "N", qm_glbl_sts0,
qm_cgm_sts, dma_core_sts0);
}
if (e)
hl_engine_data_sprintf(e,
"\nTPC is_idle QM_GLBL_STS0 QM_CGM_STS CFG_STATUS\n"
"--- ------- ------------ ---------- ----------\n");
for (i = 0 ; i < TPC_NUMBER_OF_ENGINES ; i++) {
offset = i * TPC_QMAN_OFFSET;
qm_glbl_sts0 = RREG32(mmTPC0_QM_GLBL_STS0 + offset);
qm_cgm_sts = RREG32(mmTPC0_QM_CGM_STS + offset);
tpc_cfg_sts = RREG32(mmTPC0_CFG_STATUS + offset);
is_eng_idle = IS_QM_IDLE(qm_glbl_sts0, qm_cgm_sts) &&
IS_TPC_IDLE(tpc_cfg_sts);
is_idle &= is_eng_idle;
if (mask && !is_eng_idle)
set_bit(GAUDI_ENGINE_ID_TPC_0 + i, mask);
if (e)
hl_engine_data_sprintf(e, fmt, i,
is_eng_idle ? "Y" : "N",
qm_glbl_sts0, qm_cgm_sts, tpc_cfg_sts);
}
if (e)
hl_engine_data_sprintf(e,
"\nMME is_idle QM_GLBL_STS0 QM_CGM_STS ARCH_STATUS\n"
"--- ------- ------------ ---------- -----------\n");
for (i = 0 ; i < MME_NUMBER_OF_ENGINES ; i++) {
offset = i * MME_QMAN_OFFSET;
mme_arch_sts = RREG32(mmMME0_CTRL_ARCH_STATUS + offset);
is_eng_idle = IS_MME_IDLE(mme_arch_sts);
is_slave = i % 2;
if (!is_slave) {
qm_glbl_sts0 = RREG32(mmMME0_QM_GLBL_STS0 + offset);
qm_cgm_sts = RREG32(mmMME0_QM_CGM_STS + offset);
is_eng_idle &= IS_QM_IDLE(qm_glbl_sts0, qm_cgm_sts);
}
is_idle &= is_eng_idle;
if (mask && !is_eng_idle)
set_bit(GAUDI_ENGINE_ID_MME_0 + i, mask);
if (e) {
if (!is_slave)
hl_engine_data_sprintf(e, fmt, i,
is_eng_idle ? "Y" : "N",
qm_glbl_sts0, qm_cgm_sts, mme_arch_sts);
else
hl_engine_data_sprintf(e, mme_slave_fmt, i,
is_eng_idle ? "Y" : "N", "-",
"-", mme_arch_sts);
}
}
if (e)
hl_engine_data_sprintf(e,
"\nNIC is_idle QM_GLBL_STS0 QM_CGM_STS\n"
"--- ------- ------------ ----------\n");
for (i = 0 ; i < (NIC_NUMBER_OF_ENGINES / 2) ; i++) {
offset = i * NIC_MACRO_QMAN_OFFSET;
port = 2 * i;
if (gaudi->hw_cap_initialized & BIT(HW_CAP_NIC_SHIFT + port)) {
qm_glbl_sts0 = RREG32(mmNIC0_QM0_GLBL_STS0 + offset);
qm_cgm_sts = RREG32(mmNIC0_QM0_CGM_STS + offset);
is_eng_idle = IS_QM_IDLE(qm_glbl_sts0, qm_cgm_sts);
is_idle &= is_eng_idle;
if (mask && !is_eng_idle)
set_bit(GAUDI_ENGINE_ID_NIC_0 + port, mask);
if (e)
hl_engine_data_sprintf(e, nic_fmt, port,
is_eng_idle ? "Y" : "N",
qm_glbl_sts0, qm_cgm_sts);
}
port = 2 * i + 1;
if (gaudi->hw_cap_initialized & BIT(HW_CAP_NIC_SHIFT + port)) {
qm_glbl_sts0 = RREG32(mmNIC0_QM1_GLBL_STS0 + offset);
qm_cgm_sts = RREG32(mmNIC0_QM1_CGM_STS + offset);
is_eng_idle = IS_QM_IDLE(qm_glbl_sts0, qm_cgm_sts);
is_idle &= is_eng_idle;
if (mask && !is_eng_idle)
set_bit(GAUDI_ENGINE_ID_NIC_0 + port, mask);
if (e)
hl_engine_data_sprintf(e, nic_fmt, port,
is_eng_idle ? "Y" : "N",
qm_glbl_sts0, qm_cgm_sts);
}
}
if (e)
hl_engine_data_sprintf(e, "\n");
return is_idle;
}
static void gaudi_hw_queues_lock(struct hl_device *hdev)
__acquires(&gaudi->hw_queues_lock)
{
struct gaudi_device *gaudi = hdev->asic_specific;
spin_lock(&gaudi->hw_queues_lock);
}
static void gaudi_hw_queues_unlock(struct hl_device *hdev)
__releases(&gaudi->hw_queues_lock)
{
struct gaudi_device *gaudi = hdev->asic_specific;
spin_unlock(&gaudi->hw_queues_lock);
}
static u32 gaudi_get_pci_id(struct hl_device *hdev)
{
return hdev->pdev->device;
}
static int gaudi_get_eeprom_data(struct hl_device *hdev, void *data,
size_t max_size)
{
struct gaudi_device *gaudi = hdev->asic_specific;
if (!(gaudi->hw_cap_initialized & HW_CAP_CPU_Q))
return 0;
return hl_fw_get_eeprom_data(hdev, data, max_size);
}
static int gaudi_get_monitor_dump(struct hl_device *hdev, void *data)
{
struct gaudi_device *gaudi = hdev->asic_specific;
if (!(gaudi->hw_cap_initialized & HW_CAP_CPU_Q))
return 0;
return hl_fw_get_monitor_dump(hdev, data);
}
static int gaudi_run_tpc_kernel(struct hl_device *hdev, u64 tpc_kernel, u32 tpc_id)
{
u64 kernel_timeout;
u32 status, offset;
int rc;
offset = tpc_id * (mmTPC1_CFG_STATUS - mmTPC0_CFG_STATUS);
if (hdev->pldm)
kernel_timeout = GAUDI_PLDM_TPC_KERNEL_WAIT_USEC;
else
kernel_timeout = HL_DEVICE_TIMEOUT_USEC;
WREG32(mmTPC0_CFG_QM_KERNEL_BASE_ADDRESS_LOW + offset,
lower_32_bits(tpc_kernel));
WREG32(mmTPC0_CFG_QM_KERNEL_BASE_ADDRESS_HIGH + offset,
upper_32_bits(tpc_kernel));
WREG32(mmTPC0_CFG_ICACHE_BASE_ADDERESS_LOW + offset,
lower_32_bits(tpc_kernel));
WREG32(mmTPC0_CFG_ICACHE_BASE_ADDERESS_HIGH + offset,
upper_32_bits(tpc_kernel));
WREG32(mmTPC0_CFG_LUT_FUNC256_BASE_ADDR_LO + offset,
lower_32_bits(tpc_kernel));
WREG32(mmTPC0_CFG_LUT_FUNC256_BASE_ADDR_HI + offset,
upper_32_bits(tpc_kernel));
WREG32(mmTPC0_CFG_QM_SYNC_OBJECT_ADDR + offset,
lower_32_bits(CFG_BASE +
mmSYNC_MNGR_E_N_SYNC_MNGR_OBJS_SOB_OBJ_0));
WREG32(mmTPC0_CFG_TPC_CMD + offset,
(1 << TPC0_CFG_TPC_CMD_ICACHE_INVALIDATE_SHIFT |
1 << TPC0_CFG_TPC_CMD_ICACHE_PREFETCH_64KB_SHIFT));
usleep_range(1000, 1500);
rc = hl_poll_timeout(
hdev,
mmTPC0_CFG_STATUS + offset,
status,
(status & TPC0_CFG_STATUS_VECTOR_PIPE_EMPTY_MASK) ==
TPC0_CFG_STATUS_VECTOR_PIPE_EMPTY_MASK,
1000,
kernel_timeout);
if (rc) {
dev_err(hdev->dev,
"Timeout while waiting for TPC%d icache prefetch\n",
tpc_id);
return -EIO;
}
WREG32(mmTPC0_CFG_TPC_EXECUTE + offset,
1 << TPC0_CFG_TPC_EXECUTE_V_SHIFT);
usleep_range(1000, 1500);
rc = hl_poll_timeout(
hdev,
mmTPC0_CFG_STATUS + offset,
status,
(status & TPC0_CFG_STATUS_VECTOR_PIPE_EMPTY_MASK) ==
TPC0_CFG_STATUS_VECTOR_PIPE_EMPTY_MASK,
1000,
kernel_timeout);
if (rc) {
dev_err(hdev->dev,
"Timeout while waiting for TPC%d vector pipe\n",
tpc_id);
return -EIO;
}
rc = hl_poll_timeout(
hdev,
mmTPC0_CFG_WQ_INFLIGHT_CNTR + offset,
status,
(status == 0),
1000,
kernel_timeout);
if (rc) {
dev_err(hdev->dev,
"Timeout while waiting for TPC%d kernel to execute\n",
tpc_id);
return -EIO;
}
return 0;
}
static int gaudi_internal_cb_pool_init(struct hl_device *hdev,
struct hl_ctx *ctx)
{
struct gaudi_device *gaudi = hdev->asic_specific;
int min_alloc_order, rc, collective_cb_size;
if (!(gaudi->hw_cap_initialized & HW_CAP_MMU))
return 0;
hdev->internal_cb_pool_virt_addr = hl_asic_dma_alloc_coherent(hdev,
HOST_SPACE_INTERNAL_CB_SZ,
&hdev->internal_cb_pool_dma_addr,
GFP_KERNEL | __GFP_ZERO);
if (!hdev->internal_cb_pool_virt_addr)
return -ENOMEM;
collective_cb_size = sizeof(struct packet_msg_short) * 5 +
sizeof(struct packet_fence);
min_alloc_order = ilog2(collective_cb_size);
hdev->internal_cb_pool = gen_pool_create(min_alloc_order, -1);
if (!hdev->internal_cb_pool) {
dev_err(hdev->dev,
"Failed to create internal CB pool\n");
rc = -ENOMEM;
goto free_internal_cb_pool;
}
rc = gen_pool_add(hdev->internal_cb_pool,
(uintptr_t) hdev->internal_cb_pool_virt_addr,
HOST_SPACE_INTERNAL_CB_SZ, -1);
if (rc) {
dev_err(hdev->dev,
"Failed to add memory to internal CB pool\n");
rc = -EFAULT;
goto destroy_internal_cb_pool;
}
hdev->internal_cb_va_base = hl_reserve_va_block(hdev, ctx,
HL_VA_RANGE_TYPE_HOST, HOST_SPACE_INTERNAL_CB_SZ,
HL_MMU_VA_ALIGNMENT_NOT_NEEDED);
if (!hdev->internal_cb_va_base) {
rc = -ENOMEM;
goto destroy_internal_cb_pool;
}
mutex_lock(&hdev->mmu_lock);
rc = hl_mmu_map_contiguous(ctx, hdev->internal_cb_va_base,
hdev->internal_cb_pool_dma_addr,
HOST_SPACE_INTERNAL_CB_SZ);
if (rc)
goto unreserve_internal_cb_pool;
rc = hl_mmu_invalidate_cache(hdev, false, MMU_OP_USERPTR);
if (rc)
goto unmap_internal_cb_pool;
mutex_unlock(&hdev->mmu_lock);
return 0;
unmap_internal_cb_pool:
hl_mmu_unmap_contiguous(ctx, hdev->internal_cb_va_base,
HOST_SPACE_INTERNAL_CB_SZ);
unreserve_internal_cb_pool:
mutex_unlock(&hdev->mmu_lock);
hl_unreserve_va_block(hdev, ctx, hdev->internal_cb_va_base,
HOST_SPACE_INTERNAL_CB_SZ);
destroy_internal_cb_pool:
gen_pool_destroy(hdev->internal_cb_pool);
free_internal_cb_pool:
hl_asic_dma_free_coherent(hdev, HOST_SPACE_INTERNAL_CB_SZ, hdev->internal_cb_pool_virt_addr,
hdev->internal_cb_pool_dma_addr);
return rc;
}
static void gaudi_internal_cb_pool_fini(struct hl_device *hdev,
struct hl_ctx *ctx)
{
struct gaudi_device *gaudi = hdev->asic_specific;
if (!(gaudi->hw_cap_initialized & HW_CAP_MMU))
return;
mutex_lock(&hdev->mmu_lock);
hl_mmu_unmap_contiguous(ctx, hdev->internal_cb_va_base,
HOST_SPACE_INTERNAL_CB_SZ);
hl_unreserve_va_block(hdev, ctx, hdev->internal_cb_va_base,
HOST_SPACE_INTERNAL_CB_SZ);
hl_mmu_invalidate_cache(hdev, true, MMU_OP_USERPTR);
mutex_unlock(&hdev->mmu_lock);
gen_pool_destroy(hdev->internal_cb_pool);
hl_asic_dma_free_coherent(hdev, HOST_SPACE_INTERNAL_CB_SZ, hdev->internal_cb_pool_virt_addr,
hdev->internal_cb_pool_dma_addr);
}
static int gaudi_ctx_init(struct hl_ctx *ctx)
{
int rc;
if (ctx->asid == HL_KERNEL_ASID_ID)
return 0;
rc = gaudi_internal_cb_pool_init(ctx->hdev, ctx);
if (rc)
return rc;
rc = gaudi_restore_user_registers(ctx->hdev);
if (rc)
gaudi_internal_cb_pool_fini(ctx->hdev, ctx);
return rc;
}
static void gaudi_ctx_fini(struct hl_ctx *ctx)
{
if (ctx->asid == HL_KERNEL_ASID_ID)
return;
gaudi_internal_cb_pool_fini(ctx->hdev, ctx);
}
static int gaudi_pre_schedule_cs(struct hl_cs *cs)
{
return 0;
}
static u32 gaudi_get_queue_id_for_cq(struct hl_device *hdev, u32 cq_idx)
{
return gaudi_cq_assignment[cq_idx];
}
static u32 gaudi_get_signal_cb_size(struct hl_device *hdev)
{
return sizeof(struct packet_msg_short) +
sizeof(struct packet_msg_prot) * 2;
}
static u32 gaudi_get_wait_cb_size(struct hl_device *hdev)
{
return sizeof(struct packet_msg_short) * 4 +
sizeof(struct packet_fence) +
sizeof(struct packet_msg_prot) * 2;
}
static u32 gaudi_get_sob_addr(struct hl_device *hdev, u32 sob_id)
{
return mmSYNC_MNGR_W_S_SYNC_MNGR_OBJS_SOB_OBJ_0 + (sob_id * 4);
}
static u32 gaudi_gen_signal_cb(struct hl_device *hdev, void *data, u16 sob_id,
u32 size, bool eb)
{
struct hl_cb *cb = (struct hl_cb *) data;
struct packet_msg_short *pkt;
u32 value, ctl, pkt_size = sizeof(*pkt);
pkt = cb->kernel_address + size;
memset(pkt, 0, pkt_size);
value = FIELD_PREP(GAUDI_PKT_SHORT_VAL_SOB_SYNC_VAL_MASK, 1);
value |= FIELD_PREP(GAUDI_PKT_SHORT_VAL_SOB_MOD_MASK, 1);
ctl = FIELD_PREP(GAUDI_PKT_SHORT_CTL_ADDR_MASK, sob_id * 4);
ctl |= FIELD_PREP(GAUDI_PKT_SHORT_CTL_OP_MASK, 0);
ctl |= FIELD_PREP(GAUDI_PKT_SHORT_CTL_BASE_MASK, 3);
ctl |= FIELD_PREP(GAUDI_PKT_CTL_OPCODE_MASK, PACKET_MSG_SHORT);
ctl |= FIELD_PREP(GAUDI_PKT_CTL_EB_MASK, eb);
ctl |= FIELD_PREP(GAUDI_PKT_CTL_RB_MASK, 1);
ctl |= FIELD_PREP(GAUDI_PKT_CTL_MB_MASK, 1);
pkt->value = cpu_to_le32(value);
pkt->ctl = cpu_to_le32(ctl);
return size + pkt_size;
}
static u32 gaudi_add_mon_msg_short(struct packet_msg_short *pkt, u32 value,
u16 addr)
{
u32 ctl, pkt_size = sizeof(*pkt);
memset(pkt, 0, pkt_size);
ctl = FIELD_PREP(GAUDI_PKT_SHORT_CTL_ADDR_MASK, addr);
ctl |= FIELD_PREP(GAUDI_PKT_SHORT_CTL_BASE_MASK, 2);
ctl |= FIELD_PREP(GAUDI_PKT_CTL_OPCODE_MASK, PACKET_MSG_SHORT);
ctl |= FIELD_PREP(GAUDI_PKT_CTL_EB_MASK, 0);
ctl |= FIELD_PREP(GAUDI_PKT_CTL_RB_MASK, 1);
ctl |= FIELD_PREP(GAUDI_PKT_CTL_MB_MASK, 0);
pkt->value = cpu_to_le32(value);
pkt->ctl = cpu_to_le32(ctl);
return pkt_size;
}
static u32 gaudi_add_arm_monitor_pkt(struct hl_device *hdev,
struct packet_msg_short *pkt, u16 sob_base, u8 sob_mask,
u16 sob_val, u16 mon_id)
{
u64 monitor_base;
u32 ctl, value, pkt_size = sizeof(*pkt);
u16 msg_addr_offset;
u8 mask;
if (hl_gen_sob_mask(sob_base, sob_mask, &mask)) {
dev_err(hdev->dev,
"sob_base %u (mask %#x) is not valid\n",
sob_base, sob_mask);
return 0;
}
monitor_base = mmSYNC_MNGR_W_S_SYNC_MNGR_OBJS_MON_PAY_ADDRL_0;
msg_addr_offset =
(mmSYNC_MNGR_W_S_SYNC_MNGR_OBJS_MON_ARM_0 + mon_id * 4) -
monitor_base;
memset(pkt, 0, pkt_size);
value = FIELD_PREP(GAUDI_PKT_SHORT_VAL_MON_SYNC_GID_MASK, sob_base / 8);
value |= FIELD_PREP(GAUDI_PKT_SHORT_VAL_MON_SYNC_VAL_MASK, sob_val);
value |= FIELD_PREP(GAUDI_PKT_SHORT_VAL_MON_MODE_MASK,
0);
value |= FIELD_PREP(GAUDI_PKT_SHORT_VAL_MON_MASK_MASK, mask);
ctl = FIELD_PREP(GAUDI_PKT_SHORT_CTL_ADDR_MASK, msg_addr_offset);
ctl |= FIELD_PREP(GAUDI_PKT_SHORT_CTL_OP_MASK, 0);
ctl |= FIELD_PREP(GAUDI_PKT_SHORT_CTL_BASE_MASK, 2);
ctl |= FIELD_PREP(GAUDI_PKT_CTL_OPCODE_MASK, PACKET_MSG_SHORT);
ctl |= FIELD_PREP(GAUDI_PKT_CTL_EB_MASK, 0);
ctl |= FIELD_PREP(GAUDI_PKT_CTL_RB_MASK, 1);
ctl |= FIELD_PREP(GAUDI_PKT_CTL_MB_MASK, 1);
pkt->value = cpu_to_le32(value);
pkt->ctl = cpu_to_le32(ctl);
return pkt_size;
}
static u32 gaudi_add_fence_pkt(struct packet_fence *pkt)
{
u32 ctl, cfg, pkt_size = sizeof(*pkt);
memset(pkt, 0, pkt_size);
cfg = FIELD_PREP(GAUDI_PKT_FENCE_CFG_DEC_VAL_MASK, 1);
cfg |= FIELD_PREP(GAUDI_PKT_FENCE_CFG_TARGET_VAL_MASK, 1);
cfg |= FIELD_PREP(GAUDI_PKT_FENCE_CFG_ID_MASK, 2);
ctl = FIELD_PREP(GAUDI_PKT_CTL_OPCODE_MASK, PACKET_FENCE);
ctl |= FIELD_PREP(GAUDI_PKT_CTL_EB_MASK, 0);
ctl |= FIELD_PREP(GAUDI_PKT_CTL_RB_MASK, 1);
ctl |= FIELD_PREP(GAUDI_PKT_CTL_MB_MASK, 1);
pkt->cfg = cpu_to_le32(cfg);
pkt->ctl = cpu_to_le32(ctl);
return pkt_size;
}
static int gaudi_get_fence_addr(struct hl_device *hdev, u32 queue_id, u64 *addr)
{
u32 offset, nic_index;
switch (queue_id) {
case GAUDI_QUEUE_ID_DMA_0_0:
offset = mmDMA0_QM_CP_FENCE2_RDATA_0;
break;
case GAUDI_QUEUE_ID_DMA_0_1:
offset = mmDMA0_QM_CP_FENCE2_RDATA_1;
break;
case GAUDI_QUEUE_ID_DMA_0_2:
offset = mmDMA0_QM_CP_FENCE2_RDATA_2;
break;
case GAUDI_QUEUE_ID_DMA_0_3:
offset = mmDMA0_QM_CP_FENCE2_RDATA_3;
break;
case GAUDI_QUEUE_ID_DMA_1_0:
offset = mmDMA1_QM_CP_FENCE2_RDATA_0;
break;
case GAUDI_QUEUE_ID_DMA_1_1:
offset = mmDMA1_QM_CP_FENCE2_RDATA_1;
break;
case GAUDI_QUEUE_ID_DMA_1_2:
offset = mmDMA1_QM_CP_FENCE2_RDATA_2;
break;
case GAUDI_QUEUE_ID_DMA_1_3:
offset = mmDMA1_QM_CP_FENCE2_RDATA_3;
break;
case GAUDI_QUEUE_ID_DMA_5_0:
offset = mmDMA5_QM_CP_FENCE2_RDATA_0;
break;
case GAUDI_QUEUE_ID_DMA_5_1:
offset = mmDMA5_QM_CP_FENCE2_RDATA_1;
break;
case GAUDI_QUEUE_ID_DMA_5_2:
offset = mmDMA5_QM_CP_FENCE2_RDATA_2;
break;
case GAUDI_QUEUE_ID_DMA_5_3:
offset = mmDMA5_QM_CP_FENCE2_RDATA_3;
break;
case GAUDI_QUEUE_ID_TPC_7_0:
offset = mmTPC7_QM_CP_FENCE2_RDATA_0;
break;
case GAUDI_QUEUE_ID_TPC_7_1:
offset = mmTPC7_QM_CP_FENCE2_RDATA_1;
break;
case GAUDI_QUEUE_ID_TPC_7_2:
offset = mmTPC7_QM_CP_FENCE2_RDATA_2;
break;
case GAUDI_QUEUE_ID_TPC_7_3:
offset = mmTPC7_QM_CP_FENCE2_RDATA_3;
break;
case GAUDI_QUEUE_ID_NIC_0_0:
case GAUDI_QUEUE_ID_NIC_1_0:
case GAUDI_QUEUE_ID_NIC_2_0:
case GAUDI_QUEUE_ID_NIC_3_0:
case GAUDI_QUEUE_ID_NIC_4_0:
case GAUDI_QUEUE_ID_NIC_5_0:
case GAUDI_QUEUE_ID_NIC_6_0:
case GAUDI_QUEUE_ID_NIC_7_0:
case GAUDI_QUEUE_ID_NIC_8_0:
case GAUDI_QUEUE_ID_NIC_9_0:
nic_index = (queue_id - GAUDI_QUEUE_ID_NIC_0_0) >> 2;
offset = mmNIC0_QM0_CP_FENCE2_RDATA_0 +
(nic_index >> 1) * NIC_MACRO_QMAN_OFFSET +
(nic_index & 0x1) * NIC_ENGINE_QMAN_OFFSET;
break;
case GAUDI_QUEUE_ID_NIC_0_1:
case GAUDI_QUEUE_ID_NIC_1_1:
case GAUDI_QUEUE_ID_NIC_2_1:
case GAUDI_QUEUE_ID_NIC_3_1:
case GAUDI_QUEUE_ID_NIC_4_1:
case GAUDI_QUEUE_ID_NIC_5_1:
case GAUDI_QUEUE_ID_NIC_6_1:
case GAUDI_QUEUE_ID_NIC_7_1:
case GAUDI_QUEUE_ID_NIC_8_1:
case GAUDI_QUEUE_ID_NIC_9_1:
nic_index = (queue_id - GAUDI_QUEUE_ID_NIC_0_1) >> 2;
offset = mmNIC0_QM0_CP_FENCE2_RDATA_1 +
(nic_index >> 1) * NIC_MACRO_QMAN_OFFSET +
(nic_index & 0x1) * NIC_ENGINE_QMAN_OFFSET;
break;
case GAUDI_QUEUE_ID_NIC_0_2:
case GAUDI_QUEUE_ID_NIC_1_2:
case GAUDI_QUEUE_ID_NIC_2_2:
case GAUDI_QUEUE_ID_NIC_3_2:
case GAUDI_QUEUE_ID_NIC_4_2:
case GAUDI_QUEUE_ID_NIC_5_2:
case GAUDI_QUEUE_ID_NIC_6_2:
case GAUDI_QUEUE_ID_NIC_7_2:
case GAUDI_QUEUE_ID_NIC_8_2:
case GAUDI_QUEUE_ID_NIC_9_2:
nic_index = (queue_id - GAUDI_QUEUE_ID_NIC_0_2) >> 2;
offset = mmNIC0_QM0_CP_FENCE2_RDATA_2 +
(nic_index >> 1) * NIC_MACRO_QMAN_OFFSET +
(nic_index & 0x1) * NIC_ENGINE_QMAN_OFFSET;
break;
case GAUDI_QUEUE_ID_NIC_0_3:
case GAUDI_QUEUE_ID_NIC_1_3:
case GAUDI_QUEUE_ID_NIC_2_3:
case GAUDI_QUEUE_ID_NIC_3_3:
case GAUDI_QUEUE_ID_NIC_4_3:
case GAUDI_QUEUE_ID_NIC_5_3:
case GAUDI_QUEUE_ID_NIC_6_3:
case GAUDI_QUEUE_ID_NIC_7_3:
case GAUDI_QUEUE_ID_NIC_8_3:
case GAUDI_QUEUE_ID_NIC_9_3:
nic_index = (queue_id - GAUDI_QUEUE_ID_NIC_0_3) >> 2;
offset = mmNIC0_QM0_CP_FENCE2_RDATA_3 +
(nic_index >> 1) * NIC_MACRO_QMAN_OFFSET +
(nic_index & 0x1) * NIC_ENGINE_QMAN_OFFSET;
break;
default:
return -EINVAL;
}
*addr = CFG_BASE + offset;
return 0;
}
static u32 gaudi_add_mon_pkts(void *buf, u16 mon_id, u64 fence_addr)
{
u64 monitor_base;
u32 size = 0;
u16 msg_addr_offset;
monitor_base = mmSYNC_MNGR_W_S_SYNC_MNGR_OBJS_MON_PAY_ADDRL_0;
msg_addr_offset =
(mmSYNC_MNGR_W_S_SYNC_MNGR_OBJS_MON_PAY_ADDRL_0 + mon_id * 4) -
monitor_base;
size += gaudi_add_mon_msg_short(buf + size, (u32) fence_addr,
msg_addr_offset);
msg_addr_offset =
(mmSYNC_MNGR_W_S_SYNC_MNGR_OBJS_MON_PAY_ADDRH_0 + mon_id * 4) -
monitor_base;
size += gaudi_add_mon_msg_short(buf + size, (u32) (fence_addr >> 32),
msg_addr_offset);
msg_addr_offset =
(mmSYNC_MNGR_W_S_SYNC_MNGR_OBJS_MON_PAY_DATA_0 + mon_id * 4) -
monitor_base;
size += gaudi_add_mon_msg_short(buf + size, 1, msg_addr_offset);
return size;
}
static u32 gaudi_gen_wait_cb(struct hl_device *hdev,
struct hl_gen_wait_properties *prop)
{
struct hl_cb *cb = (struct hl_cb *) prop->data;
void *buf = cb->kernel_address;
u64 fence_addr = 0;
u32 size = prop->size;
if (gaudi_get_fence_addr(hdev, prop->q_idx, &fence_addr)) {
dev_crit(hdev->dev, "wrong queue id %d for wait packet\n",
prop->q_idx);
return 0;
}
size += gaudi_add_mon_pkts(buf + size, prop->mon_id, fence_addr);
size += gaudi_add_arm_monitor_pkt(hdev, buf + size, prop->sob_base,
prop->sob_mask, prop->sob_val, prop->mon_id);
size += gaudi_add_fence_pkt(buf + size);
return size;
}
static void gaudi_reset_sob(struct hl_device *hdev, void *data)
{
struct hl_hw_sob *hw_sob = (struct hl_hw_sob *) data;
dev_dbg(hdev->dev, "reset SOB, q_idx: %d, sob_id: %d\n", hw_sob->q_idx,
hw_sob->sob_id);
WREG32(mmSYNC_MNGR_W_S_SYNC_MNGR_OBJS_SOB_OBJ_0 +
hw_sob->sob_id * 4, 0);
kref_init(&hw_sob->kref);
}
static u64 gaudi_get_device_time(struct hl_device *hdev)
{
u64 device_time = ((u64) RREG32(mmPSOC_TIMESTAMP_CNTCVU)) << 32;
return device_time | RREG32(mmPSOC_TIMESTAMP_CNTCVL);
}
static int gaudi_get_hw_block_id(struct hl_device *hdev, u64 block_addr,
u32 *block_size, u32 *block_id)
{
return -EPERM;
}
static int gaudi_block_mmap(struct hl_device *hdev,
struct vm_area_struct *vma,
u32 block_id, u32 block_size)
{
return -EPERM;
}
static void gaudi_enable_events_from_fw(struct hl_device *hdev)
{
struct cpu_dyn_regs *dyn_regs =
&hdev->fw_loader.dynamic_loader.comm_desc.cpu_dyn_regs;
u32 irq_handler_offset = hdev->asic_prop.gic_interrupts_enable ?
mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR :
le32_to_cpu(dyn_regs->gic_host_ints_irq);
WREG32(irq_handler_offset,
gaudi_irq_map_table[GAUDI_EVENT_INTS_REGISTER].cpu_id);
}
static int gaudi_ack_mmu_page_fault_or_access_error(struct hl_device *hdev, u64 mmu_cap_mask)
{
return -EINVAL;
}
static int gaudi_map_pll_idx_to_fw_idx(u32 pll_idx)
{
switch (pll_idx) {
case HL_GAUDI_CPU_PLL: return CPU_PLL;
case HL_GAUDI_PCI_PLL: return PCI_PLL;
case HL_GAUDI_NIC_PLL: return NIC_PLL;
case HL_GAUDI_DMA_PLL: return DMA_PLL;
case HL_GAUDI_MESH_PLL: return MESH_PLL;
case HL_GAUDI_MME_PLL: return MME_PLL;
case HL_GAUDI_TPC_PLL: return TPC_PLL;
case HL_GAUDI_IF_PLL: return IF_PLL;
case HL_GAUDI_SRAM_PLL: return SRAM_PLL;
case HL_GAUDI_HBM_PLL: return HBM_PLL;
default: return -EINVAL;
}
}
static int gaudi_add_sync_to_engine_map_entry(
struct hl_sync_to_engine_map *map, u32 reg_value,
enum hl_sync_engine_type engine_type, u32 engine_id)
{
struct hl_sync_to_engine_map_entry *entry;
if (reg_value == 0 || reg_value == 0xffffffff)
return 0;
reg_value -= lower_32_bits(CFG_BASE);
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
if (!entry)
return -ENOMEM;
entry->engine_type = engine_type;
entry->engine_id = engine_id;
entry->sync_id = reg_value;
hash_add(map->tb, &entry->node, reg_value);
return 0;
}
static int gaudi_gen_sync_to_engine_map(struct hl_device *hdev,
struct hl_sync_to_engine_map *map)
{
struct hl_state_dump_specs *sds = &hdev->state_dump_specs;
int i, j, rc;
u32 reg_value;
for (i = 0; i < sds->props[SP_NUM_OF_TPC_ENGINES]; ++i) {
reg_value = RREG32(sds->props[SP_TPC0_CFG_SO] +
sds->props[SP_NEXT_TPC] * i);
rc = gaudi_add_sync_to_engine_map_entry(map, reg_value,
ENGINE_TPC, i);
if (rc)
goto free_sync_to_engine_map;
}
for (i = 0; i < sds->props[SP_NUM_OF_MME_ENGINES]; ++i) {
for (j = 0; j < sds->props[SP_SUB_MME_ENG_NUM]; ++j) {
reg_value = RREG32(sds->props[SP_MME_CFG_SO] +
sds->props[SP_NEXT_MME] * i +
j * sizeof(u32));
rc = gaudi_add_sync_to_engine_map_entry(
map, reg_value, ENGINE_MME,
i * sds->props[SP_SUB_MME_ENG_NUM] + j);
if (rc)
goto free_sync_to_engine_map;
}
}
for (i = 0; i < sds->props[SP_NUM_OF_DMA_ENGINES]; ++i) {
reg_value = RREG32(sds->props[SP_DMA_CFG_SO] +
sds->props[SP_DMA_QUEUES_OFFSET] * i);
rc = gaudi_add_sync_to_engine_map_entry(map, reg_value,
ENGINE_DMA, i);
if (rc)
goto free_sync_to_engine_map;
}
return 0;
free_sync_to_engine_map:
hl_state_dump_free_sync_to_engine_map(map);
return rc;
}
static int gaudi_monitor_valid(struct hl_mon_state_dump *mon)
{
return FIELD_GET(
SYNC_MNGR_W_S_SYNC_MNGR_OBJS_MON_STATUS_0_VALID_MASK,
mon->status);
}
static void gaudi_fill_sobs_from_mon(char *sobs, struct hl_mon_state_dump *mon)
{
const size_t max_write = 10;
u32 gid, mask, sob;
int i, offset;
gid = FIELD_GET(SYNC_MNGR_W_S_SYNC_MNGR_OBJS_MON_ARM_0_SID_MASK,
mon->arm_data);
mask = FIELD_GET(SYNC_MNGR_W_S_SYNC_MNGR_OBJS_MON_ARM_0_MASK_MASK,
mon->arm_data);
for (i = 0, offset = 0; mask && offset < MONITOR_SOB_STRING_SIZE -
max_write; mask >>= 1, i++) {
if (!(mask & 1)) {
sob = gid * MONITOR_MAX_SOBS + i;
if (offset > 0)
offset += snprintf(sobs + offset, max_write,
", ");
offset += snprintf(sobs + offset, max_write, "%u", sob);
}
}
}
static int gaudi_print_single_monitor(char **buf, size_t *size, size_t *offset,
struct hl_device *hdev,
struct hl_mon_state_dump *mon)
{
const char *name;
char scratch_buf1[BIN_REG_STRING_SIZE],
scratch_buf2[BIN_REG_STRING_SIZE];
char monitored_sobs[MONITOR_SOB_STRING_SIZE] = {0};
name = hl_state_dump_get_monitor_name(hdev, mon);
if (!name)
name = "";
gaudi_fill_sobs_from_mon(monitored_sobs, mon);
return hl_snprintf_resize(
buf, size, offset,
"Mon id: %u%s, wait for group id: %u mask %s to reach val: %u and write %u to address 0x%llx. Pending: %s. Means sync objects [%s] are being monitored.",
mon->id, name,
FIELD_GET(SYNC_MNGR_W_S_SYNC_MNGR_OBJS_MON_ARM_0_SID_MASK,
mon->arm_data),
hl_format_as_binary(
scratch_buf1, sizeof(scratch_buf1),
FIELD_GET(
SYNC_MNGR_W_S_SYNC_MNGR_OBJS_MON_ARM_0_MASK_MASK,
mon->arm_data)),
FIELD_GET(SYNC_MNGR_W_S_SYNC_MNGR_OBJS_MON_ARM_0_SOD_MASK,
mon->arm_data),
mon->wr_data,
(((u64)mon->wr_addr_high) << 32) | mon->wr_addr_low,
hl_format_as_binary(
scratch_buf2, sizeof(scratch_buf2),
FIELD_GET(
SYNC_MNGR_W_S_SYNC_MNGR_OBJS_MON_STATUS_0_PENDING_MASK,
mon->status)),
monitored_sobs);
}
static int gaudi_print_fences_single_engine(
struct hl_device *hdev, u64 base_offset, u64 status_base_offset,
enum hl_sync_engine_type engine_type, u32 engine_id, char **buf,
size_t *size, size_t *offset)
{
struct hl_state_dump_specs *sds = &hdev->state_dump_specs;
int rc = -ENOMEM, i;
u32 *statuses, *fences;
statuses = kcalloc(sds->props[SP_ENGINE_NUM_OF_QUEUES],
sizeof(*statuses), GFP_KERNEL);
if (!statuses)
goto out;
fences = kcalloc(sds->props[SP_ENGINE_NUM_OF_FENCES] *
sds->props[SP_ENGINE_NUM_OF_QUEUES],
sizeof(*fences), GFP_KERNEL);
if (!fences)
goto free_status;
for (i = 0; i < sds->props[SP_ENGINE_NUM_OF_FENCES]; ++i)
statuses[i] = RREG32(status_base_offset + i * sizeof(u32));
for (i = 0; i < sds->props[SP_ENGINE_NUM_OF_FENCES] *
sds->props[SP_ENGINE_NUM_OF_QUEUES]; ++i)
fences[i] = RREG32(base_offset + i * sizeof(u32));
for (i = 0; i < sds->props[SP_ENGINE_NUM_OF_QUEUES]; ++i) {
u32 fence_id;
u64 fence_cnt, fence_rdata;
const char *engine_name;
if (!FIELD_GET(TPC0_QM_CP_STS_0_FENCE_IN_PROGRESS_MASK,
statuses[i]))
continue;
fence_id =
FIELD_GET(TPC0_QM_CP_STS_0_FENCE_ID_MASK, statuses[i]);
fence_cnt = base_offset + CFG_BASE +
sizeof(u32) *
(i + fence_id * sds->props[SP_ENGINE_NUM_OF_QUEUES]);
fence_rdata = fence_cnt - sds->props[SP_FENCE0_CNT_OFFSET] +
sds->props[SP_FENCE0_RDATA_OFFSET];
engine_name = hl_sync_engine_to_string(engine_type);
rc = hl_snprintf_resize(
buf, size, offset,
"%s%u, stream %u: fence id %u cnt = 0x%llx (%s%u_QM.CP_FENCE%u_CNT_%u) rdata = 0x%llx (%s%u_QM.CP_FENCE%u_RDATA_%u) value = %u, cp_status = %u\n",
engine_name, engine_id,
i, fence_id,
fence_cnt, engine_name, engine_id, fence_id, i,
fence_rdata, engine_name, engine_id, fence_id, i,
fences[fence_id],
statuses[i]);
if (rc)
goto free_fences;
}
rc = 0;
free_fences:
kfree(fences);
free_status:
kfree(statuses);
out:
return rc;
}
static struct hl_state_dump_specs_funcs gaudi_state_dump_funcs = {
.monitor_valid = gaudi_monitor_valid,
.print_single_monitor = gaudi_print_single_monitor,
.gen_sync_to_engine_map = gaudi_gen_sync_to_engine_map,
.print_fences_single_engine = gaudi_print_fences_single_engine,
};
static void gaudi_state_dump_init(struct hl_device *hdev)
{
struct hl_state_dump_specs *sds = &hdev->state_dump_specs;
int i;
for (i = 0; i < ARRAY_SIZE(gaudi_so_id_to_str); ++i)
hash_add(sds->so_id_to_str_tb,
&gaudi_so_id_to_str[i].node,
gaudi_so_id_to_str[i].id);
for (i = 0; i < ARRAY_SIZE(gaudi_monitor_id_to_str); ++i)
hash_add(sds->monitor_id_to_str_tb,
&gaudi_monitor_id_to_str[i].node,
gaudi_monitor_id_to_str[i].id);
sds->props = gaudi_state_dump_specs_props;
sds->sync_namager_names = gaudi_sync_manager_names;
sds->funcs = gaudi_state_dump_funcs;
}
static u32 *gaudi_get_stream_master_qid_arr(void)
{
return gaudi_stream_master;
}
static int gaudi_set_dram_properties(struct hl_device *hdev)
{
return 0;
}
static int gaudi_set_binning_masks(struct hl_device *hdev)
{
return 0;
}
static void gaudi_check_if_razwi_happened(struct hl_device *hdev)
{
}
static ssize_t infineon_ver_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct hl_device *hdev = dev_get_drvdata(dev);
struct cpucp_info *cpucp_info;
cpucp_info = &hdev->asic_prop.cpucp_info;
return sprintf(buf, "%#04x\n", le32_to_cpu(cpucp_info->infineon_version));
}
static DEVICE_ATTR_RO(infineon_ver);
static struct attribute *gaudi_vrm_dev_attrs[] = {
&dev_attr_infineon_ver.attr,
NULL,
};
static void gaudi_add_device_attr(struct hl_device *hdev, struct attribute_group *dev_clk_attr_grp,
struct attribute_group *dev_vrm_attr_grp)
{
hl_sysfs_add_dev_clk_attr(hdev, dev_clk_attr_grp);
dev_vrm_attr_grp->attrs = gaudi_vrm_dev_attrs;
}
static int gaudi_send_device_activity(struct hl_device *hdev, bool open)
{
return 0;
}
static const struct hl_asic_funcs gaudi_funcs = {
.early_init = gaudi_early_init,
.early_fini = gaudi_early_fini,
.late_init = gaudi_late_init,
.late_fini = gaudi_late_fini,
.sw_init = gaudi_sw_init,
.sw_fini = gaudi_sw_fini,
.hw_init = gaudi_hw_init,
.hw_fini = gaudi_hw_fini,
.halt_engines = gaudi_halt_engines,
.suspend = gaudi_suspend,
.resume = gaudi_resume,
.mmap = gaudi_mmap,
.ring_doorbell = gaudi_ring_doorbell,
.pqe_write = gaudi_pqe_write,
.asic_dma_alloc_coherent = gaudi_dma_alloc_coherent,
.asic_dma_free_coherent = gaudi_dma_free_coherent,
.scrub_device_mem = gaudi_scrub_device_mem,
.scrub_device_dram = gaudi_scrub_device_dram,
.get_int_queue_base = gaudi_get_int_queue_base,
.test_queues = gaudi_test_queues,
.asic_dma_pool_zalloc = gaudi_dma_pool_zalloc,
.asic_dma_pool_free = gaudi_dma_pool_free,
.cpu_accessible_dma_pool_alloc = gaudi_cpu_accessible_dma_pool_alloc,
.cpu_accessible_dma_pool_free = gaudi_cpu_accessible_dma_pool_free,
.hl_dma_unmap_sgtable = hl_dma_unmap_sgtable,
.cs_parser = gaudi_cs_parser,
.asic_dma_map_sgtable = hl_dma_map_sgtable,
.add_end_of_cb_packets = gaudi_add_end_of_cb_packets,
.update_eq_ci = gaudi_update_eq_ci,
.context_switch = gaudi_context_switch,
.restore_phase_topology = gaudi_restore_phase_topology,
.debugfs_read_dma = gaudi_debugfs_read_dma,
.add_device_attr = gaudi_add_device_attr,
.handle_eqe = gaudi_handle_eqe,
.get_events_stat = gaudi_get_events_stat,
.read_pte = gaudi_read_pte,
.write_pte = gaudi_write_pte,
.mmu_invalidate_cache = gaudi_mmu_invalidate_cache,
.mmu_invalidate_cache_range = gaudi_mmu_invalidate_cache_range,
.mmu_prefetch_cache_range = NULL,
.send_heartbeat = gaudi_send_heartbeat,
.debug_coresight = gaudi_debug_coresight,
.is_device_idle = gaudi_is_device_idle,
.compute_reset_late_init = gaudi_compute_reset_late_init,
.hw_queues_lock = gaudi_hw_queues_lock,
.hw_queues_unlock = gaudi_hw_queues_unlock,
.get_pci_id = gaudi_get_pci_id,
.get_eeprom_data = gaudi_get_eeprom_data,
.get_monitor_dump = gaudi_get_monitor_dump,
.send_cpu_message = gaudi_send_cpu_message,
.pci_bars_map = gaudi_pci_bars_map,
.init_iatu = gaudi_init_iatu,
.rreg = hl_rreg,
.wreg = hl_wreg,
.halt_coresight = gaudi_halt_coresight,
.ctx_init = gaudi_ctx_init,
.ctx_fini = gaudi_ctx_fini,
.pre_schedule_cs = gaudi_pre_schedule_cs,
.get_queue_id_for_cq = gaudi_get_queue_id_for_cq,
.load_firmware_to_device = gaudi_load_firmware_to_device,
.load_boot_fit_to_device = gaudi_load_boot_fit_to_device,
.get_signal_cb_size = gaudi_get_signal_cb_size,
.get_wait_cb_size = gaudi_get_wait_cb_size,
.gen_signal_cb = gaudi_gen_signal_cb,
.gen_wait_cb = gaudi_gen_wait_cb,
.reset_sob = gaudi_reset_sob,
.reset_sob_group = gaudi_reset_sob_group,
.get_device_time = gaudi_get_device_time,
.pb_print_security_errors = NULL,
.collective_wait_init_cs = gaudi_collective_wait_init_cs,
.collective_wait_create_jobs = gaudi_collective_wait_create_jobs,
.get_dec_base_addr = NULL,
.scramble_addr = hl_mmu_scramble_addr,
.descramble_addr = hl_mmu_descramble_addr,
.ack_protection_bits_errors = gaudi_ack_protection_bits_errors,
.get_hw_block_id = gaudi_get_hw_block_id,
.hw_block_mmap = gaudi_block_mmap,
.enable_events_from_fw = gaudi_enable_events_from_fw,
.ack_mmu_errors = gaudi_ack_mmu_page_fault_or_access_error,
.map_pll_idx_to_fw_idx = gaudi_map_pll_idx_to_fw_idx,
.init_firmware_preload_params = gaudi_init_firmware_preload_params,
.init_firmware_loader = gaudi_init_firmware_loader,
.init_cpu_scrambler_dram = gaudi_init_scrambler_hbm,
.state_dump_init = gaudi_state_dump_init,
.get_sob_addr = gaudi_get_sob_addr,
.set_pci_memory_regions = gaudi_set_pci_memory_regions,
.get_stream_master_qid_arr = gaudi_get_stream_master_qid_arr,
.check_if_razwi_happened = gaudi_check_if_razwi_happened,
.mmu_get_real_page_size = hl_mmu_get_real_page_size,
.access_dev_mem = hl_access_dev_mem,
.set_dram_bar_base = gaudi_set_hbm_bar_base,
.send_device_activity = gaudi_send_device_activity,
.set_dram_properties = gaudi_set_dram_properties,
.set_binning_masks = gaudi_set_binning_masks,
};
void gaudi_set_asic_funcs(struct hl_device *hdev)
{
hdev->asic_funcs = &gaudi_funcs;
}