Commit b7a57386 authored by Dave Airlie's avatar Dave Airlie

Merge tag 'drm-misc-fixes-2023-07-13' of ssh://git.freedesktop.org/git/drm/drm-misc into drm-fixes

A couple of nouveau patches addressing improving HDMI support and
firmware handling, a fix for TTM to skip pinned BO when evicting, and a
fix for the fbdev documentation.
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>

From: Maxime Ripard <mripard@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/nq3ke75juephbex5acfyi5t6bxv22nhmfcpfhru55haj2nv3us@gehrlmjbqgjk
parents 06c2afb8 835a65f5
......@@ -75,6 +75,7 @@ struct ivpu_wa_table {
bool punit_disabled;
bool clear_runtime_mem;
bool d3hot_after_power_off;
bool interrupt_clear_with_0;
};
struct ivpu_hw_info;
......
......@@ -101,6 +101,9 @@ static void ivpu_hw_wa_init(struct ivpu_device *vdev)
vdev->wa.punit_disabled = ivpu_is_fpga(vdev);
vdev->wa.clear_runtime_mem = false;
vdev->wa.d3hot_after_power_off = true;
if (ivpu_device_id(vdev) == PCI_DEVICE_ID_MTL && ivpu_revision(vdev) < 4)
vdev->wa.interrupt_clear_with_0 = true;
}
static void ivpu_hw_timeouts_init(struct ivpu_device *vdev)
......@@ -885,7 +888,7 @@ static void ivpu_hw_mtl_irq_disable(struct ivpu_device *vdev)
REGB_WR32(MTL_BUTTRESS_GLOBAL_INT_MASK, 0x1);
REGB_WR32(MTL_BUTTRESS_LOCAL_INT_MASK, BUTTRESS_IRQ_DISABLE_MASK);
REGV_WR64(MTL_VPU_HOST_SS_ICB_ENABLE_0, 0x0ull);
REGB_WR32(MTL_VPU_HOST_SS_FW_SOC_IRQ_EN, 0x0);
REGV_WR32(MTL_VPU_HOST_SS_FW_SOC_IRQ_EN, 0x0);
}
static void ivpu_hw_mtl_irq_wdt_nce_handler(struct ivpu_device *vdev)
......@@ -973,12 +976,15 @@ static u32 ivpu_hw_mtl_irqb_handler(struct ivpu_device *vdev, int irq)
schedule_recovery = true;
}
/* This must be done after interrupts are cleared at the source. */
if (IVPU_WA(interrupt_clear_with_0))
/*
* Clear local interrupt status by writing 0 to all bits.
* This must be done after interrupts are cleared at the source.
* Writing 1 triggers an interrupt, so we can't perform read update write.
* Clear local interrupt status by writing 0 to all bits.
*/
REGB_WR32(MTL_BUTTRESS_INTERRUPT_STAT, 0x0);
else
REGB_WR32(MTL_BUTTRESS_INTERRUPT_STAT, status);
/* Re-enable global interrupt */
REGB_WR32(MTL_BUTTRESS_GLOBAL_INT_MASK, 0x0);
......
......@@ -66,18 +66,36 @@ struct dma_fence *__dma_fence_unwrap_merge(unsigned int num_fences,
{
struct dma_fence_array *result;
struct dma_fence *tmp, **array;
ktime_t timestamp;
unsigned int i;
size_t count;
count = 0;
timestamp = ns_to_ktime(0);
for (i = 0; i < num_fences; ++i) {
dma_fence_unwrap_for_each(tmp, &iter[i], fences[i])
if (!dma_fence_is_signaled(tmp))
dma_fence_unwrap_for_each(tmp, &iter[i], fences[i]) {
if (!dma_fence_is_signaled(tmp)) {
++count;
} else if (test_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT,
&tmp->flags)) {
if (ktime_after(tmp->timestamp, timestamp))
timestamp = tmp->timestamp;
} else {
/*
* Use the current time if the fence is
* currently signaling.
*/
timestamp = ktime_get();
}
}
}
/*
* If we couldn't find a pending fence just return a private signaled
* fence with the timestamp of the last signaled one.
*/
if (count == 0)
return dma_fence_get_stub();
return dma_fence_allocate_private_stub(timestamp);
array = kmalloc_array(count, sizeof(*array), GFP_KERNEL);
if (!array)
......@@ -138,7 +156,7 @@ struct dma_fence *__dma_fence_unwrap_merge(unsigned int num_fences,
} while (tmp);
if (count == 0) {
tmp = dma_fence_get_stub();
tmp = dma_fence_allocate_private_stub(ktime_get());
goto return_tmp;
}
......
......@@ -150,16 +150,17 @@ EXPORT_SYMBOL(dma_fence_get_stub);
/**
* dma_fence_allocate_private_stub - return a private, signaled fence
* @timestamp: timestamp when the fence was signaled
*
* Return a newly allocated and signaled stub fence.
*/
struct dma_fence *dma_fence_allocate_private_stub(void)
struct dma_fence *dma_fence_allocate_private_stub(ktime_t timestamp)
{
struct dma_fence *fence;
fence = kzalloc(sizeof(*fence), GFP_KERNEL);
if (fence == NULL)
return ERR_PTR(-ENOMEM);
return NULL;
dma_fence_init(fence,
&dma_fence_stub_ops,
......@@ -169,7 +170,7 @@ struct dma_fence *dma_fence_allocate_private_stub(void)
set_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT,
&fence->flags);
dma_fence_signal(fence);
dma_fence_signal_timestamp(fence, timestamp);
return fence;
}
......
......@@ -209,10 +209,6 @@ void armada_fbdev_setup(struct drm_device *dev)
goto err_drm_client_init;
}
ret = armada_fbdev_client_hotplug(&fbh->client);
if (ret)
drm_dbg_kms(dev, "client hotplug ret=%d\n", ret);
drm_client_register(&fbh->client);
return;
......
......@@ -1426,9 +1426,9 @@ void dw_hdmi_set_high_tmds_clock_ratio(struct dw_hdmi *hdmi,
/* Control for TMDS Bit Period/TMDS Clock-Period Ratio */
if (dw_hdmi_support_scdc(hdmi, display)) {
if (mtmdsclock > HDMI14_MAX_TMDSCLK)
drm_scdc_set_high_tmds_clock_ratio(&hdmi->connector, 1);
drm_scdc_set_high_tmds_clock_ratio(hdmi->curr_conn, 1);
else
drm_scdc_set_high_tmds_clock_ratio(&hdmi->connector, 0);
drm_scdc_set_high_tmds_clock_ratio(hdmi->curr_conn, 0);
}
}
EXPORT_SYMBOL_GPL(dw_hdmi_set_high_tmds_clock_ratio);
......@@ -2116,7 +2116,7 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
min_t(u8, bytes, SCDC_MIN_SOURCE_VERSION));
/* Enabled Scrambling in the Sink */
drm_scdc_set_scrambling(&hdmi->connector, 1);
drm_scdc_set_scrambling(hdmi->curr_conn, 1);
/*
* To activate the scrambler feature, you must ensure
......@@ -2132,7 +2132,7 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
hdmi_writeb(hdmi, 0, HDMI_FC_SCRAMBLER_CTRL);
hdmi_writeb(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ,
HDMI_MC_SWRSTZ);
drm_scdc_set_scrambling(&hdmi->connector, 0);
drm_scdc_set_scrambling(hdmi->curr_conn, 0);
}
}
......@@ -3553,6 +3553,7 @@ struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev,
hdmi->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID
| DRM_BRIDGE_OP_HPD;
hdmi->bridge.interlace_allowed = true;
hdmi->bridge.ddc = hdmi->ddc;
#ifdef CONFIG_OF
hdmi->bridge.of_node = pdev->dev.of_node;
#endif
......
......@@ -170,10 +170,10 @@
* @pwm_refclk_freq: Cache for the reference clock input to the PWM.
*/
struct ti_sn65dsi86 {
struct auxiliary_device bridge_aux;
struct auxiliary_device gpio_aux;
struct auxiliary_device aux_aux;
struct auxiliary_device pwm_aux;
struct auxiliary_device *bridge_aux;
struct auxiliary_device *gpio_aux;
struct auxiliary_device *aux_aux;
struct auxiliary_device *pwm_aux;
struct device *dev;
struct regmap *regmap;
......@@ -468,27 +468,34 @@ static void ti_sn65dsi86_delete_aux(void *data)
auxiliary_device_delete(data);
}
/*
* AUX bus docs say that a non-NULL release is mandatory, but it makes no
* sense for the model used here where all of the aux devices are allocated
* in the single shared structure. We'll use this noop as a workaround.
*/
static void ti_sn65dsi86_noop(struct device *dev) {}
static void ti_sn65dsi86_aux_device_release(struct device *dev)
{
struct auxiliary_device *aux = container_of(dev, struct auxiliary_device, dev);
kfree(aux);
}
static int ti_sn65dsi86_add_aux_device(struct ti_sn65dsi86 *pdata,
struct auxiliary_device *aux,
struct auxiliary_device **aux_out,
const char *name)
{
struct device *dev = pdata->dev;
struct auxiliary_device *aux;
int ret;
aux = kzalloc(sizeof(*aux), GFP_KERNEL);
if (!aux)
return -ENOMEM;
aux->name = name;
aux->dev.parent = dev;
aux->dev.release = ti_sn65dsi86_noop;
aux->dev.release = ti_sn65dsi86_aux_device_release;
device_set_of_node_from_dev(&aux->dev, dev);
ret = auxiliary_device_init(aux);
if (ret)
if (ret) {
kfree(aux);
return ret;
}
ret = devm_add_action_or_reset(dev, ti_sn65dsi86_uninit_aux, aux);
if (ret)
return ret;
......@@ -497,6 +504,8 @@ static int ti_sn65dsi86_add_aux_device(struct ti_sn65dsi86 *pdata,
if (ret)
return ret;
ret = devm_add_action_or_reset(dev, ti_sn65dsi86_delete_aux, aux);
if (!ret)
*aux_out = aux;
return ret;
}
......
......@@ -122,13 +122,34 @@ EXPORT_SYMBOL(drm_client_init);
* drm_client_register() it is no longer permissible to call drm_client_release()
* directly (outside the unregister callback), instead cleanup will happen
* automatically on driver unload.
*
* Registering a client generates a hotplug event that allows the client
* to set up its display from pre-existing outputs. The client must have
* initialized its state to able to handle the hotplug event successfully.
*/
void drm_client_register(struct drm_client_dev *client)
{
struct drm_device *dev = client->dev;
int ret;
mutex_lock(&dev->clientlist_mutex);
list_add(&client->list, &dev->clientlist);
if (client->funcs && client->funcs->hotplug) {
/*
* Perform an initial hotplug event to pick up the
* display configuration for the client. This step
* has to be performed *after* registering the client
* in the list of clients, or a concurrent hotplug
* event might be lost; leaving the display off.
*
* Hold the clientlist_mutex as for a regular hotplug
* event.
*/
ret = client->funcs->hotplug(client);
if (ret)
drm_dbg_kms(dev, "client hotplug ret=%d\n", ret);
}
mutex_unlock(&dev->clientlist_mutex);
}
EXPORT_SYMBOL(drm_client_register);
......
......@@ -217,7 +217,7 @@ static const struct drm_client_funcs drm_fbdev_dma_client_funcs = {
* drm_fbdev_dma_setup() - Setup fbdev emulation for GEM DMA helpers
* @dev: DRM device
* @preferred_bpp: Preferred bits per pixel for the device.
* @dev->mode_config.preferred_depth is used if this is zero.
* 32 is used if this is zero.
*
* This function sets up fbdev emulation for GEM DMA drivers that support
* dumb buffers with a virtual address and that can be mmap'ed.
......@@ -252,10 +252,6 @@ void drm_fbdev_dma_setup(struct drm_device *dev, unsigned int preferred_bpp)
goto err_drm_client_init;
}
ret = drm_fbdev_dma_client_hotplug(&fb_helper->client);
if (ret)
drm_dbg_kms(dev, "client hotplug ret=%d\n", ret);
drm_client_register(&fb_helper->client);
return;
......
......@@ -339,10 +339,6 @@ void drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp)
goto err_drm_client_init;
}
ret = drm_fbdev_generic_client_hotplug(&fb_helper->client);
if (ret)
drm_dbg_kms(dev, "client hotplug ret=%d\n", ret);
drm_client_register(&fb_helper->client);
return;
......
......@@ -353,10 +353,10 @@ EXPORT_SYMBOL(drm_syncobj_replace_fence);
*/
static int drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj)
{
struct dma_fence *fence = dma_fence_allocate_private_stub();
struct dma_fence *fence = dma_fence_allocate_private_stub(ktime_get());
if (IS_ERR(fence))
return PTR_ERR(fence);
if (!fence)
return -ENOMEM;
drm_syncobj_replace_fence(syncobj, fence);
dma_fence_put(fence);
......
......@@ -215,10 +215,6 @@ void exynos_drm_fbdev_setup(struct drm_device *dev)
if (ret)
goto err_drm_client_init;
ret = exynos_drm_fbdev_client_hotplug(&fb_helper->client);
if (ret)
drm_dbg_kms(dev, "client hotplug ret=%d\n", ret);
drm_client_register(&fb_helper->client);
return;
......
......@@ -328,10 +328,6 @@ void psb_fbdev_setup(struct drm_psb_private *dev_priv)
goto err_drm_fb_helper_unprepare;
}
ret = psb_fbdev_client_hotplug(&fb_helper->client);
if (ret)
drm_dbg_kms(dev, "client hotplug ret=%d\n", ret);
drm_client_register(&fb_helper->client);
return;
......
......@@ -246,10 +246,6 @@ void msm_fbdev_setup(struct drm_device *dev)
goto err_drm_fb_helper_unprepare;
}
ret = msm_fbdev_client_hotplug(&helper->client);
if (ret)
drm_dbg_kms(dev, "client hotplug ret=%d\n", ret);
drm_client_register(&helper->client);
return;
......
......@@ -910,15 +910,19 @@ nv50_msto_prepare(struct drm_atomic_state *state,
struct nouveau_drm *drm = nouveau_drm(msto->encoder.dev);
struct nv50_mstc *mstc = msto->mstc;
struct nv50_mstm *mstm = mstc->mstm;
struct drm_dp_mst_atomic_payload *payload;
struct drm_dp_mst_topology_state *old_mst_state;
struct drm_dp_mst_atomic_payload *payload, *old_payload;
NV_ATOMIC(drm, "%s: msto prepare\n", msto->encoder.name);
old_mst_state = drm_atomic_get_old_mst_topology_state(state, mgr);
payload = drm_atomic_get_mst_payload_state(mst_state, mstc->port);
old_payload = drm_atomic_get_mst_payload_state(old_mst_state, mstc->port);
// TODO: Figure out if we want to do a better job of handling VCPI allocation failures here?
if (msto->disabled) {
drm_dp_remove_payload(mgr, mst_state, payload, payload);
drm_dp_remove_payload(mgr, mst_state, old_payload, payload);
nvif_outp_dp_mst_vcpi(&mstm->outp->outp, msto->head->base.index, 0, 0, 0, 0);
} else {
......
......@@ -90,6 +90,7 @@ nouveau_channel_del(struct nouveau_channel **pchan)
if (cli)
nouveau_svmm_part(chan->vmm->svmm, chan->inst);
nvif_object_dtor(&chan->blit);
nvif_object_dtor(&chan->nvsw);
nvif_object_dtor(&chan->gart);
nvif_object_dtor(&chan->vram);
......
......@@ -53,6 +53,7 @@ struct nouveau_channel {
u32 user_put;
struct nvif_object user;
struct nvif_object blit;
struct nvif_event kill;
atomic_t killed;
......
......@@ -375,15 +375,29 @@ nouveau_accel_gr_init(struct nouveau_drm *drm)
ret = nvif_object_ctor(&drm->channel->user, "drmNvsw",
NVDRM_NVSW, nouveau_abi16_swclass(drm),
NULL, 0, &drm->channel->nvsw);
if (ret == 0 && device->info.chipset >= 0x11) {
ret = nvif_object_ctor(&drm->channel->user, "drmBlit",
0x005f, 0x009f,
NULL, 0, &drm->channel->blit);
}
if (ret == 0) {
struct nvif_push *push = drm->channel->chan.push;
ret = PUSH_WAIT(push, 2);
if (ret == 0)
ret = PUSH_WAIT(push, 8);
if (ret == 0) {
if (device->info.chipset >= 0x11) {
PUSH_NVSQ(push, NV05F, 0x0000, drm->channel->blit.handle);
PUSH_NVSQ(push, NV09F, 0x0120, 0,
0x0124, 1,
0x0128, 2);
}
PUSH_NVSQ(push, NV_SW, 0x0000, drm->channel->nvsw.handle);
}
}
if (ret) {
NV_ERROR(drm, "failed to allocate sw class, %d\n", ret);
NV_ERROR(drm, "failed to allocate sw or blit class, %d\n", ret);
nouveau_accel_gr_fini(drm);
return;
}
......
......@@ -295,6 +295,7 @@ g94_sor = {
.clock = nv50_sor_clock,
.war_2 = g94_sor_war_2,
.war_3 = g94_sor_war_3,
.hdmi = &g84_sor_hdmi,
.dp = &g94_sor_dp,
};
......
......@@ -125,7 +125,7 @@ gt215_sor_hdmi_infoframe_avi(struct nvkm_ior *ior, int head, void *data, u32 siz
pack_hdmi_infoframe(&avi, data, size);
nvkm_mask(device, 0x61c520 + soff, 0x00000001, 0x00000000);
if (size)
if (!size)
return;
nvkm_wr32(device, 0x61c528 + soff, avi.header);
......
......@@ -224,7 +224,7 @@ nvkm_acr_oneinit(struct nvkm_subdev *subdev)
u64 falcons;
int ret, i;
if (list_empty(&acr->hsfw)) {
if (list_empty(&acr->hsfw) || !acr->func || !acr->func->wpr_layout) {
nvkm_debug(subdev, "No HSFW(s)\n");
nvkm_acr_cleanup(acr);
return 0;
......
......@@ -318,10 +318,6 @@ void omap_fbdev_setup(struct drm_device *dev)
INIT_WORK(&fbdev->work, pan_worker);
ret = omap_fbdev_client_hotplug(&helper->client);
if (ret)
drm_dbg_kms(dev, "client hotplug ret=%d\n", ret);
drm_client_register(&helper->client);
return;
......
......@@ -2178,6 +2178,7 @@ static const struct panel_desc innolux_at043tn24 = {
.height = 54,
},
.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
.connector_type = DRM_MODE_CONNECTOR_DPI,
.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE,
};
......@@ -3202,6 +3203,7 @@ static const struct drm_display_mode powertip_ph800480t013_idf02_mode = {
.vsync_start = 480 + 49,
.vsync_end = 480 + 49 + 2,
.vtotal = 480 + 49 + 2 + 22,
.flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
};
static const struct panel_desc powertip_ph800480t013_idf02 = {
......
......@@ -383,10 +383,6 @@ void radeon_fbdev_setup(struct radeon_device *rdev)
goto err_drm_client_init;
}
ret = radeon_fbdev_client_hotplug(&fb_helper->client);
if (ret)
drm_dbg_kms(rdev->ddev, "client hotplug ret=%d\n", ret);
drm_client_register(&fb_helper->client);
return;
......
......@@ -176,16 +176,32 @@ static void drm_sched_entity_kill_jobs_cb(struct dma_fence *f,
{
struct drm_sched_job *job = container_of(cb, struct drm_sched_job,
finish_cb);
int r;
unsigned long index;
dma_fence_put(f);
/* Wait for all dependencies to avoid data corruptions */
while (!xa_empty(&job->dependencies)) {
f = xa_erase(&job->dependencies, job->last_dependency++);
r = dma_fence_add_callback(f, &job->finish_cb,
drm_sched_entity_kill_jobs_cb);
if (!r)
xa_for_each(&job->dependencies, index, f) {
struct drm_sched_fence *s_fence = to_drm_sched_fence(f);
if (s_fence && f == &s_fence->scheduled) {
/* The dependencies array had a reference on the scheduled
* fence, and the finished fence refcount might have
* dropped to zero. Use dma_fence_get_rcu() so we get
* a NULL fence in that case.
*/
f = dma_fence_get_rcu(&s_fence->finished);
/* Now that we have a reference on the finished fence,
* we can release the reference the dependencies array
* had on the scheduled fence.
*/
dma_fence_put(&s_fence->scheduled);
}
xa_erase(&job->dependencies, index);
if (f && !dma_fence_add_callback(f, &job->finish_cb,
drm_sched_entity_kill_jobs_cb))
return;
dma_fence_put(f);
......@@ -415,8 +431,17 @@ static struct dma_fence *
drm_sched_job_dependency(struct drm_sched_job *job,
struct drm_sched_entity *entity)
{
if (!xa_empty(&job->dependencies))
return xa_erase(&job->dependencies, job->last_dependency++);
struct dma_fence *f;
/* We keep the fence around, so we can iterate over all dependencies
* in drm_sched_entity_kill_jobs_cb() to ensure all deps are signaled
* before killing the job.
*/
f = xa_load(&job->dependencies, job->last_dependency);
if (f) {
job->last_dependency++;
return dma_fence_get(f);
}
if (job->sched->ops->prepare_job)
return job->sched->ops->prepare_job(job, entity);
......
......@@ -48,8 +48,32 @@ static void __exit drm_sched_fence_slab_fini(void)
kmem_cache_destroy(sched_fence_slab);
}
void drm_sched_fence_scheduled(struct drm_sched_fence *fence)
static void drm_sched_fence_set_parent(struct drm_sched_fence *s_fence,
struct dma_fence *fence)
{
/*
* smp_store_release() to ensure another thread racing us
* in drm_sched_fence_set_deadline_finished() sees the
* fence's parent set before test_bit()
*/
smp_store_release(&s_fence->parent, dma_fence_get(fence));
if (test_bit(DRM_SCHED_FENCE_FLAG_HAS_DEADLINE_BIT,
&s_fence->finished.flags))
dma_fence_set_deadline(fence, s_fence->deadline);
}
void drm_sched_fence_scheduled(struct drm_sched_fence *fence,
struct dma_fence *parent)
{
/* Set the parent before signaling the scheduled fence, such that,
* any waiter expecting the parent to be filled after the job has
* been scheduled (which is the case for drivers delegating waits
* to some firmware) doesn't have to busy wait for parent to show
* up.
*/
if (!IS_ERR_OR_NULL(parent))
drm_sched_fence_set_parent(fence, parent);
dma_fence_signal(&fence->scheduled);
}
......@@ -181,20 +205,6 @@ struct drm_sched_fence *to_drm_sched_fence(struct dma_fence *f)
}
EXPORT_SYMBOL(to_drm_sched_fence);
void drm_sched_fence_set_parent(struct drm_sched_fence *s_fence,
struct dma_fence *fence)
{
/*
* smp_store_release() to ensure another thread racing us
* in drm_sched_fence_set_deadline_finished() sees the
* fence's parent set before test_bit()
*/
smp_store_release(&s_fence->parent, dma_fence_get(fence));
if (test_bit(DRM_SCHED_FENCE_FLAG_HAS_DEADLINE_BIT,
&s_fence->finished.flags))
dma_fence_set_deadline(fence, s_fence->deadline);
}
struct drm_sched_fence *drm_sched_fence_alloc(struct drm_sched_entity *entity,
void *owner)
{
......
......@@ -1043,10 +1043,9 @@ static int drm_sched_main(void *param)
trace_drm_run_job(sched_job, entity);
fence = sched->ops->run_job(sched_job);
complete_all(&entity->entity_idle);
drm_sched_fence_scheduled(s_fence);
drm_sched_fence_scheduled(s_fence, fence);
if (!IS_ERR_OR_NULL(fence)) {
drm_sched_fence_set_parent(s_fence, fence);
/* Drop for original kref_init of the fence */
dma_fence_put(fence);
......
......@@ -225,10 +225,6 @@ void tegra_fbdev_setup(struct drm_device *dev)
if (ret)
goto err_drm_client_init;
ret = tegra_fbdev_client_hotplug(&helper->client);
if (ret)
drm_dbg_kms(dev, "client hotplug ret=%d\n", ret);
drm_client_register(&helper->client);
return;
......
......@@ -458,18 +458,18 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo,
goto out;
}
bounce:
do {
ret = ttm_bo_handle_move_mem(bo, evict_mem, true, ctx, &hop);
if (ret == -EMULTIHOP) {
if (ret != -EMULTIHOP)
break;
ret = ttm_bo_bounce_temp_buffer(bo, &evict_mem, ctx, &hop);
} while (!ret);
if (ret) {
ttm_resource_free(bo, &evict_mem);
if (ret != -ERESTARTSYS && ret != -EINTR)
pr_err("Buffer eviction failed\n");
ttm_resource_free(bo, &evict_mem);
goto out;
}
/* try and move to final place now. */
goto bounce;
}
out:
return ret;
......@@ -517,6 +517,12 @@ static bool ttm_bo_evict_swapout_allowable(struct ttm_buffer_object *bo,
{
bool ret = false;
if (bo->pin_count) {
*locked = false;
*busy = false;
return false;
}
if (bo->base.resv == ctx->resv) {
dma_resv_assert_held(bo->base.resv);
if (ctx->allow_res_evict)
......@@ -1167,6 +1173,7 @@ int ttm_bo_swapout(struct ttm_buffer_object *bo, struct ttm_operation_ctx *ctx,
ret = ttm_bo_handle_move_mem(bo, evict_mem, true, &ctx, &hop);
if (unlikely(ret != 0)) {
WARN(ret == -EMULTIHOP, "Unexpected multihop in swaput - likely driver bug.\n");
ttm_resource_free(bo, &evict_mem);
goto out;
}
}
......
......@@ -86,6 +86,8 @@ static void ttm_lru_bulk_move_pos_tail(struct ttm_lru_bulk_move_pos *pos,
struct ttm_resource *res)
{
if (pos->last != res) {
if (pos->first == res)
pos->first = list_next_entry(res, lru);
list_move(&res->lru, &pos->last->lru);
pos->last = res;
}
......@@ -111,7 +113,8 @@ static void ttm_lru_bulk_move_del(struct ttm_lru_bulk_move *bulk,
{
struct ttm_lru_bulk_move_pos *pos = ttm_lru_bulk_move_pos(bulk, res);
if (unlikely(pos->first == res && pos->last == res)) {
if (unlikely(WARN_ON(!pos->first || !pos->last) ||
(pos->first == res && pos->last == res))) {
pos->first = NULL;
pos->last = NULL;
} else if (pos->first == res) {
......
......@@ -583,15 +583,14 @@ void drm_sched_entity_set_priority(struct drm_sched_entity *entity,
bool drm_sched_entity_is_ready(struct drm_sched_entity *entity);
int drm_sched_entity_error(struct drm_sched_entity *entity);
void drm_sched_fence_set_parent(struct drm_sched_fence *s_fence,
struct dma_fence *fence);
struct drm_sched_fence *drm_sched_fence_alloc(
struct drm_sched_entity *s_entity, void *owner);
void drm_sched_fence_init(struct drm_sched_fence *fence,
struct drm_sched_entity *entity);
void drm_sched_fence_free(struct drm_sched_fence *fence);
void drm_sched_fence_scheduled(struct drm_sched_fence *fence);
void drm_sched_fence_scheduled(struct drm_sched_fence *fence,
struct dma_fence *parent);
void drm_sched_fence_finished(struct drm_sched_fence *fence, int result);
unsigned long drm_sched_suspend_timeout(struct drm_gpu_scheduler *sched);
......
......@@ -606,7 +606,7 @@ static inline signed long dma_fence_wait(struct dma_fence *fence, bool intr)
void dma_fence_set_deadline(struct dma_fence *fence, ktime_t deadline);
struct dma_fence *dma_fence_get_stub(void);
struct dma_fence *dma_fence_allocate_private_stub(void);
struct dma_fence *dma_fence_allocate_private_stub(ktime_t timestamp);
u64 dma_fence_context_alloc(unsigned num);
extern const struct dma_fence_ops dma_fence_array_ops;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment