aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/udl/udl_fb.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2013-02-06 20:19:15 -0500
committerDave Airlie <airlied@redhat.com>2013-02-06 21:37:50 -0500
commitbcb39af4486be07e896fc374a2336bad3104ae0a (patch)
tree0defaeec6703bc530d178518a66937bdf8dc9b79 /drivers/gpu/drm/udl/udl_fb.c
parent9f23de52b64f7fb801fd76f3dd8651a0dc89187b (diff)
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>
Diffstat (limited to 'drivers/gpu/drm/udl/udl_fb.c')
-rw-r--r--drivers/gpu/drm/udl/udl_fb.c44
1 files changed, 40 insertions, 4 deletions
diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c
index d4ab3beaada0..c35880ff2207 100644
--- a/drivers/gpu/drm/udl/udl_fb.c
+++ b/drivers/gpu/drm/udl/udl_fb.c
@@ -153,6 +153,9 @@ int udl_handle_damage(struct udl_framebuffer *fb, int x, int y,
153 struct urb *urb; 153 struct urb *urb;
154 int aligned_x; 154 int aligned_x;
155 int bpp = (fb->base.bits_per_pixel / 8); 155 int bpp = (fb->base.bits_per_pixel / 8);
156 int x2, y2;
157 bool store_for_later = false;
158 unsigned long flags;
156 159
157 if (!fb->active_16) 160 if (!fb->active_16)
158 return 0; 161 return 0;
@@ -169,8 +172,6 @@ int udl_handle_damage(struct udl_framebuffer *fb, int x, int y,
169 } 172 }
170 } 173 }
171 174
172 start_cycles = get_cycles();
173
174 aligned_x = DL_ALIGN_DOWN(x, sizeof(unsigned long)); 175 aligned_x = DL_ALIGN_DOWN(x, sizeof(unsigned long));
175 width = DL_ALIGN_UP(width + (x-aligned_x), sizeof(unsigned long)); 176 width = DL_ALIGN_UP(width + (x-aligned_x), sizeof(unsigned long));
176 x = aligned_x; 177 x = aligned_x;
@@ -180,19 +181,53 @@ int udl_handle_damage(struct udl_framebuffer *fb, int x, int y,
180 (y + height > fb->base.height)) 181 (y + height > fb->base.height))
181 return -EINVAL; 182 return -EINVAL;
182 183
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
183 urb = udl_get_urb(dev); 218 urb = udl_get_urb(dev);
184 if (!urb) 219 if (!urb)
185 return 0; 220 return 0;
186 cmd = urb->transfer_buffer; 221 cmd = urb->transfer_buffer;
187 222
188 for (i = y; i < y + height ; i++) { 223 for (i = y; i <= y2 ; i++) {
189 const int line_offset = fb->base.pitches[0] * i; 224 const int line_offset = fb->base.pitches[0] * i;
190 const int byte_offset = line_offset + (x * bpp); 225 const int byte_offset = line_offset + (x * bpp);
191 const int dev_byte_offset = (fb->base.width * bpp * i) + (x * bpp); 226 const int dev_byte_offset = (fb->base.width * bpp * i) + (x * bpp);
192 if (udl_render_hline(dev, bpp, &urb, 227 if (udl_render_hline(dev, bpp, &urb,
193 (char *) fb->obj->vmapping, 228 (char *) fb->obj->vmapping,
194 &cmd, byte_offset, dev_byte_offset, 229 &cmd, byte_offset, dev_byte_offset,
195 width * bpp, 230 (x2 - x + 1) * bpp,
196 &bytes_identical, &bytes_sent)) 231 &bytes_identical, &bytes_sent))
197 goto error; 232 goto error;
198 } 233 }
@@ -434,6 +469,7 @@ udl_framebuffer_init(struct drm_device *dev,
434{ 469{
435 int ret; 470 int ret;
436 471
472 spin_lock_init(&ufb->dirty_lock);
437 ufb->obj = obj; 473 ufb->obj = obj;
438 ret = drm_framebuffer_init(dev, &ufb->base, &udlfb_funcs); 474 ret = drm_framebuffer_init(dev, &ufb->base, &udlfb_funcs);
439 drm_helper_mode_fill_fb_struct(&ufb->base, mode_cmd); 475 drm_helper_mode_fill_fb_struct(&ufb->base, mode_cmd);