Skip to content

Commit

Permalink
drm/nouveau: disallow fbcon accel if running in interrupt context
Browse files Browse the repository at this point in the history
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: Ben Skeggs <bskeggs@redhat.com>
  • Loading branch information
Ben Skeggs committed Dec 3, 2010
1 parent 7c74cbd commit ceed5f3
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 133 deletions.
137 changes: 101 additions & 36 deletions drivers/gpu/drm/nouveau/nouveau_fbcon.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,90 @@
#include "nouveau_fbcon.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
nouveau_fbcon_sync(struct fb_info *info)
{
Expand Down Expand Up @@ -97,24 +181,9 @@ static struct fb_ops nouveau_fbcon_ops = {
.owner = THIS_MODULE,
.fb_check_var = drm_fb_helper_check_var,
.fb_set_par = drm_fb_helper_set_par,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_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_fillrect = nouveau_fbcon_fillrect,
.fb_copyarea = nouveau_fbcon_copyarea,
.fb_imageblit = nouveau_fbcon_imageblit,
.fb_sync = nouveau_fbcon_sync,
.fb_pan_display = drm_fb_helper_pan_display,
.fb_blank = drm_fb_helper_blank,
Expand All @@ -123,14 +192,13 @@ static struct fb_ops nv04_fbcon_ops = {
.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,
.fb_check_var = drm_fb_helper_check_var,
.fb_set_par = drm_fb_helper_set_par,
.fb_fillrect = nv50_fbcon_fillrect,
.fb_copyarea = nv50_fbcon_copyarea,
.fb_imageblit = nv50_fbcon_imageblit,
.fb_sync = nouveau_fbcon_sync,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
.fb_pan_display = drm_fb_helper_pan_display,
.fb_blank = drm_fb_helper_blank,
.fb_setcmap = drm_fb_helper_setcmap,
Expand Down Expand Up @@ -257,7 +325,7 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev,
FBINFO_HWACCEL_FILLRECT |
FBINFO_HWACCEL_IMAGEBLIT;
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 -
dev_priv->vm_vram_base;
info->fix.smem_len = size;
Expand Down Expand Up @@ -286,18 +354,15 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev,
info->pixmap.scan_align = 1;

if (dev_priv->channel && !nouveau_nofbaccel) {
switch (dev_priv->card_type) {
case NV_C0:
break;
case NV_50:
nv50_fbcon_accel_init(info);
info->fbops = &nv50_fbcon_ops;
break;
default:
nv04_fbcon_accel_init(info);
info->fbops = &nv04_fbcon_ops;
break;
};
ret = -ENODEV;
if (dev_priv->card_type < NV_50)
ret = nv04_fbcon_accel_init(info);
else
if (dev_priv->card_type < NV_C0)
ret = nv50_fbcon_accel_init(info);

if (ret == 0)
info->fbops = &nouveau_fbcon_ops;
}

nouveau_fbcon_zfill(dev, nfbdev);
Expand Down
12 changes: 6 additions & 6 deletions drivers/gpu/drm/nouveau/nouveau_fbcon.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,13 @@ struct nouveau_fbdev {

void nouveau_fbcon_restore(void);

void 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);
void nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image);
int nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region);
int nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
int nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image);
int nv04_fbcon_accel_init(struct fb_info *info);
void 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);
void nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image);
int nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
int nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region);
int nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image);
int nv50_fbcon_accel_init(struct fb_info *info);

void nouveau_fbcon_gpu_lockup(struct fb_info *info);
Expand Down
68 changes: 23 additions & 45 deletions drivers/gpu/drm/nouveau/nv04_fbcon.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,52 +28,39 @@
#include "nouveau_ramht.h"
#include "nouveau_fbcon.h"

void
int
nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
{
struct nouveau_fbdev *nfbdev = info->par;
struct drm_device *dev = nfbdev->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *chan = dev_priv->channel;
int ret;

if (info->state != FBINFO_STATE_RUNNING)
return;

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;
}
ret = RING_SPACE(chan, 4);
if (ret)
return ret;

BEGIN_RING(chan, NvSubImageBlit, 0x0300, 3);
OUT_RING(chan, (region->sy << 16) | region->sx);
OUT_RING(chan, (region->dy << 16) | region->dx);
OUT_RING(chan, (region->height << 16) | region->width);
FIRE_RING(chan);
return 0;
}

void
int
nv04_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;
struct nouveau_channel *chan = dev_priv->channel;
int ret;

if (info->state != FBINFO_STATE_RUNNING)
return;

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;
}
ret = RING_SPACE(chan, 7);
if (ret)
return ret;

BEGIN_RING(chan, NvSubGdiRect, 0x02fc, 1);
OUT_RING(chan, (rect->rop != ROP_COPY) ? 1 : 3);
Expand All @@ -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->width << 16) | rect->height);
FIRE_RING(chan);
return 0;
}

void
int
nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
{
struct nouveau_fbdev *nfbdev = info->par;
Expand All @@ -101,23 +89,14 @@ nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
uint32_t dsize;
uint32_t width;
uint32_t *data = (uint32_t *)image->data;
int ret;

if (info->state != FBINFO_STATE_RUNNING)
return;

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 (image->depth != 1)
return -ENODEV;

if (info->flags & FBINFO_HWACCEL_DISABLED) {
cfb_imageblit(info, image);
return;
}
ret = RING_SPACE(chan, 8);
if (ret)
return ret;

width = ALIGN(image->width, 8);
dsize = ALIGN(width * image->height, 32) >> 5;
Expand All @@ -144,11 +123,9 @@ nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
while (dsize) {
int iter_len = dsize > 128 ? 128 : dsize;

if (RING_SPACE(chan, iter_len + 1)) {
nouveau_fbcon_gpu_lockup(info);
cfb_imageblit(info, image);
return;
}
ret = RING_SPACE(chan, iter_len + 1);
if (ret)
return ret;

BEGIN_RING(chan, NvSubGdiRect, 0x0c00, iter_len);
OUT_RINGp(chan, data, iter_len);
Expand All @@ -157,6 +134,7 @@ nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
}

FIRE_RING(chan);
return 0;
}

static int
Expand Down
Loading

0 comments on commit ceed5f3

Please sign in to comment.