drm/nouveau: kill tasks causing the GPU to raise errors
Subsystems (3)
PATCH 1/1 drm/nouveau: kill tasks causing the GPU to raise errors
Send SIGBUS (and then SIGKILL) to tasks trying to use channels, for which hardware raised fatal errors.
As we cannot kill tasks immediately from ISR, mark channels as broken and send signals to processes when they first try to use them.
Previous behaviour can be restored by appending "nouveau.error_action=0" to kernel command line.
Signed-off-by Marcin Slusarz <[email protected]>
--- drivers/gpu/drm/nouveau/nouveau_channel.c | 23 ++++++ drivers/gpu/drm/nouveau/nouveau_drv.c | 7 ++ drivers/gpu/drm/nouveau/nouveau_drv.h | 16 ++++ drivers/gpu/drm/nouveau/nouveau_gem.c | 4 + drivers/gpu/drm/nouveau/nouveau_irq.c | 111 ++++++++++++++++++++++------ drivers/gpu/drm/nouveau/nouveau_notifier.c | 2 + drivers/gpu/drm/nouveau/nouveau_object.c | 2 + drivers/gpu/drm/nouveau/nv50_fb.c | 17 ++-- 8 files changed, 152 insertions(+), 30 deletions(-)
drivers/gpu/drm/nouveau/nouveau_channel.c +23 -0
@@ -231,6 +231,9 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret,nouveau_debugfs_channel_init (chan); + chan->state =NV_CHANNEL_OK ; + chan->error_action = nouveau_default_channel_error_action; +NV_INFO (dev,"%s: initialised FIFO %d\n" , __func__, channel); *chan_ret = chan;return 0 ;
@@ -416,6 +419,26 @@ nouveau_ioctl_fifo_free(struct drm_device *dev, void *data,return 0 ; } +int nouveau_handle_state (struct nouveau_channel *chan) +{ +if (chan->state ==NV_CHANNEL_KILLED ) +return -EBADFD ; + +if (chan->state ==NV_CHANNEL_BUS ) { +NV_INFO (chan->dev,"sending SIGBUS to task %d \"%s\"\n" , +task_pid_nr (current), current->comm); +kill_pid (task_pid (current),SIGBUS ,0 ); + chan->state =NV_CHANNEL_KILL ; + }else if (chan->state ==NV_CHANNEL_KILL ) { +NV_INFO (chan->dev,"sending SIGKILL to task %d \"%s\"\n" , +task_pid_nr (current), current->comm); +kill_pid (task_pid (current),SIGKILL ,0 ); + chan->state =NV_CHANNEL_KILLED ; + } + +return -EBADFD ; +} +/*********************************** * finally, the ioctl table ***********************************/
drivers/gpu/drm/nouveau/nouveau_drv.c +7 -0
@@ -115,6 +115,13 @@ MODULE_PARM_DESC(perflvl_wr, "Allow perflvl changes (warning: dangerous!)\n");int nouveau_perflvl_wr;module_param_named (perflvl_wr, nouveau_perflvl_wr, int,0400 ); +MODULE_PARM_DESC (error_action,"Default action on error:\n" +"\t\t0 - do nothing\n" +"\t\t1 - kill process owning the offending channel (default)" ); +int nouveau_default_channel_error_action =NV_KILL_PROCESS ; +module_param_named (error_action, nouveau_default_channel_error_action, + int,0400 ); +int nouveau_fbpercrtc;#if 0 module_param_named (fbpercrtc, nouveau_fbpercrtc, int,0400 );
drivers/gpu/drm/nouveau/nouveau_drv.h +16 -0
@@ -166,6 +166,13 @@ struct nouveau_channel {struct drm_device *dev;int id; +enum nouveau_channel_state { +NV_CHANNEL_OK =0 , +NV_CHANNEL_BUS =1 , +NV_CHANNEL_KILL =2 , +NV_CHANNEL_KILLED =3 , + } state; +/* owner of this fifo */ struct drm_file *file_priv;/* mapping of the fifo itself */
@@ -248,6 +255,11 @@ struct nouveau_channel {char name[32 ];struct drm_info_list info; } debugfs; + +enum nouveau_channel_error_action { +NV_DO_NOTHING =0 , +NV_KILL_PROCESS =1 , + } error_action; };struct nouveau_instmem_engine {
@@ -740,6 +752,7 @@ extern int nouveau_fbpercrtc;extern int nouveau_tv_disable;extern char *nouveau_tv_norm;extern int nouveau_reg_debug; +extern int nouveau_default_channel_error_action;extern char *nouveau_vbios;extern int nouveau_ignorelid;extern int nouveau_nofbaccel;
@@ -810,6 +823,7 @@ extern int nouveau_channel_alloc(struct drm_device *dev,struct drm_file *file_priv, uint32_t fb_ctxdma, uint32_t tt_ctxdma);extern void nouveau_channel_free (struct nouveau_channel *); +extern int nouveau_handle_state (struct nouveau_channel *chan);/* nouveau_object.c */ extern int nouveau_gpuobj_early_init (struct drm_device *);
@@ -850,6 +864,8 @@ extern irqreturn_t nouveau_irq_handler(DRM_IRQ_ARGS);extern void nouveau_irq_preinstall (struct drm_device *);extern int nouveau_irq_postinstall (struct drm_device *);extern void nouveau_irq_uninstall (struct drm_device *); +extern void nouveau_broken_channel (struct nouveau_channel *chan); +extern void nouveau_broken_channel_id (struct drm_device *dev,int chid);/* nouveau_sgdma.c */ extern int nouveau_sgdma_init (struct drm_device *);
drivers/gpu/drm/nouveau/nouveau_gem.c +4 -0
@@ -149,6 +149,8 @@ nouveau_gem_ioctl_new(struct drm_device *dev, void *data,if (req->channel_hint) {NOUVEAU_GET_USER_CHANNEL_WITH_RETURN (req->channel_hint, file_priv, chan); +if (unlikely (chan->state !=NV_CHANNEL_OK )) +return nouveau_handle_state (chan); }if (req->info.domain &NOUVEAU_GEM_DOMAIN_VRAM )
@@ -594,6 +596,8 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data,int i, j, ret =0 , do_reloc =0 ;NOUVEAU_GET_USER_CHANNEL_WITH_RETURN (req->channel, file_priv, chan); +if (unlikely (chan->state !=NV_CHANNEL_OK )) +return nouveau_handle_state (chan); req->vram_available = dev_priv->fb_aper_free; req->gart_available = dev_priv->gart_info.aper_free;
drivers/gpu/drm/nouveau/nouveau_irq.c +89 -22
229 lines not on this page · raw message
drivers/gpu/drm/nouveau/nouveau_notifier.c +2 -0
@@ -186,6 +186,8 @@ nouveau_ioctl_notifier_alloc(struct drm_device *dev, void *data,int ret;NOUVEAU_GET_USER_CHANNEL_WITH_RETURN (na->channel, file_priv, chan); +if (unlikely (chan->state !=NV_CHANNEL_OK )) +return nouveau_handle_state (chan); ret =nouveau_notifier_alloc (chan, na->handle, na->size, &na->offset);if (ret)
drivers/gpu/drm/nouveau/nouveau_object.c +2 -0
@@ -877,6 +877,8 @@ int nouveau_ioctl_grobj_alloc(struct drm_device *dev, void *data,int ret;NOUVEAU_GET_USER_CHANNEL_WITH_RETURN (init->channel, file_priv, chan); +if (unlikely (chan->state !=NV_CHANNEL_OK )) +return nouveau_handle_state (chan);if (init->handle == ~0 )return -EINVAL ;
drivers/gpu/drm/nouveau/nv50_fb.c +9 -8
@@ -56,9 +56,6 @@ nv50_fb_vm_trap(struct drm_device *dev, int display, const char *name) }nv_wr32 (dev,0x100c90 , idx |0x80000000 ); -if (!display) -return ; - chinst = (trap[2 ] <<16 ) | trap[1 ];for (ch =0 ; ch < dev_priv->engine.fifo.channels; ch++) {struct nouveau_channel *chan = dev_priv->fifos[ch];
@@ -70,9 +67,13 @@ nv50_fb_vm_trap(struct drm_device *dev, int display, const char *name)break ; } -NV_INFO (dev,"%s - VM: Trapped %s at %02x%04x%04x status %08x " -"channel %d (0x%08x)\n" , - name, (trap[5 ] &0x100 ?"read" :"write" ), - trap[5 ] &0xff , trap[4 ] &0xffff , trap[3 ] &0xffff , - trap[0 ], ch, chinst); +if (display) { +NV_INFO (dev,"%s - VM: Trapped %s at %02x%04x%04x status %08x " +"channel %d (0x%08x)\n" , + name, (trap[5 ] &0x100 ?"read" :"write" ), + trap[5 ] &0xff , trap[4 ] &0xffff , trap[3 ] &0xffff , + trap[0 ], ch, chinst); + } + +nouveau_broken_channel_id (dev, ch); }
Signature · 1 line
1.7.3.3