162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright 2022 Advanced Micro Devices, Inc. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 562306a36Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 662306a36Sopenharmony_ci * to deal in the Software without restriction, including without limitation 762306a36Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 862306a36Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 962306a36Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 1262306a36Sopenharmony_ci * all copies or substantial portions of the Software. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1562306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1662306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1762306a36Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 1862306a36Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 1962306a36Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 2062306a36Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE. 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci */ 2362306a36Sopenharmony_ci#include "amdgpu.h" 2462306a36Sopenharmony_ci#include "soc15.h" 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include "soc15_common.h" 2762306a36Sopenharmony_ci#include "amdgpu_xcp.h" 2862306a36Sopenharmony_ci#include "gfx_v9_4_3.h" 2962306a36Sopenharmony_ci#include "gfxhub_v1_2.h" 3062306a36Sopenharmony_ci#include "sdma_v4_4_2.h" 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#define XCP_INST_MASK(num_inst, xcp_id) \ 3362306a36Sopenharmony_ci (num_inst ? GENMASK(num_inst - 1, 0) << (xcp_id * num_inst) : 0) 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#define AMDGPU_XCP_OPS_KFD (1 << 0) 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_civoid aqua_vanjaram_doorbell_index_init(struct amdgpu_device *adev) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci int i; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci adev->doorbell_index.kiq = AMDGPU_DOORBELL_LAYOUT1_KIQ_START; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci adev->doorbell_index.mec_ring0 = AMDGPU_DOORBELL_LAYOUT1_MEC_RING_START; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci adev->doorbell_index.userqueue_start = AMDGPU_DOORBELL_LAYOUT1_USERQUEUE_START; 4662306a36Sopenharmony_ci adev->doorbell_index.userqueue_end = AMDGPU_DOORBELL_LAYOUT1_USERQUEUE_END; 4762306a36Sopenharmony_ci adev->doorbell_index.xcc_doorbell_range = AMDGPU_DOORBELL_LAYOUT1_XCC_RANGE; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci adev->doorbell_index.sdma_doorbell_range = 20; 5062306a36Sopenharmony_ci for (i = 0; i < adev->sdma.num_instances; i++) 5162306a36Sopenharmony_ci adev->doorbell_index.sdma_engine[i] = 5262306a36Sopenharmony_ci AMDGPU_DOORBELL_LAYOUT1_sDMA_ENGINE_START + 5362306a36Sopenharmony_ci i * (adev->doorbell_index.sdma_doorbell_range >> 1); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci adev->doorbell_index.ih = AMDGPU_DOORBELL_LAYOUT1_IH; 5662306a36Sopenharmony_ci adev->doorbell_index.vcn.vcn_ring0_1 = AMDGPU_DOORBELL_LAYOUT1_VCN_START; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci adev->doorbell_index.first_non_cp = AMDGPU_DOORBELL_LAYOUT1_FIRST_NON_CP; 5962306a36Sopenharmony_ci adev->doorbell_index.last_non_cp = AMDGPU_DOORBELL_LAYOUT1_LAST_NON_CP; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci adev->doorbell_index.max_assignment = AMDGPU_DOORBELL_LAYOUT1_MAX_ASSIGNMENT << 1; 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic void aqua_vanjaram_set_xcp_id(struct amdgpu_device *adev, 6562306a36Sopenharmony_ci uint32_t inst_idx, struct amdgpu_ring *ring) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci int xcp_id; 6862306a36Sopenharmony_ci enum AMDGPU_XCP_IP_BLOCK ip_blk; 6962306a36Sopenharmony_ci uint32_t inst_mask; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci ring->xcp_id = AMDGPU_XCP_NO_PARTITION; 7262306a36Sopenharmony_ci if (adev->xcp_mgr->mode == AMDGPU_XCP_MODE_NONE) 7362306a36Sopenharmony_ci return; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci inst_mask = 1 << inst_idx; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci switch (ring->funcs->type) { 7862306a36Sopenharmony_ci case AMDGPU_HW_IP_GFX: 7962306a36Sopenharmony_ci case AMDGPU_RING_TYPE_COMPUTE: 8062306a36Sopenharmony_ci case AMDGPU_RING_TYPE_KIQ: 8162306a36Sopenharmony_ci ip_blk = AMDGPU_XCP_GFX; 8262306a36Sopenharmony_ci break; 8362306a36Sopenharmony_ci case AMDGPU_RING_TYPE_SDMA: 8462306a36Sopenharmony_ci ip_blk = AMDGPU_XCP_SDMA; 8562306a36Sopenharmony_ci break; 8662306a36Sopenharmony_ci case AMDGPU_RING_TYPE_VCN_ENC: 8762306a36Sopenharmony_ci case AMDGPU_RING_TYPE_VCN_JPEG: 8862306a36Sopenharmony_ci ip_blk = AMDGPU_XCP_VCN; 8962306a36Sopenharmony_ci if (adev->xcp_mgr->mode == AMDGPU_CPX_PARTITION_MODE) 9062306a36Sopenharmony_ci inst_mask = 1 << (inst_idx * 2); 9162306a36Sopenharmony_ci break; 9262306a36Sopenharmony_ci default: 9362306a36Sopenharmony_ci DRM_ERROR("Not support ring type %d!", ring->funcs->type); 9462306a36Sopenharmony_ci return; 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci for (xcp_id = 0; xcp_id < adev->xcp_mgr->num_xcps; xcp_id++) { 9862306a36Sopenharmony_ci if (adev->xcp_mgr->xcp[xcp_id].ip[ip_blk].inst_mask & inst_mask) { 9962306a36Sopenharmony_ci ring->xcp_id = xcp_id; 10062306a36Sopenharmony_ci break; 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci } 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic void aqua_vanjaram_xcp_gpu_sched_update( 10662306a36Sopenharmony_ci struct amdgpu_device *adev, 10762306a36Sopenharmony_ci struct amdgpu_ring *ring, 10862306a36Sopenharmony_ci unsigned int sel_xcp_id) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci unsigned int *num_gpu_sched; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci num_gpu_sched = &adev->xcp_mgr->xcp[sel_xcp_id] 11362306a36Sopenharmony_ci .gpu_sched[ring->funcs->type][ring->hw_prio].num_scheds; 11462306a36Sopenharmony_ci adev->xcp_mgr->xcp[sel_xcp_id].gpu_sched[ring->funcs->type][ring->hw_prio] 11562306a36Sopenharmony_ci .sched[(*num_gpu_sched)++] = &ring->sched; 11662306a36Sopenharmony_ci DRM_DEBUG("%s :[%d] gpu_sched[%d][%d] = %d", ring->name, 11762306a36Sopenharmony_ci sel_xcp_id, ring->funcs->type, 11862306a36Sopenharmony_ci ring->hw_prio, *num_gpu_sched); 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic int aqua_vanjaram_xcp_sched_list_update( 12262306a36Sopenharmony_ci struct amdgpu_device *adev) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci struct amdgpu_ring *ring; 12562306a36Sopenharmony_ci int i; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci for (i = 0; i < MAX_XCP; i++) { 12862306a36Sopenharmony_ci atomic_set(&adev->xcp_mgr->xcp[i].ref_cnt, 0); 12962306a36Sopenharmony_ci memset(adev->xcp_mgr->xcp[i].gpu_sched, 0, sizeof(adev->xcp_mgr->xcp->gpu_sched)); 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci if (adev->xcp_mgr->mode == AMDGPU_XCP_MODE_NONE) 13362306a36Sopenharmony_ci return 0; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci for (i = 0; i < AMDGPU_MAX_RINGS; i++) { 13662306a36Sopenharmony_ci ring = adev->rings[i]; 13762306a36Sopenharmony_ci if (!ring || !ring->sched.ready || ring->no_scheduler) 13862306a36Sopenharmony_ci continue; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci aqua_vanjaram_xcp_gpu_sched_update(adev, ring, ring->xcp_id); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci /* VCN is shared by two partitions under CPX MODE */ 14362306a36Sopenharmony_ci if ((ring->funcs->type == AMDGPU_RING_TYPE_VCN_ENC || 14462306a36Sopenharmony_ci ring->funcs->type == AMDGPU_RING_TYPE_VCN_JPEG) && 14562306a36Sopenharmony_ci adev->xcp_mgr->mode == AMDGPU_CPX_PARTITION_MODE) 14662306a36Sopenharmony_ci aqua_vanjaram_xcp_gpu_sched_update(adev, ring, ring->xcp_id + 1); 14762306a36Sopenharmony_ci } 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci return 0; 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistatic int aqua_vanjaram_update_partition_sched_list(struct amdgpu_device *adev) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci int i; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci for (i = 0; i < adev->num_rings; i++) { 15762306a36Sopenharmony_ci struct amdgpu_ring *ring = adev->rings[i]; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci if (ring->funcs->type == AMDGPU_RING_TYPE_COMPUTE || 16062306a36Sopenharmony_ci ring->funcs->type == AMDGPU_RING_TYPE_KIQ) 16162306a36Sopenharmony_ci aqua_vanjaram_set_xcp_id(adev, ring->xcc_id, ring); 16262306a36Sopenharmony_ci else 16362306a36Sopenharmony_ci aqua_vanjaram_set_xcp_id(adev, ring->me, ring); 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci return aqua_vanjaram_xcp_sched_list_update(adev); 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic int aqua_vanjaram_select_scheds( 17062306a36Sopenharmony_ci struct amdgpu_device *adev, 17162306a36Sopenharmony_ci u32 hw_ip, 17262306a36Sopenharmony_ci u32 hw_prio, 17362306a36Sopenharmony_ci struct amdgpu_fpriv *fpriv, 17462306a36Sopenharmony_ci unsigned int *num_scheds, 17562306a36Sopenharmony_ci struct drm_gpu_scheduler ***scheds) 17662306a36Sopenharmony_ci{ 17762306a36Sopenharmony_ci u32 sel_xcp_id; 17862306a36Sopenharmony_ci int i; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci if (fpriv->xcp_id == AMDGPU_XCP_NO_PARTITION) { 18162306a36Sopenharmony_ci u32 least_ref_cnt = ~0; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci fpriv->xcp_id = 0; 18462306a36Sopenharmony_ci for (i = 0; i < adev->xcp_mgr->num_xcps; i++) { 18562306a36Sopenharmony_ci u32 total_ref_cnt; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci total_ref_cnt = atomic_read(&adev->xcp_mgr->xcp[i].ref_cnt); 18862306a36Sopenharmony_ci if (total_ref_cnt < least_ref_cnt) { 18962306a36Sopenharmony_ci fpriv->xcp_id = i; 19062306a36Sopenharmony_ci least_ref_cnt = total_ref_cnt; 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci } 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci sel_xcp_id = fpriv->xcp_id; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci if (adev->xcp_mgr->xcp[sel_xcp_id].gpu_sched[hw_ip][hw_prio].num_scheds) { 19762306a36Sopenharmony_ci *num_scheds = adev->xcp_mgr->xcp[fpriv->xcp_id].gpu_sched[hw_ip][hw_prio].num_scheds; 19862306a36Sopenharmony_ci *scheds = adev->xcp_mgr->xcp[fpriv->xcp_id].gpu_sched[hw_ip][hw_prio].sched; 19962306a36Sopenharmony_ci atomic_inc(&adev->xcp_mgr->xcp[sel_xcp_id].ref_cnt); 20062306a36Sopenharmony_ci DRM_DEBUG("Selected partition #%d", sel_xcp_id); 20162306a36Sopenharmony_ci } else { 20262306a36Sopenharmony_ci DRM_ERROR("Failed to schedule partition #%d.", sel_xcp_id); 20362306a36Sopenharmony_ci return -ENOENT; 20462306a36Sopenharmony_ci } 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci return 0; 20762306a36Sopenharmony_ci} 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_cistatic int8_t aqua_vanjaram_logical_to_dev_inst(struct amdgpu_device *adev, 21062306a36Sopenharmony_ci enum amd_hw_ip_block_type block, 21162306a36Sopenharmony_ci int8_t inst) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci int8_t dev_inst; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci switch (block) { 21662306a36Sopenharmony_ci case GC_HWIP: 21762306a36Sopenharmony_ci case SDMA0_HWIP: 21862306a36Sopenharmony_ci /* Both JPEG and VCN as JPEG is only alias of VCN */ 21962306a36Sopenharmony_ci case VCN_HWIP: 22062306a36Sopenharmony_ci dev_inst = adev->ip_map.dev_inst[block][inst]; 22162306a36Sopenharmony_ci break; 22262306a36Sopenharmony_ci default: 22362306a36Sopenharmony_ci /* For rest of the IPs, no look up required. 22462306a36Sopenharmony_ci * Assume 'logical instance == physical instance' for all configs. */ 22562306a36Sopenharmony_ci dev_inst = inst; 22662306a36Sopenharmony_ci break; 22762306a36Sopenharmony_ci } 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci return dev_inst; 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_cistatic uint32_t aqua_vanjaram_logical_to_dev_mask(struct amdgpu_device *adev, 23362306a36Sopenharmony_ci enum amd_hw_ip_block_type block, 23462306a36Sopenharmony_ci uint32_t mask) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci uint32_t dev_mask = 0; 23762306a36Sopenharmony_ci int8_t log_inst, dev_inst; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci while (mask) { 24062306a36Sopenharmony_ci log_inst = ffs(mask) - 1; 24162306a36Sopenharmony_ci dev_inst = aqua_vanjaram_logical_to_dev_inst(adev, block, log_inst); 24262306a36Sopenharmony_ci dev_mask |= (1 << dev_inst); 24362306a36Sopenharmony_ci mask &= ~(1 << log_inst); 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci return dev_mask; 24762306a36Sopenharmony_ci} 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_cistatic void aqua_vanjaram_populate_ip_map(struct amdgpu_device *adev, 25062306a36Sopenharmony_ci enum amd_hw_ip_block_type ip_block, 25162306a36Sopenharmony_ci uint32_t inst_mask) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci int l = 0, i; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci while (inst_mask) { 25662306a36Sopenharmony_ci i = ffs(inst_mask) - 1; 25762306a36Sopenharmony_ci adev->ip_map.dev_inst[ip_block][l++] = i; 25862306a36Sopenharmony_ci inst_mask &= ~(1 << i); 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci for (; l < HWIP_MAX_INSTANCE; l++) 26162306a36Sopenharmony_ci adev->ip_map.dev_inst[ip_block][l] = -1; 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_civoid aqua_vanjaram_ip_map_init(struct amdgpu_device *adev) 26562306a36Sopenharmony_ci{ 26662306a36Sopenharmony_ci u32 ip_map[][2] = { 26762306a36Sopenharmony_ci { GC_HWIP, adev->gfx.xcc_mask }, 26862306a36Sopenharmony_ci { SDMA0_HWIP, adev->sdma.sdma_mask }, 26962306a36Sopenharmony_ci { VCN_HWIP, adev->vcn.inst_mask }, 27062306a36Sopenharmony_ci }; 27162306a36Sopenharmony_ci int i; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ip_map); ++i) 27462306a36Sopenharmony_ci aqua_vanjaram_populate_ip_map(adev, ip_map[i][0], ip_map[i][1]); 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci adev->ip_map.logical_to_dev_inst = aqua_vanjaram_logical_to_dev_inst; 27762306a36Sopenharmony_ci adev->ip_map.logical_to_dev_mask = aqua_vanjaram_logical_to_dev_mask; 27862306a36Sopenharmony_ci} 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci/* Fixed pattern for smn addressing on different AIDs: 28162306a36Sopenharmony_ci * bit[34]: indicate cross AID access 28262306a36Sopenharmony_ci * bit[33:32]: indicate target AID id 28362306a36Sopenharmony_ci * AID id range is 0 ~ 3 as maximum AID number is 4. 28462306a36Sopenharmony_ci */ 28562306a36Sopenharmony_ciu64 aqua_vanjaram_encode_ext_smn_addressing(int ext_id) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci u64 ext_offset; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci /* local routing and bit[34:32] will be zeros */ 29062306a36Sopenharmony_ci if (ext_id == 0) 29162306a36Sopenharmony_ci return 0; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci /* Initiated from host, accessing to all non-zero aids are cross traffic */ 29462306a36Sopenharmony_ci ext_offset = ((u64)(ext_id & 0x3) << 32) | (1ULL << 34); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci return ext_offset; 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cistatic int aqua_vanjaram_query_partition_mode(struct amdgpu_xcp_mgr *xcp_mgr) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci enum amdgpu_gfx_partition mode = AMDGPU_UNKNOWN_COMPUTE_PARTITION_MODE; 30262306a36Sopenharmony_ci struct amdgpu_device *adev = xcp_mgr->adev; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci if (adev->nbio.funcs->get_compute_partition_mode) 30562306a36Sopenharmony_ci mode = adev->nbio.funcs->get_compute_partition_mode(adev); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci return mode; 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_cistatic int __aqua_vanjaram_get_xcc_per_xcp(struct amdgpu_xcp_mgr *xcp_mgr, int mode) 31162306a36Sopenharmony_ci{ 31262306a36Sopenharmony_ci int num_xcc, num_xcc_per_xcp = 0; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci num_xcc = NUM_XCC(xcp_mgr->adev->gfx.xcc_mask); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci switch (mode) { 31762306a36Sopenharmony_ci case AMDGPU_SPX_PARTITION_MODE: 31862306a36Sopenharmony_ci num_xcc_per_xcp = num_xcc; 31962306a36Sopenharmony_ci break; 32062306a36Sopenharmony_ci case AMDGPU_DPX_PARTITION_MODE: 32162306a36Sopenharmony_ci num_xcc_per_xcp = num_xcc / 2; 32262306a36Sopenharmony_ci break; 32362306a36Sopenharmony_ci case AMDGPU_TPX_PARTITION_MODE: 32462306a36Sopenharmony_ci num_xcc_per_xcp = num_xcc / 3; 32562306a36Sopenharmony_ci break; 32662306a36Sopenharmony_ci case AMDGPU_QPX_PARTITION_MODE: 32762306a36Sopenharmony_ci num_xcc_per_xcp = num_xcc / 4; 32862306a36Sopenharmony_ci break; 32962306a36Sopenharmony_ci case AMDGPU_CPX_PARTITION_MODE: 33062306a36Sopenharmony_ci num_xcc_per_xcp = 1; 33162306a36Sopenharmony_ci break; 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci return num_xcc_per_xcp; 33562306a36Sopenharmony_ci} 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_cistatic int __aqua_vanjaram_get_xcp_ip_info(struct amdgpu_xcp_mgr *xcp_mgr, int xcp_id, 33862306a36Sopenharmony_ci enum AMDGPU_XCP_IP_BLOCK ip_id, 33962306a36Sopenharmony_ci struct amdgpu_xcp_ip *ip) 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci struct amdgpu_device *adev = xcp_mgr->adev; 34262306a36Sopenharmony_ci int num_xcc_xcp, num_sdma_xcp, num_vcn_xcp; 34362306a36Sopenharmony_ci int num_sdma, num_vcn; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci num_sdma = adev->sdma.num_instances; 34662306a36Sopenharmony_ci num_vcn = adev->vcn.num_vcn_inst; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci switch (xcp_mgr->mode) { 34962306a36Sopenharmony_ci case AMDGPU_SPX_PARTITION_MODE: 35062306a36Sopenharmony_ci num_sdma_xcp = num_sdma; 35162306a36Sopenharmony_ci num_vcn_xcp = num_vcn; 35262306a36Sopenharmony_ci break; 35362306a36Sopenharmony_ci case AMDGPU_DPX_PARTITION_MODE: 35462306a36Sopenharmony_ci num_sdma_xcp = num_sdma / 2; 35562306a36Sopenharmony_ci num_vcn_xcp = num_vcn / 2; 35662306a36Sopenharmony_ci break; 35762306a36Sopenharmony_ci case AMDGPU_TPX_PARTITION_MODE: 35862306a36Sopenharmony_ci num_sdma_xcp = num_sdma / 3; 35962306a36Sopenharmony_ci num_vcn_xcp = num_vcn / 3; 36062306a36Sopenharmony_ci break; 36162306a36Sopenharmony_ci case AMDGPU_QPX_PARTITION_MODE: 36262306a36Sopenharmony_ci num_sdma_xcp = num_sdma / 4; 36362306a36Sopenharmony_ci num_vcn_xcp = num_vcn / 4; 36462306a36Sopenharmony_ci break; 36562306a36Sopenharmony_ci case AMDGPU_CPX_PARTITION_MODE: 36662306a36Sopenharmony_ci num_sdma_xcp = 2; 36762306a36Sopenharmony_ci num_vcn_xcp = num_vcn ? 1 : 0; 36862306a36Sopenharmony_ci break; 36962306a36Sopenharmony_ci default: 37062306a36Sopenharmony_ci return -EINVAL; 37162306a36Sopenharmony_ci } 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci num_xcc_xcp = adev->gfx.num_xcc_per_xcp; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci switch (ip_id) { 37662306a36Sopenharmony_ci case AMDGPU_XCP_GFXHUB: 37762306a36Sopenharmony_ci ip->inst_mask = XCP_INST_MASK(num_xcc_xcp, xcp_id); 37862306a36Sopenharmony_ci ip->ip_funcs = &gfxhub_v1_2_xcp_funcs; 37962306a36Sopenharmony_ci break; 38062306a36Sopenharmony_ci case AMDGPU_XCP_GFX: 38162306a36Sopenharmony_ci ip->inst_mask = XCP_INST_MASK(num_xcc_xcp, xcp_id); 38262306a36Sopenharmony_ci ip->ip_funcs = &gfx_v9_4_3_xcp_funcs; 38362306a36Sopenharmony_ci break; 38462306a36Sopenharmony_ci case AMDGPU_XCP_SDMA: 38562306a36Sopenharmony_ci ip->inst_mask = XCP_INST_MASK(num_sdma_xcp, xcp_id); 38662306a36Sopenharmony_ci ip->ip_funcs = &sdma_v4_4_2_xcp_funcs; 38762306a36Sopenharmony_ci break; 38862306a36Sopenharmony_ci case AMDGPU_XCP_VCN: 38962306a36Sopenharmony_ci ip->inst_mask = XCP_INST_MASK(num_vcn_xcp, xcp_id); 39062306a36Sopenharmony_ci /* TODO : Assign IP funcs */ 39162306a36Sopenharmony_ci break; 39262306a36Sopenharmony_ci default: 39362306a36Sopenharmony_ci return -EINVAL; 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci ip->ip_id = ip_id; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci return 0; 39962306a36Sopenharmony_ci} 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_cistatic enum amdgpu_gfx_partition 40262306a36Sopenharmony_ci__aqua_vanjaram_get_auto_mode(struct amdgpu_xcp_mgr *xcp_mgr) 40362306a36Sopenharmony_ci{ 40462306a36Sopenharmony_ci struct amdgpu_device *adev = xcp_mgr->adev; 40562306a36Sopenharmony_ci int num_xcc; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci num_xcc = NUM_XCC(xcp_mgr->adev->gfx.xcc_mask); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci if (adev->gmc.num_mem_partitions == 1) 41062306a36Sopenharmony_ci return AMDGPU_SPX_PARTITION_MODE; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci if (adev->gmc.num_mem_partitions == num_xcc) 41362306a36Sopenharmony_ci return AMDGPU_CPX_PARTITION_MODE; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci if (adev->gmc.num_mem_partitions == num_xcc / 2) 41662306a36Sopenharmony_ci return (adev->flags & AMD_IS_APU) ? AMDGPU_TPX_PARTITION_MODE : 41762306a36Sopenharmony_ci AMDGPU_QPX_PARTITION_MODE; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci if (adev->gmc.num_mem_partitions == 2 && !(adev->flags & AMD_IS_APU)) 42062306a36Sopenharmony_ci return AMDGPU_DPX_PARTITION_MODE; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci return AMDGPU_UNKNOWN_COMPUTE_PARTITION_MODE; 42362306a36Sopenharmony_ci} 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_cistatic bool __aqua_vanjaram_is_valid_mode(struct amdgpu_xcp_mgr *xcp_mgr, 42662306a36Sopenharmony_ci enum amdgpu_gfx_partition mode) 42762306a36Sopenharmony_ci{ 42862306a36Sopenharmony_ci struct amdgpu_device *adev = xcp_mgr->adev; 42962306a36Sopenharmony_ci int num_xcc, num_xccs_per_xcp; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci num_xcc = NUM_XCC(adev->gfx.xcc_mask); 43262306a36Sopenharmony_ci switch (mode) { 43362306a36Sopenharmony_ci case AMDGPU_SPX_PARTITION_MODE: 43462306a36Sopenharmony_ci return adev->gmc.num_mem_partitions == 1 && num_xcc > 0; 43562306a36Sopenharmony_ci case AMDGPU_DPX_PARTITION_MODE: 43662306a36Sopenharmony_ci return adev->gmc.num_mem_partitions != 8 && (num_xcc % 4) == 0; 43762306a36Sopenharmony_ci case AMDGPU_TPX_PARTITION_MODE: 43862306a36Sopenharmony_ci return (adev->gmc.num_mem_partitions == 1 || 43962306a36Sopenharmony_ci adev->gmc.num_mem_partitions == 3) && 44062306a36Sopenharmony_ci ((num_xcc % 3) == 0); 44162306a36Sopenharmony_ci case AMDGPU_QPX_PARTITION_MODE: 44262306a36Sopenharmony_ci num_xccs_per_xcp = num_xcc / 4; 44362306a36Sopenharmony_ci return (adev->gmc.num_mem_partitions == 1 || 44462306a36Sopenharmony_ci adev->gmc.num_mem_partitions == 4) && 44562306a36Sopenharmony_ci (num_xccs_per_xcp >= 2); 44662306a36Sopenharmony_ci case AMDGPU_CPX_PARTITION_MODE: 44762306a36Sopenharmony_ci return ((num_xcc > 1) && 44862306a36Sopenharmony_ci (adev->gmc.num_mem_partitions == 1 || adev->gmc.num_mem_partitions == 4) && 44962306a36Sopenharmony_ci (num_xcc % adev->gmc.num_mem_partitions) == 0); 45062306a36Sopenharmony_ci default: 45162306a36Sopenharmony_ci return false; 45262306a36Sopenharmony_ci } 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci return false; 45562306a36Sopenharmony_ci} 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_cistatic int __aqua_vanjaram_pre_partition_switch(struct amdgpu_xcp_mgr *xcp_mgr, u32 flags) 45862306a36Sopenharmony_ci{ 45962306a36Sopenharmony_ci /* TODO: 46062306a36Sopenharmony_ci * Stop user queues and threads, and make sure GPU is empty of work. 46162306a36Sopenharmony_ci */ 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci if (flags & AMDGPU_XCP_OPS_KFD) 46462306a36Sopenharmony_ci amdgpu_amdkfd_device_fini_sw(xcp_mgr->adev); 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci return 0; 46762306a36Sopenharmony_ci} 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_cistatic int __aqua_vanjaram_post_partition_switch(struct amdgpu_xcp_mgr *xcp_mgr, u32 flags) 47062306a36Sopenharmony_ci{ 47162306a36Sopenharmony_ci int ret = 0; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci if (flags & AMDGPU_XCP_OPS_KFD) { 47462306a36Sopenharmony_ci amdgpu_amdkfd_device_probe(xcp_mgr->adev); 47562306a36Sopenharmony_ci amdgpu_amdkfd_device_init(xcp_mgr->adev); 47662306a36Sopenharmony_ci /* If KFD init failed, return failure */ 47762306a36Sopenharmony_ci if (!xcp_mgr->adev->kfd.init_complete) 47862306a36Sopenharmony_ci ret = -EIO; 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci return ret; 48262306a36Sopenharmony_ci} 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_cistatic int aqua_vanjaram_switch_partition_mode(struct amdgpu_xcp_mgr *xcp_mgr, 48562306a36Sopenharmony_ci int mode, int *num_xcps) 48662306a36Sopenharmony_ci{ 48762306a36Sopenharmony_ci int num_xcc_per_xcp, num_xcc, ret; 48862306a36Sopenharmony_ci struct amdgpu_device *adev; 48962306a36Sopenharmony_ci u32 flags = 0; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci adev = xcp_mgr->adev; 49262306a36Sopenharmony_ci num_xcc = NUM_XCC(adev->gfx.xcc_mask); 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci if (mode == AMDGPU_AUTO_COMPUTE_PARTITION_MODE) { 49562306a36Sopenharmony_ci mode = __aqua_vanjaram_get_auto_mode(xcp_mgr); 49662306a36Sopenharmony_ci } else if (!__aqua_vanjaram_is_valid_mode(xcp_mgr, mode)) { 49762306a36Sopenharmony_ci dev_err(adev->dev, 49862306a36Sopenharmony_ci "Invalid compute partition mode requested, requested: %s, available memory partitions: %d", 49962306a36Sopenharmony_ci amdgpu_gfx_compute_mode_desc(mode), adev->gmc.num_mem_partitions); 50062306a36Sopenharmony_ci return -EINVAL; 50162306a36Sopenharmony_ci } 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci if (adev->kfd.init_complete) 50462306a36Sopenharmony_ci flags |= AMDGPU_XCP_OPS_KFD; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci if (flags & AMDGPU_XCP_OPS_KFD) { 50762306a36Sopenharmony_ci ret = amdgpu_amdkfd_check_and_lock_kfd(adev); 50862306a36Sopenharmony_ci if (ret) 50962306a36Sopenharmony_ci goto out; 51062306a36Sopenharmony_ci } 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci ret = __aqua_vanjaram_pre_partition_switch(xcp_mgr, flags); 51362306a36Sopenharmony_ci if (ret) 51462306a36Sopenharmony_ci goto unlock; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci num_xcc_per_xcp = __aqua_vanjaram_get_xcc_per_xcp(xcp_mgr, mode); 51762306a36Sopenharmony_ci if (adev->gfx.funcs->switch_partition_mode) 51862306a36Sopenharmony_ci adev->gfx.funcs->switch_partition_mode(xcp_mgr->adev, 51962306a36Sopenharmony_ci num_xcc_per_xcp); 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci /* Init info about new xcps */ 52262306a36Sopenharmony_ci *num_xcps = num_xcc / num_xcc_per_xcp; 52362306a36Sopenharmony_ci amdgpu_xcp_init(xcp_mgr, *num_xcps, mode); 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci ret = __aqua_vanjaram_post_partition_switch(xcp_mgr, flags); 52662306a36Sopenharmony_ciunlock: 52762306a36Sopenharmony_ci if (flags & AMDGPU_XCP_OPS_KFD) 52862306a36Sopenharmony_ci amdgpu_amdkfd_unlock_kfd(adev); 52962306a36Sopenharmony_ciout: 53062306a36Sopenharmony_ci return ret; 53162306a36Sopenharmony_ci} 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_cistatic int __aqua_vanjaram_get_xcp_mem_id(struct amdgpu_device *adev, 53462306a36Sopenharmony_ci int xcc_id, uint8_t *mem_id) 53562306a36Sopenharmony_ci{ 53662306a36Sopenharmony_ci /* memory/spatial modes validation check is already done */ 53762306a36Sopenharmony_ci *mem_id = xcc_id / adev->gfx.num_xcc_per_xcp; 53862306a36Sopenharmony_ci *mem_id /= adev->xcp_mgr->num_xcp_per_mem_partition; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci return 0; 54162306a36Sopenharmony_ci} 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_cistatic int aqua_vanjaram_get_xcp_mem_id(struct amdgpu_xcp_mgr *xcp_mgr, 54462306a36Sopenharmony_ci struct amdgpu_xcp *xcp, uint8_t *mem_id) 54562306a36Sopenharmony_ci{ 54662306a36Sopenharmony_ci struct amdgpu_numa_info numa_info; 54762306a36Sopenharmony_ci struct amdgpu_device *adev; 54862306a36Sopenharmony_ci uint32_t xcc_mask; 54962306a36Sopenharmony_ci int r, i, xcc_id; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci adev = xcp_mgr->adev; 55262306a36Sopenharmony_ci /* TODO: BIOS is not returning the right info now 55362306a36Sopenharmony_ci * Check on this later 55462306a36Sopenharmony_ci */ 55562306a36Sopenharmony_ci /* 55662306a36Sopenharmony_ci if (adev->gmc.gmc_funcs->query_mem_partition_mode) 55762306a36Sopenharmony_ci mode = adev->gmc.gmc_funcs->query_mem_partition_mode(adev); 55862306a36Sopenharmony_ci */ 55962306a36Sopenharmony_ci if (adev->gmc.num_mem_partitions == 1) { 56062306a36Sopenharmony_ci /* Only one range */ 56162306a36Sopenharmony_ci *mem_id = 0; 56262306a36Sopenharmony_ci return 0; 56362306a36Sopenharmony_ci } 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci r = amdgpu_xcp_get_inst_details(xcp, AMDGPU_XCP_GFX, &xcc_mask); 56662306a36Sopenharmony_ci if (r || !xcc_mask) 56762306a36Sopenharmony_ci return -EINVAL; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci xcc_id = ffs(xcc_mask) - 1; 57062306a36Sopenharmony_ci if (!adev->gmc.is_app_apu) 57162306a36Sopenharmony_ci return __aqua_vanjaram_get_xcp_mem_id(adev, xcc_id, mem_id); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci r = amdgpu_acpi_get_mem_info(adev, xcc_id, &numa_info); 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci if (r) 57662306a36Sopenharmony_ci return r; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci r = -EINVAL; 57962306a36Sopenharmony_ci for (i = 0; i < adev->gmc.num_mem_partitions; ++i) { 58062306a36Sopenharmony_ci if (adev->gmc.mem_partitions[i].numa.node == numa_info.nid) { 58162306a36Sopenharmony_ci *mem_id = i; 58262306a36Sopenharmony_ci r = 0; 58362306a36Sopenharmony_ci break; 58462306a36Sopenharmony_ci } 58562306a36Sopenharmony_ci } 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci return r; 58862306a36Sopenharmony_ci} 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_cistatic int aqua_vanjaram_get_xcp_ip_details(struct amdgpu_xcp_mgr *xcp_mgr, int xcp_id, 59162306a36Sopenharmony_ci enum AMDGPU_XCP_IP_BLOCK ip_id, 59262306a36Sopenharmony_ci struct amdgpu_xcp_ip *ip) 59362306a36Sopenharmony_ci{ 59462306a36Sopenharmony_ci if (!ip) 59562306a36Sopenharmony_ci return -EINVAL; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci return __aqua_vanjaram_get_xcp_ip_info(xcp_mgr, xcp_id, ip_id, ip); 59862306a36Sopenharmony_ci} 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_cistruct amdgpu_xcp_mgr_funcs aqua_vanjaram_xcp_funcs = { 60162306a36Sopenharmony_ci .switch_partition_mode = &aqua_vanjaram_switch_partition_mode, 60262306a36Sopenharmony_ci .query_partition_mode = &aqua_vanjaram_query_partition_mode, 60362306a36Sopenharmony_ci .get_ip_details = &aqua_vanjaram_get_xcp_ip_details, 60462306a36Sopenharmony_ci .get_xcp_mem_id = &aqua_vanjaram_get_xcp_mem_id, 60562306a36Sopenharmony_ci .select_scheds = &aqua_vanjaram_select_scheds, 60662306a36Sopenharmony_ci .update_partition_sched_list = &aqua_vanjaram_update_partition_sched_list 60762306a36Sopenharmony_ci}; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_cistatic int aqua_vanjaram_xcp_mgr_init(struct amdgpu_device *adev) 61062306a36Sopenharmony_ci{ 61162306a36Sopenharmony_ci int ret; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci ret = amdgpu_xcp_mgr_init(adev, AMDGPU_UNKNOWN_COMPUTE_PARTITION_MODE, 1, 61462306a36Sopenharmony_ci &aqua_vanjaram_xcp_funcs); 61562306a36Sopenharmony_ci if (ret) 61662306a36Sopenharmony_ci return ret; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci /* TODO: Default memory node affinity init */ 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci return ret; 62162306a36Sopenharmony_ci} 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ciint aqua_vanjaram_init_soc_config(struct amdgpu_device *adev) 62462306a36Sopenharmony_ci{ 62562306a36Sopenharmony_ci u32 mask, inst_mask = adev->sdma.sdma_mask; 62662306a36Sopenharmony_ci int ret, i; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci /* generally 1 AID supports 4 instances */ 62962306a36Sopenharmony_ci adev->sdma.num_inst_per_aid = 4; 63062306a36Sopenharmony_ci adev->sdma.num_instances = NUM_SDMA(adev->sdma.sdma_mask); 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci adev->aid_mask = i = 1; 63362306a36Sopenharmony_ci inst_mask >>= adev->sdma.num_inst_per_aid; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci for (mask = (1 << adev->sdma.num_inst_per_aid) - 1; inst_mask; 63662306a36Sopenharmony_ci inst_mask >>= adev->sdma.num_inst_per_aid, ++i) { 63762306a36Sopenharmony_ci if ((inst_mask & mask) == mask) 63862306a36Sopenharmony_ci adev->aid_mask |= (1 << i); 63962306a36Sopenharmony_ci } 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci /* Harvest config is not used for aqua vanjaram. VCN and JPEGs will be 64262306a36Sopenharmony_ci * addressed based on logical instance ids. 64362306a36Sopenharmony_ci */ 64462306a36Sopenharmony_ci adev->vcn.harvest_config = 0; 64562306a36Sopenharmony_ci adev->vcn.num_inst_per_aid = 1; 64662306a36Sopenharmony_ci adev->vcn.num_vcn_inst = hweight32(adev->vcn.inst_mask); 64762306a36Sopenharmony_ci adev->jpeg.harvest_config = 0; 64862306a36Sopenharmony_ci adev->jpeg.num_inst_per_aid = 1; 64962306a36Sopenharmony_ci adev->jpeg.num_jpeg_inst = hweight32(adev->jpeg.inst_mask); 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci ret = aqua_vanjaram_xcp_mgr_init(adev); 65262306a36Sopenharmony_ci if (ret) 65362306a36Sopenharmony_ci return ret; 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci aqua_vanjaram_ip_map_init(adev); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci return 0; 65862306a36Sopenharmony_ci} 659