fbcon: Use delayed work for cursor
Allows us to delete a bunch of hand-rolled stuff using a timer plus a separate work). Also to simplify the code we initialize the cursor_work completely when we allocate the fbcon_ops structure, instead of trying to cope with console re-initialization. The motiviation here is that fbcon code stops using the fb_info.queue, which helps with locking issues around cleanup and all that in a later patch. Also note that this allows us to ditch the hand-rolled work cleanup in fbcon_exit - we already call fbcon_del_cursor_timer, which takes care of everything. Plus this was racy anyway. v2: - Only INIT_DELAYED_WORK when kzalloc succeeded (Tetsuo) - Explain that we replace both the timer and a work with the combined delayed_work (Javier) Reviewed-by: Javier Martinez Canillas <javierm@redhat.com> Acked-by: Thomas Zimmermann <tzimmermann@suse.de> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com> Cc: Daniel Vetter <daniel@ffwll.ch> Cc: Claudio Suarez <cssk@net-c.es> Cc: Du Cheng <ducheng2@gmail.com> Cc: Thomas Zimmermann <tzimmermann@suse.de> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> Link: https://patchwork.freedesktop.org/patch/msgid/20220405210335.3434130-7-daniel.vetter@ffwll.ch
This commit is contained in:
parent
9ad5cc9bcf
commit
3b0fb6ab25
|
@ -350,8 +350,8 @@ static int get_color(struct vc_data *vc, struct fb_info *info,
|
|||
|
||||
static void fb_flashcursor(struct work_struct *work)
|
||||
{
|
||||
struct fb_info *info = container_of(work, struct fb_info, queue);
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
struct fbcon_ops *ops = container_of(work, struct fbcon_ops, cursor_work.work);
|
||||
struct fb_info *info;
|
||||
struct vc_data *vc = NULL;
|
||||
int c;
|
||||
int mode;
|
||||
|
@ -364,7 +364,10 @@ static void fb_flashcursor(struct work_struct *work)
|
|||
if (ret == 0)
|
||||
return;
|
||||
|
||||
if (ops && ops->currcon != -1)
|
||||
/* protected by console_lock */
|
||||
info = ops->info;
|
||||
|
||||
if (ops->currcon != -1)
|
||||
vc = vc_cons[ops->currcon].d;
|
||||
|
||||
if (!vc || !con_is_visible(vc) ||
|
||||
|
@ -380,42 +383,25 @@ static void fb_flashcursor(struct work_struct *work)
|
|||
ops->cursor(vc, info, mode, get_color(vc, info, c, 1),
|
||||
get_color(vc, info, c, 0));
|
||||
console_unlock();
|
||||
|
||||
queue_delayed_work(system_power_efficient_wq, &ops->cursor_work,
|
||||
ops->cur_blink_jiffies);
|
||||
}
|
||||
|
||||
static void cursor_timer_handler(struct timer_list *t)
|
||||
{
|
||||
struct fbcon_ops *ops = from_timer(ops, t, cursor_timer);
|
||||
struct fb_info *info = ops->info;
|
||||
|
||||
queue_work(system_power_efficient_wq, &info->queue);
|
||||
mod_timer(&ops->cursor_timer, jiffies + ops->cur_blink_jiffies);
|
||||
}
|
||||
|
||||
static void fbcon_add_cursor_timer(struct fb_info *info)
|
||||
static void fbcon_add_cursor_work(struct fb_info *info)
|
||||
{
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
|
||||
if ((!info->queue.func || info->queue.func == fb_flashcursor) &&
|
||||
!(ops->flags & FBCON_FLAGS_CURSOR_TIMER) &&
|
||||
!fbcon_cursor_noblink) {
|
||||
if (!info->queue.func)
|
||||
INIT_WORK(&info->queue, fb_flashcursor);
|
||||
|
||||
timer_setup(&ops->cursor_timer, cursor_timer_handler, 0);
|
||||
mod_timer(&ops->cursor_timer, jiffies + ops->cur_blink_jiffies);
|
||||
ops->flags |= FBCON_FLAGS_CURSOR_TIMER;
|
||||
}
|
||||
if (!fbcon_cursor_noblink)
|
||||
queue_delayed_work(system_power_efficient_wq, &ops->cursor_work,
|
||||
ops->cur_blink_jiffies);
|
||||
}
|
||||
|
||||
static void fbcon_del_cursor_timer(struct fb_info *info)
|
||||
static void fbcon_del_cursor_work(struct fb_info *info)
|
||||
{
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
|
||||
if (info->queue.func == fb_flashcursor &&
|
||||
ops->flags & FBCON_FLAGS_CURSOR_TIMER) {
|
||||
del_timer_sync(&ops->cursor_timer);
|
||||
ops->flags &= ~FBCON_FLAGS_CURSOR_TIMER;
|
||||
}
|
||||
cancel_delayed_work_sync(&ops->cursor_work);
|
||||
}
|
||||
|
||||
#ifndef MODULE
|
||||
|
@ -717,6 +703,8 @@ static int con2fb_acquire_newinfo(struct vc_data *vc, struct fb_info *info,
|
|||
}
|
||||
|
||||
if (!err) {
|
||||
INIT_DELAYED_WORK(&ops->cursor_work, fb_flashcursor);
|
||||
|
||||
ops->cur_blink_jiffies = HZ / 5;
|
||||
ops->info = info;
|
||||
info->fbcon_par = ops;
|
||||
|
@ -751,7 +739,7 @@ static int con2fb_release_oldinfo(struct vc_data *vc, struct fb_info *oldinfo,
|
|||
}
|
||||
|
||||
if (!err) {
|
||||
fbcon_del_cursor_timer(oldinfo);
|
||||
fbcon_del_cursor_work(oldinfo);
|
||||
kfree(ops->cursor_state.mask);
|
||||
kfree(ops->cursor_data);
|
||||
kfree(ops->cursor_src);
|
||||
|
@ -867,7 +855,7 @@ static int set_con2fb_map(int unit, int newidx, int user)
|
|||
logo_shown != FBCON_LOGO_DONTSHOW);
|
||||
|
||||
if (!found)
|
||||
fbcon_add_cursor_timer(info);
|
||||
fbcon_add_cursor_work(info);
|
||||
con2fb_map_boot[unit] = newidx;
|
||||
con2fb_init_display(vc, info, unit, show_logo);
|
||||
}
|
||||
|
@ -964,6 +952,8 @@ static const char *fbcon_startup(void)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
INIT_DELAYED_WORK(&ops->cursor_work, fb_flashcursor);
|
||||
|
||||
ops->currcon = -1;
|
||||
ops->graphics = 1;
|
||||
ops->cur_rotate = -1;
|
||||
|
@ -1006,7 +996,7 @@ static const char *fbcon_startup(void)
|
|||
info->var.yres,
|
||||
info->var.bits_per_pixel);
|
||||
|
||||
fbcon_add_cursor_timer(info);
|
||||
fbcon_add_cursor_work(info);
|
||||
return display_desc;
|
||||
}
|
||||
|
||||
|
@ -1194,7 +1184,7 @@ static void fbcon_deinit(struct vc_data *vc)
|
|||
goto finished;
|
||||
|
||||
if (con_is_visible(vc))
|
||||
fbcon_del_cursor_timer(info);
|
||||
fbcon_del_cursor_work(info);
|
||||
|
||||
ops->flags &= ~FBCON_FLAGS_INIT;
|
||||
finished:
|
||||
|
@ -1320,9 +1310,9 @@ static void fbcon_cursor(struct vc_data *vc, int mode)
|
|||
return;
|
||||
|
||||
if (vc->vc_cursor_type & CUR_SW)
|
||||
fbcon_del_cursor_timer(info);
|
||||
fbcon_del_cursor_work(info);
|
||||
else
|
||||
fbcon_add_cursor_timer(info);
|
||||
fbcon_add_cursor_work(info);
|
||||
|
||||
ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1;
|
||||
|
||||
|
@ -2132,14 +2122,14 @@ static int fbcon_switch(struct vc_data *vc)
|
|||
}
|
||||
|
||||
if (old_info != info)
|
||||
fbcon_del_cursor_timer(old_info);
|
||||
fbcon_del_cursor_work(old_info);
|
||||
}
|
||||
|
||||
if (fbcon_is_inactive(vc, info) ||
|
||||
ops->blank_state != FB_BLANK_UNBLANK)
|
||||
fbcon_del_cursor_timer(info);
|
||||
fbcon_del_cursor_work(info);
|
||||
else
|
||||
fbcon_add_cursor_timer(info);
|
||||
fbcon_add_cursor_work(info);
|
||||
|
||||
set_blitting_type(vc, info);
|
||||
ops->cursor_reset = 1;
|
||||
|
@ -2247,9 +2237,9 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)
|
|||
|
||||
if (mode_switch || fbcon_is_inactive(vc, info) ||
|
||||
ops->blank_state != FB_BLANK_UNBLANK)
|
||||
fbcon_del_cursor_timer(info);
|
||||
fbcon_del_cursor_work(info);
|
||||
else
|
||||
fbcon_add_cursor_timer(info);
|
||||
fbcon_add_cursor_work(info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -3181,7 +3171,7 @@ static ssize_t show_cursor_blink(struct device *device,
|
|||
if (!ops)
|
||||
goto err;
|
||||
|
||||
blink = (ops->flags & FBCON_FLAGS_CURSOR_TIMER) ? 1 : 0;
|
||||
blink = delayed_work_pending(&ops->cursor_work);
|
||||
err:
|
||||
console_unlock();
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", blink);
|
||||
|
@ -3210,10 +3200,10 @@ static ssize_t store_cursor_blink(struct device *device,
|
|||
|
||||
if (blink) {
|
||||
fbcon_cursor_noblink = 0;
|
||||
fbcon_add_cursor_timer(info);
|
||||
fbcon_add_cursor_work(info);
|
||||
} else {
|
||||
fbcon_cursor_noblink = 1;
|
||||
fbcon_del_cursor_timer(info);
|
||||
fbcon_del_cursor_work(info);
|
||||
}
|
||||
|
||||
err:
|
||||
|
@ -3314,15 +3304,9 @@ static void fbcon_exit(void)
|
|||
#endif
|
||||
|
||||
for_each_registered_fb(i) {
|
||||
int pending = 0;
|
||||
|
||||
mapped = 0;
|
||||
info = registered_fb[i];
|
||||
|
||||
if (info->queue.func)
|
||||
pending = cancel_work_sync(&info->queue);
|
||||
pr_debug("fbcon: %s pending work\n", (pending ? "canceled" : "no"));
|
||||
|
||||
for (j = first_fb_vc; j <= last_fb_vc; j++) {
|
||||
if (con2fb_map[j] == i) {
|
||||
mapped = 1;
|
||||
|
@ -3338,15 +3322,12 @@ static void fbcon_exit(void)
|
|||
if (info->fbcon_par) {
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
|
||||
fbcon_del_cursor_timer(info);
|
||||
fbcon_del_cursor_work(info);
|
||||
kfree(ops->cursor_src);
|
||||
kfree(ops->cursor_state.mask);
|
||||
kfree(info->fbcon_par);
|
||||
info->fbcon_par = NULL;
|
||||
}
|
||||
|
||||
if (info->queue.func == fb_flashcursor)
|
||||
info->queue.func = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,11 +14,11 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/vt_buffer.h>
|
||||
#include <linux/vt_kern.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
#define FBCON_FLAGS_INIT 1
|
||||
#define FBCON_FLAGS_CURSOR_TIMER 2
|
||||
|
||||
/*
|
||||
* This is the interface between the low-level console driver and the
|
||||
|
@ -68,7 +68,7 @@ struct fbcon_ops {
|
|||
int (*update_start)(struct fb_info *info);
|
||||
int (*rotate_font)(struct fb_info *info, struct vc_data *vc);
|
||||
struct fb_var_screeninfo var; /* copy of the current fb_var_screeninfo */
|
||||
struct timer_list cursor_timer; /* Cursor timer */
|
||||
struct delayed_work cursor_work; /* Cursor timer */
|
||||
struct fb_cursor cursor_state;
|
||||
struct fbcon_display *p;
|
||||
struct fb_info *info;
|
||||
|
|
Loading…
Reference in New Issue