Skip to content

Commit

Permalink
drm/udl: make usage as a console safer
Browse files Browse the repository at this point in the history
Okay you don't really want to use udl devices as your console, but if
you are unlucky enough to do so, you run into a lot of schedule while atomic
due to printk being called from all sorts of funky places. So check if we
are in an atomic context, and queue the damage for later, the next printk
should cause it to appear. This isn't ideal, but it is simple, and seems to
work okay in my testing here.

(dirty area idea came from xenfb)

fixes a bunch of sleeping while atomic issues running fbcon on udl devices.

Cc: stable@vger.kernel.org
Signed-off-by: Dave Airlie <airlied@redhat.com>
  • Loading branch information
Dave Airlie committed Feb 7, 2013
1 parent 9f23de5 commit bcb39af
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 4 deletions.
2 changes: 2 additions & 0 deletions drivers/gpu/drm/udl/udl_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ struct udl_framebuffer {
struct drm_framebuffer base;
struct udl_gem_object *obj;
bool active_16; /* active on the 16-bit channel */
int x1, y1, x2, y2; /* dirty rect */
spinlock_t dirty_lock;
};

#define to_udl_fb(x) container_of(x, struct udl_framebuffer, base)
Expand Down
44 changes: 40 additions & 4 deletions drivers/gpu/drm/udl/udl_fb.c
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,9 @@ int udl_handle_damage(struct udl_framebuffer *fb, int x, int y,
struct urb *urb;
int aligned_x;
int bpp = (fb->base.bits_per_pixel / 8);
int x2, y2;
bool store_for_later = false;
unsigned long flags;

if (!fb->active_16)
return 0;
Expand All @@ -169,8 +172,6 @@ int udl_handle_damage(struct udl_framebuffer *fb, int x, int y,
}
}

start_cycles = get_cycles();

aligned_x = DL_ALIGN_DOWN(x, sizeof(unsigned long));
width = DL_ALIGN_UP(width + (x-aligned_x), sizeof(unsigned long));
x = aligned_x;
Expand All @@ -180,19 +181,53 @@ int udl_handle_damage(struct udl_framebuffer *fb, int x, int y,
(y + height > fb->base.height))
return -EINVAL;

/* if we are in atomic just store the info
can't test inside spin lock */
if (in_atomic())
store_for_later = true;

x2 = x + width - 1;
y2 = y + height - 1;

spin_lock_irqsave(&fb->dirty_lock, flags);

if (fb->y1 < y)
y = fb->y1;
if (fb->y2 > y2)
y2 = fb->y2;
if (fb->x1 < x)
x = fb->x1;
if (fb->x2 > x2)
x2 = fb->x2;

if (store_for_later) {
fb->x1 = x;
fb->x2 = x2;
fb->y1 = y;
fb->y2 = y2;
spin_unlock_irqrestore(&fb->dirty_lock, flags);
return 0;
}

fb->x1 = fb->y1 = INT_MAX;
fb->x2 = fb->y2 = 0;

spin_unlock_irqrestore(&fb->dirty_lock, flags);
start_cycles = get_cycles();

urb = udl_get_urb(dev);
if (!urb)
return 0;
cmd = urb->transfer_buffer;

for (i = y; i < y + height ; i++) {
for (i = y; i <= y2 ; i++) {
const int line_offset = fb->base.pitches[0] * i;
const int byte_offset = line_offset + (x * bpp);
const int dev_byte_offset = (fb->base.width * bpp * i) + (x * bpp);
if (udl_render_hline(dev, bpp, &urb,
(char *) fb->obj->vmapping,
&cmd, byte_offset, dev_byte_offset,
width * bpp,
(x2 - x + 1) * bpp,
&bytes_identical, &bytes_sent))
goto error;
}
Expand Down Expand Up @@ -434,6 +469,7 @@ udl_framebuffer_init(struct drm_device *dev,
{
int ret;

spin_lock_init(&ufb->dirty_lock);
ufb->obj = obj;
ret = drm_framebuffer_init(dev, &ufb->base, &udlfb_funcs);
drm_helper_mode_fill_fb_struct(&ufb->base, mode_cmd);
Expand Down

0 comments on commit bcb39af

Please sign in to comment.