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 { ...@@ -75,6 +75,7 @@ struct ivpu_wa_table {
bool punit_disabled; bool punit_disabled;
bool clear_runtime_mem; bool clear_runtime_mem;
bool d3hot_after_power_off; bool d3hot_after_power_off;
bool interrupt_clear_with_0;
}; };
struct ivpu_hw_info; struct ivpu_hw_info;
......
...@@ -101,6 +101,9 @@ static void ivpu_hw_wa_init(struct ivpu_device *vdev) ...@@ -101,6 +101,9 @@ static void ivpu_hw_wa_init(struct ivpu_device *vdev)
vdev->wa.punit_disabled = ivpu_is_fpga(vdev); vdev->wa.punit_disabled = ivpu_is_fpga(vdev);
vdev->wa.clear_runtime_mem = false; vdev->wa.clear_runtime_mem = false;
vdev->wa.d3hot_after_power_off = true; 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) 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) ...@@ -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_GLOBAL_INT_MASK, 0x1);
REGB_WR32(MTL_BUTTRESS_LOCAL_INT_MASK, BUTTRESS_IRQ_DISABLE_MASK); REGB_WR32(MTL_BUTTRESS_LOCAL_INT_MASK, BUTTRESS_IRQ_DISABLE_MASK);
REGV_WR64(MTL_VPU_HOST_SS_ICB_ENABLE_0, 0x0ull); 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) 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) ...@@ -973,12 +976,15 @@ static u32 ivpu_hw_mtl_irqb_handler(struct ivpu_device *vdev, int irq)
schedule_recovery = true; schedule_recovery = true;
} }
/* /* This must be done after interrupts are cleared at the source. */
* Clear local interrupt status by writing 0 to all bits. if (IVPU_WA(interrupt_clear_with_0))
* This must be done after interrupts are cleared at the source. /*
* Writing 1 triggers an interrupt, so we can't perform read update write. * 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); */
REGB_WR32(MTL_BUTTRESS_INTERRUPT_STAT, 0x0);
else
REGB_WR32(MTL_BUTTRESS_INTERRUPT_STAT, status);
/* Re-enable global interrupt */ /* Re-enable global interrupt */
REGB_WR32(MTL_BUTTRESS_GLOBAL_INT_MASK, 0x0); REGB_WR32(MTL_BUTTRESS_GLOBAL_INT_MASK, 0x0);
......
...@@ -66,18 +66,36 @@ struct dma_fence *__dma_fence_unwrap_merge(unsigned int num_fences, ...@@ -66,18 +66,36 @@ struct dma_fence *__dma_fence_unwrap_merge(unsigned int num_fences,
{ {
struct dma_fence_array *result; struct dma_fence_array *result;
struct dma_fence *tmp, **array; struct dma_fence *tmp, **array;
ktime_t timestamp;
unsigned int i; unsigned int i;
size_t count; size_t count;
count = 0; count = 0;
timestamp = ns_to_ktime(0);
for (i = 0; i < num_fences; ++i) { for (i = 0; i < num_fences; ++i) {
dma_fence_unwrap_for_each(tmp, &iter[i], fences[i]) dma_fence_unwrap_for_each(tmp, &iter[i], fences[i]) {
if (!dma_fence_is_signaled(tmp)) if (!dma_fence_is_signaled(tmp)) {
++count; ++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) if (count == 0)
return dma_fence_get_stub(); return dma_fence_allocate_private_stub(timestamp);
array = kmalloc_array(count, sizeof(*array), GFP_KERNEL); array = kmalloc_array(count, sizeof(*array), GFP_KERNEL);
if (!array) if (!array)
...@@ -138,7 +156,7 @@ struct dma_fence *__dma_fence_unwrap_merge(unsigned int num_fences, ...@@ -138,7 +156,7 @@ struct dma_fence *__dma_fence_unwrap_merge(unsigned int num_fences,
} while (tmp); } while (tmp);
if (count == 0) { if (count == 0) {
tmp = dma_fence_get_stub(); tmp = dma_fence_allocate_private_stub(ktime_get());
goto return_tmp; goto return_tmp;
} }
......
...@@ -150,16 +150,17 @@ EXPORT_SYMBOL(dma_fence_get_stub); ...@@ -150,16 +150,17 @@ EXPORT_SYMBOL(dma_fence_get_stub);
/** /**
* dma_fence_allocate_private_stub - return a private, signaled fence * 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. * 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; struct dma_fence *fence;
fence = kzalloc(sizeof(*fence), GFP_KERNEL); fence = kzalloc(sizeof(*fence), GFP_KERNEL);
if (fence == NULL) if (fence == NULL)
return ERR_PTR(-ENOMEM); return NULL;
dma_fence_init(fence, dma_fence_init(fence,
&dma_fence_stub_ops, &dma_fence_stub_ops,
...@@ -169,7 +170,7 @@ struct dma_fence *dma_fence_allocate_private_stub(void) ...@@ -169,7 +170,7 @@ struct dma_fence *dma_fence_allocate_private_stub(void)
set_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT, set_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT,
&fence->flags); &fence->flags);
dma_fence_signal(fence); dma_fence_signal_timestamp(fence, timestamp);
return fence; return fence;
} }
......
...@@ -209,10 +209,6 @@ void armada_fbdev_setup(struct drm_device *dev) ...@@ -209,10 +209,6 @@ void armada_fbdev_setup(struct drm_device *dev)
goto err_drm_client_init; 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); drm_client_register(&fbh->client);
return; return;
......
...@@ -1426,9 +1426,9 @@ void dw_hdmi_set_high_tmds_clock_ratio(struct dw_hdmi *hdmi, ...@@ -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 */ /* Control for TMDS Bit Period/TMDS Clock-Period Ratio */
if (dw_hdmi_support_scdc(hdmi, display)) { if (dw_hdmi_support_scdc(hdmi, display)) {
if (mtmdsclock > HDMI14_MAX_TMDSCLK) 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 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); EXPORT_SYMBOL_GPL(dw_hdmi_set_high_tmds_clock_ratio);
...@@ -2116,7 +2116,7 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi, ...@@ -2116,7 +2116,7 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
min_t(u8, bytes, SCDC_MIN_SOURCE_VERSION)); min_t(u8, bytes, SCDC_MIN_SOURCE_VERSION));
/* Enabled Scrambling in the Sink */ /* 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 * To activate the scrambler feature, you must ensure
...@@ -2132,7 +2132,7 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi, ...@@ -2132,7 +2132,7 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
hdmi_writeb(hdmi, 0, HDMI_FC_SCRAMBLER_CTRL); hdmi_writeb(hdmi, 0, HDMI_FC_SCRAMBLER_CTRL);
hdmi_writeb(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ, hdmi_writeb(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ,
HDMI_MC_SWRSTZ); 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, ...@@ -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 hdmi->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID
| DRM_BRIDGE_OP_HPD; | DRM_BRIDGE_OP_HPD;
hdmi->bridge.interlace_allowed = true; hdmi->bridge.interlace_allowed = true;
hdmi->bridge.ddc = hdmi->ddc;
#ifdef CONFIG_OF #ifdef CONFIG_OF
hdmi->bridge.of_node = pdev->dev.of_node; hdmi->bridge.of_node = pdev->dev.of_node;
#endif #endif
......
...@@ -170,10 +170,10 @@ ...@@ -170,10 +170,10 @@
* @pwm_refclk_freq: Cache for the reference clock input to the PWM. * @pwm_refclk_freq: Cache for the reference clock input to the PWM.
*/ */
struct ti_sn65dsi86 { struct ti_sn65dsi86 {
struct auxiliary_device bridge_aux; struct auxiliary_device *bridge_aux;
struct auxiliary_device gpio_aux; struct auxiliary_device *gpio_aux;
struct auxiliary_device aux_aux; struct auxiliary_device *aux_aux;
struct auxiliary_device pwm_aux; struct auxiliary_device *pwm_aux;
struct device *dev; struct device *dev;
struct regmap *regmap; struct regmap *regmap;
...@@ -468,27 +468,34 @@ static void ti_sn65dsi86_delete_aux(void *data) ...@@ -468,27 +468,34 @@ static void ti_sn65dsi86_delete_aux(void *data)
auxiliary_device_delete(data); auxiliary_device_delete(data);
} }
/* static void ti_sn65dsi86_aux_device_release(struct device *dev)
* 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 struct auxiliary_device *aux = container_of(dev, struct auxiliary_device, dev);
* in the single shared structure. We'll use this noop as a workaround.
*/ kfree(aux);
static void ti_sn65dsi86_noop(struct device *dev) {} }
static int ti_sn65dsi86_add_aux_device(struct ti_sn65dsi86 *pdata, static int ti_sn65dsi86_add_aux_device(struct ti_sn65dsi86 *pdata,
struct auxiliary_device *aux, struct auxiliary_device **aux_out,
const char *name) const char *name)
{ {
struct device *dev = pdata->dev; struct device *dev = pdata->dev;
struct auxiliary_device *aux;
int ret; int ret;
aux = kzalloc(sizeof(*aux), GFP_KERNEL);
if (!aux)
return -ENOMEM;
aux->name = name; aux->name = name;
aux->dev.parent = dev; 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); device_set_of_node_from_dev(&aux->dev, dev);
ret = auxiliary_device_init(aux); ret = auxiliary_device_init(aux);
if (ret) if (ret) {
kfree(aux);
return ret; return ret;
}
ret = devm_add_action_or_reset(dev, ti_sn65dsi86_uninit_aux, aux); ret = devm_add_action_or_reset(dev, ti_sn65dsi86_uninit_aux, aux);
if (ret) if (ret)
return ret; return ret;
...@@ -497,6 +504,8 @@ static int ti_sn65dsi86_add_aux_device(struct ti_sn65dsi86 *pdata, ...@@ -497,6 +504,8 @@ static int ti_sn65dsi86_add_aux_device(struct ti_sn65dsi86 *pdata,
if (ret) if (ret)
return ret; return ret;
ret = devm_add_action_or_reset(dev, ti_sn65dsi86_delete_aux, aux); ret = devm_add_action_or_reset(dev, ti_sn65dsi86_delete_aux, aux);
if (!ret)
*aux_out = aux;
return ret; return ret;
} }
......
...@@ -122,13 +122,34 @@ EXPORT_SYMBOL(drm_client_init); ...@@ -122,13 +122,34 @@ EXPORT_SYMBOL(drm_client_init);
* drm_client_register() it is no longer permissible to call drm_client_release() * drm_client_register() it is no longer permissible to call drm_client_release()
* directly (outside the unregister callback), instead cleanup will happen * directly (outside the unregister callback), instead cleanup will happen
* automatically on driver unload. * 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) void drm_client_register(struct drm_client_dev *client)
{ {
struct drm_device *dev = client->dev; struct drm_device *dev = client->dev;
int ret;
mutex_lock(&dev->clientlist_mutex); mutex_lock(&dev->clientlist_mutex);
list_add(&client->list, &dev->clientlist); 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); mutex_unlock(&dev->clientlist_mutex);
} }
EXPORT_SYMBOL(drm_client_register); EXPORT_SYMBOL(drm_client_register);
......
...@@ -217,7 +217,7 @@ static const struct drm_client_funcs drm_fbdev_dma_client_funcs = { ...@@ -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 * drm_fbdev_dma_setup() - Setup fbdev emulation for GEM DMA helpers
* @dev: DRM device * @dev: DRM device
* @preferred_bpp: Preferred bits per pixel for the 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 * This function sets up fbdev emulation for GEM DMA drivers that support
* dumb buffers with a virtual address and that can be mmap'ed. * 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) ...@@ -252,10 +252,6 @@ void drm_fbdev_dma_setup(struct drm_device *dev, unsigned int preferred_bpp)
goto err_drm_client_init; 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); drm_client_register(&fb_helper->client);
return; return;
......
...@@ -339,10 +339,6 @@ void drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp) ...@@ -339,10 +339,6 @@ void drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp)
goto err_drm_client_init; 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); drm_client_register(&fb_helper->client);
return; return;
......
...@@ -353,10 +353,10 @@ EXPORT_SYMBOL(drm_syncobj_replace_fence); ...@@ -353,10 +353,10 @@ EXPORT_SYMBOL(drm_syncobj_replace_fence);
*/ */
static int drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj) 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)) if (!fence)
return PTR_ERR(fence); return -ENOMEM;
drm_syncobj_replace_fence(syncobj, fence); drm_syncobj_replace_fence(syncobj, fence);
dma_fence_put(fence); dma_fence_put(fence);
......
...@@ -215,10 +215,6 @@ void exynos_drm_fbdev_setup(struct drm_device *dev) ...@@ -215,10 +215,6 @@ void exynos_drm_fbdev_setup(struct drm_device *dev)
if (ret) if (ret)
goto err_drm_client_init; 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); drm_client_register(&fb_helper->client);
return; return;
......
...@@ -328,10 +328,6 @@ void psb_fbdev_setup(struct drm_psb_private *dev_priv) ...@@ -328,10 +328,6 @@ void psb_fbdev_setup(struct drm_psb_private *dev_priv)
goto err_drm_fb_helper_unprepare; 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); drm_client_register(&fb_helper->client);
return; return;
......
...@@ -246,10 +246,6 @@ void msm_fbdev_setup(struct drm_device *dev) ...@@ -246,10 +246,6 @@ void msm_fbdev_setup(struct drm_device *dev)
goto err_drm_fb_helper_unprepare; 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); drm_client_register(&helper->client);
return; return;
......
...@@ -910,15 +910,19 @@ nv50_msto_prepare(struct drm_atomic_state *state, ...@@ -910,15 +910,19 @@ nv50_msto_prepare(struct drm_atomic_state *state,
struct nouveau_drm *drm = nouveau_drm(msto->encoder.dev); struct nouveau_drm *drm = nouveau_drm(msto->encoder.dev);
struct nv50_mstc *mstc = msto->mstc; struct nv50_mstc *mstc = msto->mstc;
struct nv50_mstm *mstm = mstc->mstm; 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); 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); 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? // TODO: Figure out if we want to do a better job of handling VCPI allocation failures here?
if (msto->disabled) { 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); nvif_outp_dp_mst_vcpi(&mstm->outp->outp, msto->head->base.index, 0, 0, 0, 0);
} else { } else {
......
...@@ -90,6 +90,7 @@ nouveau_channel_del(struct nouveau_channel **pchan) ...@@ -90,6 +90,7 @@ nouveau_channel_del(struct nouveau_channel **pchan)
if (cli) if (cli)
nouveau_svmm_part(chan->vmm->svmm, chan->inst); nouveau_svmm_part(chan->vmm->svmm, chan->inst);
nvif_object_dtor(&chan->blit);
nvif_object_dtor(&chan->nvsw); nvif_object_dtor(&chan->nvsw);
nvif_object_dtor(&chan->gart); nvif_object_dtor(&chan->gart);
nvif_object_dtor(&chan->vram); nvif_object_dtor(&chan->vram);
......
...@@ -53,6 +53,7 @@ struct nouveau_channel { ...@@ -53,6 +53,7 @@ struct nouveau_channel {
u32 user_put; u32 user_put;
struct nvif_object user; struct nvif_object user;
struct nvif_object blit;
struct nvif_event kill; struct nvif_event kill;
atomic_t killed; atomic_t killed;
......
...@@ -375,15 +375,29 @@ nouveau_accel_gr_init(struct nouveau_drm *drm) ...@@ -375,15 +375,29 @@ nouveau_accel_gr_init(struct nouveau_drm *drm)
ret = nvif_object_ctor(&drm->channel->user, "drmNvsw", ret = nvif_object_ctor(&drm->channel->user, "drmNvsw",
NVDRM_NVSW, nouveau_abi16_swclass(drm), NVDRM_NVSW, nouveau_abi16_swclass(drm),
NULL, 0, &drm->channel->nvsw); 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) { if (ret == 0) {
struct nvif_push *push = drm->channel->chan.push; struct nvif_push *push = drm->channel->chan.push;
ret = PUSH_WAIT(push, 2); ret = PUSH_WAIT(push, 8);
if (ret == 0) 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); PUSH_NVSQ(push, NV_SW, 0x0000, drm->channel->nvsw.handle);
}
} }
if (ret) { 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); nouveau_accel_gr_fini(drm);
return; return;
} }
......
...@@ -295,6 +295,7 @@ g94_sor = { ...@@ -295,6 +295,7 @@ g94_sor = {
.clock = nv50_sor_clock, .clock = nv50_sor_clock,
.war_2 = g94_sor_war_2, .war_2 = g94_sor_war_2,
.war_3 = g94_sor_war_3, .war_3 = g94_sor_war_3,
.hdmi = &g84_sor_hdmi,
.dp = &g94_sor_dp, .dp = &g94_sor_dp,
}; };
......
...@@ -125,7 +125,7 @@ gt215_sor_hdmi_infoframe_avi(struct nvkm_ior *ior, int head, void *data, u32 siz ...@@ -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); pack_hdmi_infoframe(&avi, data, size);
nvkm_mask(device, 0x61c520 + soff, 0x00000001, 0x00000000); nvkm_mask(device, 0x61c520 + soff, 0x00000001, 0x00000000);
if (size) if (!size)
return; return;
nvkm_wr32(device, 0x61c528 + soff, avi.header); nvkm_wr32(device, 0x61c528 + soff, avi.header);
......
...@@ -224,7 +224,7 @@ nvkm_acr_oneinit(struct nvkm_subdev *subdev) ...@@ -224,7 +224,7 @@ nvkm_acr_oneinit(struct nvkm_subdev *subdev)
u64 falcons; u64 falcons;
int ret, i; 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_debug(subdev, "No HSFW(s)\n");
nvkm_acr_cleanup(acr); nvkm_acr_cleanup(acr);
return 0; return 0;
......
...@@ -318,10 +318,6 @@ void omap_fbdev_setup(struct drm_device *dev) ...@@ -318,10 +318,6 @@ void omap_fbdev_setup(struct drm_device *dev)
INIT_WORK(&fbdev->work, pan_worker); 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); drm_client_register(&helper->client);
return; return;
......
...@@ -2178,6 +2178,7 @@ static const struct panel_desc innolux_at043tn24 = { ...@@ -2178,6 +2178,7 @@ static const struct panel_desc innolux_at043tn24 = {
.height = 54, .height = 54,
}, },
.bus_format = MEDIA_BUS_FMT_RGB888_1X24, .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, .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 = { ...@@ -3202,6 +3203,7 @@ static const struct drm_display_mode powertip_ph800480t013_idf02_mode = {
.vsync_start = 480 + 49, .vsync_start = 480 + 49,
.vsync_end = 480 + 49 + 2, .vsync_end = 480 + 49 + 2,
.vtotal = 480 + 49 + 2 + 22, .vtotal = 480 + 49 + 2 + 22,
.flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
}; };
static const struct panel_desc powertip_ph800480t013_idf02 = { static const struct panel_desc powertip_ph800480t013_idf02 = {
......
...@@ -383,10 +383,6 @@ void radeon_fbdev_setup(struct radeon_device *rdev) ...@@ -383,10 +383,6 @@ void radeon_fbdev_setup(struct radeon_device *rdev)
goto err_drm_client_init; 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); drm_client_register(&fb_helper->client);
return; return;
......
...@@ -176,16 +176,32 @@ static void drm_sched_entity_kill_jobs_cb(struct dma_fence *f, ...@@ -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, struct drm_sched_job *job = container_of(cb, struct drm_sched_job,
finish_cb); finish_cb);
int r; unsigned long index;
dma_fence_put(f); dma_fence_put(f);
/* Wait for all dependencies to avoid data corruptions */ /* Wait for all dependencies to avoid data corruptions */
while (!xa_empty(&job->dependencies)) { xa_for_each(&job->dependencies, index, f) {
f = xa_erase(&job->dependencies, job->last_dependency++); struct drm_sched_fence *s_fence = to_drm_sched_fence(f);
r = dma_fence_add_callback(f, &job->finish_cb,
drm_sched_entity_kill_jobs_cb); if (s_fence && f == &s_fence->scheduled) {
if (!r) /* 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; return;
dma_fence_put(f); dma_fence_put(f);
...@@ -415,8 +431,17 @@ static struct dma_fence * ...@@ -415,8 +431,17 @@ static struct dma_fence *
drm_sched_job_dependency(struct drm_sched_job *job, drm_sched_job_dependency(struct drm_sched_job *job,
struct drm_sched_entity *entity) struct drm_sched_entity *entity)
{ {
if (!xa_empty(&job->dependencies)) struct dma_fence *f;
return xa_erase(&job->dependencies, job->last_dependency++);
/* 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) if (job->sched->ops->prepare_job)
return job->sched->ops->prepare_job(job, entity); return job->sched->ops->prepare_job(job, entity);
......
...@@ -48,8 +48,32 @@ static void __exit drm_sched_fence_slab_fini(void) ...@@ -48,8 +48,32 @@ static void __exit drm_sched_fence_slab_fini(void)
kmem_cache_destroy(sched_fence_slab); 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); dma_fence_signal(&fence->scheduled);
} }
...@@ -181,20 +205,6 @@ struct drm_sched_fence *to_drm_sched_fence(struct dma_fence *f) ...@@ -181,20 +205,6 @@ struct drm_sched_fence *to_drm_sched_fence(struct dma_fence *f)
} }
EXPORT_SYMBOL(to_drm_sched_fence); 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, struct drm_sched_fence *drm_sched_fence_alloc(struct drm_sched_entity *entity,
void *owner) void *owner)
{ {
......
...@@ -1043,10 +1043,9 @@ static int drm_sched_main(void *param) ...@@ -1043,10 +1043,9 @@ static int drm_sched_main(void *param)
trace_drm_run_job(sched_job, entity); trace_drm_run_job(sched_job, entity);
fence = sched->ops->run_job(sched_job); fence = sched->ops->run_job(sched_job);
complete_all(&entity->entity_idle); complete_all(&entity->entity_idle);
drm_sched_fence_scheduled(s_fence); drm_sched_fence_scheduled(s_fence, fence);
if (!IS_ERR_OR_NULL(fence)) { if (!IS_ERR_OR_NULL(fence)) {
drm_sched_fence_set_parent(s_fence, fence);
/* Drop for original kref_init of the fence */ /* Drop for original kref_init of the fence */
dma_fence_put(fence); dma_fence_put(fence);
......
...@@ -225,10 +225,6 @@ void tegra_fbdev_setup(struct drm_device *dev) ...@@ -225,10 +225,6 @@ void tegra_fbdev_setup(struct drm_device *dev)
if (ret) if (ret)
goto err_drm_client_init; 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); drm_client_register(&helper->client);
return; return;
......
...@@ -458,18 +458,18 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo, ...@@ -458,18 +458,18 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo,
goto out; goto out;
} }
bounce: do {
ret = ttm_bo_handle_move_mem(bo, evict_mem, true, ctx, &hop); 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); ret = ttm_bo_bounce_temp_buffer(bo, &evict_mem, ctx, &hop);
if (ret) { } while (!ret);
if (ret != -ERESTARTSYS && ret != -EINTR)
pr_err("Buffer eviction failed\n"); if (ret) {
ttm_resource_free(bo, &evict_mem); ttm_resource_free(bo, &evict_mem);
goto out; if (ret != -ERESTARTSYS && ret != -EINTR)
} pr_err("Buffer eviction failed\n");
/* try and move to final place now. */
goto bounce;
} }
out: out:
return ret; return ret;
...@@ -517,6 +517,12 @@ static bool ttm_bo_evict_swapout_allowable(struct ttm_buffer_object *bo, ...@@ -517,6 +517,12 @@ static bool ttm_bo_evict_swapout_allowable(struct ttm_buffer_object *bo,
{ {
bool ret = false; bool ret = false;
if (bo->pin_count) {
*locked = false;
*busy = false;
return false;
}
if (bo->base.resv == ctx->resv) { if (bo->base.resv == ctx->resv) {
dma_resv_assert_held(bo->base.resv); dma_resv_assert_held(bo->base.resv);
if (ctx->allow_res_evict) if (ctx->allow_res_evict)
...@@ -1167,6 +1173,7 @@ int ttm_bo_swapout(struct ttm_buffer_object *bo, struct ttm_operation_ctx *ctx, ...@@ -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); ret = ttm_bo_handle_move_mem(bo, evict_mem, true, &ctx, &hop);
if (unlikely(ret != 0)) { if (unlikely(ret != 0)) {
WARN(ret == -EMULTIHOP, "Unexpected multihop in swaput - likely driver bug.\n"); WARN(ret == -EMULTIHOP, "Unexpected multihop in swaput - likely driver bug.\n");
ttm_resource_free(bo, &evict_mem);
goto out; goto out;
} }
} }
......
...@@ -86,6 +86,8 @@ static void ttm_lru_bulk_move_pos_tail(struct ttm_lru_bulk_move_pos *pos, ...@@ -86,6 +86,8 @@ static void ttm_lru_bulk_move_pos_tail(struct ttm_lru_bulk_move_pos *pos,
struct ttm_resource *res) struct ttm_resource *res)
{ {
if (pos->last != res) { if (pos->last != res) {
if (pos->first == res)
pos->first = list_next_entry(res, lru);
list_move(&res->lru, &pos->last->lru); list_move(&res->lru, &pos->last->lru);
pos->last = res; pos->last = res;
} }
...@@ -111,7 +113,8 @@ static void ttm_lru_bulk_move_del(struct ttm_lru_bulk_move *bulk, ...@@ -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); 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->first = NULL;
pos->last = NULL; pos->last = NULL;
} else if (pos->first == res) { } else if (pos->first == res) {
......
...@@ -583,15 +583,14 @@ void drm_sched_entity_set_priority(struct drm_sched_entity *entity, ...@@ -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); bool drm_sched_entity_is_ready(struct drm_sched_entity *entity);
int drm_sched_entity_error(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_fence *drm_sched_fence_alloc(
struct drm_sched_entity *s_entity, void *owner); struct drm_sched_entity *s_entity, void *owner);
void drm_sched_fence_init(struct drm_sched_fence *fence, void drm_sched_fence_init(struct drm_sched_fence *fence,
struct drm_sched_entity *entity); struct drm_sched_entity *entity);
void drm_sched_fence_free(struct drm_sched_fence *fence); 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); void drm_sched_fence_finished(struct drm_sched_fence *fence, int result);
unsigned long drm_sched_suspend_timeout(struct drm_gpu_scheduler *sched); 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) ...@@ -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); 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_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); u64 dma_fence_context_alloc(unsigned num);
extern const struct dma_fence_ops dma_fence_array_ops; 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