123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Copyright 2020 HabanaLabs, Ltd.
- * All Rights Reserved.
- */
- #include "habanalabs.h"
- /**
- * hl_get_pb_block - return the relevant block within the block array
- *
- * @hdev: pointer to hl_device structure
- * @mm_reg_addr: register address in the desired block
- * @pb_blocks: blocks array
- * @array_size: blocks array size
- *
- */
- static int hl_get_pb_block(struct hl_device *hdev, u32 mm_reg_addr,
- const u32 pb_blocks[], int array_size)
- {
- int i;
- u32 start_addr, end_addr;
- for (i = 0 ; i < array_size ; i++) {
- start_addr = pb_blocks[i];
- end_addr = start_addr + HL_BLOCK_SIZE;
- if ((mm_reg_addr >= start_addr) && (mm_reg_addr < end_addr))
- return i;
- }
- dev_err(hdev->dev, "No protection domain was found for 0x%x\n",
- mm_reg_addr);
- return -EDOM;
- }
- /**
- * hl_unset_pb_in_block - clear a specific protection bit in a block
- *
- * @hdev: pointer to hl_device structure
- * @reg_offset: register offset will be converted to bit offset in pb block
- * @sgs_entry: pb array
- *
- */
- static int hl_unset_pb_in_block(struct hl_device *hdev, u32 reg_offset,
- struct hl_block_glbl_sec *sgs_entry)
- {
- if ((reg_offset >= HL_BLOCK_SIZE) || (reg_offset & 0x3)) {
- dev_err(hdev->dev,
- "Register offset(%d) is out of range(%d) or invalid\n",
- reg_offset, HL_BLOCK_SIZE);
- return -EINVAL;
- }
- UNSET_GLBL_SEC_BIT(sgs_entry->sec_array,
- (reg_offset & (HL_BLOCK_SIZE - 1)) >> 2);
- return 0;
- }
- /**
- * hl_unsecure_register - locate the relevant block for this register and
- * remove corresponding protection bit
- *
- * @hdev: pointer to hl_device structure
- * @mm_reg_addr: register address to unsecure
- * @offset: additional offset to the register address
- * @pb_blocks: blocks array
- * @sgs_array: pb array
- * @array_size: blocks array size
- *
- */
- int hl_unsecure_register(struct hl_device *hdev, u32 mm_reg_addr, int offset,
- const u32 pb_blocks[], struct hl_block_glbl_sec sgs_array[],
- int array_size)
- {
- u32 reg_offset;
- int block_num;
- block_num = hl_get_pb_block(hdev, mm_reg_addr + offset, pb_blocks,
- array_size);
- if (block_num < 0)
- return block_num;
- reg_offset = (mm_reg_addr + offset) - pb_blocks[block_num];
- return hl_unset_pb_in_block(hdev, reg_offset, &sgs_array[block_num]);
- }
- /**
- * hl_unsecure_register_range - locate the relevant block for this register
- * range and remove corresponding protection bit
- *
- * @hdev: pointer to hl_device structure
- * @mm_reg_range: register address range to unsecure
- * @offset: additional offset to the register address
- * @pb_blocks: blocks array
- * @sgs_array: pb array
- * @array_size: blocks array size
- *
- */
- static int hl_unsecure_register_range(struct hl_device *hdev,
- struct range mm_reg_range, int offset, const u32 pb_blocks[],
- struct hl_block_glbl_sec sgs_array[],
- int array_size)
- {
- u32 reg_offset;
- int i, block_num, rc = 0;
- block_num = hl_get_pb_block(hdev,
- mm_reg_range.start + offset, pb_blocks,
- array_size);
- if (block_num < 0)
- return block_num;
- for (i = mm_reg_range.start ; i <= mm_reg_range.end ; i += 4) {
- reg_offset = (i + offset) - pb_blocks[block_num];
- rc |= hl_unset_pb_in_block(hdev, reg_offset,
- &sgs_array[block_num]);
- }
- return rc;
- }
- /**
- * hl_unsecure_registers - locate the relevant block for all registers and
- * remove corresponding protection bit
- *
- * @hdev: pointer to hl_device structure
- * @mm_reg_array: register address array to unsecure
- * @mm_array_size: register array size
- * @offset: additional offset to the register address
- * @pb_blocks: blocks array
- * @sgs_array: pb array
- * @blocks_array_size: blocks array size
- *
- */
- int hl_unsecure_registers(struct hl_device *hdev, const u32 mm_reg_array[],
- int mm_array_size, int offset, const u32 pb_blocks[],
- struct hl_block_glbl_sec sgs_array[], int blocks_array_size)
- {
- int i, rc = 0;
- for (i = 0 ; i < mm_array_size ; i++) {
- rc = hl_unsecure_register(hdev, mm_reg_array[i], offset,
- pb_blocks, sgs_array, blocks_array_size);
- if (rc)
- return rc;
- }
- return rc;
- }
- /**
- * hl_unsecure_registers_range - locate the relevant block for all register
- * ranges and remove corresponding protection bit
- *
- * @hdev: pointer to hl_device structure
- * @mm_reg_range_array: register address range array to unsecure
- * @mm_array_size: register array size
- * @offset: additional offset to the register address
- * @pb_blocks: blocks array
- * @sgs_array: pb array
- * @blocks_array_size: blocks array size
- *
- */
- static int hl_unsecure_registers_range(struct hl_device *hdev,
- const struct range mm_reg_range_array[], int mm_array_size,
- int offset, const u32 pb_blocks[],
- struct hl_block_glbl_sec sgs_array[], int blocks_array_size)
- {
- int i, rc = 0;
- for (i = 0 ; i < mm_array_size ; i++) {
- rc = hl_unsecure_register_range(hdev, mm_reg_range_array[i],
- offset, pb_blocks, sgs_array, blocks_array_size);
- if (rc)
- return rc;
- }
- return rc;
- }
- /**
- * hl_ack_pb_security_violations - Ack security violation
- *
- * @hdev: pointer to hl_device structure
- * @pb_blocks: blocks array
- * @block_offset: additional offset to the block
- * @array_size: blocks array size
- *
- */
- static void hl_ack_pb_security_violations(struct hl_device *hdev,
- const u32 pb_blocks[], u32 block_offset, int array_size)
- {
- int i;
- u32 cause, addr, block_base;
- for (i = 0 ; i < array_size ; i++) {
- block_base = pb_blocks[i] + block_offset;
- cause = RREG32(block_base + HL_BLOCK_GLBL_ERR_CAUSE);
- if (cause) {
- addr = RREG32(block_base + HL_BLOCK_GLBL_ERR_ADDR);
- hdev->asic_funcs->pb_print_security_errors(hdev,
- block_base, cause, addr);
- WREG32(block_base + HL_BLOCK_GLBL_ERR_CAUSE, cause);
- }
- }
- }
- /**
- * hl_config_glbl_sec - set pb in HW according to given pb array
- *
- * @hdev: pointer to hl_device structure
- * @pb_blocks: blocks array
- * @sgs_array: pb array
- * @block_offset: additional offset to the block
- * @array_size: blocks array size
- *
- */
- void hl_config_glbl_sec(struct hl_device *hdev, const u32 pb_blocks[],
- struct hl_block_glbl_sec sgs_array[], u32 block_offset,
- int array_size)
- {
- int i, j;
- u32 sgs_base;
- if (hdev->pldm)
- usleep_range(100, 1000);
- for (i = 0 ; i < array_size ; i++) {
- sgs_base = block_offset + pb_blocks[i] +
- HL_BLOCK_GLBL_SEC_OFFS;
- for (j = 0 ; j < HL_BLOCK_GLBL_SEC_LEN ; j++)
- WREG32(sgs_base + j * sizeof(u32),
- sgs_array[i].sec_array[j]);
- }
- }
- /**
- * hl_secure_block - locally memsets a block to 0
- *
- * @hdev: pointer to hl_device structure
- * @sgs_array: pb array to clear
- * @array_size: blocks array size
- *
- */
- void hl_secure_block(struct hl_device *hdev,
- struct hl_block_glbl_sec sgs_array[], int array_size)
- {
- int i;
- for (i = 0 ; i < array_size ; i++)
- memset((char *)(sgs_array[i].sec_array), 0,
- HL_BLOCK_GLBL_SEC_SIZE);
- }
- /**
- * hl_init_pb_with_mask - set selected pb instances with mask in HW according
- * to given configuration
- *
- * @hdev: pointer to hl_device structure
- * @num_dcores: number of decores to apply configuration to
- * set to HL_PB_SHARED if need to apply only once
- * @dcore_offset: offset between dcores
- * @num_instances: number of instances to apply configuration to
- * @instance_offset: offset between instances
- * @pb_blocks: blocks array
- * @blocks_array_size: blocks array size
- * @regs_array: register array
- * @regs_array_size: register array size
- * @mask: enabled instances mask: 1- enabled, 0- disabled
- */
- int hl_init_pb_with_mask(struct hl_device *hdev, u32 num_dcores,
- u32 dcore_offset, u32 num_instances, u32 instance_offset,
- const u32 pb_blocks[], u32 blocks_array_size,
- const u32 *regs_array, u32 regs_array_size, u64 mask)
- {
- int i, j;
- struct hl_block_glbl_sec *glbl_sec;
- glbl_sec = kcalloc(blocks_array_size,
- sizeof(struct hl_block_glbl_sec),
- GFP_KERNEL);
- if (!glbl_sec)
- return -ENOMEM;
- hl_secure_block(hdev, glbl_sec, blocks_array_size);
- hl_unsecure_registers(hdev, regs_array, regs_array_size, 0, pb_blocks,
- glbl_sec, blocks_array_size);
- /* Fill all blocks with the same configuration */
- for (i = 0 ; i < num_dcores ; i++) {
- for (j = 0 ; j < num_instances ; j++) {
- int seq = i * num_instances + j;
- if (!(mask & BIT_ULL(seq)))
- continue;
- hl_config_glbl_sec(hdev, pb_blocks, glbl_sec,
- i * dcore_offset + j * instance_offset,
- blocks_array_size);
- }
- }
- kfree(glbl_sec);
- return 0;
- }
- /**
- * hl_init_pb - set pb in HW according to given configuration
- *
- * @hdev: pointer to hl_device structure
- * @num_dcores: number of decores to apply configuration to
- * set to HL_PB_SHARED if need to apply only once
- * @dcore_offset: offset between dcores
- * @num_instances: number of instances to apply configuration to
- * @instance_offset: offset between instances
- * @pb_blocks: blocks array
- * @blocks_array_size: blocks array size
- * @regs_array: register array
- * @regs_array_size: register array size
- *
- */
- int hl_init_pb(struct hl_device *hdev, u32 num_dcores, u32 dcore_offset,
- u32 num_instances, u32 instance_offset,
- const u32 pb_blocks[], u32 blocks_array_size,
- const u32 *regs_array, u32 regs_array_size)
- {
- return hl_init_pb_with_mask(hdev, num_dcores, dcore_offset,
- num_instances, instance_offset, pb_blocks,
- blocks_array_size, regs_array, regs_array_size,
- ULLONG_MAX);
- }
- /**
- * hl_init_pb_ranges_with_mask - set pb instances using mask in HW according to
- * given configuration unsecurring registers
- * ranges instead of specific registers
- *
- * @hdev: pointer to hl_device structure
- * @num_dcores: number of decores to apply configuration to
- * set to HL_PB_SHARED if need to apply only once
- * @dcore_offset: offset between dcores
- * @num_instances: number of instances to apply configuration to
- * @instance_offset: offset between instances
- * @pb_blocks: blocks array
- * @blocks_array_size: blocks array size
- * @regs_range_array: register range array
- * @regs_range_array_size: register range array size
- * @mask: enabled instances mask: 1- enabled, 0- disabled
- */
- int hl_init_pb_ranges_with_mask(struct hl_device *hdev, u32 num_dcores,
- u32 dcore_offset, u32 num_instances, u32 instance_offset,
- const u32 pb_blocks[], u32 blocks_array_size,
- const struct range *regs_range_array, u32 regs_range_array_size,
- u64 mask)
- {
- int i, j, rc = 0;
- struct hl_block_glbl_sec *glbl_sec;
- glbl_sec = kcalloc(blocks_array_size,
- sizeof(struct hl_block_glbl_sec),
- GFP_KERNEL);
- if (!glbl_sec)
- return -ENOMEM;
- hl_secure_block(hdev, glbl_sec, blocks_array_size);
- rc = hl_unsecure_registers_range(hdev, regs_range_array,
- regs_range_array_size, 0, pb_blocks, glbl_sec,
- blocks_array_size);
- if (rc)
- goto free_glbl_sec;
- /* Fill all blocks with the same configuration */
- for (i = 0 ; i < num_dcores ; i++) {
- for (j = 0 ; j < num_instances ; j++) {
- int seq = i * num_instances + j;
- if (!(mask & BIT_ULL(seq)))
- continue;
- hl_config_glbl_sec(hdev, pb_blocks, glbl_sec,
- i * dcore_offset + j * instance_offset,
- blocks_array_size);
- }
- }
- free_glbl_sec:
- kfree(glbl_sec);
- return rc;
- }
- /**
- * hl_init_pb_ranges - set pb in HW according to given configuration unsecurring
- * registers ranges instead of specific registers
- *
- * @hdev: pointer to hl_device structure
- * @num_dcores: number of decores to apply configuration to
- * set to HL_PB_SHARED if need to apply only once
- * @dcore_offset: offset between dcores
- * @num_instances: number of instances to apply configuration to
- * @instance_offset: offset between instances
- * @pb_blocks: blocks array
- * @blocks_array_size: blocks array size
- * @regs_range_array: register range array
- * @regs_range_array_size: register range array size
- *
- */
- int hl_init_pb_ranges(struct hl_device *hdev, u32 num_dcores,
- u32 dcore_offset, u32 num_instances, u32 instance_offset,
- const u32 pb_blocks[], u32 blocks_array_size,
- const struct range *regs_range_array, u32 regs_range_array_size)
- {
- return hl_init_pb_ranges_with_mask(hdev, num_dcores, dcore_offset,
- num_instances, instance_offset, pb_blocks,
- blocks_array_size, regs_range_array,
- regs_range_array_size, ULLONG_MAX);
- }
- /**
- * hl_init_pb_single_dcore - set pb for a single docre in HW
- * according to given configuration
- *
- * @hdev: pointer to hl_device structure
- * @dcore_offset: offset from the dcore0
- * @num_instances: number of instances to apply configuration to
- * @instance_offset: offset between instances
- * @pb_blocks: blocks array
- * @blocks_array_size: blocks array size
- * @regs_array: register array
- * @regs_array_size: register array size
- *
- */
- int hl_init_pb_single_dcore(struct hl_device *hdev, u32 dcore_offset,
- u32 num_instances, u32 instance_offset,
- const u32 pb_blocks[], u32 blocks_array_size,
- const u32 *regs_array, u32 regs_array_size)
- {
- int i, rc = 0;
- struct hl_block_glbl_sec *glbl_sec;
- glbl_sec = kcalloc(blocks_array_size,
- sizeof(struct hl_block_glbl_sec),
- GFP_KERNEL);
- if (!glbl_sec)
- return -ENOMEM;
- hl_secure_block(hdev, glbl_sec, blocks_array_size);
- rc = hl_unsecure_registers(hdev, regs_array, regs_array_size, 0,
- pb_blocks, glbl_sec, blocks_array_size);
- if (rc)
- goto free_glbl_sec;
- /* Fill all blocks with the same configuration */
- for (i = 0 ; i < num_instances ; i++)
- hl_config_glbl_sec(hdev, pb_blocks, glbl_sec,
- dcore_offset + i * instance_offset,
- blocks_array_size);
- free_glbl_sec:
- kfree(glbl_sec);
- return rc;
- }
- /**
- * hl_init_pb_ranges_single_dcore - set pb for a single docre in HW according
- * to given configuration unsecurring
- * registers ranges instead of specific
- * registers
- *
- * @hdev: pointer to hl_device structure
- * @dcore_offset: offset from the dcore0
- * @num_instances: number of instances to apply configuration to
- * @instance_offset: offset between instances
- * @pb_blocks: blocks array
- * @blocks_array_size: blocks array size
- * @regs_range_array: register range array
- * @regs_range_array_size: register range array size
- *
- */
- int hl_init_pb_ranges_single_dcore(struct hl_device *hdev, u32 dcore_offset,
- u32 num_instances, u32 instance_offset,
- const u32 pb_blocks[], u32 blocks_array_size,
- const struct range *regs_range_array, u32 regs_range_array_size)
- {
- int i;
- struct hl_block_glbl_sec *glbl_sec;
- glbl_sec = kcalloc(blocks_array_size,
- sizeof(struct hl_block_glbl_sec),
- GFP_KERNEL);
- if (!glbl_sec)
- return -ENOMEM;
- hl_secure_block(hdev, glbl_sec, blocks_array_size);
- hl_unsecure_registers_range(hdev, regs_range_array,
- regs_range_array_size, 0, pb_blocks, glbl_sec,
- blocks_array_size);
- /* Fill all blocks with the same configuration */
- for (i = 0 ; i < num_instances ; i++)
- hl_config_glbl_sec(hdev, pb_blocks, glbl_sec,
- dcore_offset + i * instance_offset,
- blocks_array_size);
- kfree(glbl_sec);
- return 0;
- }
- /**
- * hl_ack_pb_with_mask - ack pb with mask in HW according to given configuration
- *
- * @hdev: pointer to hl_device structure
- * @num_dcores: number of decores to apply configuration to
- * set to HL_PB_SHARED if need to apply only once
- * @dcore_offset: offset between dcores
- * @num_instances: number of instances to apply configuration to
- * @instance_offset: offset between instances
- * @pb_blocks: blocks array
- * @blocks_array_size: blocks array size
- * @mask: enabled instances mask: 1- enabled, 0- disabled
- *
- */
- void hl_ack_pb_with_mask(struct hl_device *hdev, u32 num_dcores,
- u32 dcore_offset, u32 num_instances, u32 instance_offset,
- const u32 pb_blocks[], u32 blocks_array_size, u64 mask)
- {
- int i, j;
- /* ack all blocks */
- for (i = 0 ; i < num_dcores ; i++) {
- for (j = 0 ; j < num_instances ; j++) {
- int seq = i * num_instances + j;
- if (!(mask & BIT_ULL(seq)))
- continue;
- hl_ack_pb_security_violations(hdev, pb_blocks,
- i * dcore_offset + j * instance_offset,
- blocks_array_size);
- }
- }
- }
- /**
- * hl_ack_pb - ack pb in HW according to given configuration
- *
- * @hdev: pointer to hl_device structure
- * @num_dcores: number of decores to apply configuration to
- * set to HL_PB_SHARED if need to apply only once
- * @dcore_offset: offset between dcores
- * @num_instances: number of instances to apply configuration to
- * @instance_offset: offset between instances
- * @pb_blocks: blocks array
- * @blocks_array_size: blocks array size
- *
- */
- void hl_ack_pb(struct hl_device *hdev, u32 num_dcores, u32 dcore_offset,
- u32 num_instances, u32 instance_offset,
- const u32 pb_blocks[], u32 blocks_array_size)
- {
- hl_ack_pb_with_mask(hdev, num_dcores, dcore_offset, num_instances,
- instance_offset, pb_blocks, blocks_array_size,
- ULLONG_MAX);
- }
- /**
- * hl_ack_pb_single_dcore - ack pb for single docre in HW
- * according to given configuration
- *
- * @hdev: pointer to hl_device structure
- * @dcore_offset: offset from dcore0
- * @num_instances: number of instances to apply configuration to
- * @instance_offset: offset between instances
- * @pb_blocks: blocks array
- * @blocks_array_size: blocks array size
- *
- */
- void hl_ack_pb_single_dcore(struct hl_device *hdev, u32 dcore_offset,
- u32 num_instances, u32 instance_offset,
- const u32 pb_blocks[], u32 blocks_array_size)
- {
- int i;
- /* ack all blocks */
- for (i = 0 ; i < num_instances ; i++)
- hl_ack_pb_security_violations(hdev, pb_blocks,
- dcore_offset + i * instance_offset,
- blocks_array_size);
- }
|