aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--drivers/gpu/drm/udl/udl_drv.h2
-rw-r--r--drivers/gpu/drm/udl/udl_fb.c44
2 files changed, 42 insertions, 4 deletions
diff --git a/drivers/gpu/drm/udl/udl_drv.h b/drivers/gpu/drm/udl/udl_drv.h
index 87aa5f5d3c88..cc6d90f28c71 100644
--- a/drivers/gpu/drm/udl/udl_drv.h
+++ b/drivers/gpu/drm/udl/udl_drv.h
@@ -75,6 +75,8 @@ struct udl_framebuffer {
75 struct drm_framebuffer base; 75 struct drm_framebuffer base;
76 struct udl_gem_object *obj; 76 struct udl_gem_object *obj;
77 bool active_16; /* active on the 16-bit channel */ 77 bool active_16; /* active on the 16-bit channel */
78 int x1, y1, x2, y2; /* dirty rect */
79 spinlock_t dirty_lock;
78}; 80};
79 81
80#define to_udl_fb(x) container_of(x, struct udl_framebuffer, base) 82#define to_udl_fb(x) container_of(x, struct udl_framebuffer, base)
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);