mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-27 03:10:12 +00:00
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: Ben Skeggs <bskeggs@redhat.com>
This commit is contained in:
parent
7c74cbd01b
commit
ceed5f30bf
4 changed files with 161 additions and 141 deletions
|
@ -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)
|
||||
{
|
||||
|
@ -94,43 +178,27 @@ nouveau_fbcon_sync(struct fb_info *info)
|
|||
}
|
||||
|
||||
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 = 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,
|
||||
.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 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 = 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_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 nv50_fbcon_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_pan_display = drm_fb_helper_pan_display,
|
||||
.fb_blank = drm_fb_helper_blank,
|
||||
.fb_setcmap = drm_fb_helper_setcmap,
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
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) {
|
||||
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;
|
||||
|
@ -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);
|
||||
|
@ -157,6 +134,7 @@ nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
|
|||
}
|
||||
|
||||
FIRE_RING(chan);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
|
@ -4,26 +4,18 @@
|
|||
#include "nouveau_ramht.h"
|
||||
#include "nouveau_fbcon.h"
|
||||
|
||||
void
|
||||
int
|
||||
nv50_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, rect->rop == ROP_COPY ? 7 : 11)) {
|
||||
nouveau_fbcon_gpu_lockup(info);
|
||||
}
|
||||
|
||||
if (info->flags & FBINFO_HWACCEL_DISABLED) {
|
||||
cfb_fillrect(info, rect);
|
||||
return;
|
||||
}
|
||||
ret = RING_SPACE(chan, rect->rop == ROP_COPY ? 7 : 11);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (rect->rop != ROP_COPY) {
|
||||
BEGIN_RING(chan, NvSub2D, 0x02ac, 1);
|
||||
|
@ -45,27 +37,21 @@ nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
|
|||
OUT_RING(chan, 3);
|
||||
}
|
||||
FIRE_RING(chan);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
nv50_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, 12)) {
|
||||
nouveau_fbcon_gpu_lockup(info);
|
||||
}
|
||||
|
||||
if (info->flags & FBINFO_HWACCEL_DISABLED) {
|
||||
cfb_copyarea(info, region);
|
||||
return;
|
||||
}
|
||||
ret = RING_SPACE(chan, 12);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
BEGIN_RING(chan, NvSub2D, 0x0110, 1);
|
||||
OUT_RING(chan, 0);
|
||||
|
@ -80,9 +66,10 @@ nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
|
|||
OUT_RING(chan, 0);
|
||||
OUT_RING(chan, region->sy);
|
||||
FIRE_RING(chan);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
|
||||
{
|
||||
struct nouveau_fbdev *nfbdev = info->par;
|
||||
|
@ -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 mask = ~(~0 >> (32 - info->var.bits_per_pixel));
|
||||
uint32_t *palette = info->pseudo_palette;
|
||||
int ret;
|
||||
|
||||
if (info->state != FBINFO_STATE_RUNNING)
|
||||
return;
|
||||
if (image->depth != 1)
|
||||
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) {
|
||||
cfb_imageblit(info, image);
|
||||
return;
|
||||
}
|
||||
ret = RING_SPACE(chan, 11);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
width = ALIGN(image->width, 32);
|
||||
dwords = (width * image->height) >> 5;
|
||||
|
@ -134,11 +112,9 @@ nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
|
|||
while (dwords) {
|
||||
int push = dwords > 2047 ? 2047 : dwords;
|
||||
|
||||
if (RING_SPACE(chan, push + 1)) {
|
||||
nouveau_fbcon_gpu_lockup(info);
|
||||
cfb_imageblit(info, image);
|
||||
return;
|
||||
}
|
||||
ret = RING_SPACE(chan, push + 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dwords -= push;
|
||||
|
||||
|
@ -148,6 +124,7 @@ nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
|
|||
}
|
||||
|
||||
FIRE_RING(chan);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
|
|
Loading…
Reference in a new issue