Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/drivers/accel/habanalabs/goya/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 152 kB image not shown  

Quelle  goya.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0

/*
 * Copyright 2016-2022 HabanaLabs, Ltd.
 * All Rights Reserved.
 */


#include "goyaP.h"
#include "../include/hw_ip/mmu/mmu_general.h"
#include "../include/hw_ip/mmu/mmu_v1_0.h"
#include "../include/goya/asic_reg/goya_masks.h"
#include "../include/goya/goya_reg_map.h"

#include <linux/pci.h>
#include <linux/hwmon.h>
#include <linux/iommu.h>
#include <linux/seq_file.h>

/*
 * GOYA security scheme:
 *
 * 1. Host is protected by:
 *        - Range registers (When MMU is enabled, DMA RR does NOT protect host)
 *        - MMU
 *
 * 2. DRAM is protected by:
 *        - Range registers (protect the first 512MB)
 *        - MMU (isolation between users)
 *
 * 3. Configuration is protected by:
 *        - Range registers
 *        - Protection bits
 *
 * When MMU is disabled:
 *
 * QMAN DMA: PQ, CQ, CP, DMA are secured.
 * PQ, CB and the data are on the host.
 *
 * QMAN TPC/MME:
 * PQ, CQ and CP are not secured.
 * PQ, CB and the data are on the SRAM/DRAM.
 *
 * Since QMAN DMA is secured, the driver is parsing the DMA CB:
 *     - checks DMA pointer
 *     - WREG, MSG_PROT are not allowed.
 *     - MSG_LONG/SHORT are allowed.
 *
 * A read/write transaction by the QMAN to a protected area will succeed if
 * and only if the QMAN's CP is secured and MSG_PROT is used
 *
 *
 * When MMU is enabled:
 *
 * QMAN DMA: PQ, CQ and CP are secured.
 * MMU is set to bypass on the Secure props register of the QMAN.
 * The reasons we don't enable MMU for PQ, CQ and CP are:
 *     - PQ entry is in kernel address space and the driver doesn't map it.
 *     - CP writes to MSIX register and to kernel address space (completion
 *       queue).
 *
 * DMA is not secured but because CP is secured, the driver still needs to parse
 * the CB, but doesn't need to check the DMA addresses.
 *
 * For QMAN DMA 0, DMA is also secured because only the driver uses this DMA and
 * the driver doesn't map memory in MMU.
 *
 * QMAN TPC/MME: PQ, CQ and CP aren't secured (no change from MMU disabled mode)
 *
 * DMA RR does NOT protect host because DMA is not secured
 *
 */


#define GOYA_BOOT_FIT_FILE "habanalabs/goya/goya-boot-fit.itb"
#define GOYA_LINUX_FW_FILE "habanalabs/goya/goya-fit.itb"

#define GOYA_MMU_REGS_NUM  63

#define GOYA_DMA_POOL_BLK_SIZE  0x100  /* 256 bytes */

#define GOYA_RESET_TIMEOUT_MSEC  500  /* 500ms */
#define GOYA_PLDM_RESET_TIMEOUT_MSEC 20000  /* 20s */
#define GOYA_RESET_WAIT_MSEC  1  /* 1ms */
#define GOYA_CPU_RESET_WAIT_MSEC 100  /* 100ms */
#define GOYA_PLDM_RESET_WAIT_MSEC 1000  /* 1s */
#define GOYA_TEST_QUEUE_WAIT_USEC 100000  /* 100ms */
#define GOYA_PLDM_MMU_TIMEOUT_USEC (MMU_CONFIG_TIMEOUT_USEC * 100)
#define GOYA_PLDM_QMAN0_TIMEOUT_USEC (HL_DEVICE_TIMEOUT_USEC * 30)
#define GOYA_BOOT_FIT_REQ_TIMEOUT_USEC 1000000  /* 1s */
#define GOYA_MSG_TO_CPU_TIMEOUT_USEC 4000000  /* 4s */
#define GOYA_WAIT_FOR_BL_TIMEOUT_USEC 15000000 /* 15s */

#define GOYA_QMAN0_FENCE_VAL  0xD169B243

#define GOYA_MAX_STRING_LEN  20

#define GOYA_CB_POOL_CB_CNT  512
#define GOYA_CB_POOL_CB_SIZE  0x20000  /* 128KB */

#define IS_QM_IDLE(engine, qm_glbl_sts0) \
 (((qm_glbl_sts0) & engine##_QM_IDLE_MASK) == engine##_QM_IDLE_MASK)
#define IS_DMA_QM_IDLE(qm_glbl_sts0) IS_QM_IDLE(DMA, qm_glbl_sts0)
#define IS_TPC_QM_IDLE(qm_glbl_sts0) IS_QM_IDLE(TPC, qm_glbl_sts0)
#define IS_MME_QM_IDLE(qm_glbl_sts0) IS_QM_IDLE(MME, qm_glbl_sts0)

#define IS_CMDQ_IDLE(engine, cmdq_glbl_sts0) \
 (((cmdq_glbl_sts0) & engine##_CMDQ_IDLE_MASK) == \
   engine##_CMDQ_IDLE_MASK)
#define IS_TPC_CMDQ_IDLE(cmdq_glbl_sts0) \
 IS_CMDQ_IDLE(TPC, cmdq_glbl_sts0)
#define IS_MME_CMDQ_IDLE(cmdq_glbl_sts0) \
 IS_CMDQ_IDLE(MME, cmdq_glbl_sts0)

#define IS_DMA_IDLE(dma_core_sts0) \
 !((dma_core_sts0) & DMA_CH_0_STS0_DMA_BUSY_MASK)

#define IS_TPC_IDLE(tpc_cfg_sts) \
 (((tpc_cfg_sts) & TPC_CFG_IDLE_MASK) == TPC_CFG_IDLE_MASK)

#define IS_MME_IDLE(mme_arch_sts) \
 (((mme_arch_sts) & MME_ARCH_IDLE_MASK) == MME_ARCH_IDLE_MASK)

static const char goya_irq_name[GOYA_MSIX_ENTRIES][GOYA_MAX_STRING_LEN] = {
  "goya cq 0""goya cq 1""goya cq 2""goya cq 3",
  "goya cq 4""goya cpu eq"
};

static u16 goya_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_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)
};

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_MSG_PROT:
 case PACKET_FENCE:
 case PACKET_LIN_DMA:
 case PACKET_NOP:
 case PACKET_STOP:
  return true;
 default:
  return false;
 }
}

static u64 goya_mmu_regs[GOYA_MMU_REGS_NUM] = {
 mmDMA_QM_0_GLBL_NON_SECURE_PROPS,
 mmDMA_QM_1_GLBL_NON_SECURE_PROPS,
 mmDMA_QM_2_GLBL_NON_SECURE_PROPS,
 mmDMA_QM_3_GLBL_NON_SECURE_PROPS,
 mmDMA_QM_4_GLBL_NON_SECURE_PROPS,
 mmTPC0_QM_GLBL_SECURE_PROPS,
 mmTPC0_QM_GLBL_NON_SECURE_PROPS,
 mmTPC0_CMDQ_GLBL_SECURE_PROPS,
 mmTPC0_CMDQ_GLBL_NON_SECURE_PROPS,
 mmTPC0_CFG_ARUSER,
 mmTPC0_CFG_AWUSER,
 mmTPC1_QM_GLBL_SECURE_PROPS,
 mmTPC1_QM_GLBL_NON_SECURE_PROPS,
 mmTPC1_CMDQ_GLBL_SECURE_PROPS,
 mmTPC1_CMDQ_GLBL_NON_SECURE_PROPS,
 mmTPC1_CFG_ARUSER,
 mmTPC1_CFG_AWUSER,
 mmTPC2_QM_GLBL_SECURE_PROPS,
 mmTPC2_QM_GLBL_NON_SECURE_PROPS,
 mmTPC2_CMDQ_GLBL_SECURE_PROPS,
 mmTPC2_CMDQ_GLBL_NON_SECURE_PROPS,
 mmTPC2_CFG_ARUSER,
 mmTPC2_CFG_AWUSER,
 mmTPC3_QM_GLBL_SECURE_PROPS,
 mmTPC3_QM_GLBL_NON_SECURE_PROPS,
 mmTPC3_CMDQ_GLBL_SECURE_PROPS,
 mmTPC3_CMDQ_GLBL_NON_SECURE_PROPS,
 mmTPC3_CFG_ARUSER,
 mmTPC3_CFG_AWUSER,
 mmTPC4_QM_GLBL_SECURE_PROPS,
 mmTPC4_QM_GLBL_NON_SECURE_PROPS,
 mmTPC4_CMDQ_GLBL_SECURE_PROPS,
 mmTPC4_CMDQ_GLBL_NON_SECURE_PROPS,
 mmTPC4_CFG_ARUSER,
 mmTPC4_CFG_AWUSER,
 mmTPC5_QM_GLBL_SECURE_PROPS,
 mmTPC5_QM_GLBL_NON_SECURE_PROPS,
 mmTPC5_CMDQ_GLBL_SECURE_PROPS,
 mmTPC5_CMDQ_GLBL_NON_SECURE_PROPS,
 mmTPC5_CFG_ARUSER,
 mmTPC5_CFG_AWUSER,
 mmTPC6_QM_GLBL_SECURE_PROPS,
 mmTPC6_QM_GLBL_NON_SECURE_PROPS,
 mmTPC6_CMDQ_GLBL_SECURE_PROPS,
 mmTPC6_CMDQ_GLBL_NON_SECURE_PROPS,
 mmTPC6_CFG_ARUSER,
 mmTPC6_CFG_AWUSER,
 mmTPC7_QM_GLBL_SECURE_PROPS,
 mmTPC7_QM_GLBL_NON_SECURE_PROPS,
 mmTPC7_CMDQ_GLBL_SECURE_PROPS,
 mmTPC7_CMDQ_GLBL_NON_SECURE_PROPS,
 mmTPC7_CFG_ARUSER,
 mmTPC7_CFG_AWUSER,
 mmMME_QM_GLBL_SECURE_PROPS,
 mmMME_QM_GLBL_NON_SECURE_PROPS,
 mmMME_CMDQ_GLBL_SECURE_PROPS,
 mmMME_CMDQ_GLBL_NON_SECURE_PROPS,
 mmMME_SBA_CONTROL_DATA,
 mmMME_SBB_CONTROL_DATA,
 mmMME_SBC_CONTROL_DATA,
 mmMME_WBC_CONTROL_DATA,
 mmPCIE_WRAP_PSOC_ARUSER,
 mmPCIE_WRAP_PSOC_AWUSER
};

static u32 goya_all_events[] = {
 GOYA_ASYNC_EVENT_ID_PCIE_IF,
 GOYA_ASYNC_EVENT_ID_TPC0_ECC,
 GOYA_ASYNC_EVENT_ID_TPC1_ECC,
 GOYA_ASYNC_EVENT_ID_TPC2_ECC,
 GOYA_ASYNC_EVENT_ID_TPC3_ECC,
 GOYA_ASYNC_EVENT_ID_TPC4_ECC,
 GOYA_ASYNC_EVENT_ID_TPC5_ECC,
 GOYA_ASYNC_EVENT_ID_TPC6_ECC,
 GOYA_ASYNC_EVENT_ID_TPC7_ECC,
 GOYA_ASYNC_EVENT_ID_MME_ECC,
 GOYA_ASYNC_EVENT_ID_MME_ECC_EXT,
 GOYA_ASYNC_EVENT_ID_MMU_ECC,
 GOYA_ASYNC_EVENT_ID_DMA_MACRO,
 GOYA_ASYNC_EVENT_ID_DMA_ECC,
 GOYA_ASYNC_EVENT_ID_CPU_IF_ECC,
 GOYA_ASYNC_EVENT_ID_PSOC_MEM,
 GOYA_ASYNC_EVENT_ID_PSOC_CORESIGHT,
 GOYA_ASYNC_EVENT_ID_SRAM0,
 GOYA_ASYNC_EVENT_ID_SRAM1,
 GOYA_ASYNC_EVENT_ID_SRAM2,
 GOYA_ASYNC_EVENT_ID_SRAM3,
 GOYA_ASYNC_EVENT_ID_SRAM4,
 GOYA_ASYNC_EVENT_ID_SRAM5,
 GOYA_ASYNC_EVENT_ID_SRAM6,
 GOYA_ASYNC_EVENT_ID_SRAM7,
 GOYA_ASYNC_EVENT_ID_SRAM8,
 GOYA_ASYNC_EVENT_ID_SRAM9,
 GOYA_ASYNC_EVENT_ID_SRAM10,
 GOYA_ASYNC_EVENT_ID_SRAM11,
 GOYA_ASYNC_EVENT_ID_SRAM12,
 GOYA_ASYNC_EVENT_ID_SRAM13,
 GOYA_ASYNC_EVENT_ID_SRAM14,
 GOYA_ASYNC_EVENT_ID_SRAM15,
 GOYA_ASYNC_EVENT_ID_SRAM16,
 GOYA_ASYNC_EVENT_ID_SRAM17,
 GOYA_ASYNC_EVENT_ID_SRAM18,
 GOYA_ASYNC_EVENT_ID_SRAM19,
 GOYA_ASYNC_EVENT_ID_SRAM20,
 GOYA_ASYNC_EVENT_ID_SRAM21,
 GOYA_ASYNC_EVENT_ID_SRAM22,
 GOYA_ASYNC_EVENT_ID_SRAM23,
 GOYA_ASYNC_EVENT_ID_SRAM24,
 GOYA_ASYNC_EVENT_ID_SRAM25,
 GOYA_ASYNC_EVENT_ID_SRAM26,
 GOYA_ASYNC_EVENT_ID_SRAM27,
 GOYA_ASYNC_EVENT_ID_SRAM28,
 GOYA_ASYNC_EVENT_ID_SRAM29,
 GOYA_ASYNC_EVENT_ID_GIC500,
 GOYA_ASYNC_EVENT_ID_PLL0,
 GOYA_ASYNC_EVENT_ID_PLL1,
 GOYA_ASYNC_EVENT_ID_PLL3,
 GOYA_ASYNC_EVENT_ID_PLL4,
 GOYA_ASYNC_EVENT_ID_PLL5,
 GOYA_ASYNC_EVENT_ID_PLL6,
 GOYA_ASYNC_EVENT_ID_AXI_ECC,
 GOYA_ASYNC_EVENT_ID_L2_RAM_ECC,
 GOYA_ASYNC_EVENT_ID_PSOC_GPIO_05_SW_RESET,
 GOYA_ASYNC_EVENT_ID_PSOC_GPIO_10_VRHOT_ICRIT,
 GOYA_ASYNC_EVENT_ID_PCIE_DEC,
 GOYA_ASYNC_EVENT_ID_TPC0_DEC,
 GOYA_ASYNC_EVENT_ID_TPC1_DEC,
 GOYA_ASYNC_EVENT_ID_TPC2_DEC,
 GOYA_ASYNC_EVENT_ID_TPC3_DEC,
 GOYA_ASYNC_EVENT_ID_TPC4_DEC,
 GOYA_ASYNC_EVENT_ID_TPC5_DEC,
 GOYA_ASYNC_EVENT_ID_TPC6_DEC,
 GOYA_ASYNC_EVENT_ID_TPC7_DEC,
 GOYA_ASYNC_EVENT_ID_MME_WACS,
 GOYA_ASYNC_EVENT_ID_MME_WACSD,
 GOYA_ASYNC_EVENT_ID_CPU_AXI_SPLITTER,
 GOYA_ASYNC_EVENT_ID_PSOC_AXI_DEC,
 GOYA_ASYNC_EVENT_ID_PSOC,
 GOYA_ASYNC_EVENT_ID_TPC0_KRN_ERR,
 GOYA_ASYNC_EVENT_ID_TPC1_KRN_ERR,
 GOYA_ASYNC_EVENT_ID_TPC2_KRN_ERR,
 GOYA_ASYNC_EVENT_ID_TPC3_KRN_ERR,
 GOYA_ASYNC_EVENT_ID_TPC4_KRN_ERR,
 GOYA_ASYNC_EVENT_ID_TPC5_KRN_ERR,
 GOYA_ASYNC_EVENT_ID_TPC6_KRN_ERR,
 GOYA_ASYNC_EVENT_ID_TPC7_KRN_ERR,
 GOYA_ASYNC_EVENT_ID_TPC0_CMDQ,
 GOYA_ASYNC_EVENT_ID_TPC1_CMDQ,
 GOYA_ASYNC_EVENT_ID_TPC2_CMDQ,
 GOYA_ASYNC_EVENT_ID_TPC3_CMDQ,
 GOYA_ASYNC_EVENT_ID_TPC4_CMDQ,
 GOYA_ASYNC_EVENT_ID_TPC5_CMDQ,
 GOYA_ASYNC_EVENT_ID_TPC6_CMDQ,
 GOYA_ASYNC_EVENT_ID_TPC7_CMDQ,
 GOYA_ASYNC_EVENT_ID_TPC0_QM,
 GOYA_ASYNC_EVENT_ID_TPC1_QM,
 GOYA_ASYNC_EVENT_ID_TPC2_QM,
 GOYA_ASYNC_EVENT_ID_TPC3_QM,
 GOYA_ASYNC_EVENT_ID_TPC4_QM,
 GOYA_ASYNC_EVENT_ID_TPC5_QM,
 GOYA_ASYNC_EVENT_ID_TPC6_QM,
 GOYA_ASYNC_EVENT_ID_TPC7_QM,
 GOYA_ASYNC_EVENT_ID_MME_QM,
 GOYA_ASYNC_EVENT_ID_MME_CMDQ,
 GOYA_ASYNC_EVENT_ID_DMA0_QM,
 GOYA_ASYNC_EVENT_ID_DMA1_QM,
 GOYA_ASYNC_EVENT_ID_DMA2_QM,
 GOYA_ASYNC_EVENT_ID_DMA3_QM,
 GOYA_ASYNC_EVENT_ID_DMA4_QM,
 GOYA_ASYNC_EVENT_ID_DMA0_CH,
 GOYA_ASYNC_EVENT_ID_DMA1_CH,
 GOYA_ASYNC_EVENT_ID_DMA2_CH,
 GOYA_ASYNC_EVENT_ID_DMA3_CH,
 GOYA_ASYNC_EVENT_ID_DMA4_CH,
 GOYA_ASYNC_EVENT_ID_TPC0_BMON_SPMU,
 GOYA_ASYNC_EVENT_ID_TPC1_BMON_SPMU,
 GOYA_ASYNC_EVENT_ID_TPC2_BMON_SPMU,
 GOYA_ASYNC_EVENT_ID_TPC3_BMON_SPMU,
 GOYA_ASYNC_EVENT_ID_TPC4_BMON_SPMU,
 GOYA_ASYNC_EVENT_ID_TPC5_BMON_SPMU,
 GOYA_ASYNC_EVENT_ID_TPC6_BMON_SPMU,
 GOYA_ASYNC_EVENT_ID_TPC7_BMON_SPMU,
 GOYA_ASYNC_EVENT_ID_DMA_BM_CH0,
 GOYA_ASYNC_EVENT_ID_DMA_BM_CH1,
 GOYA_ASYNC_EVENT_ID_DMA_BM_CH2,
 GOYA_ASYNC_EVENT_ID_DMA_BM_CH3,
 GOYA_ASYNC_EVENT_ID_DMA_BM_CH4,
 GOYA_ASYNC_EVENT_ID_FIX_POWER_ENV_S,
 GOYA_ASYNC_EVENT_ID_FIX_POWER_ENV_E,
 GOYA_ASYNC_EVENT_ID_FIX_THERMAL_ENV_S,
 GOYA_ASYNC_EVENT_ID_FIX_THERMAL_ENV_E
};

static s64 goya_state_dump_specs_props[SP_MAX] = {0};

static int goya_mmu_clear_pgt_range(struct hl_device *hdev);
static int goya_mmu_set_dram_default_page(struct hl_device *hdev);
static int goya_mmu_add_mappings_for_device_cpu(struct hl_device *hdev);
static void goya_mmu_prepare(struct hl_device *hdev, u32 asid);

int goya_set_fixed_properties(struct hl_device *hdev)
{
 struct asic_fixed_properties *prop = &hdev->asic_prop;
 int i;

 prop->max_queues = GOYA_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 < NUMBER_OF_EXT_HW_QUEUES ; i++) {
  prop->hw_queues_props[i].type = QUEUE_TYPE_EXT;
  prop->hw_queues_props[i].driver_only = 0;
  prop->hw_queues_props[i].cb_alloc_flags = CB_ALLOC_KERNEL;
 }

 for (; i < NUMBER_OF_EXT_HW_QUEUES + NUMBER_OF_CPU_HW_QUEUES ; i++) {
  prop->hw_queues_props[i].type = QUEUE_TYPE_CPU;
  prop->hw_queues_props[i].driver_only = 1;
  prop->hw_queues_props[i].cb_alloc_flags = CB_ALLOC_KERNEL;
 }

 for (; i < NUMBER_OF_EXT_HW_QUEUES + NUMBER_OF_CPU_HW_QUEUES +
   NUMBER_OF_INT_HW_QUEUES; i++) {
  prop->hw_queues_props[i].type = QUEUE_TYPE_INT;
  prop->hw_queues_props[i].driver_only = 0;
  prop->hw_queues_props[i].cb_alloc_flags = CB_ALLOC_USER;
 }

 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->dram_base_address = DRAM_PHYS_BASE;
 prop->dram_size = DRAM_PHYS_DEFAULT_SIZE;
 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_pgt_addr = MMU_PAGE_TABLES_ADDR;
 prop->mmu_dram_default_page_addr = MMU_DRAM_DEFAULT_PAGE_ADDR;
 if (hdev->pldm)
  prop->mmu_pgt_size = 0x800000; /* 8MB */
 else
  prop->mmu_pgt_size = MMU_PAGE_TABLES_SIZE;
 prop->mmu_pte_size = HL_PTE_SIZE;
 prop->dram_page_size = PAGE_SIZE_2MB;
 prop->device_mem_alloc_default_page_size = prop->dram_page_size;
 prop->dram_supports_virtual_memory = true;

 prop->dmmu.hop_shifts[MMU_HOP0] = MMU_V1_0_HOP0_SHIFT;
 prop->dmmu.hop_shifts[MMU_HOP1] = MMU_V1_0_HOP1_SHIFT;
 prop->dmmu.hop_shifts[MMU_HOP2] = MMU_V1_0_HOP2_SHIFT;
 prop->dmmu.hop_shifts[MMU_HOP3] = MMU_V1_0_HOP3_SHIFT;
 prop->dmmu.hop_shifts[MMU_HOP4] = MMU_V1_0_HOP4_SHIFT;
 prop->dmmu.hop_masks[MMU_HOP0] = MMU_V1_0_HOP0_MASK;
 prop->dmmu.hop_masks[MMU_HOP1] = MMU_V1_0_HOP1_MASK;
 prop->dmmu.hop_masks[MMU_HOP2] = MMU_V1_0_HOP2_MASK;
 prop->dmmu.hop_masks[MMU_HOP3] = MMU_V1_0_HOP3_MASK;
 prop->dmmu.hop_masks[MMU_HOP4] = MMU_V1_0_HOP4_MASK;
 prop->dmmu.start_addr = VA_DDR_SPACE_START;
 prop->dmmu.end_addr = VA_DDR_SPACE_END;
 prop->dmmu.page_size = PAGE_SIZE_2MB;
 prop->dmmu.num_hops = MMU_ARCH_5_HOPS;
 prop->dmmu.last_mask = LAST_MASK;
 /* TODO: will be duplicated until implementing per-MMU props */
 prop->dmmu.hop_table_size = HOP_TABLE_SIZE_512_PTE;
 prop->dmmu.hop0_tables_total_size = HOP0_512_PTE_TABLES_TOTAL_SIZE;

 /* shifts and masks are the same in PMMU and DMMU */
 memcpy(&prop->pmmu, &prop->dmmu, sizeof(prop->dmmu));
 prop->pmmu.start_addr = VA_HOST_SPACE_START;
 prop->pmmu.end_addr = VA_HOST_SPACE_END;
 prop->pmmu.page_size = PAGE_SIZE_4KB;
 prop->pmmu.num_hops = MMU_ARCH_5_HOPS;
 prop->pmmu.last_mask = LAST_MASK;
 /* TODO: will be duplicated until implementing per-MMU props */
 prop->pmmu.hop_table_size = HOP_TABLE_SIZE_512_PTE;
 prop->pmmu.hop0_tables_total_size = HOP0_512_PTE_TABLES_TOTAL_SIZE;

 /* PMMU and HPMMU are the same except of page size */
 memcpy(&prop->pmmu_huge, &prop->pmmu, sizeof(prop->pmmu));
 prop->pmmu_huge.page_size = PAGE_SIZE_2MB;

 prop->dram_size_for_default_page_mapping = VA_DDR_SPACE_END;
 prop->cfg_size = CFG_SIZE;
 prop->max_asid = MAX_ASID;
 prop->num_of_events = GOYA_ASYNC_EVENT_ID_SIZE;
 prop->high_pll = PLL_HIGH_DEFAULT;
 prop->cb_pool_cb_cnt = GOYA_CB_POOL_CB_CNT;
 prop->cb_pool_cb_size = GOYA_CB_POOL_CB_SIZE;
 prop->max_power_default = MAX_POWER_DEFAULT;
 prop->dc_power_default = DC_POWER_DEFAULT;
 prop->tpc_enabled_mask = TPC_ENABLED_MASK;
 prop->pcie_dbi_base_address = mmPCIE_DBI_BASE;
 prop->pcie_aux_dbi_reg_addr = CFG_BASE + mmPCIE_AUX_DBI;

 strscpy_pad(prop->cpucp_info.card_name, GOYA_DEFAULT_CARD_NAME,
  CARD_NAME_MAX_LEN);

 prop->max_pending_cs = GOYA_MAX_PENDING_CS;

 prop->first_available_user_interrupt = USHRT_MAX;
 prop->tpc_interrupt_id = USHRT_MAX;
 prop->eq_interrupt_id = GOYA_EVENT_QUEUE_MSIX_IDX;

 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_GOYA_MME_PLL;

 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;

 return 0;
}

/*
 * goya_pci_bars_map - Map PCI BARS of Goya device
 *
 * @hdev: pointer to hl_device structure
 *
 * Request PCI regions and map them to kernel virtual addresses.
 * Returns 0 on success
 *
 */

static int goya_pci_bars_map(struct hl_device *hdev)
{
 static const char * const name[] = {"SRAM_CFG""MSIX""DDR"};
 bool is_wc[3] = {falsefalsetrue};
 int rc;

 rc = hl_pci_bars_map(hdev, name, is_wc);
 if (rc)
  return rc;

 hdev->rmmio = hdev->pcie_bar[SRAM_CFG_BAR_ID] +
   (CFG_BASE - SRAM_BASE_ADDR);

 return 0;
}

static u64 goya_set_ddr_bar_base(struct hl_device *hdev, u64 addr)
{
 struct goya_device *goya = hdev->asic_specific;
 struct hl_inbound_pci_region pci_region;
 u64 old_addr = addr;
 int rc;

 if ((goya) && (goya->ddr_bar_cur_addr == addr))
  return old_addr;

 /* Inbound Region 1 - Bar 4 - Point to DDR */
 pci_region.mode = PCI_BAR_MATCH_MODE;
 pci_region.bar = DDR_BAR_ID;
 pci_region.addr = addr;
 rc = hl_pci_set_inbound_region(hdev, 1, &pci_region);
 if (rc)
  return U64_MAX;

 if (goya) {
  old_addr = goya->ddr_bar_cur_addr;
  goya->ddr_bar_cur_addr = addr;
 }

 return old_addr;
}

/*
 * goya_init_iatu - Initialize the iATU unit inside the PCI controller
 *
 * @hdev: pointer to hl_device structure
 *
 * This is needed in case the firmware doesn't initialize the iATU
 *
 */

static int goya_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 0 - Bar 0 - Point to SRAM and CFG */
 inbound_region.mode = PCI_BAR_MATCH_MODE;
 inbound_region.bar = SRAM_CFG_BAR_ID;
 inbound_region.addr = SRAM_BASE_ADDR;
 rc = hl_pci_set_inbound_region(hdev, 0, &inbound_region);
 if (rc)
  goto done;

 /* Inbound Region 1 - Bar 4 - Point to DDR */
 inbound_region.mode = PCI_BAR_MATCH_MODE;
 inbound_region.bar = DDR_BAR_ID;
 inbound_region.addr = DRAM_PHYS_BASE;
 rc = hl_pci_set_inbound_region(hdev, 1, &inbound_region);
 if (rc)
  goto done;

 /* Outbound Region 0 - Point to Host  */
 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 goya_get_hw_state(struct hl_device *hdev)
{
 return RREG32(mmHW_STATE);
}

/*
 * goya_early_init - GOYA early initialization code
 *
 * @hdev: pointer to hl_device structure
 *
 * Verify PCI bars
 * Set DMA masks
 * PCI controller initialization
 * Map PCI bars
 *
 */

static int goya_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, val;
 int rc;

 rc = goya_set_fixed_properties(hdev);
 if (rc) {
  dev_err(hdev->dev, "Failed to get fixed properties\n");
  return rc;
 }

 /* Check BAR sizes */
 pci_bar_size = pci_resource_len(pdev, SRAM_CFG_BAR_ID);

 if (pci_bar_size != CFG_BAR_SIZE) {
  dev_err(hdev->dev, "Not " HL_NAME "? BAR %d size %pa, expecting %llu\n",
   SRAM_CFG_BAR_ID, &pci_bar_size, CFG_BAR_SIZE);
  rc = -ENODEV;
  goto free_queue_props;
 }

 pci_bar_size = pci_resource_len(pdev, MSIX_BAR_ID);

 if (pci_bar_size != MSIX_BAR_SIZE) {
  dev_err(hdev->dev, "Not " HL_NAME "? BAR %d size %pa, expecting %llu\n",
   MSIX_BAR_ID, &pci_bar_size, MSIX_BAR_SIZE);
  rc = -ENODEV;
  goto free_queue_props;
 }

 prop->dram_pci_bar_size = pci_resource_len(pdev, DDR_BAR_ID);
 hdev->dram_pci_bar_start = pci_resource_start(pdev, DDR_BAR_ID);

 /* If FW security is enabled at this point it means no access to ELBI */
 if (hdev->asic_prop.fw_security_enabled) {
  hdev->asic_prop.iatu_done_by_fw = true;
  goto pci_init;
 }

 rc = hl_pci_elbi_read(hdev, CFG_BASE + mmCPU_BOOT_DEV_STS0,
    &fw_boot_status);
 if (rc)
  goto free_queue_props;

 /* Check whether FW is configuring iATU */
 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;

 /* Before continuing in the initialization, we need to read the preboot
 * version to determine whether we run with a security-enabled firmware
 */

 rc = hl_fw_read_preboot_status(hdev);
 if (rc) {
  if (hdev->reset_on_preboot_fail)
   /* we are already on failure flow, so don't check if hw_fini fails. */
   hdev->asic_funcs->hw_fini(hdev, truefalse);
  goto pci_fini;
 }

 if (goya_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, truefalse);
  if (rc) {
   dev_err(hdev->dev, "failed to reset HW in dirty state (%d)\n", rc);
   goto pci_fini;
  }
 }

 if (!hdev->pldm) {
  val = RREG32(mmPSOC_GLOBAL_CONF_BOOT_STRAP_PINS);
  if (val & PSOC_GLOBAL_CONF_BOOT_STRAP_PINS_SRIOV_EN_MASK)
   dev_warn(hdev->dev,
    "PCI strap is not configured correctly, PCI bus errors may occur\n");
 }

 return 0;

pci_fini:
 hl_pci_fini(hdev);
free_queue_props:
 kfree(hdev->asic_prop.hw_queues_props);
 return rc;
}

/*
 * goya_early_fini - GOYA early finalization code
 *
 * @hdev: pointer to hl_device structure
 *
 * Unmap PCI bars
 *
 */

static int goya_early_fini(struct hl_device *hdev)
{
 kfree(hdev->asic_prop.hw_queues_props);
 hl_pci_fini(hdev);

 return 0;
}

static void goya_mmu_prepare_reg(struct hl_device *hdev, u64 reg, u32 asid)
{
 /* mask to zero the MMBP and ASID bits */
 WREG32_AND(reg, ~0x7FF);
 WREG32_OR(reg, asid);
}

static void goya_qman0_set_security(struct hl_device *hdev, bool secure)
{
 struct goya_device *goya = hdev->asic_specific;

 if (!(goya->hw_cap_initialized & HW_CAP_MMU))
  return;

 if (secure)
  WREG32(mmDMA_QM_0_GLBL_PROT, QMAN_DMA_FULLY_TRUSTED);
 else
  WREG32(mmDMA_QM_0_GLBL_PROT, QMAN_DMA_PARTLY_TRUSTED);

 RREG32(mmDMA_QM_0_GLBL_PROT);
}

/*
 * goya_fetch_psoc_frequency - Fetch PSOC frequency values
 *
 * @hdev: pointer to hl_device structure
 *
 */

static void goya_fetch_psoc_frequency(struct hl_device *hdev)
{
 struct asic_fixed_properties *prop = &hdev->asic_prop;
 u32 nr = 0, nf = 0, od = 0, div_fctr = 0, pll_clk, div_sel;
 u16 pll_freq_arr[HL_PLL_NUM_OUTPUTS], freq;
 int rc;

 if (hdev->asic_prop.fw_security_enabled) {
  struct goya_device *goya = hdev->asic_specific;

  if (!(goya->hw_cap_initialized & HW_CAP_CPU_Q))
   return;

  rc = hl_fw_cpucp_pll_info_get(hdev, HL_GOYA_PCI_PLL,
    pll_freq_arr);

  if (rc)
   return;

  freq = pll_freq_arr[1];
 } else {
  div_fctr = RREG32(mmPSOC_PCI_PLL_DIV_FACTOR_1);
  div_sel = RREG32(mmPSOC_PCI_PLL_DIV_SEL_1);
  nr = RREG32(mmPSOC_PCI_PLL_NR);
  nf = RREG32(mmPSOC_PCI_PLL_NF);
  od = RREG32(mmPSOC_PCI_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: %d",
    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;
}

/*
 * goya_set_frequency - set the frequency of the device
 *
 * @hdev: pointer to habanalabs device structure
 * @freq: the new frequency value
 *
 * Change the frequency if needed. This function has no protection against
 * concurrency, therefore it is assumed that the calling function has protected
 * itself against the case of calling this function from multiple threads with
 * different values
 *
 * Returns 0 if no change was done, otherwise returns 1
 */

int goya_set_frequency(struct hl_device *hdev, enum hl_pll_frequency freq)
{
 struct goya_device *goya = hdev->asic_specific;

 if ((goya->pm_mng_profile == PM_MANUAL) ||
   (goya->curr_pll_profile == freq))
  return 0;

 dev_dbg(hdev->dev, "Changing device frequency to %s\n",
  freq == PLL_HIGH ? "high" : "low");

 goya_set_pll_profile(hdev, freq);

 goya->curr_pll_profile = freq;

 return 1;
}

static void goya_set_freq_to_low_job(struct work_struct *work)
{
 struct goya_work_freq *goya_work = container_of(work,
      struct goya_work_freq,
      work_freq.work);
 struct hl_device *hdev = goya_work->hdev;

 mutex_lock(&hdev->fpriv_list_lock);

 if (!hdev->is_compute_ctx_active)
  goya_set_frequency(hdev, PLL_LOW);

 mutex_unlock(&hdev->fpriv_list_lock);

 schedule_delayed_work(&goya_work->work_freq,
   usecs_to_jiffies(HL_PLL_LOW_JOB_FREQ_USEC));
}

int goya_late_init(struct hl_device *hdev)
{
 struct asic_fixed_properties *prop = &hdev->asic_prop;
 struct goya_device *goya = hdev->asic_specific;
 int rc;

 goya_fetch_psoc_frequency(hdev);

 rc = goya_mmu_clear_pgt_range(hdev);
 if (rc) {
  dev_err(hdev->dev,
   "Failed to clear MMU page tables range %d\n", rc);
  return rc;
 }

 rc = goya_mmu_set_dram_default_page(hdev);
 if (rc) {
  dev_err(hdev->dev, "Failed to set DRAM default page %d\n", rc);
  return rc;
 }

 rc = goya_mmu_add_mappings_for_device_cpu(hdev);
 if (rc)
  return rc;

 rc = goya_init_cpu_queues(hdev);
 if (rc)
  return rc;

 rc = goya_test_cpu_queue(hdev);
 if (rc)
  return rc;

 rc = goya_cpucp_info_get(hdev);
 if (rc) {
  dev_err(hdev->dev, "Failed to get cpucp info %d\n", rc);
  return rc;
 }

 /* Now that we have the DRAM size in ASIC prop, we need to check
 * its size and configure the DMA_IF DDR wrap protection (which is in
 * the MMU block) accordingly. The value is the log2 of the DRAM size
 */

 WREG32(mmMMU_LOG2_DDR_SIZE, ilog2(prop->dram_size));

 rc = hl_fw_send_pci_access_msg(hdev, CPUCP_PACKET_ENABLE_PCI_ACCESS, 0x0);
 if (rc)
  return rc;

 /* force setting to low frequency */
 goya->curr_pll_profile = PLL_LOW;

 goya->pm_mng_profile = PM_AUTO;

 goya_set_pll_profile(hdev, PLL_LOW);

 schedule_delayed_work(&goya->goya_work->work_freq,
  usecs_to_jiffies(HL_PLL_LOW_JOB_FREQ_USEC));

 return 0;
}

/*
 * goya_late_fini - GOYA late tear-down code
 *
 * @hdev: pointer to hl_device structure
 *
 * Free sensors allocated structures
 */

void goya_late_fini(struct hl_device *hdev)
{
 struct goya_device *goya = hdev->asic_specific;

 cancel_delayed_work_sync(&goya->goya_work->work_freq);

 hl_hwmon_release_resources(hdev);
}

static void goya_set_pci_memory_regions(struct hl_device *hdev)
{
 struct asic_fixed_properties *prop = &hdev->asic_prop;
 struct pci_mem_region *region;

 /* CFG */
 region = &hdev->pci_mem_region[PCI_REGION_CFG];
 region->region_base = CFG_BASE;
 region->region_size = CFG_SIZE;
 region->offset_in_bar = CFG_BASE - SRAM_BASE_ADDR;
 region->bar_size = CFG_BAR_SIZE;
 region->bar_id = SRAM_CFG_BAR_ID;
 region->used = 1;

 /* SRAM */
 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 = CFG_BAR_SIZE;
 region->bar_id = SRAM_CFG_BAR_ID;
 region->used = 1;

 /* DRAM */
 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 = DDR_BAR_ID;
 region->used = 1;
}

/*
 * goya_sw_init - Goya software initialization code
 *
 * @hdev: pointer to hl_device structure
 *
 */

static int goya_sw_init(struct hl_device *hdev)
{
 struct goya_device *goya;
 int rc;

 /* Allocate device structure */
 goya = kzalloc(sizeof(*goya), GFP_KERNEL);
 if (!goya)
  return -ENOMEM;

 /* according to goya_init_iatu */
 goya->ddr_bar_cur_addr = DRAM_PHYS_BASE;

 goya->mme_clk = GOYA_PLL_FREQ_LOW;
 goya->tpc_clk = GOYA_PLL_FREQ_LOW;
 goya->ic_clk = GOYA_PLL_FREQ_LOW;

 hdev->asic_specific = goya;

 /* Create DMA pool for small allocations */
 hdev->dma_pool = dma_pool_create(dev_name(hdev->dev),
   &hdev->pdev->dev, GOYA_DMA_POOL_BLK_SIZE, 8, 0);
 if (!hdev->dma_pool) {
  dev_err(hdev->dev, "failed to create DMA pool\n");
  rc = -ENOMEM;
  goto free_goya_device;
 }

 hdev->cpu_accessible_dma_mem = hl_asic_dma_alloc_coherent(hdev, HL_CPU_ACCESSIBLE_MEM_SIZE,
       &hdev->cpu_accessible_dma_address,
       GFP_KERNEL | __GFP_ZERO);

 if (!hdev->cpu_accessible_dma_mem) {
  rc = -ENOMEM;
  goto free_dma_pool;
 }

 dev_dbg(hdev->dev, "cpu accessible memory at bus address %pad\n",
  &hdev->cpu_accessible_dma_address);

 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;
 }

 spin_lock_init(&goya->hw_queues_lock);
 hdev->supports_coresight = true;
 hdev->asic_prop.supports_compute_reset = true;
 hdev->asic_prop.allow_inference_soft_reset = true;
 hdev->supports_wait_for_multi_cs = false;
 hdev->supports_ctx_switch = true;

 hdev->asic_funcs->set_pci_memory_regions(hdev);

 goya->goya_work = kmalloc(sizeof(struct goya_work_freq), GFP_KERNEL);
 if (!goya->goya_work) {
  rc = -ENOMEM;
  goto free_cpu_accessible_dma_pool;
 }

 goya->goya_work->hdev = hdev;
 INIT_DELAYED_WORK(&goya->goya_work->work_freq, goya_set_freq_to_low_job);

 return 0;

free_cpu_accessible_dma_pool:
 gen_pool_destroy(hdev->cpu_accessible_dma_pool);
free_cpu_dma_mem:
 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_goya_device:
 kfree(goya);

 return rc;
}

/*
 * goya_sw_fini - Goya software tear-down code
 *
 * @hdev: pointer to hl_device structure
 *
 */

static int goya_sw_fini(struct hl_device *hdev)
{
 struct goya_device *goya = hdev->asic_specific;

 gen_pool_destroy(hdev->cpu_accessible_dma_pool);

 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(goya->goya_work);
 kfree(goya);

 return 0;
}

static void goya_init_dma_qman(struct hl_device *hdev, int dma_id,
  dma_addr_t bus_address)
{
 struct goya_device *goya = hdev->asic_specific;
 u32 mtr_base_lo, mtr_base_hi;
 u32 so_base_lo, so_base_hi;
 u32 gic_base_lo, gic_base_hi;
 u32 reg_off = dma_id * (mmDMA_QM_1_PQ_PI - mmDMA_QM_0_PQ_PI);
 u32 dma_err_cfg = QMAN_DMA_ERR_MSG_EN;

 mtr_base_lo = lower_32_bits(CFG_BASE + mmSYNC_MNGR_MON_PAY_ADDRL_0);
 mtr_base_hi = upper_32_bits(CFG_BASE + mmSYNC_MNGR_MON_PAY_ADDRL_0);
 so_base_lo = lower_32_bits(CFG_BASE + mmSYNC_MNGR_SOB_OBJ_0);
 so_base_hi = upper_32_bits(CFG_BASE + mmSYNC_MNGR_SOB_OBJ_0);

 gic_base_lo =
  lower_32_bits(CFG_BASE + mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR);
 gic_base_hi =
  upper_32_bits(CFG_BASE + mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR);

 WREG32(mmDMA_QM_0_PQ_BASE_LO + reg_off, lower_32_bits(bus_address));
 WREG32(mmDMA_QM_0_PQ_BASE_HI + reg_off, upper_32_bits(bus_address));

 WREG32(mmDMA_QM_0_PQ_SIZE + reg_off, ilog2(HL_QUEUE_LENGTH));
 WREG32(mmDMA_QM_0_PQ_PI + reg_off, 0);
 WREG32(mmDMA_QM_0_PQ_CI + reg_off, 0);

 WREG32(mmDMA_QM_0_CP_MSG_BASE0_ADDR_LO + reg_off, mtr_base_lo);
 WREG32(mmDMA_QM_0_CP_MSG_BASE0_ADDR_HI + reg_off, mtr_base_hi);
 WREG32(mmDMA_QM_0_CP_MSG_BASE1_ADDR_LO + reg_off, so_base_lo);
 WREG32(mmDMA_QM_0_CP_MSG_BASE1_ADDR_HI + reg_off, so_base_hi);
 WREG32(mmDMA_QM_0_GLBL_ERR_ADDR_LO + reg_off, gic_base_lo);
 WREG32(mmDMA_QM_0_GLBL_ERR_ADDR_HI + reg_off, gic_base_hi);
 WREG32(mmDMA_QM_0_GLBL_ERR_WDATA + reg_off,
   GOYA_ASYNC_EVENT_ID_DMA0_QM + dma_id);

 /* PQ has buffer of 2 cache lines, while CQ has 8 lines */
 WREG32(mmDMA_QM_0_PQ_CFG1 + reg_off, 0x00020002);
 WREG32(mmDMA_QM_0_CQ_CFG1 + reg_off, 0x00080008);

 if (goya->hw_cap_initialized & HW_CAP_MMU)
  WREG32(mmDMA_QM_0_GLBL_PROT + reg_off, QMAN_DMA_PARTLY_TRUSTED);
 else
  WREG32(mmDMA_QM_0_GLBL_PROT + reg_off, QMAN_DMA_FULLY_TRUSTED);

 if (hdev->stop_on_err)
  dma_err_cfg |= 1 << DMA_QM_0_GLBL_ERR_CFG_DMA_STOP_ON_ERR_SHIFT;

 WREG32(mmDMA_QM_0_GLBL_ERR_CFG + reg_off, dma_err_cfg);
 WREG32(mmDMA_QM_0_GLBL_CFG0 + reg_off, QMAN_DMA_ENABLE);
}

static void goya_init_dma_ch(struct hl_device *hdev, int dma_id)
{
 u32 gic_base_lo, gic_base_hi;
 u64 sob_addr;
 u32 reg_off = dma_id * (mmDMA_CH_1_CFG1 - mmDMA_CH_0_CFG1);

 gic_base_lo =
  lower_32_bits(CFG_BASE + mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR);
 gic_base_hi =
  upper_32_bits(CFG_BASE + mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR);

 WREG32(mmDMA_CH_0_ERRMSG_ADDR_LO + reg_off, gic_base_lo);
 WREG32(mmDMA_CH_0_ERRMSG_ADDR_HI + reg_off, gic_base_hi);
 WREG32(mmDMA_CH_0_ERRMSG_WDATA + reg_off,
   GOYA_ASYNC_EVENT_ID_DMA0_CH + dma_id);

 if (dma_id)
  sob_addr = CFG_BASE + mmSYNC_MNGR_SOB_OBJ_1000 +
    (dma_id - 1) * 4;
 else
  sob_addr = CFG_BASE + mmSYNC_MNGR_SOB_OBJ_1007;

 WREG32(mmDMA_CH_0_WR_COMP_ADDR_HI + reg_off, upper_32_bits(sob_addr));
 WREG32(mmDMA_CH_0_WR_COMP_WDATA + reg_off, 0x80000001);
}

/*
 * goya_init_dma_qmans - Initialize QMAN DMA registers
 *
 * @hdev: pointer to hl_device structure
 *
 * Initialize the H/W registers of the QMAN DMA channels
 *
 */

void goya_init_dma_qmans(struct hl_device *hdev)
{
 struct goya_device *goya = hdev->asic_specific;
 struct hl_hw_queue *q;
 int i;

 if (goya->hw_cap_initialized & HW_CAP_DMA)
  return;

 q = &hdev->kernel_queues[0];

 for (i = 0 ; i < NUMBER_OF_EXT_HW_QUEUES ; i++, q++) {
  q->cq_id = q->msi_vec = i;
  goya_init_dma_qman(hdev, i, q->bus_address);
  goya_init_dma_ch(hdev, i);
 }

 goya->hw_cap_initialized |= HW_CAP_DMA;
}

/*
 * goya_disable_external_queues - Disable external queues
 *
 * @hdev: pointer to hl_device structure
 *
 */

static void goya_disable_external_queues(struct hl_device *hdev)
{
 struct goya_device *goya = hdev->asic_specific;

 if (!(goya->hw_cap_initialized & HW_CAP_DMA))
  return;

 WREG32(mmDMA_QM_0_GLBL_CFG0, 0);
 WREG32(mmDMA_QM_1_GLBL_CFG0, 0);
 WREG32(mmDMA_QM_2_GLBL_CFG0, 0);
 WREG32(mmDMA_QM_3_GLBL_CFG0, 0);
 WREG32(mmDMA_QM_4_GLBL_CFG0, 0);
}

static int goya_stop_queue(struct hl_device *hdev, u32 cfg_reg,
    u32 cp_sts_reg, u32 glbl_sts0_reg)
{
 int rc;
 u32 status;

 /* use the values of TPC0 as they are all the same*/

 WREG32(cfg_reg, 1 << TPC0_QM_GLBL_CFG1_CP_STOP_SHIFT);

 status = RREG32(cp_sts_reg);
 if (status & TPC0_QM_CP_STS_FENCE_IN_PROGRESS_MASK) {
  rc = hl_poll_timeout(
   hdev,
   cp_sts_reg,
   status,
   !(status & TPC0_QM_CP_STS_FENCE_IN_PROGRESS_MASK),
   1000,
   QMAN_FENCE_TIMEOUT_USEC);

  /* if QMAN is stuck in fence no need to check for stop */
  if (rc)
   return 0;
 }

 rc = hl_poll_timeout(
  hdev,
  glbl_sts0_reg,
  status,
  (status & TPC0_QM_GLBL_STS0_CP_IS_STOP_MASK),
  1000,
  QMAN_STOP_TIMEOUT_USEC);

 if (rc) {
  dev_err(hdev->dev,
   "Timeout while waiting for QMAN to stop\n");
  return -EINVAL;
 }

 return 0;
}

/*
 * goya_stop_external_queues - Stop external queues
 *
 * @hdev: pointer to hl_device structure
 *
 * Returns 0 on success
 *
 */

static int goya_stop_external_queues(struct hl_device *hdev)
{
 int rc, retval = 0;

 struct goya_device *goya = hdev->asic_specific;

 if (!(goya->hw_cap_initialized & HW_CAP_DMA))
  return retval;

 rc = goya_stop_queue(hdev,
   mmDMA_QM_0_GLBL_CFG1,
   mmDMA_QM_0_CP_STS,
   mmDMA_QM_0_GLBL_STS0);

 if (rc) {
  dev_err(hdev->dev, "failed to stop DMA QMAN 0\n");
  retval = -EIO;
 }

 rc = goya_stop_queue(hdev,
   mmDMA_QM_1_GLBL_CFG1,
   mmDMA_QM_1_CP_STS,
   mmDMA_QM_1_GLBL_STS0);

 if (rc) {
  dev_err(hdev->dev, "failed to stop DMA QMAN 1\n");
  retval = -EIO;
 }

 rc = goya_stop_queue(hdev,
   mmDMA_QM_2_GLBL_CFG1,
   mmDMA_QM_2_CP_STS,
   mmDMA_QM_2_GLBL_STS0);

 if (rc) {
  dev_err(hdev->dev, "failed to stop DMA QMAN 2\n");
  retval = -EIO;
 }

 rc = goya_stop_queue(hdev,
   mmDMA_QM_3_GLBL_CFG1,
   mmDMA_QM_3_CP_STS,
   mmDMA_QM_3_GLBL_STS0);

 if (rc) {
  dev_err(hdev->dev, "failed to stop DMA QMAN 3\n");
  retval = -EIO;
 }

 rc = goya_stop_queue(hdev,
   mmDMA_QM_4_GLBL_CFG1,
   mmDMA_QM_4_CP_STS,
   mmDMA_QM_4_GLBL_STS0);

 if (rc) {
  dev_err(hdev->dev, "failed to stop DMA QMAN 4\n");
  retval = -EIO;
 }

 return retval;
}

/*
 * goya_init_cpu_queues - Initialize PQ/CQ/EQ of CPU
 *
 * @hdev: pointer to hl_device structure
 *
 * Returns 0 on success
 *
 */

int goya_init_cpu_queues(struct hl_device *hdev)
{
 struct goya_device *goya = hdev->asic_specific;
 struct asic_fixed_properties *prop = &hdev->asic_prop;
 struct hl_eq *eq;
 u32 status;
 struct hl_hw_queue *cpu_pq = &hdev->kernel_queues[GOYA_QUEUE_ID_CPU_PQ];
 int err;

 if (!hdev->cpu_queues_enable)
  return 0;

 if (goya->hw_cap_initialized & HW_CAP_CPU_Q)
  return 0;

 eq = &hdev->event_queue;

 WREG32(mmCPU_PQ_BASE_ADDR_LOW, lower_32_bits(cpu_pq->bus_address));
 WREG32(mmCPU_PQ_BASE_ADDR_HIGH, upper_32_bits(cpu_pq->bus_address));

 WREG32(mmCPU_EQ_BASE_ADDR_LOW, lower_32_bits(eq->bus_address));
 WREG32(mmCPU_EQ_BASE_ADDR_HIGH, upper_32_bits(eq->bus_address));

 WREG32(mmCPU_CQ_BASE_ADDR_LOW,
   lower_32_bits(VA_CPU_ACCESSIBLE_MEM_ADDR));
 WREG32(mmCPU_CQ_BASE_ADDR_HIGH,
   upper_32_bits(VA_CPU_ACCESSIBLE_MEM_ADDR));

 WREG32(mmCPU_PQ_LENGTH, HL_QUEUE_SIZE_IN_BYTES);
 WREG32(mmCPU_EQ_LENGTH, HL_EQ_SIZE_IN_BYTES);
 WREG32(mmCPU_CQ_LENGTH, HL_CPU_ACCESSIBLE_MEM_SIZE);

 /* Used for EQ CI */
 WREG32(mmCPU_EQ_CI, 0);

 WREG32(mmCPU_IF_PF_PQ_PI, 0);

 WREG32(mmCPU_PQ_INIT_STATUS, PQ_INIT_STATUS_READY_FOR_CP);

 WREG32(mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR,
   GOYA_ASYNC_EVENT_ID_PI_UPDATE);

 err = hl_poll_timeout(
  hdev,
  mmCPU_PQ_INIT_STATUS,
  status,
  (status == PQ_INIT_STATUS_READY_FOR_HOST),
  1000,
  GOYA_CPU_TIMEOUT_USEC);

 if (err) {
  dev_err(hdev->dev,
   "Failed to setup communication with device CPU\n");
  return -EIO;
 }

 /* update FW application security bits */
 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);

 goya->hw_cap_initialized |= HW_CAP_CPU_Q;
 return 0;
}

static void goya_set_pll_refclk(struct hl_device *hdev)
{
 WREG32(mmCPU_PLL_DIV_SEL_0, 0x0);
 WREG32(mmCPU_PLL_DIV_SEL_1, 0x0);
 WREG32(mmCPU_PLL_DIV_SEL_2, 0x0);
 WREG32(mmCPU_PLL_DIV_SEL_3, 0x0);

 WREG32(mmIC_PLL_DIV_SEL_0, 0x0);
 WREG32(mmIC_PLL_DIV_SEL_1, 0x0);
 WREG32(mmIC_PLL_DIV_SEL_2, 0x0);
 WREG32(mmIC_PLL_DIV_SEL_3, 0x0);

 WREG32(mmMC_PLL_DIV_SEL_0, 0x0);
 WREG32(mmMC_PLL_DIV_SEL_1, 0x0);
 WREG32(mmMC_PLL_DIV_SEL_2, 0x0);
 WREG32(mmMC_PLL_DIV_SEL_3, 0x0);

 WREG32(mmPSOC_MME_PLL_DIV_SEL_0, 0x0);
 WREG32(mmPSOC_MME_PLL_DIV_SEL_1, 0x0);
 WREG32(mmPSOC_MME_PLL_DIV_SEL_2, 0x0);
 WREG32(mmPSOC_MME_PLL_DIV_SEL_3, 0x0);

 WREG32(mmPSOC_PCI_PLL_DIV_SEL_0, 0x0);
 WREG32(mmPSOC_PCI_PLL_DIV_SEL_1, 0x0);
 WREG32(mmPSOC_PCI_PLL_DIV_SEL_2, 0x0);
 WREG32(mmPSOC_PCI_PLL_DIV_SEL_3, 0x0);

 WREG32(mmPSOC_EMMC_PLL_DIV_SEL_0, 0x0);
 WREG32(mmPSOC_EMMC_PLL_DIV_SEL_1, 0x0);
 WREG32(mmPSOC_EMMC_PLL_DIV_SEL_2, 0x0);
 WREG32(mmPSOC_EMMC_PLL_DIV_SEL_3, 0x0);

 WREG32(mmTPC_PLL_DIV_SEL_0, 0x0);
 WREG32(mmTPC_PLL_DIV_SEL_1, 0x0);
 WREG32(mmTPC_PLL_DIV_SEL_2, 0x0);
 WREG32(mmTPC_PLL_DIV_SEL_3, 0x0);
}

static void goya_disable_clk_rlx(struct hl_device *hdev)
{
 WREG32(mmPSOC_MME_PLL_CLK_RLX_0, 0x100010);
 WREG32(mmIC_PLL_CLK_RLX_0, 0x100010);
}

static void _goya_tpc_mbist_workaround(struct hl_device *hdev, u8 tpc_id)
{
 u64 tpc_eml_address;
 u32 val, tpc_offset, tpc_eml_offset, tpc_slm_offset;
 int err, slm_index;

 tpc_offset = tpc_id * 0x40000;
 tpc_eml_offset = tpc_id * 0x200000;
 tpc_eml_address = (mmTPC0_EML_CFG_BASE + tpc_eml_offset - CFG_BASE);
 tpc_slm_offset = tpc_eml_address + 0x100000;

 /*
 * Workaround for Bug H2 #2443 :
 * "TPC SB is not initialized on chip reset"
 */


 val = RREG32(mmTPC0_CFG_FUNC_MBIST_CNTRL + tpc_offset);
 if (val & TPC0_CFG_FUNC_MBIST_CNTRL_MBIST_ACTIVE_MASK)
  dev_warn(hdev->dev, "TPC%d MBIST ACTIVE is not cleared\n",
   tpc_id);

 WREG32(mmTPC0_CFG_FUNC_MBIST_PAT + tpc_offset, val & 0xFFFFF000);

 WREG32(mmTPC0_CFG_FUNC_MBIST_MEM_0 + tpc_offset, 0x37FF);
 WREG32(mmTPC0_CFG_FUNC_MBIST_MEM_1 + tpc_offset, 0x303F);
 WREG32(mmTPC0_CFG_FUNC_MBIST_MEM_2 + tpc_offset, 0x71FF);
 WREG32(mmTPC0_CFG_FUNC_MBIST_MEM_3 + tpc_offset, 0x71FF);
 WREG32(mmTPC0_CFG_FUNC_MBIST_MEM_4 + tpc_offset, 0x70FF);
 WREG32(mmTPC0_CFG_FUNC_MBIST_MEM_5 + tpc_offset, 0x70FF);
 WREG32(mmTPC0_CFG_FUNC_MBIST_MEM_6 + tpc_offset, 0x70FF);
 WREG32(mmTPC0_CFG_FUNC_MBIST_MEM_7 + tpc_offset, 0x70FF);
 WREG32(mmTPC0_CFG_FUNC_MBIST_MEM_8 + tpc_offset, 0x70FF);
 WREG32(mmTPC0_CFG_FUNC_MBIST_MEM_9 + tpc_offset, 0x70FF);

 WREG32_OR(mmTPC0_CFG_FUNC_MBIST_CNTRL + tpc_offset,
  1 << TPC0_CFG_FUNC_MBIST_CNTRL_MBIST_START_SHIFT);

 err = hl_poll_timeout(
  hdev,
  mmTPC0_CFG_FUNC_MBIST_CNTRL + tpc_offset,
  val,
  (val & TPC0_CFG_FUNC_MBIST_CNTRL_MBIST_DONE_MASK),
  1000,
  HL_DEVICE_TIMEOUT_USEC);

 if (err)
  dev_err(hdev->dev,
   "Timeout while waiting for TPC%d MBIST DONE\n", tpc_id);

 WREG32_OR(mmTPC0_EML_CFG_DBG_CNT + tpc_eml_offset,
  1 << TPC0_EML_CFG_DBG_CNT_CORE_RST_SHIFT);

 msleep(GOYA_RESET_WAIT_MSEC);

 WREG32_AND(mmTPC0_EML_CFG_DBG_CNT + tpc_eml_offset,
  ~(1 << TPC0_EML_CFG_DBG_CNT_CORE_RST_SHIFT));

 msleep(GOYA_RESET_WAIT_MSEC);

 for (slm_index = 0 ; slm_index < 256 ; slm_index++)
  WREG32(tpc_slm_offset + (slm_index << 2), 0);

 val = RREG32(tpc_slm_offset);
}

static void goya_tpc_mbist_workaround(struct hl_device *hdev)
{
 struct goya_device *goya = hdev->asic_specific;
 int i;

 if (hdev->pldm)
  return;

 if (goya->hw_cap_initialized & HW_CAP_TPC_MBIST)
  return;

 /* Workaround for H2 #2443 */

 for (i = 0 ; i < TPC_MAX_NUM ; i++)
  _goya_tpc_mbist_workaround(hdev, i);

 goya->hw_cap_initialized |= HW_CAP_TPC_MBIST;
}

/*
 * goya_init_golden_registers - Initialize golden registers
 *
 * @hdev: pointer to hl_device structure
 *
 * Initialize the H/W registers of the device
 *
 */

static void goya_init_golden_registers(struct hl_device *hdev)
{
 struct goya_device *goya = hdev->asic_specific;
 u32 polynom[10], tpc_intr_mask, offset;
 int i;

 if (goya->hw_cap_initialized & HW_CAP_GOLDEN)
  return;

 polynom[0] = 0x00020080;
 polynom[1] = 0x00401000;
 polynom[2] = 0x00200800;
 polynom[3] = 0x00002000;
 polynom[4] = 0x00080200;
 polynom[5] = 0x00040100;
 polynom[6] = 0x00100400;
 polynom[7] = 0x00004000;
 polynom[8] = 0x00010000;
 polynom[9] = 0x00008000;

 /* Mask all arithmetic interrupts from TPC */
 tpc_intr_mask = 0x7FFF;

 for (i = 0, offset = 0 ; i < 6 ; i++, offset += 0x20000) {
  WREG32(mmSRAM_Y0_X0_RTR_HBW_RD_RQ_L_ARB + offset, 0x302);
  WREG32(mmSRAM_Y0_X1_RTR_HBW_RD_RQ_L_ARB + offset, 0x302);
  WREG32(mmSRAM_Y0_X2_RTR_HBW_RD_RQ_L_ARB + offset, 0x302);
  WREG32(mmSRAM_Y0_X3_RTR_HBW_RD_RQ_L_ARB + offset, 0x302);
  WREG32(mmSRAM_Y0_X4_RTR_HBW_RD_RQ_L_ARB + offset, 0x302);

  WREG32(mmSRAM_Y0_X0_RTR_HBW_DATA_L_ARB + offset, 0x204);
  WREG32(mmSRAM_Y0_X1_RTR_HBW_DATA_L_ARB + offset, 0x204);
  WREG32(mmSRAM_Y0_X2_RTR_HBW_DATA_L_ARB + offset, 0x204);
  WREG32(mmSRAM_Y0_X3_RTR_HBW_DATA_L_ARB + offset, 0x204);
  WREG32(mmSRAM_Y0_X4_RTR_HBW_DATA_L_ARB + offset, 0x204);


  WREG32(mmSRAM_Y0_X0_RTR_HBW_DATA_E_ARB + offset, 0x206);
  WREG32(mmSRAM_Y0_X1_RTR_HBW_DATA_E_ARB + offset, 0x206);
  WREG32(mmSRAM_Y0_X2_RTR_HBW_DATA_E_ARB + offset, 0x206);
  WREG32(mmSRAM_Y0_X3_RTR_HBW_DATA_E_ARB + offset, 0x207);
  WREG32(mmSRAM_Y0_X4_RTR_HBW_DATA_E_ARB + offset, 0x207);

  WREG32(mmSRAM_Y0_X0_RTR_HBW_DATA_W_ARB + offset, 0x207);
  WREG32(mmSRAM_Y0_X1_RTR_HBW_DATA_W_ARB + offset, 0x207);
  WREG32(mmSRAM_Y0_X2_RTR_HBW_DATA_W_ARB + offset, 0x206);
  WREG32(mmSRAM_Y0_X3_RTR_HBW_DATA_W_ARB + offset, 0x206);
  WREG32(mmSRAM_Y0_X4_RTR_HBW_DATA_W_ARB + offset, 0x206);

  WREG32(mmSRAM_Y0_X0_RTR_HBW_WR_RS_E_ARB + offset, 0x101);
  WREG32(mmSRAM_Y0_X1_RTR_HBW_WR_RS_E_ARB + offset, 0x102);
  WREG32(mmSRAM_Y0_X2_RTR_HBW_WR_RS_E_ARB + offset, 0x103);
  WREG32(mmSRAM_Y0_X3_RTR_HBW_WR_RS_E_ARB + offset, 0x104);
  WREG32(mmSRAM_Y0_X4_RTR_HBW_WR_RS_E_ARB + offset, 0x105);

  WREG32(mmSRAM_Y0_X0_RTR_HBW_WR_RS_W_ARB + offset, 0x105);
  WREG32(mmSRAM_Y0_X1_RTR_HBW_WR_RS_W_ARB + offset, 0x104);
  WREG32(mmSRAM_Y0_X2_RTR_HBW_WR_RS_W_ARB + offset, 0x103);
  WREG32(mmSRAM_Y0_X3_RTR_HBW_WR_RS_W_ARB + offset, 0x102);
  WREG32(mmSRAM_Y0_X4_RTR_HBW_WR_RS_W_ARB + offset, 0x101);
 }

 WREG32(mmMME_STORE_MAX_CREDIT, 0x21);
 WREG32(mmMME_AGU, 0x0f0f0f10);
 WREG32(mmMME_SEI_MASK, ~0x0);

 WREG32(mmMME6_RTR_HBW_RD_RQ_N_ARB, 0x01010101);
 WREG32(mmMME5_RTR_HBW_RD_RQ_N_ARB, 0x01040101);
 WREG32(mmMME4_RTR_HBW_RD_RQ_N_ARB, 0x01030101);
 WREG32(mmMME3_RTR_HBW_RD_RQ_N_ARB, 0x01020101);
 WREG32(mmMME2_RTR_HBW_RD_RQ_N_ARB, 0x01010101);
 WREG32(mmMME1_RTR_HBW_RD_RQ_N_ARB, 0x07010701);
 WREG32(mmMME6_RTR_HBW_RD_RQ_S_ARB, 0x04010401);
 WREG32(mmMME5_RTR_HBW_RD_RQ_S_ARB, 0x04050401);
 WREG32(mmMME4_RTR_HBW_RD_RQ_S_ARB, 0x03070301);
 WREG32(mmMME3_RTR_HBW_RD_RQ_S_ARB, 0x01030101);
 WREG32(mmMME2_RTR_HBW_RD_RQ_S_ARB, 0x01040101);
 WREG32(mmMME1_RTR_HBW_RD_RQ_S_ARB, 0x01050105);
 WREG32(mmMME6_RTR_HBW_RD_RQ_W_ARB, 0x01010501);
 WREG32(mmMME5_RTR_HBW_RD_RQ_W_ARB, 0x01010501);
 WREG32(mmMME4_RTR_HBW_RD_RQ_W_ARB, 0x01040301);
 WREG32(mmMME3_RTR_HBW_RD_RQ_W_ARB, 0x01030401);
 WREG32(mmMME2_RTR_HBW_RD_RQ_W_ARB, 0x01040101);
 WREG32(mmMME1_RTR_HBW_RD_RQ_W_ARB, 0x01050101);
 WREG32(mmMME6_RTR_HBW_WR_RQ_N_ARB, 0x02020202);
 WREG32(mmMME5_RTR_HBW_WR_RQ_N_ARB, 0x01070101);
 WREG32(mmMME4_RTR_HBW_WR_RQ_N_ARB, 0x02020201);
 WREG32(mmMME3_RTR_HBW_WR_RQ_N_ARB, 0x07020701);
 WREG32(mmMME2_RTR_HBW_WR_RQ_N_ARB, 0x01020101);
 WREG32(mmMME1_RTR_HBW_WR_RQ_S_ARB, 0x01010101);
 WREG32(mmMME6_RTR_HBW_WR_RQ_S_ARB, 0x01070101);
 WREG32(mmMME5_RTR_HBW_WR_RQ_S_ARB, 0x01070101);
 WREG32(mmMME4_RTR_HBW_WR_RQ_S_ARB, 0x07020701);
 WREG32(mmMME3_RTR_HBW_WR_RQ_S_ARB, 0x02020201);
 WREG32(mmMME2_RTR_HBW_WR_RQ_S_ARB, 0x01070101);
 WREG32(mmMME1_RTR_HBW_WR_RQ_S_ARB, 0x01020102);
 WREG32(mmMME6_RTR_HBW_WR_RQ_W_ARB, 0x01020701);
 WREG32(mmMME5_RTR_HBW_WR_RQ_W_ARB, 0x01020701);
 WREG32(mmMME4_RTR_HBW_WR_RQ_W_ARB, 0x07020707);
 WREG32(mmMME3_RTR_HBW_WR_RQ_W_ARB, 0x01020201);
 WREG32(mmMME2_RTR_HBW_WR_RQ_W_ARB, 0x01070201);
 WREG32(mmMME1_RTR_HBW_WR_RQ_W_ARB, 0x01070201);
 WREG32(mmMME6_RTR_HBW_RD_RS_N_ARB, 0x01070102);
 WREG32(mmMME5_RTR_HBW_RD_RS_N_ARB, 0x01070102);
 WREG32(mmMME4_RTR_HBW_RD_RS_N_ARB, 0x01060102);
 WREG32(mmMME3_RTR_HBW_RD_RS_N_ARB, 0x01040102);
 WREG32(mmMME2_RTR_HBW_RD_RS_N_ARB, 0x01020102);
 WREG32(mmMME1_RTR_HBW_RD_RS_N_ARB, 0x01020107);
 WREG32(mmMME6_RTR_HBW_RD_RS_S_ARB, 0x01020106);
 WREG32(mmMME5_RTR_HBW_RD_RS_S_ARB, 0x01020102);
 WREG32(mmMME4_RTR_HBW_RD_RS_S_ARB, 0x01040102);
 WREG32(mmMME3_RTR_HBW_RD_RS_S_ARB, 0x01060102);
 WREG32(mmMME2_RTR_HBW_RD_RS_S_ARB, 0x01070102);
 WREG32(mmMME1_RTR_HBW_RD_RS_S_ARB, 0x01070102);
 WREG32(mmMME6_RTR_HBW_RD_RS_E_ARB, 0x01020702);
 WREG32(mmMME5_RTR_HBW_RD_RS_E_ARB, 0x01020702);
 WREG32(mmMME4_RTR_HBW_RD_RS_E_ARB, 0x01040602);
 WREG32(mmMME3_RTR_HBW_RD_RS_E_ARB, 0x01060402);
 WREG32(mmMME2_RTR_HBW_RD_RS_E_ARB, 0x01070202);
 WREG32(mmMME1_RTR_HBW_RD_RS_E_ARB, 0x01070102);
 WREG32(mmMME6_RTR_HBW_RD_RS_W_ARB, 0x01060401);
 WREG32(mmMME5_RTR_HBW_RD_RS_W_ARB, 0x01060401);
 WREG32(mmMME4_RTR_HBW_RD_RS_W_ARB, 0x01060401);
 WREG32(mmMME3_RTR_HBW_RD_RS_W_ARB, 0x01060401);
 WREG32(mmMME2_RTR_HBW_RD_RS_W_ARB, 0x01060401);
 WREG32(mmMME1_RTR_HBW_RD_RS_W_ARB, 0x01060401);
 WREG32(mmMME6_RTR_HBW_WR_RS_N_ARB, 0x01050101);
 WREG32(mmMME5_RTR_HBW_WR_RS_N_ARB, 0x01040101);
 WREG32(mmMME4_RTR_HBW_WR_RS_N_ARB, 0x01030101);
 WREG32(mmMME3_RTR_HBW_WR_RS_N_ARB, 0x01020101);
 WREG32(mmMME2_RTR_HBW_WR_RS_N_ARB, 0x01010101);
 WREG32(mmMME1_RTR_HBW_WR_RS_N_ARB, 0x01010107);
 WREG32(mmMME6_RTR_HBW_WR_RS_S_ARB, 0x01010107);
 WREG32(mmMME5_RTR_HBW_WR_RS_S_ARB, 0x01010101);
 WREG32(mmMME4_RTR_HBW_WR_RS_S_ARB, 0x01020101);
 WREG32(mmMME3_RTR_HBW_WR_RS_S_ARB, 0x01030101);
 WREG32(mmMME2_RTR_HBW_WR_RS_S_ARB, 0x01040101);
 WREG32(mmMME1_RTR_HBW_WR_RS_S_ARB, 0x01050101);
 WREG32(mmMME6_RTR_HBW_WR_RS_E_ARB, 0x01010501);
 WREG32(mmMME5_RTR_HBW_WR_RS_E_ARB, 0x01010501);
 WREG32(mmMME4_RTR_HBW_WR_RS_E_ARB, 0x01040301);
 WREG32(mmMME3_RTR_HBW_WR_RS_E_ARB, 0x01030401);
 WREG32(mmMME2_RTR_HBW_WR_RS_E_ARB, 0x01040101);
 WREG32(mmMME1_RTR_HBW_WR_RS_E_ARB, 0x01050101);
 WREG32(mmMME6_RTR_HBW_WR_RS_W_ARB, 0x01010101);
 WREG32(mmMME5_RTR_HBW_WR_RS_W_ARB, 0x01010101);
 WREG32(mmMME4_RTR_HBW_WR_RS_W_ARB, 0x01010101);
 WREG32(mmMME3_RTR_HBW_WR_RS_W_ARB, 0x01010101);
 WREG32(mmMME2_RTR_HBW_WR_RS_W_ARB, 0x01010101);
 WREG32(mmMME1_RTR_HBW_WR_RS_W_ARB, 0x01010101);

 WREG32(mmTPC1_RTR_HBW_RD_RQ_N_ARB, 0x01010101);
 WREG32(mmTPC1_RTR_HBW_RD_RQ_S_ARB, 0x01010101);
 WREG32(mmTPC1_RTR_HBW_RD_RQ_E_ARB, 0x01060101);
 WREG32(mmTPC1_RTR_HBW_WR_RQ_N_ARB, 0x02020102);
 WREG32(mmTPC1_RTR_HBW_WR_RQ_S_ARB, 0x01010101);
 WREG32(mmTPC1_RTR_HBW_WR_RQ_E_ARB, 0x02070202);
 WREG32(mmTPC1_RTR_HBW_RD_RS_N_ARB, 0x01020201);
 WREG32(mmTPC1_RTR_HBW_RD_RS_S_ARB, 0x01070201);
 WREG32(mmTPC1_RTR_HBW_RD_RS_W_ARB, 0x01070202);
 WREG32(mmTPC1_RTR_HBW_WR_RS_N_ARB, 0x01010101);
 WREG32(mmTPC1_RTR_HBW_WR_RS_S_ARB, 0x01050101);
 WREG32(mmTPC1_RTR_HBW_WR_RS_W_ARB, 0x01050101);

 WREG32(mmTPC2_RTR_HBW_RD_RQ_N_ARB, 0x01020101);
 WREG32(mmTPC2_RTR_HBW_RD_RQ_S_ARB, 0x01050101);
 WREG32(mmTPC2_RTR_HBW_RD_RQ_E_ARB, 0x01010201);
 WREG32(mmTPC2_RTR_HBW_WR_RQ_N_ARB, 0x02040102);
 WREG32(mmTPC2_RTR_HBW_WR_RQ_S_ARB, 0x01050101);
 WREG32(mmTPC2_RTR_HBW_WR_RQ_E_ARB, 0x02060202);
 WREG32(mmTPC2_RTR_HBW_RD_RS_N_ARB, 0x01020201);
 WREG32(mmTPC2_RTR_HBW_RD_RS_S_ARB, 0x01070201);
 WREG32(mmTPC2_RTR_HBW_RD_RS_W_ARB, 0x01070202);
 WREG32(mmTPC2_RTR_HBW_WR_RS_N_ARB, 0x01010101);
 WREG32(mmTPC2_RTR_HBW_WR_RS_S_ARB, 0x01040101);
 WREG32(mmTPC2_RTR_HBW_WR_RS_W_ARB, 0x01040101);

 WREG32(mmTPC3_RTR_HBW_RD_RQ_N_ARB, 0x01030101);
 WREG32(mmTPC3_RTR_HBW_RD_RQ_S_ARB, 0x01040101);
 WREG32(mmTPC3_RTR_HBW_RD_RQ_E_ARB, 0x01040301);
 WREG32(mmTPC3_RTR_HBW_WR_RQ_N_ARB, 0x02060102);
 WREG32(mmTPC3_RTR_HBW_WR_RQ_S_ARB, 0x01040101);
 WREG32(mmTPC3_RTR_HBW_WR_RQ_E_ARB, 0x01040301);
 WREG32(mmTPC3_RTR_HBW_RD_RS_N_ARB, 0x01040201);
 WREG32(mmTPC3_RTR_HBW_RD_RS_S_ARB, 0x01060201);
 WREG32(mmTPC3_RTR_HBW_RD_RS_W_ARB, 0x01060402);
 WREG32(mmTPC3_RTR_HBW_WR_RS_N_ARB, 0x01020101);
 WREG32(mmTPC3_RTR_HBW_WR_RS_S_ARB, 0x01030101);
 WREG32(mmTPC3_RTR_HBW_WR_RS_W_ARB, 0x01030401);

 WREG32(mmTPC4_RTR_HBW_RD_RQ_N_ARB, 0x01040101);
 WREG32(mmTPC4_RTR_HBW_RD_RQ_S_ARB, 0x01030101);
 WREG32(mmTPC4_RTR_HBW_RD_RQ_E_ARB, 0x01030401);
 WREG32(mmTPC4_RTR_HBW_WR_RQ_N_ARB, 0x02070102);
 WREG32(mmTPC4_RTR_HBW_WR_RQ_S_ARB, 0x01030101);
 WREG32(mmTPC4_RTR_HBW_WR_RQ_E_ARB, 0x02060702);
 WREG32(mmTPC4_RTR_HBW_RD_RS_N_ARB, 0x01060201);
 WREG32(mmTPC4_RTR_HBW_RD_RS_S_ARB, 0x01040201);
 WREG32(mmTPC4_RTR_HBW_RD_RS_W_ARB, 0x01040602);
 WREG32(mmTPC4_RTR_HBW_WR_RS_N_ARB, 0x01030101);
 WREG32(mmTPC4_RTR_HBW_WR_RS_S_ARB, 0x01020101);
 WREG32(mmTPC4_RTR_HBW_WR_RS_W_ARB, 0x01040301);

 WREG32(mmTPC5_RTR_HBW_RD_RQ_N_ARB, 0x01050101);
 WREG32(mmTPC5_RTR_HBW_RD_RQ_S_ARB, 0x01020101);
 WREG32(mmTPC5_RTR_HBW_RD_RQ_E_ARB, 0x01200501);
 WREG32(mmTPC5_RTR_HBW_WR_RQ_N_ARB, 0x02070102);
 WREG32(mmTPC5_RTR_HBW_WR_RQ_S_ARB, 0x01020101);
 WREG32(mmTPC5_RTR_HBW_WR_RQ_E_ARB, 0x02020602);
 WREG32(mmTPC5_RTR_HBW_RD_RS_N_ARB, 0x01070201);
 WREG32(mmTPC5_RTR_HBW_RD_RS_S_ARB, 0x01020201);
 WREG32(mmTPC5_RTR_HBW_RD_RS_W_ARB, 0x01020702);
 WREG32(mmTPC5_RTR_HBW_WR_RS_N_ARB, 0x01040101);
 WREG32(mmTPC5_RTR_HBW_WR_RS_S_ARB, 0x01010101);
 WREG32(mmTPC5_RTR_HBW_WR_RS_W_ARB, 0x01010501);

 WREG32(mmTPC6_RTR_HBW_RD_RQ_N_ARB, 0x01010101);
 WREG32(mmTPC6_RTR_HBW_RD_RQ_S_ARB, 0x01010101);
 WREG32(mmTPC6_RTR_HBW_RD_RQ_E_ARB, 0x01010601);
 WREG32(mmTPC6_RTR_HBW_WR_RQ_N_ARB, 0x01010101);
 WREG32(mmTPC6_RTR_HBW_WR_RQ_S_ARB, 0x01010101);
 WREG32(mmTPC6_RTR_HBW_WR_RQ_E_ARB, 0x02020702);
 WREG32(mmTPC6_RTR_HBW_RD_RS_N_ARB, 0x01010101);
 WREG32(mmTPC6_RTR_HBW_RD_RS_S_ARB, 0x01010101);
 WREG32(mmTPC6_RTR_HBW_RD_RS_W_ARB, 0x01020702);
 WREG32(mmTPC6_RTR_HBW_WR_RS_N_ARB, 0x01050101);
 WREG32(mmTPC6_RTR_HBW_WR_RS_S_ARB, 0x01010101);
 WREG32(mmTPC6_RTR_HBW_WR_RS_W_ARB, 0x01010501);

 for (i = 0, offset = 0 ; i < 10 ; i++, offset += 4) {
  WREG32(mmMME1_RTR_SPLIT_COEF_0 + offset, polynom[i] >> 7);
  WREG32(mmMME2_RTR_SPLIT_COEF_0 + offset, polynom[i] >> 7);
  WREG32(mmMME3_RTR_SPLIT_COEF_0 + offset, polynom[i] >> 7);
  WREG32(mmMME4_RTR_SPLIT_COEF_0 + offset, polynom[i] >> 7);
  WREG32(mmMME5_RTR_SPLIT_COEF_0 + offset, polynom[i] >> 7);
  WREG32(mmMME6_RTR_SPLIT_COEF_0 + offset, polynom[i] >> 7);

  WREG32(mmTPC0_NRTR_SPLIT_COEF_0 + offset, polynom[i] >> 7);
  WREG32(mmTPC1_RTR_SPLIT_COEF_0 + offset, polynom[i] >> 7);
  WREG32(mmTPC2_RTR_SPLIT_COEF_0 + offset, polynom[i] >> 7);
  WREG32(mmTPC3_RTR_SPLIT_COEF_0 + offset, polynom[i] >> 7);
  WREG32(mmTPC4_RTR_SPLIT_COEF_0 + offset, polynom[i] >> 7);
  WREG32(mmTPC5_RTR_SPLIT_COEF_0 + offset, polynom[i] >> 7);
  WREG32(mmTPC6_RTR_SPLIT_COEF_0 + offset, polynom[i] >> 7);
  WREG32(mmTPC7_NRTR_SPLIT_COEF_0 + offset, polynom[i] >> 7);

  WREG32(mmPCI_NRTR_SPLIT_COEF_0 + offset, polynom[i] >> 7);
  WREG32(mmDMA_NRTR_SPLIT_COEF_0 + offset, polynom[i] >> 7);
 }

 for (i = 0, offset = 0 ; i < 6 ; i++, offset += 0x40000) {
  WREG32(mmMME1_RTR_SCRAMB_EN + offset,
    1 << MME1_RTR_SCRAMB_EN_VAL_SHIFT);
  WREG32(mmMME1_RTR_NON_LIN_SCRAMB + offset,
    1 << MME1_RTR_NON_LIN_SCRAMB_EN_SHIFT);
 }

 for (i = 0, offset = 0 ; i < 8 ; i++, offset += 0x40000) {
  /*
 * Workaround for Bug H2 #2441 :
 * "ST.NOP set trace event illegal opcode"
 */

  WREG32(mmTPC0_CFG_TPC_INTR_MASK + offset, tpc_intr_mask);

  WREG32(mmTPC0_NRTR_SCRAMB_EN + offset,
    1 << TPC0_NRTR_SCRAMB_EN_VAL_SHIFT);
  WREG32(mmTPC0_NRTR_NON_LIN_SCRAMB + offset,
    1 << TPC0_NRTR_NON_LIN_SCRAMB_EN_SHIFT);

  WREG32_FIELD(TPC0_CFG_MSS_CONFIG, offset,
    ICACHE_FETCH_LINE_NUM, 2);
 }

 WREG32(mmDMA_NRTR_SCRAMB_EN, 1 << DMA_NRTR_SCRAMB_EN_VAL_SHIFT);
 WREG32(mmDMA_NRTR_NON_LIN_SCRAMB,
   1 << DMA_NRTR_NON_LIN_SCRAMB_EN_SHIFT);

 WREG32(mmPCI_NRTR_SCRAMB_EN, 1 << PCI_NRTR_SCRAMB_EN_VAL_SHIFT);
 WREG32(mmPCI_NRTR_NON_LIN_SCRAMB,
   1 << PCI_NRTR_NON_LIN_SCRAMB_EN_SHIFT);

 /*
 * Workaround for H2 #HW-23 bug
 * Set DMA max outstanding read requests to 240 on DMA CH 1.
 * This limitation is still large enough to not affect Gen4 bandwidth.
 * We need to only limit that DMA channel because the user can only read
 * from Host using DMA CH 1
 */

 WREG32(mmDMA_CH_1_CFG0, 0x0fff00F0);

 WREG32(mmTPC_PLL_CLK_RLX_0, 0x200020);

 goya->hw_cap_initialized |= HW_CAP_GOLDEN;
}

static void goya_init_mme_qman(struct hl_device *hdev)
{
 u32 mtr_base_lo, mtr_base_hi;
 u32 so_base_lo, so_base_hi;
 u32 gic_base_lo, gic_base_hi;
 u64 qman_base_addr;

 mtr_base_lo = lower_32_bits(CFG_BASE + mmSYNC_MNGR_MON_PAY_ADDRL_0);
 mtr_base_hi = upper_32_bits(CFG_BASE + mmSYNC_MNGR_MON_PAY_ADDRL_0);
 so_base_lo = lower_32_bits(CFG_BASE + mmSYNC_MNGR_SOB_OBJ_0);
 so_base_hi = upper_32_bits(CFG_BASE + mmSYNC_MNGR_SOB_OBJ_0);

 gic_base_lo =
  lower_32_bits(CFG_BASE + mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR);
 gic_base_hi =
  upper_32_bits(CFG_BASE + mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR);

 qman_base_addr = hdev->asic_prop.sram_base_address +
    MME_QMAN_BASE_OFFSET;

 WREG32(mmMME_QM_PQ_BASE_LO, lower_32_bits(qman_base_addr));
 WREG32(mmMME_QM_PQ_BASE_HI, upper_32_bits(qman_base_addr));
 WREG32(mmMME_QM_PQ_SIZE, ilog2(MME_QMAN_LENGTH));
 WREG32(mmMME_QM_PQ_PI, 0);
 WREG32(mmMME_QM_PQ_CI, 0);
 WREG32(mmMME_QM_CP_LDMA_SRC_BASE_LO_OFFSET, 0x10C0);
 WREG32(mmMME_QM_CP_LDMA_SRC_BASE_HI_OFFSET, 0x10C4);
 WREG32(mmMME_QM_CP_LDMA_TSIZE_OFFSET, 0x10C8);
 WREG32(mmMME_QM_CP_LDMA_COMMIT_OFFSET, 0x10CC);

 WREG32(mmMME_QM_CP_MSG_BASE0_ADDR_LO, mtr_base_lo);
 WREG32(mmMME_QM_CP_MSG_BASE0_ADDR_HI, mtr_base_hi);
 WREG32(mmMME_QM_CP_MSG_BASE1_ADDR_LO, so_base_lo);
 WREG32(mmMME_QM_CP_MSG_BASE1_ADDR_HI, so_base_hi);

 /* QMAN CQ has 8 cache lines */
 WREG32(mmMME_QM_CQ_CFG1, 0x00080008);

 WREG32(mmMME_QM_GLBL_ERR_ADDR_LO, gic_base_lo);
 WREG32(mmMME_QM_GLBL_ERR_ADDR_HI, gic_base_hi);

 WREG32(mmMME_QM_GLBL_ERR_WDATA, GOYA_ASYNC_EVENT_ID_MME_QM);

 WREG32(mmMME_QM_GLBL_ERR_CFG, QMAN_MME_ERR_MSG_EN);

 WREG32(mmMME_QM_GLBL_PROT, QMAN_MME_ERR_PROT);

 WREG32(mmMME_QM_GLBL_CFG0, QMAN_MME_ENABLE);
}

static void goya_init_mme_cmdq(struct hl_device *hdev)
{
 u32 mtr_base_lo, mtr_base_hi;
 u32 so_base_lo, so_base_hi;
 u32 gic_base_lo, gic_base_hi;

 mtr_base_lo = lower_32_bits(CFG_BASE + mmSYNC_MNGR_MON_PAY_ADDRL_0);
 mtr_base_hi = upper_32_bits(CFG_BASE + mmSYNC_MNGR_MON_PAY_ADDRL_0);
 so_base_lo = lower_32_bits(CFG_BASE + mmSYNC_MNGR_SOB_OBJ_0);
 so_base_hi = upper_32_bits(CFG_BASE + mmSYNC_MNGR_SOB_OBJ_0);

 gic_base_lo =
  lower_32_bits(CFG_BASE + mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR);
 gic_base_hi =
  upper_32_bits(CFG_BASE + mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR);

 WREG32(mmMME_CMDQ_CP_MSG_BASE0_ADDR_LO, mtr_base_lo);
 WREG32(mmMME_CMDQ_CP_MSG_BASE0_ADDR_HI, mtr_base_hi);
 WREG32(mmMME_CMDQ_CP_MSG_BASE1_ADDR_LO, so_base_lo);
 WREG32(mmMME_CMDQ_CP_MSG_BASE1_ADDR_HI, so_base_hi);

 /* CMDQ CQ has 20 cache lines */
 WREG32(mmMME_CMDQ_CQ_CFG1, 0x00140014);

 WREG32(mmMME_CMDQ_GLBL_ERR_ADDR_LO, gic_base_lo);
 WREG32(mmMME_CMDQ_GLBL_ERR_ADDR_HI, gic_base_hi);

 WREG32(mmMME_CMDQ_GLBL_ERR_WDATA, GOYA_ASYNC_EVENT_ID_MME_CMDQ);

 WREG32(mmMME_CMDQ_GLBL_ERR_CFG, CMDQ_MME_ERR_MSG_EN);

 WREG32(mmMME_CMDQ_GLBL_PROT, CMDQ_MME_ERR_PROT);

 WREG32(mmMME_CMDQ_GLBL_CFG0, CMDQ_MME_ENABLE);
}

void goya_init_mme_qmans(struct hl_device *hdev)
{
 struct goya_device *goya = hdev->asic_specific;
 u32 so_base_lo, so_base_hi;

 if (goya->hw_cap_initialized & HW_CAP_MME)
  return;

 so_base_lo = lower_32_bits(CFG_BASE + mmSYNC_MNGR_SOB_OBJ_0);
 so_base_hi = upper_32_bits(CFG_BASE + mmSYNC_MNGR_SOB_OBJ_0);

 WREG32(mmMME_SM_BASE_ADDRESS_LOW, so_base_lo);
 WREG32(mmMME_SM_BASE_ADDRESS_HIGH, so_base_hi);

 goya_init_mme_qman(hdev);
 goya_init_mme_cmdq(hdev);

 goya->hw_cap_initialized |= HW_CAP_MME;
}

static void goya_init_tpc_qman(struct hl_device *hdev, u32 base_off, int tpc_id)
{
 u32 mtr_base_lo, mtr_base_hi;
 u32 so_base_lo, so_base_hi;
 u32 gic_base_lo, gic_base_hi;
 u64 qman_base_addr;
 u32 reg_off = tpc_id * (mmTPC1_QM_PQ_PI - mmTPC0_QM_PQ_PI);

 mtr_base_lo = lower_32_bits(CFG_BASE + mmSYNC_MNGR_MON_PAY_ADDRL_0);
 mtr_base_hi = upper_32_bits(CFG_BASE + mmSYNC_MNGR_MON_PAY_ADDRL_0);
 so_base_lo = lower_32_bits(CFG_BASE + mmSYNC_MNGR_SOB_OBJ_0);
 so_base_hi = upper_32_bits(CFG_BASE + mmSYNC_MNGR_SOB_OBJ_0);

 gic_base_lo =
  lower_32_bits(CFG_BASE + mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR);
 gic_base_hi =
  upper_32_bits(CFG_BASE + mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR);

 qman_base_addr = hdev->asic_prop.sram_base_address + base_off;

 WREG32(mmTPC0_QM_PQ_BASE_LO + reg_off, lower_32_bits(qman_base_addr));
 WREG32(mmTPC0_QM_PQ_BASE_HI + reg_off, upper_32_bits(qman_base_addr));
 WREG32(mmTPC0_QM_PQ_SIZE + reg_off, ilog2(TPC_QMAN_LENGTH));
 WREG32(mmTPC0_QM_PQ_PI + reg_off, 0);
 WREG32(mmTPC0_QM_PQ_CI + reg_off, 0);
 WREG32(mmTPC0_QM_CP_LDMA_SRC_BASE_LO_OFFSET + reg_off, 0x10C0);
 WREG32(mmTPC0_QM_CP_LDMA_SRC_BASE_HI_OFFSET + reg_off, 0x10C4);
 WREG32(mmTPC0_QM_CP_LDMA_TSIZE_OFFSET + reg_off, 0x10C8);
 WREG32(mmTPC0_QM_CP_LDMA_COMMIT_OFFSET + reg_off, 0x10CC);

 WREG32(mmTPC0_QM_CP_MSG_BASE0_ADDR_LO + reg_off, mtr_base_lo);
 WREG32(mmTPC0_QM_CP_MSG_BASE0_ADDR_HI + reg_off, mtr_base_hi);
 WREG32(mmTPC0_QM_CP_MSG_BASE1_ADDR_LO + reg_off, so_base_lo);
 WREG32(mmTPC0_QM_CP_MSG_BASE1_ADDR_HI + reg_off, so_base_hi);

 WREG32(mmTPC0_QM_CQ_CFG1 + reg_off, 0x00080008);

 WREG32(mmTPC0_QM_GLBL_ERR_ADDR_LO + reg_off, gic_base_lo);
 WREG32(mmTPC0_QM_GLBL_ERR_ADDR_HI + reg_off, gic_base_hi);

 WREG32(mmTPC0_QM_GLBL_ERR_WDATA + reg_off,
   GOYA_ASYNC_EVENT_ID_TPC0_QM + tpc_id);

 WREG32(mmTPC0_QM_GLBL_ERR_CFG + reg_off, QMAN_TPC_ERR_MSG_EN);

 WREG32(mmTPC0_QM_GLBL_PROT + reg_off, QMAN_TPC_ERR_PROT);

 WREG32(mmTPC0_QM_GLBL_CFG0 + reg_off, QMAN_TPC_ENABLE);
}

static void goya_init_tpc_cmdq(struct hl_device *hdev, int tpc_id)
{
 u32 mtr_base_lo, mtr_base_hi;
 u32 so_base_lo, so_base_hi;
 u32 gic_base_lo, gic_base_hi;
 u32 reg_off = tpc_id * (mmTPC1_CMDQ_CQ_CFG1 - mmTPC0_CMDQ_CQ_CFG1);

 mtr_base_lo = lower_32_bits(CFG_BASE + mmSYNC_MNGR_MON_PAY_ADDRL_0);
 mtr_base_hi = upper_32_bits(CFG_BASE + mmSYNC_MNGR_MON_PAY_ADDRL_0);
 so_base_lo = lower_32_bits(CFG_BASE + mmSYNC_MNGR_SOB_OBJ_0);
 so_base_hi = upper_32_bits(CFG_BASE + mmSYNC_MNGR_SOB_OBJ_0);

 gic_base_lo =
  lower_32_bits(CFG_BASE + mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR);
 gic_base_hi =
  upper_32_bits(CFG_BASE + mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR);

 WREG32(mmTPC0_CMDQ_CP_MSG_BASE0_ADDR_LO + reg_off, mtr_base_lo);
 WREG32(mmTPC0_CMDQ_CP_MSG_BASE0_ADDR_HI + reg_off, mtr_base_hi);
 WREG32(mmTPC0_CMDQ_CP_MSG_BASE1_ADDR_LO + reg_off, so_base_lo);
 WREG32(mmTPC0_CMDQ_CP_MSG_BASE1_ADDR_HI + reg_off, so_base_hi);

 WREG32(mmTPC0_CMDQ_CQ_CFG1 + reg_off, 0x00140014);

 WREG32(mmTPC0_CMDQ_GLBL_ERR_ADDR_LO + reg_off, gic_base_lo);
 WREG32(mmTPC0_CMDQ_GLBL_ERR_ADDR_HI + reg_off, gic_base_hi);

 WREG32(mmTPC0_CMDQ_GLBL_ERR_WDATA + reg_off,
   GOYA_ASYNC_EVENT_ID_TPC0_CMDQ + tpc_id);

 WREG32(mmTPC0_CMDQ_GLBL_ERR_CFG + reg_off, CMDQ_TPC_ERR_MSG_EN);

 WREG32(mmTPC0_CMDQ_GLBL_PROT + reg_off, CMDQ_TPC_ERR_PROT);

 WREG32(mmTPC0_CMDQ_GLBL_CFG0 + reg_off, CMDQ_TPC_ENABLE);
}

void goya_init_tpc_qmans(struct hl_device *hdev)
{
 struct goya_device *goya = hdev->asic_specific;
 u32 so_base_lo, so_base_hi;
 u32 cfg_off = mmTPC1_CFG_SM_BASE_ADDRESS_LOW -
   mmTPC0_CFG_SM_BASE_ADDRESS_LOW;
 int i;

 if (goya->hw_cap_initialized & HW_CAP_TPC)
  return;

 so_base_lo = lower_32_bits(CFG_BASE + mmSYNC_MNGR_SOB_OBJ_0);
 so_base_hi = upper_32_bits(CFG_BASE + mmSYNC_MNGR_SOB_OBJ_0);

 for (i = 0 ; i < TPC_MAX_NUM ; i++) {
  WREG32(mmTPC0_CFG_SM_BASE_ADDRESS_LOW + i * cfg_off,
    so_base_lo);
  WREG32(mmTPC0_CFG_SM_BASE_ADDRESS_HIGH + i * cfg_off,
    so_base_hi);
 }

 goya_init_tpc_qman(hdev, TPC0_QMAN_BASE_OFFSET, 0);
 goya_init_tpc_qman(hdev, TPC1_QMAN_BASE_OFFSET, 1);
 goya_init_tpc_qman(hdev, TPC2_QMAN_BASE_OFFSET, 2);
 goya_init_tpc_qman(hdev, TPC3_QMAN_BASE_OFFSET, 3);
 goya_init_tpc_qman(hdev, TPC4_QMAN_BASE_OFFSET, 4);
 goya_init_tpc_qman(hdev, TPC5_QMAN_BASE_OFFSET, 5);
 goya_init_tpc_qman(hdev, TPC6_QMAN_BASE_OFFSET, 6);
 goya_init_tpc_qman(hdev, TPC7_QMAN_BASE_OFFSET, 7);

 for (i = 0 ; i < TPC_MAX_NUM ; i++)
  goya_init_tpc_cmdq(hdev, i);

 goya->hw_cap_initialized |= HW_CAP_TPC;
}

/*
 * goya_disable_internal_queues - Disable internal queues
 *
 * @hdev: pointer to hl_device structure
 *
 */

static void goya_disable_internal_queues(struct hl_device *hdev)
{
 struct goya_device *goya = hdev->asic_specific;

 if (!(goya->hw_cap_initialized & HW_CAP_MME))
  goto disable_tpc;

 WREG32(mmMME_QM_GLBL_CFG0, 0);
 WREG32(mmMME_CMDQ_GLBL_CFG0, 0);

disable_tpc:
 if (!(goya->hw_cap_initialized & HW_CAP_TPC))
  return;

 WREG32(mmTPC0_QM_GLBL_CFG0, 0);
 WREG32(mmTPC0_CMDQ_GLBL_CFG0, 0);

 WREG32(mmTPC1_QM_GLBL_CFG0, 0);
 WREG32(mmTPC1_CMDQ_GLBL_CFG0, 0);

 WREG32(mmTPC2_QM_GLBL_CFG0, 0);
 WREG32(mmTPC2_CMDQ_GLBL_CFG0, 0);

 WREG32(mmTPC3_QM_GLBL_CFG0, 0);
 WREG32(mmTPC3_CMDQ_GLBL_CFG0, 0);

 WREG32(mmTPC4_QM_GLBL_CFG0, 0);
 WREG32(mmTPC4_CMDQ_GLBL_CFG0, 0);

 WREG32(mmTPC5_QM_GLBL_CFG0, 0);
 WREG32(mmTPC5_CMDQ_GLBL_CFG0, 0);

 WREG32(mmTPC6_QM_GLBL_CFG0, 0);
 WREG32(mmTPC6_CMDQ_GLBL_CFG0, 0);

 WREG32(mmTPC7_QM_GLBL_CFG0, 0);
 WREG32(mmTPC7_CMDQ_GLBL_CFG0, 0);
}

/*
 * goya_stop_internal_queues - Stop internal queues
 *
 * @hdev: pointer to hl_device structure
 *
 * Returns 0 on success
 *
 */

static int goya_stop_internal_queues(struct hl_device *hdev)
{
 struct goya_device *goya = hdev->asic_specific;
 int rc, retval = 0;

 if (!(goya->hw_cap_initialized & HW_CAP_MME))
  goto stop_tpc;

 /*
 * Each queue (QMAN) is a separate H/W logic. That means that each
 * QMAN can be stopped independently and failure to stop one does NOT
 * mandate we should not try to stop other QMANs
 */


 rc = goya_stop_queue(hdev,
   mmMME_QM_GLBL_CFG1,
   mmMME_QM_CP_STS,
   mmMME_QM_GLBL_STS0);

 if (rc) {
  dev_err(hdev->dev, "failed to stop MME QMAN\n");
  retval = -EIO;
 }

 rc = goya_stop_queue(hdev,
   mmMME_CMDQ_GLBL_CFG1,
   mmMME_CMDQ_CP_STS,
   mmMME_CMDQ_GLBL_STS0);

 if (rc) {
  dev_err(hdev->dev, "failed to stop MME CMDQ\n");
  retval = -EIO;
 }

stop_tpc:
 if (!(goya->hw_cap_initialized & HW_CAP_TPC))
  return retval;

 rc = goya_stop_queue(hdev,
   mmTPC0_QM_GLBL_CFG1,
   mmTPC0_QM_CP_STS,
   mmTPC0_QM_GLBL_STS0);

 if (rc) {
  dev_err(hdev->dev, "failed to stop TPC 0 QMAN\n");
  retval = -EIO;
 }

 rc = goya_stop_queue(hdev,
   mmTPC0_CMDQ_GLBL_CFG1,
   mmTPC0_CMDQ_CP_STS,
   mmTPC0_CMDQ_GLBL_STS0);

 if (rc) {
  dev_err(hdev->dev, "failed to stop TPC 0 CMDQ\n");
  retval = -EIO;
 }

 rc = goya_stop_queue(hdev,
   mmTPC1_QM_GLBL_CFG1,
   mmTPC1_QM_CP_STS,
   mmTPC1_QM_GLBL_STS0);

--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=97 H=87 G=91

¤ Dauer der Verarbeitung: 0.21 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.