mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 17:47:41 +02:00
drm-misc-fixes for v7.2-rc2:
- Fix potential null pointer dereference in dma-buf. - Handle 0 in dma_fence_dedup_array. - Use the correct callback in dma_fence_timeline_name. - Fix device removal handling in amdxdna. - kernel-doc fixes. - Include header fix for drm_ras.h - Handle edids better in virtio. - Use the clk_bulk api for error handling in malidp. - More clk handling fixes for komeda. - panthor scheduler block fallout fixes. - panthor unplug fixes. - other panthor fixes. - Fix unnecessary WARN_ON in topology probe after teardown. - Add refcount to amdxdna job to fix use-after free. - Fix increasing args->size in ioctl's of drm/imagination. - Handle stride correctly in pvr_set_uobj_array. - Only call imagination's drm_sched_entity_fini once. -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEuXvWqAysSYEJGuVH/lWMcqZwE8MFAmpGi4sACgkQ/lWMcqZw E8NhNA/+JHDKw3iO6f2+/2KWdgJseXXs2G+Y4Bm0lWgpl2eP1Sj6adwMStGvBj9o mVoO0CHCAxiIIj1UAY+pZ92aAaPpfH10Ka4gHT0mWzpLoH2Gzgt97Qb8jmVSF8sD yWwujaM4Z1hhlq6F3492WBqf13RmMMUUnqTBMr5LdnxKA9tFFXFVN2snO2JRUMWI 8sfXIB83BYuXuJ3aJH0ToSctV2k5Ji6inbTODL5rAmhYxiyGiIV1NV72FeiiL7pC l+aDE14+FB1OZ/iw1fxFFmm1ox507IGnopv0coExEg1hK7HlaQgPJooS/CkjK2JM tpzQHaVhX3V3PABQD1HnWaCUBDdEqRCr1DNHNuXbM1vPCGlhvD/lpiN4i2UCEUyx g64GfIm7JA7AowaSV57651B1vZwQmVkg8y9PWYNn7avD4n5+ZwHkEyFO4wpRwwdZ tVHqVBgMJvCQolA269XNPtLwoIebdQuRZUKaxX2IjrEJJk23S1VDPqJY2cTvoi6L u1XUWM7iz3XjCTDU0uN7VZ0vCft0g0Ha1mY9GU2Gn+AMpxgi8qzMBSLDduS6K27v tzxQsduZ5bvUpclrX7jshJ0F3vQJnCnyQ5qVdF1I/J4/O/umcyuI+ZhKZPiFyhQe PW8SbHqJGXtMRIPR95sMoTkMZKes4QTfSF1qbU2NhM6w6MB6bpY= =heUt -----END PGP SIGNATURE----- Merge tag 'drm-misc-fixes-2026-07-02' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-fixes drm-misc-fixes for v7.2-rc2: - Fix potential null pointer dereference in dma-buf. - Handle 0 in dma_fence_dedup_array. - Use the correct callback in dma_fence_timeline_name. - Fix device removal handling in amdxdna. - kernel-doc fixes. - Include header fix for drm_ras.h - Handle edids better in virtio. - Use the clk_bulk api for error handling in malidp. - More clk handling fixes for komeda. - panthor scheduler block fallout fixes. - panthor unplug fixes. - other panthor fixes. - Fix unnecessary WARN_ON in topology probe after teardown. - Add refcount to amdxdna job to fix use-after free. - Fix increasing args->size in ioctl's of drm/imagination. - Handle stride correctly in pvr_set_uobj_array. - Only call imagination's drm_sched_entity_fini once. Signed-off-by: Dave Airlie <airlied@redhat.com> From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Link: https://patch.msgid.link/786bdc92-0ce3-4c0f-9668-b0fa8a0047ea@linux.intel.com
This commit is contained in:
commit
acd7c71ba8
|
|
@ -59,6 +59,18 @@ static bool aie2_tdr_detect(struct amdxdna_dev *xdna)
|
|||
return false;
|
||||
}
|
||||
|
||||
static void aie2_cmd_release(struct kref *ref)
|
||||
{
|
||||
struct amdxdna_drv_cmd *drv_cmd = container_of(ref, struct amdxdna_drv_cmd, refcnt);
|
||||
|
||||
kfree(drv_cmd);
|
||||
}
|
||||
|
||||
static void aie2_cmd_put(struct amdxdna_drv_cmd *drv_cmd)
|
||||
{
|
||||
kref_put(&drv_cmd->refcnt, aie2_cmd_release);
|
||||
}
|
||||
|
||||
static void aie2_job_release(struct kref *ref)
|
||||
{
|
||||
struct amdxdna_sched_job *job;
|
||||
|
|
@ -70,6 +82,8 @@ static void aie2_job_release(struct kref *ref)
|
|||
wake_up(&job->hwctx->priv->job_free_wq);
|
||||
if (job->out_fence)
|
||||
dma_fence_put(job->out_fence);
|
||||
if (job->drv_cmd)
|
||||
aie2_cmd_put(job->drv_cmd);
|
||||
kfree(job->aie2_job_health);
|
||||
kfree(job);
|
||||
}
|
||||
|
|
@ -901,7 +915,7 @@ static int aie2_hwctx_cfg_debug_bo(struct amdxdna_hwctx *hwctx, u32 bo_hdl,
|
|||
{
|
||||
struct amdxdna_client *client = hwctx->client;
|
||||
struct amdxdna_dev *xdna = client->xdna;
|
||||
struct amdxdna_drv_cmd cmd = { 0 };
|
||||
struct amdxdna_drv_cmd *cmd;
|
||||
struct amdxdna_gem_obj *abo;
|
||||
u64 seq;
|
||||
int ret;
|
||||
|
|
@ -912,32 +926,39 @@ static int aie2_hwctx_cfg_debug_bo(struct amdxdna_hwctx *hwctx, u32 bo_hdl,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
cmd = kzalloc_obj(*cmd);
|
||||
if (!cmd) {
|
||||
ret = -ENOMEM;
|
||||
goto put_obj;
|
||||
}
|
||||
kref_init(&cmd->refcnt);
|
||||
|
||||
if (attach) {
|
||||
if (abo->assigned_hwctx != AMDXDNA_INVALID_CTX_HANDLE) {
|
||||
ret = -EBUSY;
|
||||
goto put_obj;
|
||||
goto put_cmd;
|
||||
}
|
||||
cmd.opcode = ATTACH_DEBUG_BO;
|
||||
cmd->opcode = ATTACH_DEBUG_BO;
|
||||
} else {
|
||||
if (abo->assigned_hwctx != hwctx->id) {
|
||||
ret = -EINVAL;
|
||||
goto put_obj;
|
||||
goto put_cmd;
|
||||
}
|
||||
cmd.opcode = DETACH_DEBUG_BO;
|
||||
cmd->opcode = DETACH_DEBUG_BO;
|
||||
}
|
||||
|
||||
ret = amdxdna_cmd_submit(client, &cmd, AMDXDNA_INVALID_BO_HANDLE,
|
||||
ret = amdxdna_cmd_submit(client, cmd, AMDXDNA_INVALID_BO_HANDLE,
|
||||
&bo_hdl, 1, hwctx->id, &seq);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "Submit command failed");
|
||||
goto put_obj;
|
||||
goto put_cmd;
|
||||
}
|
||||
|
||||
aie2_cmd_wait(hwctx, seq);
|
||||
if (cmd.result) {
|
||||
XDNA_ERR(xdna, "Response failure 0x%x", cmd.result);
|
||||
if (cmd->result) {
|
||||
XDNA_ERR(xdna, "Response failure 0x%x", cmd->result);
|
||||
ret = -EINVAL;
|
||||
goto put_obj;
|
||||
goto put_cmd;
|
||||
}
|
||||
|
||||
if (attach)
|
||||
|
|
@ -947,6 +968,8 @@ static int aie2_hwctx_cfg_debug_bo(struct amdxdna_hwctx *hwctx, u32 bo_hdl,
|
|||
|
||||
XDNA_DBG(xdna, "Config debug BO %d to %s", bo_hdl, hwctx->name);
|
||||
|
||||
put_cmd:
|
||||
aie2_cmd_put(cmd);
|
||||
put_obj:
|
||||
amdxdna_gem_put_obj(abo);
|
||||
return ret;
|
||||
|
|
@ -974,25 +997,32 @@ int aie2_hwctx_sync_debug_bo(struct amdxdna_hwctx *hwctx, u32 debug_bo_hdl)
|
|||
{
|
||||
struct amdxdna_client *client = hwctx->client;
|
||||
struct amdxdna_dev *xdna = client->xdna;
|
||||
struct amdxdna_drv_cmd cmd = { 0 };
|
||||
struct amdxdna_drv_cmd *cmd;
|
||||
u64 seq;
|
||||
int ret;
|
||||
|
||||
cmd.opcode = SYNC_DEBUG_BO;
|
||||
ret = amdxdna_cmd_submit(client, &cmd, AMDXDNA_INVALID_BO_HANDLE,
|
||||
cmd = kzalloc_obj(*cmd);
|
||||
if (!cmd)
|
||||
return -ENOMEM;
|
||||
kref_init(&cmd->refcnt);
|
||||
|
||||
cmd->opcode = SYNC_DEBUG_BO;
|
||||
ret = amdxdna_cmd_submit(client, cmd, AMDXDNA_INVALID_BO_HANDLE,
|
||||
&debug_bo_hdl, 1, hwctx->id, &seq);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "Submit command failed");
|
||||
return ret;
|
||||
goto put_cmd;
|
||||
}
|
||||
|
||||
aie2_cmd_wait(hwctx, seq);
|
||||
if (cmd.result) {
|
||||
XDNA_ERR(xdna, "Response failure 0x%x", cmd.result);
|
||||
return -EINVAL;
|
||||
if (cmd->result) {
|
||||
XDNA_ERR(xdna, "Response failure 0x%x", cmd->result);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
put_cmd:
|
||||
aie2_cmd_put(cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int aie2_populate_range(struct amdxdna_gem_obj *abo)
|
||||
|
|
@ -1142,6 +1172,8 @@ int aie2_cmd_submit(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *job,
|
|||
dma_resv_add_fence(job->bos[i]->resv, job->out_fence, DMA_RESV_USAGE_WRITE);
|
||||
job->seq = hwctx->priv->seq++;
|
||||
kref_get(&job->refcnt);
|
||||
if (job->drv_cmd)
|
||||
kref_get(&job->drv_cmd->refcnt);
|
||||
drm_sched_entity_push_job(&job->base);
|
||||
|
||||
*seq = job->seq;
|
||||
|
|
|
|||
|
|
@ -132,6 +132,7 @@ enum amdxdna_job_opcode {
|
|||
struct amdxdna_drv_cmd {
|
||||
enum amdxdna_job_opcode opcode;
|
||||
u32 result;
|
||||
struct kref refcnt;
|
||||
};
|
||||
|
||||
struct app_health_report;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
*/
|
||||
|
||||
#include <drm/amdxdna_accel.h>
|
||||
#include <drm/drm_managed.h>
|
||||
#include <linux/iommu.h>
|
||||
#include <linux/iova.h>
|
||||
|
||||
|
|
@ -153,10 +154,30 @@ void amdxdna_iommu_free(struct amdxdna_dev *xdna, size_t size,
|
|||
free_pages((unsigned long)cpu_addr, get_order(size));
|
||||
}
|
||||
|
||||
static void amdxdna_cleanup_force_iova(struct drm_device *dev, void *res)
|
||||
{
|
||||
struct amdxdna_dev *xdna = to_xdna_dev(dev);
|
||||
|
||||
if (xdna->domain) {
|
||||
iommu_detach_group(xdna->domain, xdna->group);
|
||||
put_iova_domain(&xdna->iovad);
|
||||
iova_cache_put();
|
||||
iommu_domain_free(xdna->domain);
|
||||
}
|
||||
|
||||
iommu_group_put(xdna->group);
|
||||
}
|
||||
|
||||
void amdxdna_iommu_fini(struct amdxdna_dev *xdna)
|
||||
{
|
||||
if (xdna->group && !xdna->domain)
|
||||
iommu_group_put(xdna->group);
|
||||
}
|
||||
|
||||
int amdxdna_iommu_init(struct amdxdna_dev *xdna)
|
||||
{
|
||||
unsigned long order;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
xdna->group = iommu_group_get(xdna->ddev.dev);
|
||||
if (!xdna->group || !force_iova)
|
||||
|
|
@ -182,8 +203,14 @@ int amdxdna_iommu_init(struct amdxdna_dev *xdna)
|
|||
if (ret)
|
||||
goto put_iova;
|
||||
|
||||
ret = drmm_add_action(&xdna->ddev, amdxdna_cleanup_force_iova, NULL);
|
||||
if (ret)
|
||||
goto detach_group;
|
||||
|
||||
return 0;
|
||||
|
||||
detach_group:
|
||||
iommu_detach_group(xdna->domain, xdna->group);
|
||||
put_iova:
|
||||
put_iova_domain(&xdna->iovad);
|
||||
iova_cache_put();
|
||||
|
|
@ -191,20 +218,8 @@ int amdxdna_iommu_init(struct amdxdna_dev *xdna)
|
|||
iommu_domain_free(xdna->domain);
|
||||
put_group:
|
||||
iommu_group_put(xdna->group);
|
||||
xdna->group = NULL;
|
||||
xdna->domain = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void amdxdna_iommu_fini(struct amdxdna_dev *xdna)
|
||||
{
|
||||
if (xdna->domain) {
|
||||
iommu_detach_group(xdna->domain, xdna->group);
|
||||
put_iova_domain(&xdna->iovad);
|
||||
iova_cache_put();
|
||||
iommu_domain_free(xdna->domain);
|
||||
}
|
||||
|
||||
if (xdna->group)
|
||||
iommu_group_put(xdna->group);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -138,9 +138,11 @@ static int amdxdna_drm_open(struct drm_device *ddev, struct drm_file *filp)
|
|||
xdna->dev_info->dev_heap_max_size);
|
||||
mutex_init(&client->mm_lock);
|
||||
|
||||
mutex_lock(&xdna->client_lock);
|
||||
mutex_lock(&xdna->dev_lock);
|
||||
list_add_tail(&client->node, &xdna->client_list);
|
||||
mutex_unlock(&xdna->dev_lock);
|
||||
mutex_unlock(&xdna->client_lock);
|
||||
|
||||
filp->driver_priv = client;
|
||||
client->filp = filp;
|
||||
|
|
@ -174,18 +176,14 @@ static void amdxdna_drm_close(struct drm_device *ddev, struct drm_file *filp)
|
|||
{
|
||||
struct amdxdna_client *client = filp->driver_priv;
|
||||
struct amdxdna_dev *xdna = to_xdna_dev(ddev);
|
||||
int idx;
|
||||
|
||||
XDNA_DBG(xdna, "closing pid %d", client->pid);
|
||||
|
||||
if (!drm_dev_enter(&xdna->ddev, &idx))
|
||||
return;
|
||||
|
||||
mutex_lock(&xdna->client_lock);
|
||||
mutex_lock(&xdna->dev_lock);
|
||||
amdxdna_client_cleanup(client);
|
||||
mutex_unlock(&xdna->dev_lock);
|
||||
|
||||
drm_dev_exit(idx);
|
||||
mutex_unlock(&xdna->client_lock);
|
||||
}
|
||||
|
||||
static int amdxdna_drm_get_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
|
||||
|
|
@ -371,6 +369,10 @@ static int amdxdna_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
if (!xdna->dev_info)
|
||||
return -ENODEV;
|
||||
|
||||
ret = drmm_mutex_init(ddev, &xdna->client_lock);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
drmm_mutex_init(ddev, &xdna->dev_lock);
|
||||
init_rwsem(&xdna->notifier_lock);
|
||||
INIT_LIST_HEAD(&xdna->client_list);
|
||||
|
|
@ -390,9 +392,9 @@ static int amdxdna_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
xdna->notifier_wq = alloc_ordered_workqueue("notifier_wq", WQ_MEM_RECLAIM);
|
||||
if (!xdna->notifier_wq) {
|
||||
ret = -ENOMEM;
|
||||
xdna->notifier_wq = drmm_alloc_ordered_workqueue(ddev, "notifier_wq", WQ_MEM_RECLAIM);
|
||||
if (IS_ERR(xdna->notifier_wq)) {
|
||||
ret = PTR_ERR(xdna->notifier_wq);
|
||||
goto iommu_fini;
|
||||
}
|
||||
|
||||
|
|
@ -401,7 +403,7 @@ static int amdxdna_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
mutex_unlock(&xdna->dev_lock);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "Hardware init failed, ret %d", ret);
|
||||
goto destroy_notifier_wq;
|
||||
goto iommu_fini;
|
||||
}
|
||||
|
||||
ret = amdxdna_sysfs_init(xdna);
|
||||
|
|
@ -425,8 +427,6 @@ static int amdxdna_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
mutex_lock(&xdna->dev_lock);
|
||||
xdna->dev_info->ops->fini(xdna);
|
||||
mutex_unlock(&xdna->dev_lock);
|
||||
destroy_notifier_wq:
|
||||
destroy_workqueue(xdna->notifier_wq);
|
||||
iommu_fini:
|
||||
amdxdna_iommu_fini(xdna);
|
||||
return ret;
|
||||
|
|
@ -437,23 +437,19 @@ static void amdxdna_remove(struct pci_dev *pdev)
|
|||
struct amdxdna_dev *xdna = pci_get_drvdata(pdev);
|
||||
struct amdxdna_client *client;
|
||||
|
||||
destroy_workqueue(xdna->notifier_wq);
|
||||
|
||||
drm_dev_unplug(&xdna->ddev);
|
||||
amdxdna_sysfs_fini(xdna);
|
||||
|
||||
mutex_lock(&xdna->client_lock);
|
||||
mutex_lock(&xdna->dev_lock);
|
||||
client = list_first_entry_or_null(&xdna->client_list,
|
||||
struct amdxdna_client, node);
|
||||
while (client) {
|
||||
amdxdna_client_cleanup(client);
|
||||
|
||||
client = list_first_entry_or_null(&xdna->client_list,
|
||||
struct amdxdna_client, node);
|
||||
list_for_each_entry(client, &xdna->client_list, node) {
|
||||
amdxdna_hwctx_remove_all(client);
|
||||
amdxdna_sva_fini(client);
|
||||
}
|
||||
|
||||
xdna->dev_info->ops->fini(xdna);
|
||||
mutex_unlock(&xdna->dev_lock);
|
||||
mutex_unlock(&xdna->client_lock);
|
||||
|
||||
amdxdna_iommu_fini(xdna);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -120,6 +120,7 @@ struct amdxdna_dev {
|
|||
|
||||
struct mutex dev_lock; /* per device lock */
|
||||
struct list_head client_list;
|
||||
struct mutex client_lock; /* client_list */
|
||||
struct amdxdna_fw_ver fw_ver;
|
||||
struct rw_semaphore notifier_lock; /* for mmu notifier*/
|
||||
struct workqueue_struct *notifier_wq;
|
||||
|
|
|
|||
|
|
@ -97,6 +97,9 @@ int dma_fence_dedup_array(struct dma_fence **fences, int num_fences)
|
|||
{
|
||||
int i, j;
|
||||
|
||||
if (!num_fences)
|
||||
return 0;
|
||||
|
||||
sort(fences, num_fences, sizeof(*fences), fence_cmp, NULL);
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -1168,7 +1168,7 @@ const char __rcu *dma_fence_driver_name(struct dma_fence *fence)
|
|||
|
||||
/* RCU protection is required for safe access to returned string */
|
||||
ops = rcu_dereference(fence->ops);
|
||||
if (!dma_fence_test_signaled_flag(fence))
|
||||
if (ops)
|
||||
return (const char __rcu *)ops->get_driver_name(fence);
|
||||
else
|
||||
return (const char __rcu *)"detached-driver";
|
||||
|
|
@ -1201,8 +1201,8 @@ const char __rcu *dma_fence_timeline_name(struct dma_fence *fence)
|
|||
|
||||
/* RCU protection is required for safe access to returned string */
|
||||
ops = rcu_dereference(fence->ops);
|
||||
if (!dma_fence_test_signaled_flag(fence))
|
||||
return (const char __rcu *)ops->get_driver_name(fence);
|
||||
if (ops)
|
||||
return (const char __rcu *)ops->get_timeline_name(fence);
|
||||
else
|
||||
return (const char __rcu *)"signaled-timeline";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -313,7 +313,11 @@ void komeda_dev_destroy(struct komeda_dev *mdev)
|
|||
|
||||
int komeda_dev_resume(struct komeda_dev *mdev)
|
||||
{
|
||||
clk_prepare_enable(mdev->aclk);
|
||||
int err;
|
||||
|
||||
err = clk_prepare_enable(mdev->aclk);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mdev->funcs->enable_irq(mdev);
|
||||
|
||||
|
|
|
|||
|
|
@ -74,8 +74,11 @@ static int komeda_platform_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
if (!pm_runtime_enabled(dev))
|
||||
komeda_dev_resume(mdrv->mdev);
|
||||
if (!pm_runtime_enabled(dev)) {
|
||||
err = komeda_dev_resume(mdrv->mdev);
|
||||
if (err)
|
||||
goto err_destroy_mdev;
|
||||
}
|
||||
|
||||
mdrv->kms = komeda_kms_attach(mdrv->mdev);
|
||||
if (IS_ERR(mdrv->kms)) {
|
||||
|
|
@ -93,7 +96,7 @@ static int komeda_platform_probe(struct platform_device *pdev)
|
|||
pm_runtime_disable(dev);
|
||||
else
|
||||
komeda_dev_suspend(mdrv->mdev);
|
||||
|
||||
err_destroy_mdev:
|
||||
komeda_dev_destroy(mdrv->mdev);
|
||||
|
||||
free_mdrv:
|
||||
|
|
@ -140,11 +143,12 @@ static int __maybe_unused komeda_pm_suspend(struct device *dev)
|
|||
static int __maybe_unused komeda_pm_resume(struct device *dev)
|
||||
{
|
||||
struct komeda_drv *mdrv = dev_get_drvdata(dev);
|
||||
int err = 0;
|
||||
|
||||
if (!pm_runtime_status_suspended(dev))
|
||||
komeda_dev_resume(mdrv->mdev);
|
||||
err = komeda_dev_resume(mdrv->mdev);
|
||||
|
||||
return drm_mode_config_helper_resume(&mdrv->kms->base);
|
||||
return err ? err : drm_mode_config_helper_resume(&mdrv->kms->base);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops komeda_pm_ops = {
|
||||
|
|
|
|||
|
|
@ -670,6 +670,11 @@ static int malidp_runtime_pm_suspend(struct device *dev)
|
|||
struct drm_device *drm = dev_get_drvdata(dev);
|
||||
struct malidp_drm *malidp = drm_to_malidp(drm);
|
||||
struct malidp_hw_device *hwdev = malidp->dev;
|
||||
struct clk_bulk_data clks[] = {
|
||||
{ .clk = hwdev->pclk },
|
||||
{ .clk = hwdev->aclk },
|
||||
{ .clk = hwdev->mclk },
|
||||
};
|
||||
|
||||
/* we can only suspend if the hardware is in config mode */
|
||||
WARN_ON(!hwdev->hw->in_config_mode(hwdev));
|
||||
|
|
@ -677,9 +682,7 @@ static int malidp_runtime_pm_suspend(struct device *dev)
|
|||
malidp_se_irq_fini(hwdev);
|
||||
malidp_de_irq_fini(hwdev);
|
||||
hwdev->pm_suspended = true;
|
||||
clk_disable_unprepare(hwdev->mclk);
|
||||
clk_disable_unprepare(hwdev->aclk);
|
||||
clk_disable_unprepare(hwdev->pclk);
|
||||
clk_bulk_disable_unprepare(ARRAY_SIZE(clks), clks);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -689,10 +692,17 @@ static int malidp_runtime_pm_resume(struct device *dev)
|
|||
struct drm_device *drm = dev_get_drvdata(dev);
|
||||
struct malidp_drm *malidp = drm_to_malidp(drm);
|
||||
struct malidp_hw_device *hwdev = malidp->dev;
|
||||
struct clk_bulk_data clks[] = {
|
||||
{ .clk = hwdev->pclk },
|
||||
{ .clk = hwdev->aclk },
|
||||
{ .clk = hwdev->mclk },
|
||||
};
|
||||
int err;
|
||||
|
||||
err = clk_bulk_prepare_enable(ARRAY_SIZE(clks), clks);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
clk_prepare_enable(hwdev->pclk);
|
||||
clk_prepare_enable(hwdev->aclk);
|
||||
clk_prepare_enable(hwdev->mclk);
|
||||
hwdev->pm_suspended = false;
|
||||
malidp_de_irq_hw_init(hwdev);
|
||||
malidp_se_irq_hw_init(hwdev);
|
||||
|
|
|
|||
|
|
@ -3740,8 +3740,10 @@ void drm_dp_mst_topology_queue_probe(struct drm_dp_mst_topology_mgr *mgr)
|
|||
{
|
||||
mutex_lock(&mgr->lock);
|
||||
|
||||
if (drm_WARN_ON(mgr->dev, !mgr->mst_state || !mgr->mst_primary))
|
||||
if (!mgr->mst_state || !mgr->mst_primary) {
|
||||
drm_dbg_kms(mgr->dev, "queue_probe skipped: topology torn down\n");
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
drm_dp_mst_topology_mgr_invalidate_mstb(mgr->mst_primary);
|
||||
drm_dp_mst_queue_probe_work(mgr);
|
||||
|
|
|
|||
|
|
@ -161,22 +161,24 @@ ctx_fw_data_init(void *cpu_ptr, void *priv)
|
|||
/**
|
||||
* pvr_context_destroy_queues() - Destroy all queues attached to a context.
|
||||
* @ctx: Context to destroy queues on.
|
||||
* @cleanup_queue_entity: Whether to cleanup the queue entity e.g. context
|
||||
* creation failure path.
|
||||
*
|
||||
* Should be called when the last reference to a context object is dropped.
|
||||
* It releases all resources attached to the queues bound to this context.
|
||||
*/
|
||||
static void pvr_context_destroy_queues(struct pvr_context *ctx)
|
||||
static void pvr_context_destroy_queues(struct pvr_context *ctx, bool cleanup_queue_entity)
|
||||
{
|
||||
switch (ctx->type) {
|
||||
case DRM_PVR_CTX_TYPE_RENDER:
|
||||
pvr_queue_destroy(ctx->queues.fragment);
|
||||
pvr_queue_destroy(ctx->queues.geometry);
|
||||
pvr_queue_destroy(ctx->queues.fragment, cleanup_queue_entity);
|
||||
pvr_queue_destroy(ctx->queues.geometry, cleanup_queue_entity);
|
||||
break;
|
||||
case DRM_PVR_CTX_TYPE_COMPUTE:
|
||||
pvr_queue_destroy(ctx->queues.compute);
|
||||
pvr_queue_destroy(ctx->queues.compute, cleanup_queue_entity);
|
||||
break;
|
||||
case DRM_PVR_CTX_TYPE_TRANSFER_FRAG:
|
||||
pvr_queue_destroy(ctx->queues.transfer);
|
||||
pvr_queue_destroy(ctx->queues.transfer, cleanup_queue_entity);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -240,7 +242,7 @@ static int pvr_context_create_queues(struct pvr_context *ctx,
|
|||
return -EINVAL;
|
||||
|
||||
err_destroy_queues:
|
||||
pvr_context_destroy_queues(ctx);
|
||||
pvr_context_destroy_queues(ctx, true);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -349,7 +351,7 @@ int pvr_context_create(struct pvr_file *pvr_file, struct drm_pvr_ioctl_create_co
|
|||
pvr_fw_object_destroy(ctx->fw_obj);
|
||||
|
||||
err_destroy_queues:
|
||||
pvr_context_destroy_queues(ctx);
|
||||
pvr_context_destroy_queues(ctx, true);
|
||||
|
||||
err_free_ctx_id:
|
||||
/*
|
||||
|
|
@ -384,7 +386,7 @@ pvr_context_release(struct kref *ref_count)
|
|||
spin_unlock(&pvr_dev->ctx_list_lock);
|
||||
|
||||
xa_erase(&pvr_dev->ctx_ids, ctx->ctx_id);
|
||||
pvr_context_destroy_queues(ctx);
|
||||
pvr_context_destroy_queues(ctx, false);
|
||||
pvr_fw_object_destroy(ctx->fw_obj);
|
||||
kfree(ctx->data);
|
||||
pvr_vm_context_put(ctx->vm_ctx);
|
||||
|
|
|
|||
|
|
@ -515,7 +515,8 @@ pvr_dev_query_quirks_get(struct pvr_device *pvr_dev,
|
|||
if (err < 0)
|
||||
return err;
|
||||
|
||||
args->size = sizeof(query);
|
||||
if (args->size > sizeof(query))
|
||||
args->size = sizeof(query);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -596,7 +597,8 @@ pvr_dev_query_enhancements_get(struct pvr_device *pvr_dev,
|
|||
if (err < 0)
|
||||
return err;
|
||||
|
||||
args->size = sizeof(query);
|
||||
if (args->size > sizeof(query))
|
||||
args->size = sizeof(query);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1255,14 +1257,13 @@ pvr_set_uobj_array(const struct drm_pvr_obj_array *out, u32 min_stride, u32 obj_
|
|||
if (copy_to_user(out_ptr, in_ptr, cpy_elem_size))
|
||||
return -EFAULT;
|
||||
|
||||
out_ptr += obj_size;
|
||||
in_ptr += out->stride;
|
||||
}
|
||||
if (out->stride > obj_size &&
|
||||
clear_user(out_ptr + cpy_elem_size, out->stride - obj_size)) {
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (out->stride > obj_size &&
|
||||
clear_user(u64_to_user_ptr(out->array + obj_size),
|
||||
out->stride - obj_size)) {
|
||||
return -EFAULT;
|
||||
out_ptr += out->stride;
|
||||
in_ptr += obj_size;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1439,11 +1439,12 @@ void pvr_queue_kill(struct pvr_queue *queue)
|
|||
/**
|
||||
* pvr_queue_destroy() - Destroy a queue.
|
||||
* @queue: The queue to destroy.
|
||||
* @cleanup_queue_entity: Whether to cleanup the queue entity.
|
||||
*
|
||||
* Cleanup the queue and free the resources attached to it. Should be
|
||||
* called from the context release function.
|
||||
*/
|
||||
void pvr_queue_destroy(struct pvr_queue *queue)
|
||||
void pvr_queue_destroy(struct pvr_queue *queue, bool cleanup_queue_entity)
|
||||
{
|
||||
if (!queue)
|
||||
return;
|
||||
|
|
@ -1453,7 +1454,8 @@ void pvr_queue_destroy(struct pvr_queue *queue)
|
|||
mutex_unlock(&queue->ctx->pvr_dev->queues.lock);
|
||||
|
||||
drm_sched_fini(&queue->scheduler);
|
||||
drm_sched_entity_fini(&queue->entity);
|
||||
if (cleanup_queue_entity)
|
||||
drm_sched_entity_fini(&queue->entity);
|
||||
|
||||
if (WARN_ON(queue->last_queued_job_scheduled_fence))
|
||||
dma_fence_put(queue->last_queued_job_scheduled_fence);
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ struct pvr_queue *pvr_queue_create(struct pvr_context *ctx,
|
|||
|
||||
void pvr_queue_kill(struct pvr_queue *queue);
|
||||
|
||||
void pvr_queue_destroy(struct pvr_queue *queue);
|
||||
void pvr_queue_destroy(struct pvr_queue *queue, bool cleanup_queue_entity);
|
||||
|
||||
void pvr_queue_process(struct pvr_queue *queue);
|
||||
|
||||
|
|
|
|||
|
|
@ -1019,7 +1019,8 @@ pvr_static_data_areas_get(const struct pvr_device *pvr_dev,
|
|||
if (err < 0)
|
||||
return err;
|
||||
|
||||
args->size = sizeof(query);
|
||||
if (args->size > sizeof(query))
|
||||
args->size = sizeof(query);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1069,7 +1070,8 @@ pvr_heap_info_get(const struct pvr_device *pvr_dev,
|
|||
if (err < 0)
|
||||
return err;
|
||||
|
||||
args->size = sizeof(query);
|
||||
if (args->size > sizeof(query))
|
||||
args->size = sizeof(query);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -207,6 +207,7 @@ int panthor_device_init(struct panthor_device *ptdev)
|
|||
*dummy_page_virt = 1;
|
||||
|
||||
INIT_WORK(&ptdev->reset.work, panthor_device_reset_work);
|
||||
disable_work(&ptdev->reset.work);
|
||||
ptdev->reset.wq = alloc_ordered_workqueue("panthor-reset-wq", 0);
|
||||
if (!ptdev->reset.wq)
|
||||
return -ENOMEM;
|
||||
|
|
@ -285,6 +286,9 @@ int panthor_device_init(struct panthor_device *ptdev)
|
|||
|
||||
panthor_gem_init(ptdev);
|
||||
|
||||
/* Now that everything is initialized, we can enable the reset work. */
|
||||
enable_work(&ptdev->reset.work);
|
||||
|
||||
/* ~3 frames */
|
||||
pm_runtime_set_autosuspend_delay(ptdev->base.dev, 50);
|
||||
pm_runtime_use_autosuspend(ptdev->base.dev);
|
||||
|
|
|
|||
|
|
@ -509,9 +509,6 @@ static irqreturn_t panthor_ ## __name ## _irq_raw_handler(int irq, void *data)
|
|||
struct panthor_irq *pirq = data; \
|
||||
enum panthor_irq_state old_state; \
|
||||
\
|
||||
if (!gpu_read(pirq->iomem, INT_STAT)) \
|
||||
return IRQ_NONE; \
|
||||
\
|
||||
guard(spinlock_irqsave)(&pirq->mask_lock); \
|
||||
old_state = atomic_cmpxchg(&pirq->state, \
|
||||
PANTHOR_IRQ_STATE_ACTIVE, \
|
||||
|
|
@ -519,6 +516,13 @@ static irqreturn_t panthor_ ## __name ## _irq_raw_handler(int irq, void *data)
|
|||
if (old_state != PANTHOR_IRQ_STATE_ACTIVE) \
|
||||
return IRQ_NONE; \
|
||||
\
|
||||
if (!gpu_read(pirq->iomem, INT_STAT)) { \
|
||||
atomic_cmpxchg(&pirq->state, \
|
||||
PANTHOR_IRQ_STATE_PROCESSING, \
|
||||
PANTHOR_IRQ_STATE_ACTIVE); \
|
||||
return IRQ_NONE; \
|
||||
} \
|
||||
\
|
||||
gpu_write(pirq->iomem, INT_MASK, 0); \
|
||||
return IRQ_WAKE_THREAD; \
|
||||
} \
|
||||
|
|
@ -581,14 +585,15 @@ static inline void panthor_ ## __name ## _irq_resume(struct panthor_irq *pirq)
|
|||
\
|
||||
static int panthor_request_ ## __name ## _irq(struct panthor_device *ptdev, \
|
||||
struct panthor_irq *pirq, \
|
||||
int irq, u32 mask, void __iomem *iomem) \
|
||||
int irq, void __iomem *iomem) \
|
||||
{ \
|
||||
pirq->ptdev = ptdev; \
|
||||
pirq->irq = irq; \
|
||||
pirq->mask = mask; \
|
||||
pirq->mask = 0; \
|
||||
pirq->iomem = iomem; \
|
||||
spin_lock_init(&pirq->mask_lock); \
|
||||
panthor_ ## __name ## _irq_resume(pirq); \
|
||||
atomic_set(&pirq->state, PANTHOR_IRQ_STATE_SUSPENDED); \
|
||||
gpu_write(pirq->iomem, INT_MASK, 0); \
|
||||
\
|
||||
return devm_request_threaded_irq(ptdev->base.dev, irq, \
|
||||
panthor_ ## __name ## _irq_raw_handler, \
|
||||
|
|
|
|||
|
|
@ -1279,9 +1279,7 @@ void panthor_fw_unplug(struct panthor_device *ptdev)
|
|||
|
||||
if (!IS_ENABLED(CONFIG_PM) || pm_runtime_active(ptdev->base.dev)) {
|
||||
/* Make sure the IRQ handler cannot be called after that point. */
|
||||
if (ptdev->fw->irq.irq)
|
||||
panthor_job_irq_suspend(&ptdev->fw->irq);
|
||||
|
||||
panthor_job_irq_suspend(&ptdev->fw->irq);
|
||||
panthor_fw_stop(ptdev);
|
||||
}
|
||||
|
||||
|
|
@ -1476,7 +1474,7 @@ int panthor_fw_init(struct panthor_device *ptdev)
|
|||
if (irq <= 0)
|
||||
return -ENODEV;
|
||||
|
||||
ret = panthor_request_job_irq(ptdev, &fw->irq, irq, 0,
|
||||
ret = panthor_request_job_irq(ptdev, &fw->irq, irq,
|
||||
ptdev->iomem + JOB_INT_BASE);
|
||||
if (ret) {
|
||||
drm_err(&ptdev->base, "failed to request job irq");
|
||||
|
|
|
|||
|
|
@ -170,11 +170,12 @@ int panthor_gpu_init(struct panthor_device *ptdev)
|
|||
return irq;
|
||||
|
||||
ret = panthor_request_gpu_irq(ptdev, &ptdev->gpu->irq, irq,
|
||||
GPU_INTERRUPTS_MASK,
|
||||
ptdev->iomem + GPU_INT_BASE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
panthor_gpu_irq_enable_events(&ptdev->gpu->irq, GPU_INTERRUPTS_MASK);
|
||||
panthor_gpu_irq_resume(&ptdev->gpu->irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3262,7 +3262,6 @@ int panthor_mmu_init(struct panthor_device *ptdev)
|
|||
return -ENODEV;
|
||||
|
||||
ret = panthor_request_mmu_irq(ptdev, &mmu->irq, irq,
|
||||
panthor_mmu_fault_mask(ptdev, ~0),
|
||||
ptdev->iomem + MMU_INT_BASE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -3280,7 +3279,13 @@ int panthor_mmu_init(struct panthor_device *ptdev)
|
|||
ptdev->gpu_info.mmu_features |= BITS_PER_LONG;
|
||||
}
|
||||
|
||||
return drmm_add_action_or_reset(&ptdev->base, panthor_mmu_release_wq, mmu->vm.wq);
|
||||
ret = drmm_add_action_or_reset(&ptdev->base, panthor_mmu_release_wq, mmu->vm.wq);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
panthor_mmu_irq_enable_events(&mmu->irq, panthor_mmu_fault_mask(ptdev, ~0));
|
||||
panthor_mmu_irq_resume(&mmu->irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
|
|
|
|||
|
|
@ -453,7 +453,8 @@ void panthor_pwr_unplug(struct panthor_device *ptdev)
|
|||
return;
|
||||
|
||||
/* Make sure the IRQ handler is not running after that point. */
|
||||
panthor_pwr_irq_suspend(&ptdev->pwr->irq);
|
||||
if (!IS_ENABLED(CONFIG_PM) || pm_runtime_active(ptdev->base.dev))
|
||||
panthor_pwr_irq_suspend(&ptdev->pwr->irq);
|
||||
|
||||
/* Wake-up all waiters. */
|
||||
spin_lock_irqsave(&ptdev->pwr->reqs_lock, flags);
|
||||
|
|
@ -483,12 +484,13 @@ int panthor_pwr_init(struct panthor_device *ptdev)
|
|||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
err = panthor_request_pwr_irq(
|
||||
ptdev, &pwr->irq, irq, PWR_INTERRUPTS_MASK,
|
||||
pwr->iomem + PWR_INT_BASE);
|
||||
err = panthor_request_pwr_irq(ptdev, &pwr->irq, irq,
|
||||
pwr->iomem + PWR_INT_BASE);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
panthor_pwr_irq_enable_events(&pwr->irq, PWR_INTERRUPTS_MASK);
|
||||
panthor_pwr_irq_resume(&pwr->irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1057,7 +1057,8 @@ group_unbind_locked(struct panthor_group *group)
|
|||
|
||||
/* Tiler OOM events will be re-issued next time the group is scheduled. */
|
||||
atomic_set(&group->tiler_oom, 0);
|
||||
cancel_work(&group->tiler_oom_work);
|
||||
if (cancel_work(&group->tiler_oom_work))
|
||||
group_put(group);
|
||||
|
||||
for (u32 i = 0; i < group->queue_count; i++)
|
||||
group->queues[i]->doorbell_id = -1;
|
||||
|
|
@ -1151,15 +1152,14 @@ queue_suspend_timeout_locked(struct panthor_queue *queue)
|
|||
static void
|
||||
queue_suspend_timeout(struct panthor_queue *queue)
|
||||
{
|
||||
spin_lock(&queue->fence_ctx.lock);
|
||||
guard(spinlock_irqsave)(&queue->fence_ctx.lock);
|
||||
queue_suspend_timeout_locked(queue);
|
||||
spin_unlock(&queue->fence_ctx.lock);
|
||||
}
|
||||
|
||||
static void
|
||||
queue_resume_timeout(struct panthor_queue *queue)
|
||||
{
|
||||
spin_lock(&queue->fence_ctx.lock);
|
||||
guard(spinlock_irqsave)(&queue->fence_ctx.lock);
|
||||
|
||||
if (queue_timeout_is_suspended(queue)) {
|
||||
mod_delayed_work(queue->scheduler.timeout_wq,
|
||||
|
|
@ -1168,8 +1168,6 @@ queue_resume_timeout(struct panthor_queue *queue)
|
|||
|
||||
queue->timeout.remaining = MAX_SCHEDULE_TIMEOUT;
|
||||
}
|
||||
|
||||
spin_unlock(&queue->fence_ctx.lock);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1542,7 +1540,7 @@ cs_slot_process_fault_event_locked(struct panthor_device *ptdev,
|
|||
u64 cs_extract = queue->iface.output->extract;
|
||||
struct panthor_job *job;
|
||||
|
||||
spin_lock(&queue->fence_ctx.lock);
|
||||
guard(spinlock_irqsave)(&queue->fence_ctx.lock);
|
||||
list_for_each_entry(job, &queue->fence_ctx.in_flight_jobs, node) {
|
||||
if (cs_extract >= job->ringbuf.end)
|
||||
continue;
|
||||
|
|
@ -1552,7 +1550,6 @@ cs_slot_process_fault_event_locked(struct panthor_device *ptdev,
|
|||
|
||||
dma_fence_set_error(job->done_fence, -EINVAL);
|
||||
}
|
||||
spin_unlock(&queue->fence_ctx.lock);
|
||||
}
|
||||
|
||||
if (group) {
|
||||
|
|
@ -1604,7 +1601,10 @@ static int group_process_tiler_oom(struct panthor_group *group, u32 cs_id)
|
|||
if (unlikely(csg_id < 0))
|
||||
return 0;
|
||||
|
||||
if (IS_ERR(heaps) || frag_end > vt_end || vt_end >= vt_start) {
|
||||
if (IS_ERR(heaps)) {
|
||||
ret = -EINVAL;
|
||||
heaps = NULL;
|
||||
} else if (frag_end > vt_end || vt_end >= vt_start) {
|
||||
ret = -EINVAL;
|
||||
} else {
|
||||
/* We do the allocation without holding the scheduler lock to avoid
|
||||
|
|
@ -2183,13 +2183,13 @@ group_term_post_processing(struct panthor_group *group)
|
|||
if (!queue)
|
||||
continue;
|
||||
|
||||
spin_lock(&queue->fence_ctx.lock);
|
||||
list_for_each_entry_safe(job, tmp, &queue->fence_ctx.in_flight_jobs, node) {
|
||||
list_move_tail(&job->node, &faulty_jobs);
|
||||
dma_fence_set_error(job->done_fence, err);
|
||||
dma_fence_signal_locked(job->done_fence);
|
||||
scoped_guard(spinlock_irqsave, &queue->fence_ctx.lock) {
|
||||
list_for_each_entry_safe(job, tmp, &queue->fence_ctx.in_flight_jobs, node) {
|
||||
list_move_tail(&job->node, &faulty_jobs);
|
||||
dma_fence_set_error(job->done_fence, err);
|
||||
dma_fence_signal_locked(job->done_fence);
|
||||
}
|
||||
}
|
||||
spin_unlock(&queue->fence_ctx.lock);
|
||||
|
||||
/* Manually update the syncobj seqno to unblock waiters. */
|
||||
syncobj = group->syncobjs->kmap + (i * sizeof(*syncobj));
|
||||
|
|
@ -2368,7 +2368,13 @@ tick_ctx_apply(struct panthor_scheduler *sched, struct panthor_sched_tick_ctx *c
|
|||
|
||||
csg_iface = panthor_fw_get_csg_iface(ptdev, csg_id);
|
||||
csg_slot = &sched->csg_slots[csg_id];
|
||||
group_bind_locked(group, csg_id);
|
||||
ret = group_bind_locked(group, csg_id);
|
||||
if (ret) {
|
||||
panthor_device_schedule_reset(ptdev);
|
||||
ctx->csg_upd_failed_mask |= BIT(csg_id);
|
||||
return;
|
||||
}
|
||||
|
||||
csg_slot_prog_locked(ptdev, csg_id, new_csg_prio--);
|
||||
csgs_upd_ctx_queue_reqs(ptdev, &upd_ctx, csg_id,
|
||||
group->state == PANTHOR_CS_GROUP_SUSPENDED ?
|
||||
|
|
@ -2668,7 +2674,14 @@ static void sched_resume_tick(struct panthor_device *ptdev)
|
|||
else
|
||||
delay_jiffies = 0;
|
||||
|
||||
sched_queue_delayed_work(sched, tick, delay_jiffies);
|
||||
/* We schedule immediate ticks when we need to process events on CSGs,
|
||||
* but those don't change the resched_target because we want the other
|
||||
* groups to stay scheduled for the remaining of the GPU timeslot they
|
||||
* were given. Make sure those immediate ticks don't get overruled by
|
||||
* a sched_queue_delayed_work() that would delay the tick execution.
|
||||
*/
|
||||
if (!delayed_work_pending(&sched->tick_work))
|
||||
sched_queue_delayed_work(sched, tick, delay_jiffies);
|
||||
}
|
||||
|
||||
static void group_schedule_locked(struct panthor_group *group, u32 queue_mask)
|
||||
|
|
@ -3049,39 +3062,39 @@ static bool queue_check_job_completion(struct panthor_queue *queue)
|
|||
LIST_HEAD(done_jobs);
|
||||
|
||||
cookie = dma_fence_begin_signalling();
|
||||
spin_lock(&queue->fence_ctx.lock);
|
||||
list_for_each_entry_safe(job, job_tmp, &queue->fence_ctx.in_flight_jobs, node) {
|
||||
if (!syncobj) {
|
||||
struct panthor_group *group = job->group;
|
||||
scoped_guard(spinlock_irqsave, &queue->fence_ctx.lock) {
|
||||
list_for_each_entry_safe(job, job_tmp, &queue->fence_ctx.in_flight_jobs, node) {
|
||||
if (!syncobj) {
|
||||
struct panthor_group *group = job->group;
|
||||
|
||||
syncobj = group->syncobjs->kmap +
|
||||
(job->queue_idx * sizeof(*syncobj));
|
||||
syncobj = group->syncobjs->kmap +
|
||||
(job->queue_idx * sizeof(*syncobj));
|
||||
}
|
||||
|
||||
if (syncobj->seqno < job->done_fence->seqno)
|
||||
break;
|
||||
|
||||
list_move_tail(&job->node, &done_jobs);
|
||||
dma_fence_signal_locked(job->done_fence);
|
||||
}
|
||||
|
||||
if (syncobj->seqno < job->done_fence->seqno)
|
||||
break;
|
||||
if (list_empty(&queue->fence_ctx.in_flight_jobs)) {
|
||||
/* If we have no job left, we cancel the timer, and reset remaining
|
||||
* time to its default so it can be restarted next time
|
||||
* queue_resume_timeout() is called.
|
||||
*/
|
||||
queue_suspend_timeout_locked(queue);
|
||||
|
||||
list_move_tail(&job->node, &done_jobs);
|
||||
dma_fence_signal_locked(job->done_fence);
|
||||
/* If there's no job pending, we consider it progress to avoid a
|
||||
* spurious timeout if the timeout handler and the sync update
|
||||
* handler raced.
|
||||
*/
|
||||
progress = true;
|
||||
} else if (!list_empty(&done_jobs)) {
|
||||
queue_reset_timeout_locked(queue);
|
||||
progress = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (list_empty(&queue->fence_ctx.in_flight_jobs)) {
|
||||
/* If we have no job left, we cancel the timer, and reset remaining
|
||||
* time to its default so it can be restarted next time
|
||||
* queue_resume_timeout() is called.
|
||||
*/
|
||||
queue_suspend_timeout_locked(queue);
|
||||
|
||||
/* If there's no job pending, we consider it progress to avoid a
|
||||
* spurious timeout if the timeout handler and the sync update
|
||||
* handler raced.
|
||||
*/
|
||||
progress = true;
|
||||
} else if (!list_empty(&done_jobs)) {
|
||||
queue_reset_timeout_locked(queue);
|
||||
progress = true;
|
||||
}
|
||||
spin_unlock(&queue->fence_ctx.lock);
|
||||
dma_fence_end_signalling(cookie);
|
||||
|
||||
list_for_each_entry_safe(job, job_tmp, &done_jobs, node) {
|
||||
|
|
@ -3346,9 +3359,8 @@ queue_run_job(struct drm_sched_job *sched_job)
|
|||
job->ringbuf.end = job->ringbuf.start + (instrs.count * sizeof(u64));
|
||||
|
||||
panthor_job_get(&job->base);
|
||||
spin_lock(&queue->fence_ctx.lock);
|
||||
list_add_tail(&job->node, &queue->fence_ctx.in_flight_jobs);
|
||||
spin_unlock(&queue->fence_ctx.lock);
|
||||
scoped_guard(spinlock_irqsave, &queue->fence_ctx.lock)
|
||||
list_add_tail(&job->node, &queue->fence_ctx.in_flight_jobs);
|
||||
|
||||
/* Make sure the ring buffer is updated before the INSERT
|
||||
* register.
|
||||
|
|
|
|||
|
|
@ -897,7 +897,8 @@ static int virtio_get_edid_block(void *data, u8 *buf,
|
|||
struct virtio_gpu_resp_edid *resp = data;
|
||||
size_t start = block * EDID_LENGTH;
|
||||
|
||||
if (start + len > le32_to_cpu(resp->size))
|
||||
if (start + len > le32_to_cpu(resp->size) ||
|
||||
start + len > sizeof(resp->edid))
|
||||
return -EINVAL;
|
||||
memcpy(buf, resp->edid + start, len);
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -115,6 +115,7 @@ struct drm_dp_vsc_sdp {
|
|||
* @duration_decr_ms: Successive frame duration decrease
|
||||
* @target_rr_divider: Target refresh rate divider
|
||||
* @mode: Adaptive Sync Operation Mode
|
||||
* @coasting_vtotal: Coasting vtotal
|
||||
*/
|
||||
struct drm_dp_as_sdp {
|
||||
unsigned char sdp_type;
|
||||
|
|
|
|||
|
|
@ -79,7 +79,8 @@ static inline u32 dfixed_div(fixed20_12 A, fixed20_12 B)
|
|||
#define DRM_FIXED_ALMOST_ONE (DRM_FIXED_ONE - DRM_FIXED_EPSILON)
|
||||
|
||||
/**
|
||||
* @drm_sm2fixp
|
||||
* drm_sm2fixp() - convert signed-magnitude to fixed point
|
||||
* @a: 1.31.32 signed-magnitude fixed point
|
||||
*
|
||||
* Convert a 1.31.32 signed-magnitude fixed point to 32.32
|
||||
* 2s-complement fixed point
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
#ifndef __DRM_RAS_H__
|
||||
#define __DRM_RAS_H__
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <uapi/drm/drm_ras.h>
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user