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:
commit
9779714c8a
|
@ -199,10 +199,33 @@
|
||||||
may be configured as a kernel built-in or a kernel loadable module.
|
may be configured as a kernel built-in or a kernel loadable module.
|
||||||
You can only make use of <constant>kgdbwait</constant> and early
|
You can only make use of <constant>kgdbwait</constant> and early
|
||||||
debugging if you build kgdboc into the kernel as a built-in.
|
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>
|
</para>
|
||||||
<sect2 id="kgdbocArgs">
|
<sect2 id="kgdbocArgs">
|
||||||
<title>kgdboc arguments</title>
|
<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">
|
<sect3 id="kgdbocArgs1">
|
||||||
<title>Using loadable module or built-in</title>
|
<title>Using loadable module or built-in</title>
|
||||||
<para>
|
<para>
|
||||||
|
@ -212,7 +235,7 @@
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>As a kernel loadable module:</para>
|
<para>As a kernel loadable module:</para>
|
||||||
<para>Use the command: <constant>modprobe kgdboc kgdboc=<tty-device>,[baud]</constant></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.
|
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
|
The second example is for the ARM Versatile AB using the second
|
||||||
serial port.
|
serial port.
|
||||||
|
@ -240,6 +263,9 @@
|
||||||
</sect3>
|
</sect3>
|
||||||
<sect3 id="kgdbocArgs3">
|
<sect3 id="kgdbocArgs3">
|
||||||
<title>More examples</title>
|
<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
|
<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
|
depending on if you are using kdb and or kgdb, in one of the
|
||||||
following scenarios.
|
following scenarios.
|
||||||
|
@ -255,6 +281,12 @@
|
||||||
<listitem><para>kdb with a keyboard</para>
|
<listitem><para>kdb with a keyboard</para>
|
||||||
<para><constant>kgdboc=kbd</constant></para>
|
<para><constant>kgdboc=kbd</constant></para>
|
||||||
</listitem>
|
</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>
|
</orderedlist>
|
||||||
</para>
|
</para>
|
||||||
</sect3>
|
</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>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>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 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>
|
</itemizedlist>
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
@ -747,6 +781,8 @@ Task Addr Pid Parent [*] cpu State Thread Command
|
||||||
</sect1>
|
</sect1>
|
||||||
<sect1 id="kgdbocDesign">
|
<sect1 id="kgdbocDesign">
|
||||||
<title>kgdboc internals</title>
|
<title>kgdboc internals</title>
|
||||||
|
<sect2>
|
||||||
|
<title>kgdboc and uarts</title>
|
||||||
<para>
|
<para>
|
||||||
The kgdboc driver is actually a very thin driver that relies on the
|
The kgdboc driver is actually a very thin driver that relies on the
|
||||||
underlying low level to the hardware driver having "polling hooks"
|
underlying low level to the hardware driver having "polling hooks"
|
||||||
|
@ -755,10 +791,7 @@ Task Addr Pid Parent [*] cpu State Thread Command
|
||||||
low level UART hook for doing polled mode reading and writing of 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
|
single character while in an atomic context. When kgdb makes an I/O
|
||||||
request to the debugger, kgdboc invokes a callback in the serial
|
request to the debugger, kgdboc invokes a callback in the serial
|
||||||
core which in turn uses the call back in the UART driver. It is
|
core which in turn uses the callback in the UART driver.</para>
|
||||||
certainly possible to extend kgdboc to work with non-UART based
|
|
||||||
consoles in the future.
|
|
||||||
</para>
|
|
||||||
<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>
|
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
|
#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
|
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
|
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
|
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.
|
going to mean pressing the reset button.
|
||||||
</para>
|
</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>
|
</sect1>
|
||||||
</chapter>
|
</chapter>
|
||||||
<chapter id="credits">
|
<chapter id="credits">
|
||||||
|
|
|
@ -1148,6 +1148,9 @@ and is between 256 and 4096 characters. It is defined in the file
|
||||||
Serial only format: <serial_device>[,baud]
|
Serial only format: <serial_device>[,baud]
|
||||||
keyboard only format: kbd
|
keyboard only format: kbd
|
||||||
keyboard and serial format: kbd,<serial_device>[,baud]
|
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
|
kgdbwait [KGDB] Stop kernel execution and enter the
|
||||||
kernel debugger at the earliest opportunity.
|
kernel debugger at the earliest opportunity.
|
||||||
|
|
|
@ -104,6 +104,7 @@
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <asm/system.h>
|
#include <asm/system.h>
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
|
#include <linux/kdb.h>
|
||||||
|
|
||||||
#define MAX_NR_CON_DRIVER 16
|
#define MAX_NR_CON_DRIVER 16
|
||||||
|
|
||||||
|
@ -187,10 +188,15 @@ static DECLARE_WORK(console_work, console_callback);
|
||||||
* fg_console is the current virtual console,
|
* fg_console is the current virtual console,
|
||||||
* last_console is the last used one,
|
* last_console is the last used one,
|
||||||
* want_console is the console we want to switch to,
|
* 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 fg_console;
|
||||||
int last_console;
|
int last_console;
|
||||||
int want_console = -1;
|
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
|
* 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);
|
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
|
* register_con_driver - register console driver to console layer
|
||||||
* @csw: console driver
|
* @csw: console driver
|
||||||
|
|
|
@ -241,6 +241,80 @@ static int drm_fb_helper_parse_command_line(struct drm_fb_helper *fb_helper)
|
||||||
return 0;
|
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)
|
bool drm_fb_helper_force_kernel_mode(void)
|
||||||
{
|
{
|
||||||
int i = 0;
|
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;
|
struct drm_framebuffer *fb = fb_helper->fb;
|
||||||
int depth;
|
int depth;
|
||||||
|
|
||||||
if (var->pixclock != 0)
|
if (var->pixclock != 0 || in_dbg_master())
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/* Need to resize the fb object !!! */
|
/* Need to resize the fb object !!! */
|
||||||
|
|
|
@ -975,6 +975,9 @@ void
|
||||||
intel_wait_for_vblank(struct drm_device *dev)
|
intel_wait_for_vblank(struct drm_device *dev)
|
||||||
{
|
{
|
||||||
/* Wait for 20ms, i.e. one cycle at 50hz. */
|
/* Wait for 20ms, i.e. one cycle at 50hz. */
|
||||||
|
if (in_dbg_master())
|
||||||
|
mdelay(20); /* The kernel debugger cannot call msleep() */
|
||||||
|
else
|
||||||
msleep(20);
|
msleep(20);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1248,6 +1251,10 @@ static void intel_update_fbc(struct drm_crtc *crtc,
|
||||||
goto out_disable;
|
goto out_disable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If the kernel debugger is active, always disable compression */
|
||||||
|
if (in_dbg_master())
|
||||||
|
goto out_disable;
|
||||||
|
|
||||||
if (intel_fbc_enabled(dev)) {
|
if (intel_fbc_enabled(dev)) {
|
||||||
/* We can re-enable it in this case, but need to update pitch */
|
/* We can re-enable it in this case, but need to update pitch */
|
||||||
if ((fb->pitch > dev_priv->cfb_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;
|
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
|
static int
|
||||||
intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
|
intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
|
||||||
struct drm_framebuffer *old_fb)
|
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_fixup = intel_crtc_mode_fixup,
|
||||||
.mode_set = intel_crtc_mode_set,
|
.mode_set = intel_crtc_mode_set,
|
||||||
.mode_set_base = intel_pipe_set_base,
|
.mode_set_base = intel_pipe_set_base,
|
||||||
|
.mode_set_base_atomic = intel_pipe_set_base_atomic,
|
||||||
.prepare = intel_crtc_prepare,
|
.prepare = intel_crtc_prepare,
|
||||||
.commit = intel_crtc_commit,
|
.commit = intel_crtc_commit,
|
||||||
.load_lut = intel_crtc_load_lut,
|
.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_pan_display = drm_fb_helper_pan_display,
|
||||||
.fb_blank = drm_fb_helper_blank,
|
.fb_blank = drm_fb_helper_blank,
|
||||||
.fb_setcmap = drm_fb_helper_setcmap,
|
.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,
|
static int intelfb_create(struct intel_fbdev *ifbdev,
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include <linux/kdb.h>
|
#include <linux/kdb.h>
|
||||||
#include <linux/tty.h>
|
#include <linux/tty.h>
|
||||||
#include <linux/console.h>
|
#include <linux/console.h>
|
||||||
|
#include <linux/vt_kern.h>
|
||||||
|
|
||||||
#define MAX_CONFIG_LEN 40
|
#define MAX_CONFIG_LEN 40
|
||||||
|
|
||||||
|
@ -31,6 +32,7 @@ static struct kparam_string kps = {
|
||||||
.maxlen = MAX_CONFIG_LEN,
|
.maxlen = MAX_CONFIG_LEN,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int kgdboc_use_kms; /* 1 if we use kernel mode switching */
|
||||||
static struct tty_driver *kgdb_tty_driver;
|
static struct tty_driver *kgdb_tty_driver;
|
||||||
static int kgdb_tty_line;
|
static int kgdb_tty_line;
|
||||||
|
|
||||||
|
@ -104,6 +106,12 @@ static int configure_kgdboc(void)
|
||||||
kgdboc_io_ops.is_console = 0;
|
kgdboc_io_ops.is_console = 0;
|
||||||
kgdb_tty_driver = NULL;
|
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))
|
if (kgdboc_register_kbd(&cptr))
|
||||||
goto do_register;
|
goto do_register;
|
||||||
|
|
||||||
|
@ -201,8 +209,14 @@ static int param_set_kgdboc_var(const char *kmessage, struct kernel_param *kp)
|
||||||
return configure_kgdboc();
|
return configure_kgdboc();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int dbg_restore_graphics;
|
||||||
|
|
||||||
static void kgdboc_pre_exp_handler(void)
|
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 */
|
/* Increment the module count when the debugger is active */
|
||||||
if (!kgdb_connected)
|
if (!kgdb_connected)
|
||||||
try_module_get(THIS_MODULE);
|
try_module_get(THIS_MODULE);
|
||||||
|
@ -213,6 +227,10 @@ static void kgdboc_post_exp_handler(void)
|
||||||
/* decrement the module count when the debugger detaches */
|
/* decrement the module count when the debugger detaches */
|
||||||
if (!kgdb_connected)
|
if (!kgdb_connected)
|
||||||
module_put(THIS_MODULE);
|
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 = {
|
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;
|
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)
|
static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
|
||||||
{
|
{
|
||||||
u8 *fontdata = vc->vc_font.data;
|
u8 *fontdata = vc->vc_font.data;
|
||||||
|
@ -3276,6 +3300,8 @@ static const struct consw fb_con = {
|
||||||
.con_screen_pos = fbcon_screen_pos,
|
.con_screen_pos = fbcon_screen_pos,
|
||||||
.con_getxy = fbcon_getxy,
|
.con_getxy = fbcon_getxy,
|
||||||
.con_resize = fbcon_resize,
|
.con_resize = fbcon_resize,
|
||||||
|
.con_debug_enter = fbcon_debug_enter,
|
||||||
|
.con_debug_leave = fbcon_debug_leave,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct notifier_block fbcon_event_notifier = {
|
static struct notifier_block fbcon_event_notifier = {
|
||||||
|
|
|
@ -74,6 +74,7 @@ struct fbcon_ops {
|
||||||
int cursor_reset;
|
int cursor_reset;
|
||||||
int blank_state;
|
int blank_state;
|
||||||
int graphics;
|
int graphics;
|
||||||
|
int save_graphics; /* for debug enter/leave */
|
||||||
int flags;
|
int flags;
|
||||||
int rotate;
|
int rotate;
|
||||||
int cur_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* */
|
/* Move the crtc on the current fb to the given position *optional* */
|
||||||
int (*mode_set_base)(struct drm_crtc *crtc, int x, int y,
|
int (*mode_set_base)(struct drm_crtc *crtc, int x, int y,
|
||||||
struct drm_framebuffer *old_fb);
|
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 */
|
/* reload the current crtc LUT */
|
||||||
void (*load_lut)(struct drm_crtc *crtc);
|
void (*load_lut)(struct drm_crtc *crtc);
|
||||||
|
|
|
@ -32,6 +32,8 @@
|
||||||
|
|
||||||
struct drm_fb_helper;
|
struct drm_fb_helper;
|
||||||
|
|
||||||
|
#include <linux/kgdb.h>
|
||||||
|
|
||||||
struct drm_fb_helper_crtc {
|
struct drm_fb_helper_crtc {
|
||||||
uint32_t crtc_id;
|
uint32_t crtc_id;
|
||||||
struct drm_mode_set mode_set;
|
struct drm_mode_set mode_set;
|
||||||
|
@ -78,6 +80,7 @@ struct drm_fb_helper_connector {
|
||||||
|
|
||||||
struct drm_fb_helper {
|
struct drm_fb_helper {
|
||||||
struct drm_framebuffer *fb;
|
struct drm_framebuffer *fb;
|
||||||
|
struct drm_framebuffer *saved_fb;
|
||||||
struct drm_device *dev;
|
struct drm_device *dev;
|
||||||
struct drm_display_mode *mode;
|
struct drm_display_mode *mode;
|
||||||
int crtc_count;
|
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_hotplug_event(struct drm_fb_helper *fb_helper);
|
||||||
bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel);
|
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_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
|
#endif
|
||||||
|
|
|
@ -55,6 +55,16 @@ struct consw {
|
||||||
void (*con_invert_region)(struct vc_data *, u16 *, int);
|
void (*con_invert_region)(struct vc_data *, u16 *, int);
|
||||||
u16 *(*con_screen_pos)(struct vc_data *, int);
|
u16 *(*con_screen_pos)(struct vc_data *, int);
|
||||||
unsigned long (*con_getxy)(struct vc_data *, unsigned long, int *, 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;
|
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 unregister_con_driver(const struct consw *csw);
|
||||||
int take_over_console(const struct consw *sw, int first, int last, int deflt);
|
int take_over_console(const struct consw *sw, int first, int last, int deflt);
|
||||||
void give_up_console(const struct consw *sw);
|
void give_up_console(const struct consw *sw);
|
||||||
|
int con_debug_enter(struct vc_data *vc);
|
||||||
|
int con_debug_leave(void);
|
||||||
|
|
||||||
/* scroll */
|
/* scroll */
|
||||||
#define SM_UP (1)
|
#define SM_UP (1)
|
||||||
#define SM_DOWN (2)
|
#define SM_DOWN (2)
|
||||||
|
|
|
@ -3,6 +3,9 @@
|
||||||
|
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
|
#ifdef __KERNEL__
|
||||||
|
#include <linux/kgdb.h>
|
||||||
|
#endif /* __KERNEL__ */
|
||||||
|
|
||||||
/* Definitions of frame buffers */
|
/* Definitions of frame buffers */
|
||||||
|
|
||||||
|
@ -607,6 +610,12 @@ struct fb_deferred_io {
|
||||||
* LOCKING NOTE: those functions must _ALL_ be called with the console
|
* LOCKING NOTE: those functions must _ALL_ be called with the console
|
||||||
* semaphore held, this is the only suitable locking mechanism we have
|
* 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.
|
* 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 {
|
struct fb_ops {
|
||||||
|
@ -676,6 +685,10 @@ struct fb_ops {
|
||||||
|
|
||||||
/* teardown any resources to do with this framebuffer */
|
/* teardown any resources to do with this framebuffer */
|
||||||
void (*fb_destroy)(struct fb_info *info);
|
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
|
#ifdef CONFIG_FB_TILEBLITTING
|
||||||
|
|
|
@ -114,4 +114,8 @@ enum {
|
||||||
KDB_INIT_EARLY,
|
KDB_INIT_EARLY,
|
||||||
KDB_INIT_FULL,
|
KDB_INIT_FULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern int kdbgetintenv(const char *, int *);
|
||||||
|
extern int kdb_set(int, const char **);
|
||||||
|
|
||||||
#endif /* !_KDB_H */
|
#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 kdb_putword(unsigned long, unsigned long, size_t);
|
||||||
|
|
||||||
extern int kdbgetularg(const char *, unsigned long *);
|
extern int kdbgetularg(const char *, unsigned long *);
|
||||||
extern int kdb_set(int, const char **);
|
|
||||||
extern char *kdbgetenv(const char *);
|
extern char *kdbgetenv(const char *);
|
||||||
extern int kdbgetintenv(const char *, int *);
|
|
||||||
extern int kdbgetaddrarg(int, const char **, int*, unsigned long *,
|
extern int kdbgetaddrarg(int, const char **, int*, unsigned long *,
|
||||||
long *, char **);
|
long *, char **);
|
||||||
extern int kdbgetsymval(const char *, kdb_symtab_t *);
|
extern int kdbgetsymval(const char *, kdb_symtab_t *);
|
||||||
|
|
Loading…
Reference in New Issue