提交 ceed5f30 编写于 作者: B Ben Skeggs

drm/nouveau: disallow fbcon accel if running in interrupt context

A future commit will add locking to the DRM's channel, and there's numerous
problems that come up if we allow printk from an interrupt context to be
accelerated.  It seems saner to just disallow it completely.

As a nice side-effect, all the "to accel or not to accel" logic gets moved
out of the chipset-specific code.
Signed-off-by: NBen Skeggs <bskeggs@redhat.com>
上级 7c74cbd0
...@@ -49,6 +49,90 @@ ...@@ -49,6 +49,90 @@
#include "nouveau_fbcon.h" #include "nouveau_fbcon.h"
#include "nouveau_dma.h" #include "nouveau_dma.h"
static void
nouveau_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
{
struct nouveau_fbdev *nfbdev = info->par;
struct drm_device *dev = nfbdev->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
int ret;
if (info->state != FBINFO_STATE_RUNNING)
return;
ret = -ENODEV;
if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED)) {
if (dev_priv->card_type < NV_50)
ret = nv04_fbcon_fillrect(info, rect);
else
if (dev_priv->card_type < NV_C0)
ret = nv50_fbcon_fillrect(info, rect);
}
if (ret == 0)
return;
if (ret != -ENODEV)
nouveau_fbcon_gpu_lockup(info);
cfb_fillrect(info, rect);
}
static void
nouveau_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *image)
{
struct nouveau_fbdev *nfbdev = info->par;
struct drm_device *dev = nfbdev->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
int ret;
if (info->state != FBINFO_STATE_RUNNING)
return;
ret = -ENODEV;
if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED)) {
if (dev_priv->card_type < NV_50)
ret = nv04_fbcon_copyarea(info, image);
else
if (dev_priv->card_type < NV_C0)
ret = nv50_fbcon_copyarea(info, image);
}
if (ret == 0)
return;
if (ret != -ENODEV)
nouveau_fbcon_gpu_lockup(info);
cfb_copyarea(info, image);
}
static void
nouveau_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
{
struct nouveau_fbdev *nfbdev = info->par;
struct drm_device *dev = nfbdev->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
int ret;
if (info->state != FBINFO_STATE_RUNNING)
return;
ret = -ENODEV;
if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED)) {
if (dev_priv->card_type < NV_50)
ret = nv04_fbcon_imageblit(info, image);
else
if (dev_priv->card_type < NV_C0)
ret = nv50_fbcon_imageblit(info, image);
}
if (ret == 0)
return;
if (ret != -ENODEV)
nouveau_fbcon_gpu_lockup(info);
cfb_imageblit(info, image);
}
static int static int
nouveau_fbcon_sync(struct fb_info *info) nouveau_fbcon_sync(struct fb_info *info)
{ {
...@@ -97,24 +181,9 @@ static struct fb_ops nouveau_fbcon_ops = { ...@@ -97,24 +181,9 @@ static struct fb_ops nouveau_fbcon_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.fb_check_var = drm_fb_helper_check_var, .fb_check_var = drm_fb_helper_check_var,
.fb_set_par = drm_fb_helper_set_par, .fb_set_par = drm_fb_helper_set_par,
.fb_fillrect = cfb_fillrect, .fb_fillrect = nouveau_fbcon_fillrect,
.fb_copyarea = cfb_copyarea, .fb_copyarea = nouveau_fbcon_copyarea,
.fb_imageblit = cfb_imageblit, .fb_imageblit = nouveau_fbcon_imageblit,
.fb_sync = nouveau_fbcon_sync,
.fb_pan_display = drm_fb_helper_pan_display,
.fb_blank = drm_fb_helper_blank,
.fb_setcmap = drm_fb_helper_setcmap,
.fb_debug_enter = drm_fb_helper_debug_enter,
.fb_debug_leave = drm_fb_helper_debug_leave,
};
static struct fb_ops nv04_fbcon_ops = {
.owner = THIS_MODULE,
.fb_check_var = drm_fb_helper_check_var,
.fb_set_par = drm_fb_helper_set_par,
.fb_fillrect = nv04_fbcon_fillrect,
.fb_copyarea = nv04_fbcon_copyarea,
.fb_imageblit = nv04_fbcon_imageblit,
.fb_sync = nouveau_fbcon_sync, .fb_sync = nouveau_fbcon_sync,
.fb_pan_display = drm_fb_helper_pan_display, .fb_pan_display = drm_fb_helper_pan_display,
.fb_blank = drm_fb_helper_blank, .fb_blank = drm_fb_helper_blank,
...@@ -123,14 +192,13 @@ static struct fb_ops nv04_fbcon_ops = { ...@@ -123,14 +192,13 @@ static struct fb_ops nv04_fbcon_ops = {
.fb_debug_leave = drm_fb_helper_debug_leave, .fb_debug_leave = drm_fb_helper_debug_leave,
}; };
static struct fb_ops nv50_fbcon_ops = { static struct fb_ops nouveau_fbcon_sw_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.fb_check_var = drm_fb_helper_check_var, .fb_check_var = drm_fb_helper_check_var,
.fb_set_par = drm_fb_helper_set_par, .fb_set_par = drm_fb_helper_set_par,
.fb_fillrect = nv50_fbcon_fillrect, .fb_fillrect = cfb_fillrect,
.fb_copyarea = nv50_fbcon_copyarea, .fb_copyarea = cfb_copyarea,
.fb_imageblit = nv50_fbcon_imageblit, .fb_imageblit = cfb_imageblit,
.fb_sync = nouveau_fbcon_sync,
.fb_pan_display = drm_fb_helper_pan_display, .fb_pan_display = drm_fb_helper_pan_display,
.fb_blank = drm_fb_helper_blank, .fb_blank = drm_fb_helper_blank,
.fb_setcmap = drm_fb_helper_setcmap, .fb_setcmap = drm_fb_helper_setcmap,
...@@ -257,7 +325,7 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev, ...@@ -257,7 +325,7 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev,
FBINFO_HWACCEL_FILLRECT | FBINFO_HWACCEL_FILLRECT |
FBINFO_HWACCEL_IMAGEBLIT; FBINFO_HWACCEL_IMAGEBLIT;
info->flags |= FBINFO_CAN_FORCE_OUTPUT; info->flags |= FBINFO_CAN_FORCE_OUTPUT;
info->fbops = &nouveau_fbcon_ops; info->fbops = &nouveau_fbcon_sw_ops;
info->fix.smem_start = dev->mode_config.fb_base + nvbo->bo.offset - info->fix.smem_start = dev->mode_config.fb_base + nvbo->bo.offset -
dev_priv->vm_vram_base; dev_priv->vm_vram_base;
info->fix.smem_len = size; info->fix.smem_len = size;
...@@ -286,18 +354,15 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev, ...@@ -286,18 +354,15 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev,
info->pixmap.scan_align = 1; info->pixmap.scan_align = 1;
if (dev_priv->channel && !nouveau_nofbaccel) { if (dev_priv->channel && !nouveau_nofbaccel) {
switch (dev_priv->card_type) { ret = -ENODEV;
case NV_C0: if (dev_priv->card_type < NV_50)
break; ret = nv04_fbcon_accel_init(info);
case NV_50: else
nv50_fbcon_accel_init(info); if (dev_priv->card_type < NV_C0)
info->fbops = &nv50_fbcon_ops; ret = nv50_fbcon_accel_init(info);
break;
default: if (ret == 0)
nv04_fbcon_accel_init(info); info->fbops = &nouveau_fbcon_ops;
info->fbops = &nv04_fbcon_ops;
break;
};
} }
nouveau_fbcon_zfill(dev, nfbdev); nouveau_fbcon_zfill(dev, nfbdev);
......
...@@ -40,13 +40,13 @@ struct nouveau_fbdev { ...@@ -40,13 +40,13 @@ struct nouveau_fbdev {
void nouveau_fbcon_restore(void); void nouveau_fbcon_restore(void);
void nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region); int nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region);
void nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect); int nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
void nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image); int nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image);
int nv04_fbcon_accel_init(struct fb_info *info); int nv04_fbcon_accel_init(struct fb_info *info);
void nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect); int nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
void nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region); int nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region);
void nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image); int nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image);
int nv50_fbcon_accel_init(struct fb_info *info); int nv50_fbcon_accel_init(struct fb_info *info);
void nouveau_fbcon_gpu_lockup(struct fb_info *info); void nouveau_fbcon_gpu_lockup(struct fb_info *info);
......
...@@ -28,52 +28,39 @@ ...@@ -28,52 +28,39 @@
#include "nouveau_ramht.h" #include "nouveau_ramht.h"
#include "nouveau_fbcon.h" #include "nouveau_fbcon.h"
void int
nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
{ {
struct nouveau_fbdev *nfbdev = info->par; struct nouveau_fbdev *nfbdev = info->par;
struct drm_device *dev = nfbdev->dev; struct drm_device *dev = nfbdev->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *chan = dev_priv->channel; struct nouveau_channel *chan = dev_priv->channel;
int ret;
if (info->state != FBINFO_STATE_RUNNING) ret = RING_SPACE(chan, 4);
return; if (ret)
return ret;
if (!(info->flags & FBINFO_HWACCEL_DISABLED) && RING_SPACE(chan, 4)) {
nouveau_fbcon_gpu_lockup(info);
}
if (info->flags & FBINFO_HWACCEL_DISABLED) {
cfb_copyarea(info, region);
return;
}
BEGIN_RING(chan, NvSubImageBlit, 0x0300, 3); BEGIN_RING(chan, NvSubImageBlit, 0x0300, 3);
OUT_RING(chan, (region->sy << 16) | region->sx); OUT_RING(chan, (region->sy << 16) | region->sx);
OUT_RING(chan, (region->dy << 16) | region->dx); OUT_RING(chan, (region->dy << 16) | region->dx);
OUT_RING(chan, (region->height << 16) | region->width); OUT_RING(chan, (region->height << 16) | region->width);
FIRE_RING(chan); FIRE_RING(chan);
return 0;
} }
void int
nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
{ {
struct nouveau_fbdev *nfbdev = info->par; struct nouveau_fbdev *nfbdev = info->par;
struct drm_device *dev = nfbdev->dev; struct drm_device *dev = nfbdev->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *chan = dev_priv->channel; struct nouveau_channel *chan = dev_priv->channel;
int ret;
if (info->state != FBINFO_STATE_RUNNING) ret = RING_SPACE(chan, 7);
return; if (ret)
return ret;
if (!(info->flags & FBINFO_HWACCEL_DISABLED) && RING_SPACE(chan, 7)) {
nouveau_fbcon_gpu_lockup(info);
}
if (info->flags & FBINFO_HWACCEL_DISABLED) {
cfb_fillrect(info, rect);
return;
}
BEGIN_RING(chan, NvSubGdiRect, 0x02fc, 1); BEGIN_RING(chan, NvSubGdiRect, 0x02fc, 1);
OUT_RING(chan, (rect->rop != ROP_COPY) ? 1 : 3); OUT_RING(chan, (rect->rop != ROP_COPY) ? 1 : 3);
...@@ -87,9 +74,10 @@ nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) ...@@ -87,9 +74,10 @@ nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
OUT_RING(chan, (rect->dx << 16) | rect->dy); OUT_RING(chan, (rect->dx << 16) | rect->dy);
OUT_RING(chan, (rect->width << 16) | rect->height); OUT_RING(chan, (rect->width << 16) | rect->height);
FIRE_RING(chan); FIRE_RING(chan);
return 0;
} }
void int
nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
{ {
struct nouveau_fbdev *nfbdev = info->par; struct nouveau_fbdev *nfbdev = info->par;
...@@ -101,23 +89,14 @@ nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) ...@@ -101,23 +89,14 @@ nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
uint32_t dsize; uint32_t dsize;
uint32_t width; uint32_t width;
uint32_t *data = (uint32_t *)image->data; uint32_t *data = (uint32_t *)image->data;
int ret;
if (info->state != FBINFO_STATE_RUNNING) if (image->depth != 1)
return; return -ENODEV;
if (image->depth != 1) {
cfb_imageblit(info, image);
return;
}
if (!(info->flags & FBINFO_HWACCEL_DISABLED) && RING_SPACE(chan, 8)) {
nouveau_fbcon_gpu_lockup(info);
}
if (info->flags & FBINFO_HWACCEL_DISABLED) { ret = RING_SPACE(chan, 8);
cfb_imageblit(info, image); if (ret)
return; return ret;
}
width = ALIGN(image->width, 8); width = ALIGN(image->width, 8);
dsize = ALIGN(width * image->height, 32) >> 5; dsize = ALIGN(width * image->height, 32) >> 5;
...@@ -144,11 +123,9 @@ nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) ...@@ -144,11 +123,9 @@ nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
while (dsize) { while (dsize) {
int iter_len = dsize > 128 ? 128 : dsize; int iter_len = dsize > 128 ? 128 : dsize;
if (RING_SPACE(chan, iter_len + 1)) { ret = RING_SPACE(chan, iter_len + 1);
nouveau_fbcon_gpu_lockup(info); if (ret)
cfb_imageblit(info, image); return ret;
return;
}
BEGIN_RING(chan, NvSubGdiRect, 0x0c00, iter_len); BEGIN_RING(chan, NvSubGdiRect, 0x0c00, iter_len);
OUT_RINGp(chan, data, iter_len); OUT_RINGp(chan, data, iter_len);
...@@ -157,6 +134,7 @@ nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) ...@@ -157,6 +134,7 @@ nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
} }
FIRE_RING(chan); FIRE_RING(chan);
return 0;
} }
static int static int
......
...@@ -4,26 +4,18 @@ ...@@ -4,26 +4,18 @@
#include "nouveau_ramht.h" #include "nouveau_ramht.h"
#include "nouveau_fbcon.h" #include "nouveau_fbcon.h"
void int
nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
{ {
struct nouveau_fbdev *nfbdev = info->par; struct nouveau_fbdev *nfbdev = info->par;
struct drm_device *dev = nfbdev->dev; struct drm_device *dev = nfbdev->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *chan = dev_priv->channel; struct nouveau_channel *chan = dev_priv->channel;
int ret;
if (info->state != FBINFO_STATE_RUNNING) ret = RING_SPACE(chan, rect->rop == ROP_COPY ? 7 : 11);
return; if (ret)
return ret;
if (!(info->flags & FBINFO_HWACCEL_DISABLED) &&
RING_SPACE(chan, rect->rop == ROP_COPY ? 7 : 11)) {
nouveau_fbcon_gpu_lockup(info);
}
if (info->flags & FBINFO_HWACCEL_DISABLED) {
cfb_fillrect(info, rect);
return;
}
if (rect->rop != ROP_COPY) { if (rect->rop != ROP_COPY) {
BEGIN_RING(chan, NvSub2D, 0x02ac, 1); BEGIN_RING(chan, NvSub2D, 0x02ac, 1);
...@@ -45,27 +37,21 @@ nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) ...@@ -45,27 +37,21 @@ nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
OUT_RING(chan, 3); OUT_RING(chan, 3);
} }
FIRE_RING(chan); FIRE_RING(chan);
return 0;
} }
void int
nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
{ {
struct nouveau_fbdev *nfbdev = info->par; struct nouveau_fbdev *nfbdev = info->par;
struct drm_device *dev = nfbdev->dev; struct drm_device *dev = nfbdev->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *chan = dev_priv->channel; struct nouveau_channel *chan = dev_priv->channel;
int ret;
if (info->state != FBINFO_STATE_RUNNING) ret = RING_SPACE(chan, 12);
return; if (ret)
return ret;
if (!(info->flags & FBINFO_HWACCEL_DISABLED) && RING_SPACE(chan, 12)) {
nouveau_fbcon_gpu_lockup(info);
}
if (info->flags & FBINFO_HWACCEL_DISABLED) {
cfb_copyarea(info, region);
return;
}
BEGIN_RING(chan, NvSub2D, 0x0110, 1); BEGIN_RING(chan, NvSub2D, 0x0110, 1);
OUT_RING(chan, 0); OUT_RING(chan, 0);
...@@ -80,9 +66,10 @@ nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) ...@@ -80,9 +66,10 @@ nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
OUT_RING(chan, 0); OUT_RING(chan, 0);
OUT_RING(chan, region->sy); OUT_RING(chan, region->sy);
FIRE_RING(chan); FIRE_RING(chan);
return 0;
} }
void int
nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
{ {
struct nouveau_fbdev *nfbdev = info->par; struct nouveau_fbdev *nfbdev = info->par;
...@@ -92,23 +79,14 @@ nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) ...@@ -92,23 +79,14 @@ nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
uint32_t width, dwords, *data = (uint32_t *)image->data; uint32_t width, dwords, *data = (uint32_t *)image->data;
uint32_t mask = ~(~0 >> (32 - info->var.bits_per_pixel)); uint32_t mask = ~(~0 >> (32 - info->var.bits_per_pixel));
uint32_t *palette = info->pseudo_palette; uint32_t *palette = info->pseudo_palette;
int ret;
if (info->state != FBINFO_STATE_RUNNING) if (image->depth != 1)
return; return -ENODEV;
if (image->depth != 1) {
cfb_imageblit(info, image);
return;
}
if (!(info->flags & FBINFO_HWACCEL_DISABLED) && RING_SPACE(chan, 11)) {
nouveau_fbcon_gpu_lockup(info);
}
if (info->flags & FBINFO_HWACCEL_DISABLED) { ret = RING_SPACE(chan, 11);
cfb_imageblit(info, image); if (ret)
return; return ret;
}
width = ALIGN(image->width, 32); width = ALIGN(image->width, 32);
dwords = (width * image->height) >> 5; dwords = (width * image->height) >> 5;
...@@ -134,11 +112,9 @@ nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) ...@@ -134,11 +112,9 @@ nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
while (dwords) { while (dwords) {
int push = dwords > 2047 ? 2047 : dwords; int push = dwords > 2047 ? 2047 : dwords;
if (RING_SPACE(chan, push + 1)) { ret = RING_SPACE(chan, push + 1);
nouveau_fbcon_gpu_lockup(info); if (ret)
cfb_imageblit(info, image); return ret;
return;
}
dwords -= push; dwords -= push;
...@@ -148,6 +124,7 @@ nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) ...@@ -148,6 +124,7 @@ nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
} }
FIRE_RING(chan); FIRE_RING(chan);
return 0;
} }
int int
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册