/* * 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 *
*/
staticinlinebool 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: returntrue; default: returnfalse;
}
}
/* 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;
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 *
*/ staticint 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) return0;
/* 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);
/* 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;
}
/* 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, true, false); 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, true, false); 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");
}
/* * 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)) return0;
dev_dbg(hdev->dev, "Changing device frequency to %s\n",
freq == PLL_HIGH ? "high" : "low");
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;
/* * 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);
/* * 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);
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);
}
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
*/
if (!(goya->hw_cap_initialized & HW_CAP_MSIX)) return;
/* Wait for all pending IRQs to be finished */ for (i = 0 ; i < hdev->asic_prop.completion_queues_count ; i++)
synchronize_irq(pci_irq_vector(hdev->pdev, i));
/* Zero the lower/upper parts of the 64-bit counter */
WREG32(mmPSOC_TIMESTAMP_BASE - CFG_BASE + 0xC, 0);
WREG32(mmPSOC_TIMESTAMP_BASE - CFG_BASE + 0x8, 0);
/* Enable the counter */
WREG32(mmPSOC_TIMESTAMP_BASE - CFG_BASE, 1);
}
/* * here we update initial values for few specific dynamic regs (as * before reading the first descriptor from FW those value has to be * hard-coded) in later stages of the protocol those values will be * updated automatically by reading the FW descriptor so data there * will always be up-to-date
*/
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);
if (!(hdev->fw_components & FW_TYPE_PREBOOT_CPU)) return0;
if (goya->hw_cap_initialized & HW_CAP_CPU) return0;
/* * Before pushing u-boot/linux to device, need to set the ddr bar to * base address of dram
*/ if (goya_set_ddr_bar_base(hdev, DRAM_PHYS_BASE) == U64_MAX) {
dev_err(hdev->dev, "failed to map DDR bar to DRAM base address\n"); return -EIO;
}
/* Perform read from the device to make sure device is up */
RREG32(mmPCIE_DBI_DEVICE_ID_VENDOR_ID_REG);
/* * Let's mark in the H/W that we have reached this point. We check * this value in the reset_before_init function to understand whether * we need to reset the chip before doing H/W init. This register is * cleared by the H/W upon H/W reset
*/
WREG32(mmHW_STATE, HL_DEVICE_HW_STATE_DIRTY);
rc = goya_init_cpu(hdev); if (rc) {
dev_err(hdev->dev, "failed to initialize CPU\n"); return rc;
}
goya_tpc_mbist_workaround(hdev);
goya_init_golden_registers(hdev);
/* * After CPU initialization is finished, change DDR bar mapping inside * iATU to point to the start address of the MMU page tables
*/ if (goya_set_ddr_bar_base(hdev, (MMU_PAGE_TABLES_ADDR &
~(prop->dram_pci_bar_size - 0x1ull))) == U64_MAX) {
dev_err(hdev->dev, "failed to map DDR bar to MMU page tables\n"); return -EIO;
}
rc = goya_mmu_init(hdev); if (rc) return rc;
goya_init_security(hdev);
goya_init_dma_qmans(hdev);
goya_init_mme_qmans(hdev);
goya_init_tpc_qmans(hdev);
goya_enable_timestamp(hdev);
/* MSI-X must be enabled before CPU queues are initialized */
rc = goya_enable_msix(hdev); if (rc) goto disable_queues;
/* Perform read from the device to flush all MSI-X configuration */
RREG32(mmPCIE_DBI_DEVICE_ID_VENDOR_ID_REG);
if (hard_reset) { /* I don't know what is the state of the CPU so make sure it is * stopped in any means necessary
*/
WREG32(mmPSOC_GLOBAL_CONF_UBOOT_MAGIC, KMD_MSG_GOTO_WFE);
WREG32(mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR,
GOYA_ASYNC_EVENT_ID_HALT_MACHINE);
WREG32(mmPSOC_GLOBAL_CONF_SW_ALL_RST_CFG, RESET_ALL);
dev_dbg(hdev->dev, "Issued HARD reset command, going to wait %dms\n",
reset_timeout_ms);
} else {
WREG32(mmPSOC_GLOBAL_CONF_SW_ALL_RST_CFG, DMA_MME_TPC_RESET);
dev_dbg(hdev->dev, "Issued SOFT reset command, going to wait %dms\n",
reset_timeout_ms);
}
/* * After hard reset, we can't poll the BTM_FSM register because the PSOC * itself is in reset. In either reset we need to wait until the reset * is deasserted
*/
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;
}
switch (hw_queue_id) { case GOYA_QUEUE_ID_DMA_0:
db_reg_offset = mmDMA_QM_0_PQ_PI; break;
case GOYA_QUEUE_ID_DMA_1:
db_reg_offset = mmDMA_QM_1_PQ_PI; break;
case GOYA_QUEUE_ID_DMA_2:
db_reg_offset = mmDMA_QM_2_PQ_PI; break;
case GOYA_QUEUE_ID_DMA_3:
db_reg_offset = mmDMA_QM_3_PQ_PI; break;
case GOYA_QUEUE_ID_DMA_4:
db_reg_offset = mmDMA_QM_4_PQ_PI; break;
case GOYA_QUEUE_ID_CPU_PQ:
db_reg_offset = mmCPU_IF_PF_PQ_PI; break;
case GOYA_QUEUE_ID_MME:
db_reg_offset = mmMME_QM_PQ_PI; break;
case GOYA_QUEUE_ID_TPC0:
db_reg_offset = mmTPC0_QM_PQ_PI; break;
case GOYA_QUEUE_ID_TPC1:
db_reg_offset = mmTPC1_QM_PQ_PI; break;
case GOYA_QUEUE_ID_TPC2:
db_reg_offset = mmTPC2_QM_PQ_PI; break;
case GOYA_QUEUE_ID_TPC3:
db_reg_offset = mmTPC3_QM_PQ_PI; break;
case GOYA_QUEUE_ID_TPC4:
db_reg_offset = mmTPC4_QM_PQ_PI; break;
case GOYA_QUEUE_ID_TPC5:
db_reg_offset = mmTPC5_QM_PQ_PI; break;
case GOYA_QUEUE_ID_TPC6:
db_reg_offset = mmTPC6_QM_PQ_PI; break;
case GOYA_QUEUE_ID_TPC7:
db_reg_offset = mmTPC7_QM_PQ_PI; break;
default: /* Should never get here */
dev_err(hdev->dev, "H/W queue %d is invalid. Can't set pi\n",
hw_queue_id); return;
}
db_value = pi;
/* ring the doorbell */
WREG32(db_reg_offset, db_value);
if (hw_queue_id == GOYA_QUEUE_ID_CPU_PQ) { /* make sure device CPU will read latest data from host */
mb();
WREG32(mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR,
GOYA_ASYNC_EVENT_ID_PI_UPDATE);
}
}
void goya_pqe_write(struct hl_device *hdev, __le64 *pqe, struct hl_bd *bd)
{ /* The QMANs are on the SRAM so need to copy to IO space */
memcpy_toio((void __iomem *) pqe, bd, sizeof(struct hl_bd));
}
if (hdev->pldm)
timeout = GOYA_PLDM_QMAN0_TIMEOUT_USEC; else
timeout = HL_DEVICE_TIMEOUT_USEC;
if (!hdev->asic_funcs->is_device_idle(hdev, NULL, 0, NULL)) {
dev_err_ratelimited(hdev->dev, "Can't send driver job on QMAN0 because the device is not idle\n"); return -EBUSY;
}
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;
}
int goya_test_cpu_queue(struct hl_device *hdev)
{ struct goya_device *goya = hdev->asic_specific;
/* * check capability here as send_cpu_message() won't update the result * value if no capability
*/ if (!(goya->hw_cap_initialized & HW_CAP_CPU_Q)) return0;
return hl_fw_test_cpu_queue(hdev);
}
int goya_test_queues(struct hl_device *hdev)
{ int i, rc, ret_val = 0;
for (i = 0 ; i < NUMBER_OF_EXT_HW_QUEUES ; i++) {
rc = goya_test_queue(hdev, i); if (rc)
ret_val = -EINVAL;
}
switch (user_dir) { case HL_DMA_HOST_TO_DRAM:
dev_dbg(hdev->dev, "DMA direction is HOST --> DRAM\n");
dir = DMA_TO_DEVICE;
sram_addr = false;
addr = le64_to_cpu(user_dma_pkt->src_addr);
device_memory_addr = le64_to_cpu(user_dma_pkt->dst_addr); if (user_memset)
skip_host_mem_pin = true; break;
case HL_DMA_DRAM_TO_HOST:
dev_dbg(hdev->dev, "DMA direction is DRAM --> HOST\n");
dir = DMA_FROM_DEVICE;
sram_addr = false;
addr = le64_to_cpu(user_dma_pkt->dst_addr);
device_memory_addr = le64_to_cpu(user_dma_pkt->src_addr); break;
case HL_DMA_HOST_TO_SRAM:
dev_dbg(hdev->dev, "DMA direction is HOST --> SRAM\n");
dir = DMA_TO_DEVICE;
addr = le64_to_cpu(user_dma_pkt->src_addr);
device_memory_addr = le64_to_cpu(user_dma_pkt->dst_addr); if (user_memset)
skip_host_mem_pin = true; break;
case HL_DMA_SRAM_TO_HOST:
dev_dbg(hdev->dev, "DMA direction is SRAM --> HOST\n");
dir = DMA_FROM_DEVICE;
addr = le64_to_cpu(user_dma_pkt->dst_addr);
device_memory_addr = le64_to_cpu(user_dma_pkt->src_addr); break; default:
dev_err(hdev->dev, "DMA direction %d is unsupported/undefined\n", user_dir); return -EFAULT;
}
if (sram_addr) { if (!hl_mem_area_inside_range(device_memory_addr,
le32_to_cpu(user_dma_pkt->tsize),
hdev->asic_prop.sram_user_base_address,
hdev->asic_prop.sram_end_address)) {
if (skip_host_mem_pin)
parser->patched_cb_size += sizeof(*user_dma_pkt); else { if ((dir == DMA_TO_DEVICE) &&
(parser->hw_queue_id > GOYA_QUEUE_ID_DMA_1)) {
dev_err(hdev->dev, "Can't DMA from host on queue other then 1\n"); return -EFAULT;
}
/* * Special handling for DMA with size 0. The H/W has a bug where * this can cause the QMAN DMA to get stuck, so block it here.
*/ if (user_dma_pkt->tsize == 0) {
dev_err(hdev->dev, "Got DMA with size 0, might reset the device\n"); return -EINVAL;
}
/* * WA for HW-23. * We can't allow user to read from Host using QMANs other than 1. * PMMU and HPMMU addresses are equal, check only one of them.
*/ if (parser->hw_queue_id != GOYA_QUEUE_ID_DMA_1 &&
hl_mem_area_inside_range(le64_to_cpu(user_dma_pkt->src_addr),
le32_to_cpu(user_dma_pkt->tsize),
hdev->asic_prop.pmmu.start_addr,
hdev->asic_prop.pmmu.end_addr)) {
dev_err(hdev->dev, "Can't DMA from host on queue other then 1\n"); return -EFAULT;
}
if (user_dma_pkt->tsize == 0) {
dev_err(hdev->dev, "Got DMA with size 0, might reset the device\n"); return -EINVAL;
}
if (reg_offset != (mmDMA_CH_0_WR_COMP_ADDR_LO & 0x1FFF)) {
dev_err(hdev->dev, "WREG32 packet with illegal address 0x%x\n",
reg_offset); return -EPERM;
}
/* * With MMU, DMA channels are not secured, so it doesn't matter where * the WR COMP will be written to because it will go out with * non-secured property
*/ if (goya->hw_cap_initialized & HW_CAP_MMU) return0;
/* cb_user_size is more than 0 so loop will always be executed */ while (cb_parsed_length < parser->user_cb_size) { enum packet_id pkt_id;
u16 pkt_size; struct goya_packet *user_pkt;
if (!validate_packet_id(pkt_id)) {
dev_err(hdev->dev, "Invalid packet id %u\n", pkt_id);
rc = -EINVAL; break;
}
pkt_size = goya_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_WREG_32: /* * Although it is validated after copy in patch_cb(), * need to validate here as well because patch_cb() is * not called in MMU path while this function is called
*/
rc = goya_validate_wreg32(hdev,
parser, (struct packet_wreg32 *) user_pkt);
parser->patched_cb_size += pkt_size; break;
case PACKET_WREG_BULK:
dev_err(hdev->dev, "User not allowed to use WREG_BULK\n");
rc = -EPERM; 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;
/* * The new CB should have space at the end for two MSG_PROT packets: * 1. A packet that will act as a completion packet * 2. A packet that will generate MSI-X interrupt
*/
parser->patched_cb_size += sizeof(struct packet_msg_prot) * 2;
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;
}
/* Fix the last dma packet - rdcomp/wrcomp must be as user set them */
new_dma_pkt--;
new_dma_pkt->ctl |= cpu_to_le32(user_rdcomp_mask | user_wrcomp_mask);
/* cb_user_size is more than 0 so loop will always be executed */ while (cb_parsed_length < parser->user_cb_size) { enum packet_id pkt_id;
u16 pkt_size;
u32 new_pkt_size = 0; struct goya_packet *user_pkt, *kernel_pkt;
case PACKET_WREG_BULK:
dev_err(hdev->dev, "User not allowed to use WREG_BULK\n");
rc = -EPERM; 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_MSG_LONG: case PACKET_MSG_SHORT: case PACKET_FENCE: case PACKET_NOP:
memcpy(kernel_pkt, user_pkt, pkt_size);
cb_patched_cur_length += pkt_size; break;
/* * The new CB should have space at the end for two MSG_PROT pkt: * 1. A packet that will act as a completion packet * 2. A packet that will generate MSI-X interrupt
*/
parser->patched_cb_size = parser->user_cb_size + sizeof(struct packet_msg_prot) * 2;
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); /* hl_cb_get should never fail here */ if (!parser->patched_cb) {
dev_crit(hdev->dev, "DMA CB handle invalid 0x%llx\n", handle);
rc = -EFAULT; goto out;
}
/* * The check that parser->user_cb_size <= parser->user_cb->size was done * in validate_queue_index().
*/
memcpy(parser->patched_cb->kernel_address,
parser->user_cb->kernel_address,
parser->user_cb_size);
out: /* * Always call cb destroy here because we still have 1 reference * to it by calling cb_get earlier. After the job will be completed, * cb_put will release it, but here we want to remove it from the * idr
*/
hl_cb_destroy(&hdev->kernel_mem_mgr, handle);
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); /* hl_cb_get should never fail here */ if (!parser->patched_cb) {
dev_crit(hdev->dev, "DMA CB handle invalid 0x%llx\n", handle);
rc = -EFAULT; goto out;
}
rc = goya_patch_cb(hdev, parser);
if (rc)
hl_cb_put(parser->patched_cb);
out: /* * Always call cb destroy here because we still have 1 reference * to it by calling cb_get earlier. After the job will be completed, * cb_put will release it, but here we want to remove it from the * idr
*/
hl_cb_destroy(&hdev->kernel_mem_mgr, handle);
free_userptr: if (rc)
hl_userptr_delete_list(hdev, parser->job_userptr_list); return rc;
}
if (goya->hw_cap_initialized & HW_CAP_MMU) return0;
/* For internal queue jobs, just check if CB address is valid */ 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)) return0;
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)) return0;
dev_err(hdev->dev, "Internal CB address 0x%px + 0x%x is not in SRAM nor in DRAM\n",
parser->user_cb, parser->user_cb_size);
staticconstchar *_goya_get_event_desc(u16 event_type)
{ switch (event_type) { case GOYA_ASYNC_EVENT_ID_PCIE_IF: return"PCIe_if"; case GOYA_ASYNC_EVENT_ID_TPC0_ECC: case GOYA_ASYNC_EVENT_ID_TPC1_ECC: case GOYA_ASYNC_EVENT_ID_TPC2_ECC: case GOYA_ASYNC_EVENT_ID_TPC3_ECC: case GOYA_ASYNC_EVENT_ID_TPC4_ECC: case GOYA_ASYNC_EVENT_ID_TPC5_ECC: case GOYA_ASYNC_EVENT_ID_TPC6_ECC: case GOYA_ASYNC_EVENT_ID_TPC7_ECC: return"TPC%d_ecc"; case GOYA_ASYNC_EVENT_ID_MME_ECC: return"MME_ecc"; case GOYA_ASYNC_EVENT_ID_MME_ECC_EXT: return"MME_ecc_ext"; case GOYA_ASYNC_EVENT_ID_MMU_ECC: return"MMU_ecc"; case GOYA_ASYNC_EVENT_ID_DMA_MACRO: return"DMA_macro"; case GOYA_ASYNC_EVENT_ID_DMA_ECC: return"DMA_ecc"; case GOYA_ASYNC_EVENT_ID_CPU_IF_ECC: return"CPU_if_ecc"; case GOYA_ASYNC_EVENT_ID_PSOC_MEM: return"PSOC_mem"; case GOYA_ASYNC_EVENT_ID_PSOC_CORESIGHT: return"PSOC_coresight"; case GOYA_ASYNC_EVENT_ID_SRAM0 ... GOYA_ASYNC_EVENT_ID_SRAM29: return"SRAM%d"; case GOYA_ASYNC_EVENT_ID_GIC500: return"GIC500"; case GOYA_ASYNC_EVENT_ID_PLL0 ... GOYA_ASYNC_EVENT_ID_PLL6: return"PLL%d"; case GOYA_ASYNC_EVENT_ID_AXI_ECC: return"AXI_ecc"; case GOYA_ASYNC_EVENT_ID_L2_RAM_ECC: return"L2_ram_ecc"; case GOYA_ASYNC_EVENT_ID_PSOC_GPIO_05_SW_RESET: return"PSOC_gpio_05_sw_reset"; case GOYA_ASYNC_EVENT_ID_PSOC_GPIO_10_VRHOT_ICRIT: return"PSOC_gpio_10_vrhot_icrit"; case GOYA_ASYNC_EVENT_ID_PCIE_DEC: return"PCIe_dec"; case GOYA_ASYNC_EVENT_ID_TPC0_DEC: case GOYA_ASYNC_EVENT_ID_TPC1_DEC: case GOYA_ASYNC_EVENT_ID_TPC2_DEC: case GOYA_ASYNC_EVENT_ID_TPC3_DEC: case GOYA_ASYNC_EVENT_ID_TPC4_DEC: case GOYA_ASYNC_EVENT_ID_TPC5_DEC: case GOYA_ASYNC_EVENT_ID_TPC6_DEC: case GOYA_ASYNC_EVENT_ID_TPC7_DEC: return"TPC%d_dec"; case GOYA_ASYNC_EVENT_ID_MME_WACS: return"MME_wacs"; case GOYA_ASYNC_EVENT_ID_MME_WACSD: return"MME_wacsd"; case GOYA_ASYNC_EVENT_ID_CPU_AXI_SPLITTER: return"CPU_axi_splitter"; case GOYA_ASYNC_EVENT_ID_PSOC_AXI_DEC: return"PSOC_axi_dec"; case GOYA_ASYNC_EVENT_ID_PSOC: return"PSOC"; case GOYA_ASYNC_EVENT_ID_TPC0_KRN_ERR: case GOYA_ASYNC_EVENT_ID_TPC1_KRN_ERR: case GOYA_ASYNC_EVENT_ID_TPC2_KRN_ERR: case GOYA_ASYNC_EVENT_ID_TPC3_KRN_ERR: case GOYA_ASYNC_EVENT_ID_TPC4_KRN_ERR: case GOYA_ASYNC_EVENT_ID_TPC5_KRN_ERR: case GOYA_ASYNC_EVENT_ID_TPC6_KRN_ERR: case GOYA_ASYNC_EVENT_ID_TPC7_KRN_ERR: return"TPC%d_krn_err"; case GOYA_ASYNC_EVENT_ID_TPC0_CMDQ ... GOYA_ASYNC_EVENT_ID_TPC7_CMDQ: return"TPC%d_cq"; case GOYA_ASYNC_EVENT_ID_TPC0_QM ... GOYA_ASYNC_EVENT_ID_TPC7_QM: return"TPC%d_qm"; case GOYA_ASYNC_EVENT_ID_MME_QM: return"MME_qm"; case GOYA_ASYNC_EVENT_ID_MME_CMDQ: return"MME_cq"; case GOYA_ASYNC_EVENT_ID_DMA0_QM ... GOYA_ASYNC_EVENT_ID_DMA4_QM: return"DMA%d_qm"; case GOYA_ASYNC_EVENT_ID_DMA0_CH ... GOYA_ASYNC_EVENT_ID_DMA4_CH: return"DMA%d_ch"; case GOYA_ASYNC_EVENT_ID_TPC0_BMON_SPMU: case GOYA_ASYNC_EVENT_ID_TPC1_BMON_SPMU: case GOYA_ASYNC_EVENT_ID_TPC2_BMON_SPMU: case GOYA_ASYNC_EVENT_ID_TPC3_BMON_SPMU: case GOYA_ASYNC_EVENT_ID_TPC4_BMON_SPMU: case GOYA_ASYNC_EVENT_ID_TPC5_BMON_SPMU: case GOYA_ASYNC_EVENT_ID_TPC6_BMON_SPMU: case GOYA_ASYNC_EVENT_ID_TPC7_BMON_SPMU: return"TPC%d_bmon_spmu"; case GOYA_ASYNC_EVENT_ID_DMA_BM_CH0 ... GOYA_ASYNC_EVENT_ID_DMA_BM_CH4: return"DMA_bm_ch%d"; case GOYA_ASYNC_EVENT_ID_FIX_POWER_ENV_S: return"POWER_ENV_S"; case GOYA_ASYNC_EVENT_ID_FIX_POWER_ENV_E: return"POWER_ENV_E"; case GOYA_ASYNC_EVENT_ID_FIX_THERMAL_ENV_S: return"THERMAL_ENV_S"; case GOYA_ASYNC_EVENT_ID_FIX_THERMAL_ENV_E: return"THERMAL_ENV_E"; case GOYA_ASYNC_EVENT_PKT_QUEUE_OUT_SYNC: return"QUEUE_OUT_OF_SYNC"; default: return"N/A";
}
}
switch (event_type) { case GOYA_ASYNC_EVENT_ID_TPC0_ECC: case GOYA_ASYNC_EVENT_ID_TPC1_ECC: case GOYA_ASYNC_EVENT_ID_TPC2_ECC: case GOYA_ASYNC_EVENT_ID_TPC3_ECC: case GOYA_ASYNC_EVENT_ID_TPC4_ECC: case GOYA_ASYNC_EVENT_ID_TPC5_ECC: case GOYA_ASYNC_EVENT_ID_TPC6_ECC: case GOYA_ASYNC_EVENT_ID_TPC7_ECC:
index = (event_type - GOYA_ASYNC_EVENT_ID_TPC0_ECC) / 3;
snprintf(desc, size, _goya_get_event_desc(event_type), index); break; case GOYA_ASYNC_EVENT_ID_SRAM0 ... GOYA_ASYNC_EVENT_ID_SRAM29:
index = event_type - GOYA_ASYNC_EVENT_ID_SRAM0;
snprintf(desc, size, _goya_get_event_desc(event_type), index); break; case GOYA_ASYNC_EVENT_ID_PLL0 ... GOYA_ASYNC_EVENT_ID_PLL6:
index = event_type - GOYA_ASYNC_EVENT_ID_PLL0;
snprintf(desc, size, _goya_get_event_desc(event_type), index); break; case GOYA_ASYNC_EVENT_ID_TPC0_DEC: case GOYA_ASYNC_EVENT_ID_TPC1_DEC: case GOYA_ASYNC_EVENT_ID_TPC2_DEC: case GOYA_ASYNC_EVENT_ID_TPC3_DEC: case GOYA_ASYNC_EVENT_ID_TPC4_DEC: case GOYA_ASYNC_EVENT_ID_TPC5_DEC: case GOYA_ASYNC_EVENT_ID_TPC6_DEC: case GOYA_ASYNC_EVENT_ID_TPC7_DEC:
index = (event_type - GOYA_ASYNC_EVENT_ID_TPC0_DEC) / 3;
snprintf(desc, size, _goya_get_event_desc(event_type), index); break; case GOYA_ASYNC_EVENT_ID_TPC0_KRN_ERR: case GOYA_ASYNC_EVENT_ID_TPC1_KRN_ERR: case GOYA_ASYNC_EVENT_ID_TPC2_KRN_ERR: case GOYA_ASYNC_EVENT_ID_TPC3_KRN_ERR: case GOYA_ASYNC_EVENT_ID_TPC4_KRN_ERR: case GOYA_ASYNC_EVENT_ID_TPC5_KRN_ERR: case GOYA_ASYNC_EVENT_ID_TPC6_KRN_ERR: case GOYA_ASYNC_EVENT_ID_TPC7_KRN_ERR:
index = (event_type - GOYA_ASYNC_EVENT_ID_TPC0_KRN_ERR) / 10;
snprintf(desc, size, _goya_get_event_desc(event_type), index); break; case GOYA_ASYNC_EVENT_ID_TPC0_CMDQ ... GOYA_ASYNC_EVENT_ID_TPC7_CMDQ:
index = event_type - GOYA_ASYNC_EVENT_ID_TPC0_CMDQ;
snprintf(desc, size, _goya_get_event_desc(event_type), index); break; case GOYA_ASYNC_EVENT_ID_TPC0_QM ... GOYA_ASYNC_EVENT_ID_TPC7_QM:
index = event_type - GOYA_ASYNC_EVENT_ID_TPC0_QM;
snprintf(desc, size, _goya_get_event_desc(event_type), index); break; case GOYA_ASYNC_EVENT_ID_DMA0_QM ... GOYA_ASYNC_EVENT_ID_DMA4_QM:
index = event_type - GOYA_ASYNC_EVENT_ID_DMA0_QM;
snprintf(desc, size, _goya_get_event_desc(event_type), index); break; case GOYA_ASYNC_EVENT_ID_DMA0_CH ... GOYA_ASYNC_EVENT_ID_DMA4_CH:
index = event_type - GOYA_ASYNC_EVENT_ID_DMA0_CH;
snprintf(desc, size, _goya_get_event_desc(event_type), index); break; case GOYA_ASYNC_EVENT_ID_TPC0_BMON_SPMU: case GOYA_ASYNC_EVENT_ID_TPC1_BMON_SPMU: case GOYA_ASYNC_EVENT_ID_TPC2_BMON_SPMU: case GOYA_ASYNC_EVENT_ID_TPC3_BMON_SPMU: case GOYA_ASYNC_EVENT_ID_TPC4_BMON_SPMU: case GOYA_ASYNC_EVENT_ID_TPC5_BMON_SPMU: case GOYA_ASYNC_EVENT_ID_TPC6_BMON_SPMU: case GOYA_ASYNC_EVENT_ID_TPC7_BMON_SPMU:
index = (event_type - GOYA_ASYNC_EVENT_ID_TPC0_BMON_SPMU) / 10;
snprintf(desc, size, _goya_get_event_desc(event_type), index); break; case GOYA_ASYNC_EVENT_ID_DMA_BM_CH0 ... GOYA_ASYNC_EVENT_ID_DMA_BM_CH4:
index = event_type - GOYA_ASYNC_EVENT_ID_DMA_BM_CH0;
snprintf(desc, size, _goya_get_event_desc(event_type), index); break; case GOYA_ASYNC_EVENT_PKT_QUEUE_OUT_SYNC:
snprintf(desc, size, _goya_get_event_desc(event_type)); break; default:
snprintf(desc, size, _goya_get_event_desc(event_type)); break;
}
}
staticvoid goya_print_razwi_info(struct hl_device *hdev)
{ if (RREG32(mmDMA_MACRO_RAZWI_LBW_WT_VLD)) {
dev_err_ratelimited(hdev->dev, "Illegal write to LBW\n");
WREG32(mmDMA_MACRO_RAZWI_LBW_WT_VLD, 0);
}
if (RREG32(mmDMA_MACRO_RAZWI_LBW_RD_VLD)) {
dev_err_ratelimited(hdev->dev, "Illegal read from LBW\n");
WREG32(mmDMA_MACRO_RAZWI_LBW_RD_VLD, 0);
}
if (RREG32(mmDMA_MACRO_RAZWI_HBW_WT_VLD)) {
dev_err_ratelimited(hdev->dev, "Illegal write to HBW\n");
WREG32(mmDMA_MACRO_RAZWI_HBW_WT_VLD, 0);
}
if (RREG32(mmDMA_MACRO_RAZWI_HBW_RD_VLD)) {
dev_err_ratelimited(hdev->dev, "Illegal read from HBW\n");
WREG32(mmDMA_MACRO_RAZWI_HBW_RD_VLD, 0);
}
}
/* data should be aligned to 8 bytes in order to CPU-CP to copy it */
total_pkt_size = (total_pkt_size + 0x7) & ~0x7;
/* total_pkt_size is casted to u16 later on */ if (total_pkt_size > USHRT_MAX) {
dev_err(hdev->dev, "too many elements in IRQ array\n"); return -EINVAL;
}
pkt = kzalloc(total_pkt_size, GFP_KERNEL); if (!pkt) return -ENOMEM;
/* We must perform any necessary endianness conversation on the irq * array being passed to the goya hardware
*/ for (irq_arr_index = 0, goya_irq_arr = (__le32 *) &pkt->irqs;
irq_arr_index < irq_num_entries ; irq_arr_index++)
goya_irq_arr[irq_arr_index] =
cpu_to_le32(irq_arr[irq_arr_index]);
if (rc)
dev_err(hdev->dev, "failed to unmask IRQ array\n");
kfree(pkt);
return rc;
}
staticint goya_compute_reset_late_init(struct hl_device *hdev)
{ /* * Unmask all IRQs since some could have been received * during the soft reset
*/ return goya_unmask_irq_arr(hdev, goya_all_events, sizeof(goya_all_events));
}
switch (event_type) { case GOYA_ASYNC_EVENT_ID_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 GOYA_ASYNC_EVENT_ID_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 GOYA_ASYNC_EVENT_ID_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;
dev_info_ratelimited(hdev->dev, "Clock throttling due to overheating\n"); break;
case GOYA_ASYNC_EVENT_ID_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();
dev_info_ratelimited(hdev->dev, "Thermal envelop is safe, back to optimal clock\n"); break;
if (event_type >= GOYA_ASYNC_EVENT_ID_SIZE) {
dev_err(hdev->dev, "Event type %u exceeds maximum of %u",
event_type, GOYA_ASYNC_EVENT_ID_SIZE - 1); return;
}
switch (event_type) { case GOYA_ASYNC_EVENT_ID_PCIE_IF: case GOYA_ASYNC_EVENT_ID_TPC0_ECC: case GOYA_ASYNC_EVENT_ID_TPC1_ECC: case GOYA_ASYNC_EVENT_ID_TPC2_ECC: case GOYA_ASYNC_EVENT_ID_TPC3_ECC: case GOYA_ASYNC_EVENT_ID_TPC4_ECC: case GOYA_ASYNC_EVENT_ID_TPC5_ECC: case GOYA_ASYNC_EVENT_ID_TPC6_ECC: case GOYA_ASYNC_EVENT_ID_TPC7_ECC: case GOYA_ASYNC_EVENT_ID_MME_ECC: case GOYA_ASYNC_EVENT_ID_MME_ECC_EXT: case GOYA_ASYNC_EVENT_ID_MMU_ECC: case GOYA_ASYNC_EVENT_ID_DMA_MACRO: case GOYA_ASYNC_EVENT_ID_DMA_ECC: case GOYA_ASYNC_EVENT_ID_CPU_IF_ECC: case GOYA_ASYNC_EVENT_ID_PSOC_MEM: case GOYA_ASYNC_EVENT_ID_PSOC_CORESIGHT: case GOYA_ASYNC_EVENT_ID_SRAM0 ... GOYA_ASYNC_EVENT_ID_SRAM29: case GOYA_ASYNC_EVENT_ID_GIC500: case GOYA_ASYNC_EVENT_ID_PLL0 ... GOYA_ASYNC_EVENT_ID_PLL6: case GOYA_ASYNC_EVENT_ID_AXI_ECC: case GOYA_ASYNC_EVENT_ID_L2_RAM_ECC:
goya_print_irq_info(hdev, event_type, false); if (hdev->hard_reset_on_fw_events)
hl_device_reset(hdev, (HL_DRV_RESET_HARD |
HL_DRV_RESET_FW_FATAL_ERR)); break;
case GOYA_ASYNC_EVENT_ID_PSOC_GPIO_05_SW_RESET:
goya_print_irq_info(hdev, event_type, false); if (hdev->hard_reset_on_fw_events)
hl_device_reset(hdev, HL_DRV_RESET_HARD); break;
case GOYA_ASYNC_EVENT_ID_PCIE_DEC: case GOYA_ASYNC_EVENT_ID_TPC0_DEC: case GOYA_ASYNC_EVENT_ID_TPC1_DEC: case GOYA_ASYNC_EVENT_ID_TPC2_DEC: case GOYA_ASYNC_EVENT_ID_TPC3_DEC: case GOYA_ASYNC_EVENT_ID_TPC4_DEC: case GOYA_ASYNC_EVENT_ID_TPC5_DEC: case GOYA_ASYNC_EVENT_ID_TPC6_DEC: case GOYA_ASYNC_EVENT_ID_TPC7_DEC: case GOYA_ASYNC_EVENT_ID_MME_WACS: case GOYA_ASYNC_EVENT_ID_MME_WACSD: case GOYA_ASYNC_EVENT_ID_CPU_AXI_SPLITTER: case GOYA_ASYNC_EVENT_ID_PSOC_AXI_DEC: case GOYA_ASYNC_EVENT_ID_PSOC: case GOYA_ASYNC_EVENT_ID_TPC0_KRN_ERR: case GOYA_ASYNC_EVENT_ID_TPC1_KRN_ERR: case GOYA_ASYNC_EVENT_ID_TPC2_KRN_ERR: case GOYA_ASYNC_EVENT_ID_TPC3_KRN_ERR: case GOYA_ASYNC_EVENT_ID_TPC4_KRN_ERR: case GOYA_ASYNC_EVENT_ID_TPC5_KRN_ERR: case GOYA_ASYNC_EVENT_ID_TPC6_KRN_ERR: case GOYA_ASYNC_EVENT_ID_TPC7_KRN_ERR: case GOYA_ASYNC_EVENT_ID_TPC0_CMDQ ... GOYA_ASYNC_EVENT_ID_TPC7_QM: case GOYA_ASYNC_EVENT_ID_MME_QM: case GOYA_ASYNC_EVENT_ID_MME_CMDQ: case GOYA_ASYNC_EVENT_ID_DMA0_QM ... GOYA_ASYNC_EVENT_ID_DMA4_QM: case GOYA_ASYNC_EVENT_ID_DMA0_CH ... GOYA_ASYNC_EVENT_ID_DMA4_CH:
goya_print_irq_info(hdev, event_type, true);
goya_unmask_irq(hdev, event_type); break;
case GOYA_ASYNC_EVENT_ID_PSOC_GPIO_10_VRHOT_ICRIT: case GOYA_ASYNC_EVENT_ID_TPC0_BMON_SPMU: case GOYA_ASYNC_EVENT_ID_TPC1_BMON_SPMU: case GOYA_ASYNC_EVENT_ID_TPC2_BMON_SPMU: case GOYA_ASYNC_EVENT_ID_TPC3_BMON_SPMU: case GOYA_ASYNC_EVENT_ID_TPC4_BMON_SPMU: case GOYA_ASYNC_EVENT_ID_TPC5_BMON_SPMU: case GOYA_ASYNC_EVENT_ID_TPC6_BMON_SPMU: case GOYA_ASYNC_EVENT_ID_TPC7_BMON_SPMU: case GOYA_ASYNC_EVENT_ID_DMA_BM_CH0 ... GOYA_ASYNC_EVENT_ID_DMA_BM_CH4:
goya_print_irq_info(hdev, event_type, false);
goya_unmask_irq(hdev, event_type); break;
case GOYA_ASYNC_EVENT_ID_FIX_POWER_ENV_S: case GOYA_ASYNC_EVENT_ID_FIX_POWER_ENV_E: case GOYA_ASYNC_EVENT_ID_FIX_THERMAL_ENV_S: case GOYA_ASYNC_EVENT_ID_FIX_THERMAL_ENV_E:
goya_print_clk_change_info(hdev, event_type);
goya_unmask_irq(hdev, event_type); break;
case GOYA_ASYNC_EVENT_PKT_QUEUE_OUT_SYNC:
goya_print_irq_info(hdev, event_type, false);
goya_print_out_of_sync_info(hdev, &eq_entry->pkt_sync_err); if (hdev->hard_reset_on_fw_events)
hl_device_reset(hdev, HL_DRV_RESET_HARD); else
hl_fw_unmask_irq(hdev, event_type); break;
rc = goya_memset_device_memory(hdev, addr, size, val, false); if (rc) {
dev_err(hdev->dev, "Failed to clear SRAM in context switch\n"); return rc;
}
/* we need to reset registers that the user is allowed to change */
sob_addr = CFG_BASE + mmSYNC_MNGR_SOB_OBJ_1007;
WREG32(mmDMA_CH_0_WR_COMP_ADDR_LO, lower_32_bits(sob_addr));
if (!(goya->hw_cap_initialized & HW_CAP_MMU)) return;
if (asid & ~MME_QM_GLBL_SECURE_PROPS_ASID_MASK) {
dev_crit(hdev->dev, "asid %u is too big\n", asid); return;
}
/* zero the MMBP and ASID bits and then set the ASID */ for (i = 0 ; i < GOYA_MMU_REGS_NUM ; i++)
goya_mmu_prepare_reg(hdev, goya_mmu_regs[i], asid);
}
staticint goya_mmu_invalidate_cache_range(struct hl_device *hdev, bool is_hard, u32 flags,
u32 asid, u64 va, u64 size)
{ /* Treat as invalidate all because there is no range invalidation * in Goya
*/ return hl_mmu_invalidate_cache(hdev, is_hard, flags);
}
int goya_send_heartbeat(struct hl_device *hdev)
{ struct goya_device *goya = hdev->asic_specific;
if (!(goya->hw_cap_initialized & HW_CAP_CPU_Q)) return0;
return hl_fw_send_heartbeat(hdev);
}
int goya_cpucp_info_get(struct hl_device *hdev)
{ struct goya_device *goya = hdev->asic_specific; struct asic_fixed_properties *prop = &hdev->asic_prop;
u64 dram_size; int rc;
if (!(goya->hw_cap_initialized & HW_CAP_CPU_Q)) return0;
/* * goya_set_asic_funcs - set Goya function pointers * * @*hdev: pointer to hl_device structure *
*/ void goya_set_asic_funcs(struct hl_device *hdev)
{
hdev->asic_funcs = &goya_funcs;
}
Messung V0.5 in Prozent
¤ 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.0.129Bemerkung:
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-06-07)
¤
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.