Merge branch 'kms-merge' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/linux-2.6-kgdb
* 'kms-merge' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/linux-2.6-kgdb: kgdb,docs: Update the kgdb docs to include kms drm_fb_helper: Preserve capability to use atomic kms i915: when kgdb is active display compression should be off drm/i915: use new fb debug hooks drm: add KGDB/KDB support fb: add hooks to handle KDB enter/exit kgdboc: Add call backs to allow kernel mode switching vt,console,kdb: automatically set kdb LINES variable vt,console,kdb: implement atomic console enter/leave functions
This commit is contained in:
Коммит
9779714c8a
|
@ -199,10 +199,33 @@
|
|||
may be configured as a kernel built-in or a kernel loadable module.
|
||||
You can only make use of <constant>kgdbwait</constant> and early
|
||||
debugging if you build kgdboc into the kernel as a built-in.
|
||||
<para>Optionally you can elect to activate kms (Kernel Mode
|
||||
Setting) integration. When you use kms with kgdboc and you have a
|
||||
video driver that has atomic mode setting hooks, it is possible to
|
||||
enter the debugger on the graphics console. When the kernel
|
||||
execution is resumed, the previous graphics mode will be restored.
|
||||
This integration can serve as a useful tool to aid in diagnosing
|
||||
crashes or doing analysis of memory with kdb while allowing the
|
||||
full graphics console applications to run.
|
||||
</para>
|
||||
</para>
|
||||
<sect2 id="kgdbocArgs">
|
||||
<title>kgdboc arguments</title>
|
||||
<para>Usage: <constant>kgdboc=[kbd][[,]serial_device][,baud]</constant></para>
|
||||
<para>Usage: <constant>kgdboc=[kms][[,]kbd][[,]serial_device][,baud]</constant></para>
|
||||
<para>The order listed above must be observed if you use any of the
|
||||
optional configurations together.
|
||||
</para>
|
||||
<para>Abbreviations:
|
||||
<itemizedlist>
|
||||
<listitem><para>kms = Kernel Mode Setting</para></listitem>
|
||||
<listitem><para>kbd = Keyboard</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
<para>You can configure kgdboc to use the keyboard, and or a serial
|
||||
device depending on if you are using kdb and or kgdb, in one of the
|
||||
following scenarios. The order listed above must be observed if
|
||||
you use any of the optional configurations together. Using kms +
|
||||
only gdb is generally not a useful combination.</para>
|
||||
<sect3 id="kgdbocArgs1">
|
||||
<title>Using loadable module or built-in</title>
|
||||
<para>
|
||||
|
@ -212,7 +235,7 @@
|
|||
<listitem>
|
||||
<para>As a kernel loadable module:</para>
|
||||
<para>Use the command: <constant>modprobe kgdboc kgdboc=<tty-device>,[baud]</constant></para>
|
||||
<para>Here are two examples of how you might formate the kgdboc
|
||||
<para>Here are two examples of how you might format the kgdboc
|
||||
string. The first is for an x86 target using the first serial port.
|
||||
The second example is for the ARM Versatile AB using the second
|
||||
serial port.
|
||||
|
@ -240,6 +263,9 @@
|
|||
</sect3>
|
||||
<sect3 id="kgdbocArgs3">
|
||||
<title>More examples</title>
|
||||
<para>You can configure kgdboc to use the keyboard, and or a serial
|
||||
device depending on if you are using kdb and or kgdb, in one of the
|
||||
following scenarios.</para>
|
||||
<para>You can configure kgdboc to use the keyboard, and or a serial device
|
||||
depending on if you are using kdb and or kgdb, in one of the
|
||||
following scenarios.
|
||||
|
@ -255,6 +281,12 @@
|
|||
<listitem><para>kdb with a keyboard</para>
|
||||
<para><constant>kgdboc=kbd</constant></para>
|
||||
</listitem>
|
||||
<listitem><para>kdb with kernel mode setting</para>
|
||||
<para><constant>kgdboc=kms,kbd</constant></para>
|
||||
</listitem>
|
||||
<listitem><para>kdb with kernel mode setting and kgdb over a serial port</para>
|
||||
<para><constant>kgdboc=kms,kbd,ttyS0,115200</constant></para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
</para>
|
||||
</sect3>
|
||||
|
@ -637,6 +669,8 @@ Task Addr Pid Parent [*] cpu State Thread Command
|
|||
<listitem><para>The logic to perform safe memory reads and writes to memory while using the debugger</para></listitem>
|
||||
<listitem><para>A full implementation for software breakpoints unless overridden by the arch</para></listitem>
|
||||
<listitem><para>The API to invoke either the kdb or kgdb frontend to the debug core.</para></listitem>
|
||||
<listitem><para>The structures and callback API for atomic kernel mode setting.</para>
|
||||
<para>NOTE: kgdboc is where the kms callbacks are invoked.</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</listitem>
|
||||
|
@ -747,6 +781,8 @@ Task Addr Pid Parent [*] cpu State Thread Command
|
|||
</sect1>
|
||||
<sect1 id="kgdbocDesign">
|
||||
<title>kgdboc internals</title>
|
||||
<sect2>
|
||||
<title>kgdboc and uarts</title>
|
||||
<para>
|
||||
The kgdboc driver is actually a very thin driver that relies on the
|
||||
underlying low level to the hardware driver having "polling hooks"
|
||||
|
@ -754,11 +790,8 @@ Task Addr Pid Parent [*] cpu State Thread Command
|
|||
implementation of kgdboc it the serial_core was changed to expose a
|
||||
low level UART hook for doing polled mode reading and writing of a
|
||||
single character while in an atomic context. When kgdb makes an I/O
|
||||
request to the debugger, kgdboc invokes a call back in the serial
|
||||
core which in turn uses the call back in the UART driver. It is
|
||||
certainly possible to extend kgdboc to work with non-UART based
|
||||
consoles in the future.
|
||||
</para>
|
||||
request to the debugger, kgdboc invokes a callback in the serial
|
||||
core which in turn uses the callback in the UART driver.</para>
|
||||
<para>
|
||||
When using kgdboc with a UART, the UART driver must implement two callbacks in the <constant>struct uart_ops</constant>. Example from drivers/8250.c:<programlisting>
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
|
@ -772,9 +805,68 @@ Task Addr Pid Parent [*] cpu State Thread Command
|
|||
that they can be called from an atomic context and have to restore
|
||||
the state of the UART chip on return such that the system can return
|
||||
to normal when the debugger detaches. You need to be very careful
|
||||
with any kind of lock you consider, because failing here is most
|
||||
with any kind of lock you consider, because failing here is most likely
|
||||
going to mean pressing the reset button.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2 id="kgdbocKbd">
|
||||
<title>kgdboc and keyboards</title>
|
||||
<para>The kgdboc driver contains logic to configure communications
|
||||
with an attached keyboard. The keyboard infrastructure is only
|
||||
compiled into the kernel when CONFIG_KDB_KEYBOARD=y is set in the
|
||||
kernel configuration.</para>
|
||||
<para>The core polled keyboard driver driver for PS/2 type keyboards
|
||||
is in drivers/char/kdb_keyboard.c. This driver is hooked into the
|
||||
debug core when kgdboc populates the callback in the array
|
||||
called <constant>kdb_poll_funcs[]</constant>. The
|
||||
kdb_get_kbd_char() is the top-level function which polls hardware
|
||||
for single character input.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2 id="kgdbocKms">
|
||||
<title>kgdboc and kms</title>
|
||||
<para>The kgdboc driver contains logic to request the graphics
|
||||
display to switch to a text context when you are using
|
||||
"kgdboc=kms,kbd", provided that you have a video driver which has a
|
||||
frame buffer console and atomic kernel mode setting support.</para>
|
||||
<para>
|
||||
Every time the kernel
|
||||
debugger is entered it calls kgdboc_pre_exp_handler() which in turn
|
||||
calls con_debug_enter() in the virtual console layer. On resuming kernel
|
||||
execution, the kernel debugger calls kgdboc_post_exp_handler() which
|
||||
in turn calls con_debug_leave().</para>
|
||||
<para>Any video driver that wants to be compatible with the kernel
|
||||
debugger and the atomic kms callbacks must implement the
|
||||
mode_set_base_atomic, fb_debug_enter and fb_debug_leave operations.
|
||||
For the fb_debug_enter and fb_debug_leave the option exists to use
|
||||
the generic drm fb helper functions or implement something custom for
|
||||
the hardware. The following example shows the initialization of the
|
||||
.mode_set_base_atomic operation in
|
||||
drivers/gpu/drm/i915/intel_display.c:
|
||||
<informalexample>
|
||||
<programlisting>
|
||||
static const struct drm_crtc_helper_funcs intel_helper_funcs = {
|
||||
[...]
|
||||
.mode_set_base_atomic = intel_pipe_set_base_atomic,
|
||||
[...]
|
||||
};
|
||||
</programlisting>
|
||||
</informalexample>
|
||||
</para>
|
||||
<para>Here is an example of how the i915 driver initializes the fb_debug_enter and fb_debug_leave functions to use the generic drm helpers in
|
||||
drivers/gpu/drm/i915/intel_fb.c:
|
||||
<informalexample>
|
||||
<programlisting>
|
||||
static struct fb_ops intelfb_ops = {
|
||||
[...]
|
||||
.fb_debug_enter = drm_fb_helper_debug_enter,
|
||||
.fb_debug_leave = drm_fb_helper_debug_leave,
|
||||
[...]
|
||||
};
|
||||
</programlisting>
|
||||
</informalexample>
|
||||
</para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
</chapter>
|
||||
<chapter id="credits">
|
||||
|
|
|
@ -1145,9 +1145,12 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
kgdboc= [KGDB,HW] kgdb over consoles.
|
||||
Requires a tty driver that supports console polling,
|
||||
or a supported polling keyboard driver (non-usb).
|
||||
Serial only format: <serial_device>[,baud]
|
||||
keyboard only format: kbd
|
||||
keyboard and serial format: kbd,<serial_device>[,baud]
|
||||
Serial only format: <serial_device>[,baud]
|
||||
keyboard only format: kbd
|
||||
keyboard and serial format: kbd,<serial_device>[,baud]
|
||||
Optional Kernel mode setting:
|
||||
kms, kbd format: kms,kbd
|
||||
kms, kbd and serial format: kms,kbd,<ser_dev>[,baud]
|
||||
|
||||
kgdbwait [KGDB] Stop kernel execution and enter the
|
||||
kernel debugger at the earliest opportunity.
|
||||
|
|
|
@ -104,6 +104,7 @@
|
|||
#include <linux/io.h>
|
||||
#include <asm/system.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/kdb.h>
|
||||
|
||||
#define MAX_NR_CON_DRIVER 16
|
||||
|
||||
|
@ -187,10 +188,15 @@ static DECLARE_WORK(console_work, console_callback);
|
|||
* fg_console is the current virtual console,
|
||||
* last_console is the last used one,
|
||||
* want_console is the console we want to switch to,
|
||||
* saved_* variants are for save/restore around kernel debugger enter/leave
|
||||
*/
|
||||
int fg_console;
|
||||
int last_console;
|
||||
int want_console = -1;
|
||||
int saved_fg_console;
|
||||
int saved_last_console;
|
||||
int saved_want_console;
|
||||
int saved_vc_mode;
|
||||
|
||||
/*
|
||||
* For each existing display, we have a pointer to console currently visible
|
||||
|
@ -3413,6 +3419,78 @@ int con_is_bound(const struct consw *csw)
|
|||
}
|
||||
EXPORT_SYMBOL(con_is_bound);
|
||||
|
||||
/**
|
||||
* con_debug_enter - prepare the console for the kernel debugger
|
||||
* @sw: console driver
|
||||
*
|
||||
* Called when the console is taken over by the kernel debugger, this
|
||||
* function needs to save the current console state, then put the console
|
||||
* into a state suitable for the kernel debugger.
|
||||
*
|
||||
* RETURNS:
|
||||
* Zero on success, nonzero if a failure occurred when trying to prepare
|
||||
* the console for the debugger.
|
||||
*/
|
||||
int con_debug_enter(struct vc_data *vc)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
saved_fg_console = fg_console;
|
||||
saved_last_console = last_console;
|
||||
saved_want_console = want_console;
|
||||
saved_vc_mode = vc->vc_mode;
|
||||
vc->vc_mode = KD_TEXT;
|
||||
console_blanked = 0;
|
||||
if (vc->vc_sw->con_debug_enter)
|
||||
ret = vc->vc_sw->con_debug_enter(vc);
|
||||
#ifdef CONFIG_KGDB_KDB
|
||||
/* Set the initial LINES variable if it is not already set */
|
||||
if (vc->vc_rows < 999) {
|
||||
int linecount;
|
||||
char lns[4];
|
||||
const char *setargs[3] = {
|
||||
"set",
|
||||
"LINES",
|
||||
lns,
|
||||
};
|
||||
if (kdbgetintenv(setargs[0], &linecount)) {
|
||||
snprintf(lns, 4, "%i", vc->vc_rows);
|
||||
kdb_set(2, setargs);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_KGDB_KDB */
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(con_debug_enter);
|
||||
|
||||
/**
|
||||
* con_debug_leave - restore console state
|
||||
* @sw: console driver
|
||||
*
|
||||
* Restore the console state to what it was before the kernel debugger
|
||||
* was invoked.
|
||||
*
|
||||
* RETURNS:
|
||||
* Zero on success, nonzero if a failure occurred when trying to restore
|
||||
* the console.
|
||||
*/
|
||||
int con_debug_leave(void)
|
||||
{
|
||||
struct vc_data *vc;
|
||||
int ret = 0;
|
||||
|
||||
fg_console = saved_fg_console;
|
||||
last_console = saved_last_console;
|
||||
want_console = saved_want_console;
|
||||
vc_cons[fg_console].d->vc_mode = saved_vc_mode;
|
||||
|
||||
vc = vc_cons[fg_console].d;
|
||||
if (vc->vc_sw->con_debug_leave)
|
||||
ret = vc->vc_sw->con_debug_leave(vc);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(con_debug_leave);
|
||||
|
||||
/**
|
||||
* register_con_driver - register console driver to console layer
|
||||
* @csw: console driver
|
||||
|
|
|
@ -241,6 +241,80 @@ static int drm_fb_helper_parse_command_line(struct drm_fb_helper *fb_helper)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int drm_fb_helper_debug_enter(struct fb_info *info)
|
||||
{
|
||||
struct drm_fb_helper *helper = info->par;
|
||||
struct drm_crtc_helper_funcs *funcs;
|
||||
int i;
|
||||
|
||||
if (list_empty(&kernel_fb_helper_list))
|
||||
return false;
|
||||
|
||||
list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) {
|
||||
for (i = 0; i < helper->crtc_count; i++) {
|
||||
struct drm_mode_set *mode_set =
|
||||
&helper->crtc_info[i].mode_set;
|
||||
|
||||
if (!mode_set->crtc->enabled)
|
||||
continue;
|
||||
|
||||
funcs = mode_set->crtc->helper_private;
|
||||
funcs->mode_set_base_atomic(mode_set->crtc,
|
||||
mode_set->fb,
|
||||
mode_set->x,
|
||||
mode_set->y);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_helper_debug_enter);
|
||||
|
||||
/* Find the real fb for a given fb helper CRTC */
|
||||
static struct drm_framebuffer *drm_mode_config_fb(struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_crtc *c;
|
||||
|
||||
list_for_each_entry(c, &dev->mode_config.crtc_list, head) {
|
||||
if (crtc->base.id == c->base.id)
|
||||
return c->fb;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int drm_fb_helper_debug_leave(struct fb_info *info)
|
||||
{
|
||||
struct drm_fb_helper *helper = info->par;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_crtc_helper_funcs *funcs;
|
||||
struct drm_framebuffer *fb;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < helper->crtc_count; i++) {
|
||||
struct drm_mode_set *mode_set = &helper->crtc_info[i].mode_set;
|
||||
crtc = mode_set->crtc;
|
||||
funcs = crtc->helper_private;
|
||||
fb = drm_mode_config_fb(crtc);
|
||||
|
||||
if (!crtc->enabled)
|
||||
continue;
|
||||
|
||||
if (!fb) {
|
||||
DRM_ERROR("no fb to restore??\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
funcs->mode_set_base_atomic(mode_set->crtc, fb, crtc->x,
|
||||
crtc->y);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_helper_debug_leave);
|
||||
|
||||
bool drm_fb_helper_force_kernel_mode(void)
|
||||
{
|
||||
int i = 0;
|
||||
|
@ -611,7 +685,7 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
|
|||
struct drm_framebuffer *fb = fb_helper->fb;
|
||||
int depth;
|
||||
|
||||
if (var->pixclock != 0)
|
||||
if (var->pixclock != 0 || in_dbg_master())
|
||||
return -EINVAL;
|
||||
|
||||
/* Need to resize the fb object !!! */
|
||||
|
|
|
@ -975,7 +975,10 @@ void
|
|||
intel_wait_for_vblank(struct drm_device *dev)
|
||||
{
|
||||
/* Wait for 20ms, i.e. one cycle at 50hz. */
|
||||
msleep(20);
|
||||
if (in_dbg_master())
|
||||
mdelay(20); /* The kernel debugger cannot call msleep() */
|
||||
else
|
||||
msleep(20);
|
||||
}
|
||||
|
||||
/* Parameters have changed, update FBC info */
|
||||
|
@ -1248,6 +1251,10 @@ static void intel_update_fbc(struct drm_crtc *crtc,
|
|||
goto out_disable;
|
||||
}
|
||||
|
||||
/* If the kernel debugger is active, always disable compression */
|
||||
if (in_dbg_master())
|
||||
goto out_disable;
|
||||
|
||||
if (intel_fbc_enabled(dev)) {
|
||||
/* We can re-enable it in this case, but need to update pitch */
|
||||
if ((fb->pitch > dev_priv->cfb_pitch) ||
|
||||
|
@ -1314,6 +1321,98 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_gem_object *obj)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Assume fb object is pinned & idle & fenced and just update base pointers */
|
||||
static int
|
||||
intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
|
||||
int x, int y)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
struct intel_framebuffer *intel_fb;
|
||||
struct drm_i915_gem_object *obj_priv;
|
||||
struct drm_gem_object *obj;
|
||||
int plane = intel_crtc->plane;
|
||||
unsigned long Start, Offset;
|
||||
int dspbase = (plane == 0 ? DSPAADDR : DSPBADDR);
|
||||
int dspsurf = (plane == 0 ? DSPASURF : DSPBSURF);
|
||||
int dspstride = (plane == 0) ? DSPASTRIDE : DSPBSTRIDE;
|
||||
int dsptileoff = (plane == 0 ? DSPATILEOFF : DSPBTILEOFF);
|
||||
int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
|
||||
u32 dspcntr;
|
||||
|
||||
switch (plane) {
|
||||
case 0:
|
||||
case 1:
|
||||
break;
|
||||
default:
|
||||
DRM_ERROR("Can't update plane %d in SAREA\n", plane);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
intel_fb = to_intel_framebuffer(fb);
|
||||
obj = intel_fb->obj;
|
||||
obj_priv = to_intel_bo(obj);
|
||||
|
||||
dspcntr = I915_READ(dspcntr_reg);
|
||||
/* Mask out pixel format bits in case we change it */
|
||||
dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
|
||||
switch (fb->bits_per_pixel) {
|
||||
case 8:
|
||||
dspcntr |= DISPPLANE_8BPP;
|
||||
break;
|
||||
case 16:
|
||||
if (fb->depth == 15)
|
||||
dspcntr |= DISPPLANE_15_16BPP;
|
||||
else
|
||||
dspcntr |= DISPPLANE_16BPP;
|
||||
break;
|
||||
case 24:
|
||||
case 32:
|
||||
dspcntr |= DISPPLANE_32BPP_NO_ALPHA;
|
||||
break;
|
||||
default:
|
||||
DRM_ERROR("Unknown color depth\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (IS_I965G(dev)) {
|
||||
if (obj_priv->tiling_mode != I915_TILING_NONE)
|
||||
dspcntr |= DISPPLANE_TILED;
|
||||
else
|
||||
dspcntr &= ~DISPPLANE_TILED;
|
||||
}
|
||||
|
||||
if (IS_IRONLAKE(dev))
|
||||
/* must disable */
|
||||
dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
|
||||
|
||||
I915_WRITE(dspcntr_reg, dspcntr);
|
||||
|
||||
Start = obj_priv->gtt_offset;
|
||||
Offset = y * fb->pitch + x * (fb->bits_per_pixel / 8);
|
||||
|
||||
DRM_DEBUG("Writing base %08lX %08lX %d %d\n", Start, Offset, x, y);
|
||||
I915_WRITE(dspstride, fb->pitch);
|
||||
if (IS_I965G(dev)) {
|
||||
I915_WRITE(dspbase, Offset);
|
||||
I915_READ(dspbase);
|
||||
I915_WRITE(dspsurf, Start);
|
||||
I915_READ(dspsurf);
|
||||
I915_WRITE(dsptileoff, (y << 16) | x);
|
||||
} else {
|
||||
I915_WRITE(dspbase, Start + Offset);
|
||||
I915_READ(dspbase);
|
||||
}
|
||||
|
||||
if ((IS_I965G(dev) || plane == 0))
|
||||
intel_update_fbc(crtc, &crtc->mode);
|
||||
|
||||
intel_wait_for_vblank(dev);
|
||||
intel_increase_pllclock(crtc, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
|
||||
struct drm_framebuffer *old_fb)
|
||||
|
@ -4814,6 +4913,7 @@ static const struct drm_crtc_helper_funcs intel_helper_funcs = {
|
|||
.mode_fixup = intel_crtc_mode_fixup,
|
||||
.mode_set = intel_crtc_mode_set,
|
||||
.mode_set_base = intel_pipe_set_base,
|
||||
.mode_set_base_atomic = intel_pipe_set_base_atomic,
|
||||
.prepare = intel_crtc_prepare,
|
||||
.commit = intel_crtc_commit,
|
||||
.load_lut = intel_crtc_load_lut,
|
||||
|
|
|
@ -61,6 +61,8 @@ static struct fb_ops intelfb_ops = {
|
|||
.fb_pan_display = drm_fb_helper_pan_display,
|
||||
.fb_blank = drm_fb_helper_blank,
|
||||
.fb_setcmap = drm_fb_helper_setcmap,
|
||||
.fb_debug_enter = drm_fb_helper_debug_enter,
|
||||
.fb_debug_leave = drm_fb_helper_debug_leave,
|
||||
};
|
||||
|
||||
static int intelfb_create(struct intel_fbdev *ifbdev,
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/kdb.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/vt_kern.h>
|
||||
|
||||
#define MAX_CONFIG_LEN 40
|
||||
|
||||
|
@ -31,6 +32,7 @@ static struct kparam_string kps = {
|
|||
.maxlen = MAX_CONFIG_LEN,
|
||||
};
|
||||
|
||||
static int kgdboc_use_kms; /* 1 if we use kernel mode switching */
|
||||
static struct tty_driver *kgdb_tty_driver;
|
||||
static int kgdb_tty_line;
|
||||
|
||||
|
@ -104,6 +106,12 @@ static int configure_kgdboc(void)
|
|||
kgdboc_io_ops.is_console = 0;
|
||||
kgdb_tty_driver = NULL;
|
||||
|
||||
kgdboc_use_kms = 0;
|
||||
if (strncmp(cptr, "kms,", 4) == 0) {
|
||||
cptr += 4;
|
||||
kgdboc_use_kms = 1;
|
||||
}
|
||||
|
||||
if (kgdboc_register_kbd(&cptr))
|
||||
goto do_register;
|
||||
|
||||
|
@ -201,8 +209,14 @@ static int param_set_kgdboc_var(const char *kmessage, struct kernel_param *kp)
|
|||
return configure_kgdboc();
|
||||
}
|
||||
|
||||
static int dbg_restore_graphics;
|
||||
|
||||
static void kgdboc_pre_exp_handler(void)
|
||||
{
|
||||
if (!dbg_restore_graphics && kgdboc_use_kms) {
|
||||
dbg_restore_graphics = 1;
|
||||
con_debug_enter(vc_cons[fg_console].d);
|
||||
}
|
||||
/* Increment the module count when the debugger is active */
|
||||
if (!kgdb_connected)
|
||||
try_module_get(THIS_MODULE);
|
||||
|
@ -213,6 +227,10 @@ static void kgdboc_post_exp_handler(void)
|
|||
/* decrement the module count when the debugger detaches */
|
||||
if (!kgdb_connected)
|
||||
module_put(THIS_MODULE);
|
||||
if (kgdboc_use_kms && dbg_restore_graphics) {
|
||||
dbg_restore_graphics = 0;
|
||||
con_debug_leave();
|
||||
}
|
||||
}
|
||||
|
||||
static struct kgdb_io kgdboc_io_ops = {
|
||||
|
|
|
@ -2342,6 +2342,30 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int fbcon_debug_enter(struct vc_data *vc)
|
||||
{
|
||||
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
|
||||
ops->save_graphics = ops->graphics;
|
||||
ops->graphics = 0;
|
||||
if (info->fbops->fb_debug_enter)
|
||||
info->fbops->fb_debug_enter(info);
|
||||
fbcon_set_palette(vc, color_table);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fbcon_debug_leave(struct vc_data *vc)
|
||||
{
|
||||
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
|
||||
ops->graphics = ops->save_graphics;
|
||||
if (info->fbops->fb_debug_leave)
|
||||
info->fbops->fb_debug_leave(info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
|
||||
{
|
||||
u8 *fontdata = vc->vc_font.data;
|
||||
|
@ -3276,6 +3300,8 @@ static const struct consw fb_con = {
|
|||
.con_screen_pos = fbcon_screen_pos,
|
||||
.con_getxy = fbcon_getxy,
|
||||
.con_resize = fbcon_resize,
|
||||
.con_debug_enter = fbcon_debug_enter,
|
||||
.con_debug_leave = fbcon_debug_leave,
|
||||
};
|
||||
|
||||
static struct notifier_block fbcon_event_notifier = {
|
||||
|
|
|
@ -74,6 +74,7 @@ struct fbcon_ops {
|
|||
int cursor_reset;
|
||||
int blank_state;
|
||||
int graphics;
|
||||
int save_graphics; /* for debug enter/leave */
|
||||
int flags;
|
||||
int rotate;
|
||||
int cur_rotate;
|
||||
|
|
|
@ -60,6 +60,8 @@ struct drm_crtc_helper_funcs {
|
|||
/* Move the crtc on the current fb to the given position *optional* */
|
||||
int (*mode_set_base)(struct drm_crtc *crtc, int x, int y,
|
||||
struct drm_framebuffer *old_fb);
|
||||
int (*mode_set_base_atomic)(struct drm_crtc *crtc,
|
||||
struct drm_framebuffer *fb, int x, int y);
|
||||
|
||||
/* reload the current crtc LUT */
|
||||
void (*load_lut)(struct drm_crtc *crtc);
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
|
||||
struct drm_fb_helper;
|
||||
|
||||
#include <linux/kgdb.h>
|
||||
|
||||
struct drm_fb_helper_crtc {
|
||||
uint32_t crtc_id;
|
||||
struct drm_mode_set mode_set;
|
||||
|
@ -78,6 +80,7 @@ struct drm_fb_helper_connector {
|
|||
|
||||
struct drm_fb_helper {
|
||||
struct drm_framebuffer *fb;
|
||||
struct drm_framebuffer *saved_fb;
|
||||
struct drm_device *dev;
|
||||
struct drm_display_mode *mode;
|
||||
int crtc_count;
|
||||
|
@ -126,5 +129,7 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info);
|
|||
bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper);
|
||||
bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel);
|
||||
int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper);
|
||||
int drm_fb_helper_debug_enter(struct fb_info *info);
|
||||
int drm_fb_helper_debug_leave(struct fb_info *info);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -55,6 +55,16 @@ struct consw {
|
|||
void (*con_invert_region)(struct vc_data *, u16 *, int);
|
||||
u16 *(*con_screen_pos)(struct vc_data *, int);
|
||||
unsigned long (*con_getxy)(struct vc_data *, unsigned long, int *, int *);
|
||||
/*
|
||||
* Prepare the console for the debugger. This includes, but is not
|
||||
* limited to, unblanking the console, loading an appropriate
|
||||
* palette, and allowing debugger generated output.
|
||||
*/
|
||||
int (*con_debug_enter)(struct vc_data *);
|
||||
/*
|
||||
* Restore the console to its pre-debug state as closely as possible.
|
||||
*/
|
||||
int (*con_debug_leave)(struct vc_data *);
|
||||
};
|
||||
|
||||
extern const struct consw *conswitchp;
|
||||
|
@ -69,6 +79,9 @@ int register_con_driver(const struct consw *csw, int first, int last);
|
|||
int unregister_con_driver(const struct consw *csw);
|
||||
int take_over_console(const struct consw *sw, int first, int last, int deflt);
|
||||
void give_up_console(const struct consw *sw);
|
||||
int con_debug_enter(struct vc_data *vc);
|
||||
int con_debug_leave(void);
|
||||
|
||||
/* scroll */
|
||||
#define SM_UP (1)
|
||||
#define SM_DOWN (2)
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
|
||||
#include <linux/types.h>
|
||||
#include <linux/i2c.h>
|
||||
#ifdef __KERNEL__
|
||||
#include <linux/kgdb.h>
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
/* Definitions of frame buffers */
|
||||
|
||||
|
@ -607,6 +610,12 @@ struct fb_deferred_io {
|
|||
* LOCKING NOTE: those functions must _ALL_ be called with the console
|
||||
* semaphore held, this is the only suitable locking mechanism we have
|
||||
* in 2.6. Some may be called at interrupt time at this point though.
|
||||
*
|
||||
* The exception to this is the debug related hooks. Putting the fb
|
||||
* into a debug state (e.g. flipping to the kernel console) and restoring
|
||||
* it must be done in a lock-free manner, so low level drivers should
|
||||
* keep track of the initial console (if applicable) and may need to
|
||||
* perform direct, unlocked hardware writes in these hooks.
|
||||
*/
|
||||
|
||||
struct fb_ops {
|
||||
|
@ -676,6 +685,10 @@ struct fb_ops {
|
|||
|
||||
/* teardown any resources to do with this framebuffer */
|
||||
void (*fb_destroy)(struct fb_info *info);
|
||||
|
||||
/* called at KDB enter and leave time to prepare the console */
|
||||
int (*fb_debug_enter)(struct fb_info *info);
|
||||
int (*fb_debug_leave)(struct fb_info *info);
|
||||
};
|
||||
|
||||
#ifdef CONFIG_FB_TILEBLITTING
|
||||
|
|
|
@ -114,4 +114,8 @@ enum {
|
|||
KDB_INIT_EARLY,
|
||||
KDB_INIT_FULL,
|
||||
};
|
||||
|
||||
extern int kdbgetintenv(const char *, int *);
|
||||
extern int kdb_set(int, const char **);
|
||||
|
||||
#endif /* !_KDB_H */
|
||||
|
|
|
@ -144,9 +144,7 @@ extern int kdb_getword(unsigned long *, unsigned long, size_t);
|
|||
extern int kdb_putword(unsigned long, unsigned long, size_t);
|
||||
|
||||
extern int kdbgetularg(const char *, unsigned long *);
|
||||
extern int kdb_set(int, const char **);
|
||||
extern char *kdbgetenv(const char *);
|
||||
extern int kdbgetintenv(const char *, int *);
|
||||
extern int kdbgetaddrarg(int, const char **, int*, unsigned long *,
|
||||
long *, char **);
|
||||
extern int kdbgetsymval(const char *, kdb_symtab_t *);
|
||||
|
|
Загрузка…
Ссылка в новой задаче