Skip to content

Commit bcb39af

Browse files
committed
drm/udl: make usage as a console safer
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>
1 parent 9f23de5 commit bcb39af

File tree

2 files changed

+42
-4
lines changed

2 files changed

+42
-4
lines changed

drivers/gpu/drm/udl/udl_drv.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ struct udl_framebuffer {
7575
struct drm_framebuffer base;
7676
struct udl_gem_object *obj;
7777
bool active_16; /* active on the 16-bit channel */
78+
int x1, y1, x2, y2; /* dirty rect */
79+
spinlock_t dirty_lock;
7880
};
7981

8082
#define to_udl_fb(x) container_of(x, struct udl_framebuffer, base)

drivers/gpu/drm/udl/udl_fb.c

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,9 @@ int udl_handle_damage(struct udl_framebuffer *fb, int x, int y,
153153
struct urb *urb;
154154
int aligned_x;
155155
int bpp = (fb->base.bits_per_pixel / 8);
156+
int x2, y2;
157+
bool store_for_later = false;
158+
unsigned long flags;
156159

157160
if (!fb->active_16)
158161
return 0;
@@ -169,8 +172,6 @@ int udl_handle_damage(struct udl_framebuffer *fb, int x, int y,
169172
}
170173
}
171174

172-
start_cycles = get_cycles();
173-
174175
aligned_x = DL_ALIGN_DOWN(x, sizeof(unsigned long));
175176
width = DL_ALIGN_UP(width + (x-aligned_x), sizeof(unsigned long));
176177
x = aligned_x;
@@ -180,19 +181,53 @@ int udl_handle_damage(struct udl_framebuffer *fb, int x, int y,
180181
(y + height > fb->base.height))
181182
return -EINVAL;
182183

184+
/* if we are in atomic just store the info
185+
can't test inside spin lock */
186+
if (in_atomic())
187+
store_for_later = true;
188+
189+
x2 = x + width - 1;
190+
y2 = y + height - 1;
191+
192+
spin_lock_irqsave(&fb->dirty_lock, flags);
193+
194+
if (fb->y1 < y)
195+
y = fb->y1;
196+
if (fb->y2 > y2)
197+
y2 = fb->y2;
198+
if (fb->x1 < x)
199+
x = fb->x1;
200+
if (fb->x2 > x2)
201+
x2 = fb->x2;
202+
203+
if (store_for_later) {
204+
fb->x1 = x;
205+
fb->x2 = x2;
206+
fb->y1 = y;
207+
fb->y2 = y2;
208+
spin_unlock_irqrestore(&fb->dirty_lock, flags);
209+
return 0;
210+
}
211+
212+
fb->x1 = fb->y1 = INT_MAX;
213+
fb->x2 = fb->y2 = 0;
214+
215+
spin_unlock_irqrestore(&fb->dirty_lock, flags);
216+
start_cycles = get_cycles();
217+
183218
urb = udl_get_urb(dev);
184219
if (!urb)
185220
return 0;
186221
cmd = urb->transfer_buffer;
187222

188-
for (i = y; i < y + height ; i++) {
223+
for (i = y; i <= y2 ; i++) {
189224
const int line_offset = fb->base.pitches[0] * i;
190225
const int byte_offset = line_offset + (x * bpp);
191226
const int dev_byte_offset = (fb->base.width * bpp * i) + (x * bpp);
192227
if (udl_render_hline(dev, bpp, &urb,
193228
(char *) fb->obj->vmapping,
194229
&cmd, byte_offset, dev_byte_offset,
195-
width * bpp,
230+
(x2 - x + 1) * bpp,
196231
&bytes_identical, &bytes_sent))
197232
goto error;
198233
}
@@ -434,6 +469,7 @@ udl_framebuffer_init(struct drm_device *dev,
434469
{
435470
int ret;
436471

472+
spin_lock_init(&ufb->dirty_lock);
437473
ufb->obj = obj;
438474
ret = drm_framebuffer_init(dev, &ufb->base, &udlfb_funcs);
439475
drm_helper_mode_fill_fb_struct(&ufb->base, mode_cmd);

0 commit comments

Comments
 (0)