diff options
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c')
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c | 386 |
1 files changed, 374 insertions, 12 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c index 23b6f7a4aa4a..c417f8689220 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c @@ -27,6 +27,9 @@ #include <drm/drm_drv.h> #include "../amdxcp/amdgpu_xcp_drv.h" +static void amdgpu_xcp_sysfs_entries_init(struct amdgpu_xcp_mgr *xcp_mgr); +static void amdgpu_xcp_sysfs_entries_update(struct amdgpu_xcp_mgr *xcp_mgr); + static int __amdgpu_xcp_run(struct amdgpu_xcp_mgr *xcp_mgr, struct amdgpu_xcp_ip *xcp_ip, int xcp_state) { @@ -189,7 +192,7 @@ static int __amdgpu_xcp_switch_partition_mode(struct amdgpu_xcp_mgr *xcp_mgr, goto out; } - + amdgpu_xcp_sysfs_entries_update(xcp_mgr); out: mutex_unlock(&xcp_mgr->xcp_lock); @@ -215,15 +218,27 @@ int amdgpu_xcp_restore_partition_mode(struct amdgpu_xcp_mgr *xcp_mgr) return __amdgpu_xcp_switch_partition_mode(xcp_mgr, xcp_mgr->mode); } -int amdgpu_xcp_query_partition_mode(struct amdgpu_xcp_mgr *xcp_mgr, u32 flags) +static bool __amdgpu_xcp_is_cached_mode_valid(struct amdgpu_xcp_mgr *xcp_mgr) { - int mode; + if (!xcp_mgr->funcs || !xcp_mgr->funcs->query_partition_mode) + return true; if (!amdgpu_sriov_vf(xcp_mgr->adev) && xcp_mgr->mode == AMDGPU_XCP_MODE_NONE) - return xcp_mgr->mode; + return true; - if (!xcp_mgr->funcs || !xcp_mgr->funcs->query_partition_mode) + if (xcp_mgr->mode != AMDGPU_XCP_MODE_NONE && + xcp_mgr->mode != AMDGPU_XCP_MODE_TRANS) + return true; + + return false; +} + +int amdgpu_xcp_query_partition_mode(struct amdgpu_xcp_mgr *xcp_mgr, u32 flags) +{ + int mode; + + if (__amdgpu_xcp_is_cached_mode_valid(xcp_mgr)) return xcp_mgr->mode; if (!(flags & AMDGPU_XCP_FL_LOCKED)) @@ -263,9 +278,10 @@ static int amdgpu_xcp_dev_alloc(struct amdgpu_device *adev) if (ret == -ENOSPC) { dev_warn(adev->dev, "Skip xcp node #%d when out of drm node resource.", i); - return 0; + ret = 0; + goto out; } else if (ret) { - return ret; + goto out; } /* Redirect all IOCTLs to the primary device */ @@ -278,9 +294,14 @@ static int amdgpu_xcp_dev_alloc(struct amdgpu_device *adev) p_ddev->vma_offset_manager = ddev->vma_offset_manager; p_ddev->driver = &amdgpu_partition_driver; adev->xcp_mgr->xcp[i].ddev = p_ddev; + + dev_set_drvdata(p_ddev->dev, &adev->xcp_mgr->xcp[i]); } + ret = 0; +out: + amdgpu_xcp_sysfs_entries_init(adev->xcp_mgr); - return 0; + return ret; } int amdgpu_xcp_mgr_init(struct amdgpu_device *adev, int init_mode, @@ -288,6 +309,7 @@ int amdgpu_xcp_mgr_init(struct amdgpu_device *adev, int init_mode, struct amdgpu_xcp_mgr_funcs *xcp_funcs) { struct amdgpu_xcp_mgr *xcp_mgr; + int i; if (!xcp_funcs || !xcp_funcs->get_ip_details) return -EINVAL; @@ -306,6 +328,8 @@ int amdgpu_xcp_mgr_init(struct amdgpu_device *adev, int init_mode, amdgpu_xcp_init(xcp_mgr, init_num_xcps, init_mode); adev->xcp_mgr = xcp_mgr; + for (i = 0; i < MAX_XCP; ++i) + xcp_mgr->xcp[i].xcp_mgr = xcp_mgr; return amdgpu_xcp_dev_alloc(adev); } @@ -433,6 +457,223 @@ void amdgpu_xcp_release_sched(struct amdgpu_device *adev, } } +int amdgpu_xcp_select_scheds(struct amdgpu_device *adev, + u32 hw_ip, u32 hw_prio, + struct amdgpu_fpriv *fpriv, + unsigned int *num_scheds, + struct drm_gpu_scheduler ***scheds) +{ + u32 sel_xcp_id; + int i; + struct amdgpu_xcp_mgr *xcp_mgr = adev->xcp_mgr; + + if (fpriv->xcp_id == AMDGPU_XCP_NO_PARTITION) { + u32 least_ref_cnt = ~0; + + fpriv->xcp_id = 0; + for (i = 0; i < xcp_mgr->num_xcps; i++) { + u32 total_ref_cnt; + + total_ref_cnt = atomic_read(&xcp_mgr->xcp[i].ref_cnt); + if (total_ref_cnt < least_ref_cnt) { + fpriv->xcp_id = i; + least_ref_cnt = total_ref_cnt; + } + } + } + sel_xcp_id = fpriv->xcp_id; + + if (xcp_mgr->xcp[sel_xcp_id].gpu_sched[hw_ip][hw_prio].num_scheds) { + *num_scheds = + xcp_mgr->xcp[fpriv->xcp_id].gpu_sched[hw_ip][hw_prio].num_scheds; + *scheds = + xcp_mgr->xcp[fpriv->xcp_id].gpu_sched[hw_ip][hw_prio].sched; + atomic_inc(&adev->xcp_mgr->xcp[sel_xcp_id].ref_cnt); + dev_dbg(adev->dev, "Selected partition #%d", sel_xcp_id); + } else { + dev_err(adev->dev, "Failed to schedule partition #%d.", sel_xcp_id); + return -ENOENT; + } + + return 0; +} + +static void amdgpu_set_xcp_id(struct amdgpu_device *adev, + uint32_t inst_idx, + struct amdgpu_ring *ring) +{ + int xcp_id; + enum AMDGPU_XCP_IP_BLOCK ip_blk; + uint32_t inst_mask; + + ring->xcp_id = AMDGPU_XCP_NO_PARTITION; + if (ring->funcs->type == AMDGPU_RING_TYPE_COMPUTE) + adev->gfx.enforce_isolation[0].xcp_id = ring->xcp_id; + if ((adev->xcp_mgr->mode == AMDGPU_XCP_MODE_NONE) || + (ring->funcs->type == AMDGPU_RING_TYPE_CPER)) + return; + + inst_mask = 1 << inst_idx; + + switch (ring->funcs->type) { + case AMDGPU_HW_IP_GFX: + case AMDGPU_RING_TYPE_COMPUTE: + case AMDGPU_RING_TYPE_KIQ: + ip_blk = AMDGPU_XCP_GFX; + break; + case AMDGPU_RING_TYPE_SDMA: + ip_blk = AMDGPU_XCP_SDMA; + break; + case AMDGPU_RING_TYPE_VCN_ENC: + case AMDGPU_RING_TYPE_VCN_JPEG: + ip_blk = AMDGPU_XCP_VCN; + break; + default: + dev_err(adev->dev, "Not support ring type %d!", ring->funcs->type); + return; + } + + for (xcp_id = 0; xcp_id < adev->xcp_mgr->num_xcps; xcp_id++) { + if (adev->xcp_mgr->xcp[xcp_id].ip[ip_blk].inst_mask & inst_mask) { + ring->xcp_id = xcp_id; + dev_dbg(adev->dev, "ring:%s xcp_id :%u", ring->name, + ring->xcp_id); + if (ring->funcs->type == AMDGPU_RING_TYPE_COMPUTE) + adev->gfx.enforce_isolation[xcp_id].xcp_id = xcp_id; + break; + } + } +} + +static void amdgpu_xcp_gpu_sched_update(struct amdgpu_device *adev, + struct amdgpu_ring *ring, + unsigned int sel_xcp_id) +{ + unsigned int *num_gpu_sched; + + num_gpu_sched = &adev->xcp_mgr->xcp[sel_xcp_id] + .gpu_sched[ring->funcs->type][ring->hw_prio].num_scheds; + adev->xcp_mgr->xcp[sel_xcp_id].gpu_sched[ring->funcs->type][ring->hw_prio] + .sched[(*num_gpu_sched)++] = &ring->sched; + dev_dbg(adev->dev, "%s :[%d] gpu_sched[%d][%d] = %d", + ring->name, sel_xcp_id, ring->funcs->type, + ring->hw_prio, *num_gpu_sched); +} + +static int amdgpu_xcp_sched_list_update(struct amdgpu_device *adev) +{ + struct amdgpu_ring *ring; + int i; + + for (i = 0; i < MAX_XCP; i++) { + atomic_set(&adev->xcp_mgr->xcp[i].ref_cnt, 0); + memset(adev->xcp_mgr->xcp[i].gpu_sched, 0, sizeof(adev->xcp_mgr->xcp->gpu_sched)); + } + + if (adev->xcp_mgr->mode == AMDGPU_XCP_MODE_NONE) + return 0; + + for (i = 0; i < AMDGPU_MAX_RINGS; i++) { + ring = adev->rings[i]; + if (!ring || !ring->sched.ready || ring->no_scheduler) + continue; + + amdgpu_xcp_gpu_sched_update(adev, ring, ring->xcp_id); + + /* VCN may be shared by two partitions under CPX MODE in certain + * configs. + */ + if ((ring->funcs->type == AMDGPU_RING_TYPE_VCN_ENC || + ring->funcs->type == AMDGPU_RING_TYPE_VCN_JPEG) && + (adev->xcp_mgr->num_xcps > adev->vcn.num_vcn_inst)) + amdgpu_xcp_gpu_sched_update(adev, ring, ring->xcp_id + 1); + } + + return 0; +} + +int amdgpu_xcp_update_partition_sched_list(struct amdgpu_device *adev) +{ + int i; + + for (i = 0; i < adev->num_rings; i++) { + struct amdgpu_ring *ring = adev->rings[i]; + + if (ring->funcs->type == AMDGPU_RING_TYPE_COMPUTE || + ring->funcs->type == AMDGPU_RING_TYPE_KIQ) + amdgpu_set_xcp_id(adev, ring->xcc_id, ring); + else + amdgpu_set_xcp_id(adev, ring->me, ring); + } + + return amdgpu_xcp_sched_list_update(adev); +} + +void amdgpu_xcp_update_supported_modes(struct amdgpu_xcp_mgr *xcp_mgr) +{ + struct amdgpu_device *adev = xcp_mgr->adev; + + xcp_mgr->supp_xcp_modes = 0; + + switch (NUM_XCC(adev->gfx.xcc_mask)) { + case 8: + xcp_mgr->supp_xcp_modes = BIT(AMDGPU_SPX_PARTITION_MODE) | + BIT(AMDGPU_DPX_PARTITION_MODE) | + BIT(AMDGPU_QPX_PARTITION_MODE) | + BIT(AMDGPU_CPX_PARTITION_MODE); + break; + case 6: + xcp_mgr->supp_xcp_modes = BIT(AMDGPU_SPX_PARTITION_MODE) | + BIT(AMDGPU_TPX_PARTITION_MODE) | + BIT(AMDGPU_CPX_PARTITION_MODE); + break; + case 4: + xcp_mgr->supp_xcp_modes = BIT(AMDGPU_SPX_PARTITION_MODE) | + BIT(AMDGPU_DPX_PARTITION_MODE) | + BIT(AMDGPU_CPX_PARTITION_MODE); + break; + case 2: + xcp_mgr->supp_xcp_modes = BIT(AMDGPU_SPX_PARTITION_MODE) | + BIT(AMDGPU_CPX_PARTITION_MODE); + break; + case 1: + xcp_mgr->supp_xcp_modes = BIT(AMDGPU_SPX_PARTITION_MODE) | + BIT(AMDGPU_CPX_PARTITION_MODE); + break; + + default: + break; + } +} + +int amdgpu_xcp_pre_partition_switch(struct amdgpu_xcp_mgr *xcp_mgr, u32 flags) +{ + /* TODO: + * Stop user queues and threads, and make sure GPU is empty of work. + */ + + if (flags & AMDGPU_XCP_OPS_KFD) + amdgpu_amdkfd_device_fini_sw(xcp_mgr->adev); + + return 0; +} + +int amdgpu_xcp_post_partition_switch(struct amdgpu_xcp_mgr *xcp_mgr, u32 flags) +{ + int ret = 0; + + if (flags & AMDGPU_XCP_OPS_KFD) { + amdgpu_amdkfd_device_probe(xcp_mgr->adev); + amdgpu_amdkfd_device_init(xcp_mgr->adev); + /* If KFD init failed, return failure */ + if (!xcp_mgr->adev->kfd.init_complete) + ret = -EIO; + } + + return ret; +} + +/*====================== xcp sysfs - configuration ======================*/ #define XCP_CFG_SYSFS_RES_ATTR_SHOW(_name) \ static ssize_t amdgpu_xcp_res_sysfs_##_name##_show( \ struct amdgpu_xcp_res_details *xcp_res, char *buf) \ @@ -635,7 +876,7 @@ static const struct attribute *xcp_attrs[] = { NULL, }; -void amdgpu_xcp_cfg_sysfs_init(struct amdgpu_device *adev) +static void amdgpu_xcp_cfg_sysfs_init(struct amdgpu_device *adev) { struct amdgpu_xcp_res_details *xcp_res; struct amdgpu_xcp_cfg *xcp_cfg; @@ -703,16 +944,16 @@ err1: kobject_put(&xcp_cfg->kobj); } -void amdgpu_xcp_cfg_sysfs_fini(struct amdgpu_device *adev) +static void amdgpu_xcp_cfg_sysfs_fini(struct amdgpu_device *adev) { struct amdgpu_xcp_res_details *xcp_res; struct amdgpu_xcp_cfg *xcp_cfg; int i; - if (!adev->xcp_mgr) + if (!adev->xcp_mgr || !adev->xcp_mgr->xcp_cfg) return; - xcp_cfg = adev->xcp_mgr->xcp_cfg; + xcp_cfg = adev->xcp_mgr->xcp_cfg; for (i = 0; i < xcp_cfg->num_res; i++) { xcp_res = &xcp_cfg->xcp_res[i]; kobject_put(&xcp_res->kobj); @@ -722,3 +963,124 @@ void amdgpu_xcp_cfg_sysfs_fini(struct amdgpu_device *adev) sysfs_remove_files(&xcp_cfg->kobj, xcp_attrs); kobject_put(&xcp_cfg->kobj); } + +/*====================== xcp sysfs - data entries ======================*/ + +#define to_xcp(x) container_of(x, struct amdgpu_xcp, kobj) + +static ssize_t xcp_metrics_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct amdgpu_xcp *xcp = to_xcp(kobj); + struct amdgpu_xcp_mgr *xcp_mgr; + ssize_t size; + + xcp_mgr = xcp->xcp_mgr; + size = amdgpu_dpm_get_xcp_metrics(xcp_mgr->adev, xcp->id, NULL); + if (size <= 0) + return size; + + if (size > PAGE_SIZE) + return -ENOSPC; + + return amdgpu_dpm_get_xcp_metrics(xcp_mgr->adev, xcp->id, buf); +} + +static umode_t amdgpu_xcp_attrs_is_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + struct amdgpu_xcp *xcp = to_xcp(kobj); + + if (!xcp || !xcp->valid) + return 0; + + return attr->mode; +} + +static struct kobj_attribute xcp_sysfs_metrics = __ATTR_RO(xcp_metrics); + +static struct attribute *amdgpu_xcp_attrs[] = { + &xcp_sysfs_metrics.attr, + NULL, +}; + +static const struct attribute_group amdgpu_xcp_attrs_group = { + .attrs = amdgpu_xcp_attrs, + .is_visible = amdgpu_xcp_attrs_is_visible +}; + +static const struct kobj_type xcp_sysfs_ktype = { + .sysfs_ops = &kobj_sysfs_ops, +}; + +static void amdgpu_xcp_sysfs_entries_fini(struct amdgpu_xcp_mgr *xcp_mgr, int n) +{ + struct amdgpu_xcp *xcp; + + for (n--; n >= 0; n--) { + xcp = &xcp_mgr->xcp[n]; + if (!xcp->ddev || !xcp->valid) + continue; + sysfs_remove_group(&xcp->kobj, &amdgpu_xcp_attrs_group); + kobject_put(&xcp->kobj); + } +} + +static void amdgpu_xcp_sysfs_entries_init(struct amdgpu_xcp_mgr *xcp_mgr) +{ + struct amdgpu_xcp *xcp; + int i, r; + + for (i = 0; i < MAX_XCP; i++) { + /* Redirect all IOCTLs to the primary device */ + xcp = &xcp_mgr->xcp[i]; + if (!xcp->ddev) + break; + r = kobject_init_and_add(&xcp->kobj, &xcp_sysfs_ktype, + &xcp->ddev->dev->kobj, "xcp"); + if (r) + goto out; + + r = sysfs_create_group(&xcp->kobj, &amdgpu_xcp_attrs_group); + if (r) + goto out; + } + + return; +out: + kobject_put(&xcp->kobj); +} + +static void amdgpu_xcp_sysfs_entries_update(struct amdgpu_xcp_mgr *xcp_mgr) +{ + struct amdgpu_xcp *xcp; + int i; + + for (i = 0; i < MAX_XCP; i++) { + /* Redirect all IOCTLs to the primary device */ + xcp = &xcp_mgr->xcp[i]; + if (!xcp->ddev) + continue; + sysfs_update_group(&xcp->kobj, &amdgpu_xcp_attrs_group); + } + + return; +} + +void amdgpu_xcp_sysfs_init(struct amdgpu_device *adev) +{ + if (!adev->xcp_mgr) + return; + + amdgpu_xcp_cfg_sysfs_init(adev); + + return; +} + +void amdgpu_xcp_sysfs_fini(struct amdgpu_device *adev) +{ + if (!adev->xcp_mgr) + return; + amdgpu_xcp_sysfs_entries_fini(adev->xcp_mgr, MAX_XCP); + amdgpu_xcp_cfg_sysfs_fini(adev); +} |