diff options
author | Stephen Rothwell <sfr@canb.auug.org.au> | 2010-01-07 13:19:35 +1100 |
---|---|---|
committer | Stephen Rothwell <sfr@canb.auug.org.au> | 2010-01-07 13:19:35 +1100 |
commit | c815d1d661e3a1ff499d6c697ec7c43d7fdff20c (patch) | |
tree | 9c1da86d550ac558aba1c2004e5aacc01951b7e3 /drivers | |
parent | af975d27f27a180fa5f49c097156e07b560dfc2d (diff) | |
parent | fba960efa4f3ef65d700722b2bdb333a15aa3cfe (diff) |
Merge remote branch 'kgdb/kgdb-next'
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/char/Makefile | 1 | ||||
-rw-r--r-- | drivers/char/kdb_keyboard.c | 204 | ||||
-rw-r--r-- | drivers/char/kdb_keyboard.h | 143 | ||||
-rw-r--r-- | drivers/char/keyboard.c | 30 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_fb_helper.c | 93 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 114 | ||||
-rw-r--r-- | drivers/input/input.c | 15 | ||||
-rw-r--r-- | drivers/misc/kgdbts.c | 6 | ||||
-rw-r--r-- | drivers/serial/8250.c | 4 | ||||
-rw-r--r-- | drivers/serial/amba-pl011.c | 6 | ||||
-rw-r--r-- | drivers/serial/kgdboc.c | 117 | ||||
-rw-r--r-- | drivers/serial/sh-sci.c | 6 | ||||
-rw-r--r-- | drivers/serial/sunzilog.c | 50 | ||||
-rw-r--r-- | drivers/video/console/fbcon.c | 7 |
14 files changed, 766 insertions, 30 deletions
diff --git a/drivers/char/Makefile b/drivers/char/Makefile index f957edf7e45d..dbc579e13b2b 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_LEGACY_PTYS) += pty.o obj-$(CONFIG_UNIX98_PTYS) += pty.o obj-y += misc.o obj-$(CONFIG_VT) += vt_ioctl.o vc_screen.o selection.o keyboard.o +obj-$(CONFIG_KDB_KEYBOARD) += kdb_keyboard.o obj-$(CONFIG_BFIN_JTAG_COMM) += bfin_jtag_comm.o obj-$(CONFIG_CONSOLE_TRANSLATIONS) += consolemap.o consolemap_deftbl.o obj-$(CONFIG_HW_CONSOLE) += vt.o defkeymap.o diff --git a/drivers/char/kdb_keyboard.c b/drivers/char/kdb_keyboard.c new file mode 100644 index 000000000000..95aa10286e40 --- /dev/null +++ b/drivers/char/kdb_keyboard.c @@ -0,0 +1,204 @@ +/* + * Kernel Debugger Architecture Dependent Console I/O handler + * + * This file is subject to the terms and conditions of the GNU General Public + * License. + * + * Copyright (c) 1999-2006 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2009 Wind River Systems, Inc. All Rights Reserved. + */ + +#include <linux/kdb.h> +#include <linux/keyboard.h> +#include <linux/ctype.h> +#include <linux/module.h> +#include <linux/io.h> +#include "kdb_keyboard.h" + + +static int kbd_exists; + +/* + * Check if the keyboard controller has a keypress for us. + * Some parts (Enter Release, LED change) are still blocking polled here, + * but hopefully they are all short. + */ +int kdb_get_kbd_char(void) +{ + int scancode, scanstatus; + static int shift_lock; /* CAPS LOCK state (0-off, 1-on) */ + static int shift_key; /* Shift next keypress */ + static int ctrl_key; + u_short keychar; + + if (KDB_FLAG(NO_I8042) || KDB_FLAG(NO_VT_CONSOLE) || + (inb(KBD_STATUS_REG) == 0xff && inb(KBD_DATA_REG) == 0xff)) { + kbd_exists = 0; + return -1; + } + kbd_exists = 1; + + if ((inb(KBD_STATUS_REG) & KBD_STAT_OBF) == 0) + return -1; + + /* + * Fetch the scancode + */ + scancode = inb(KBD_DATA_REG); + scanstatus = inb(KBD_STATUS_REG); + + /* + * Ignore mouse events. + */ + if (scanstatus & KBD_STAT_MOUSE_OBF) + return -1; + + /* + * Ignore release, trigger on make + * (except for shift keys, where we want to + * keep the shift state so long as the key is + * held down). + */ + + if (((scancode&0x7f) == 0x2a) || ((scancode&0x7f) == 0x36)) { + /* + * Next key may use shift table + */ + if ((scancode & 0x80) == 0) + shift_key = 1; + else + shift_key = 0; + return -1; + } + + if ((scancode&0x7f) == 0x1d) { + /* + * Left ctrl key + */ + if ((scancode & 0x80) == 0) + ctrl_key = 1; + else + ctrl_key = 0; + return -1; + } + + if ((scancode & 0x80) != 0) + return -1; + + scancode &= 0x7f; + + /* + * Translate scancode + */ + + if (scancode == 0x3a) { + /* + * Toggle caps lock + */ + shift_lock ^= 1; + +#ifdef KDB_BLINK_LED + kdb_toggleled(0x4); +#endif + return -1; + } + + if (scancode == 0x0e) { + /* + * Backspace + */ + return 8; + } + + /* Special Key */ + switch (scancode) { + case 0xF: /* Tab */ + return 9; + case 0x53: /* Del */ + return 4; + case 0x47: /* Home */ + return 1; + case 0x4F: /* End */ + return 5; + case 0x4B: /* Left */ + return 2; + case 0x48: /* Up */ + return 16; + case 0x50: /* Down */ + return 14; + case 0x4D: /* Right */ + return 6; + } + + if (scancode == 0xe0) + return -1; + + /* + * For Japanese 86/106 keyboards + * See comment in drivers/char/pc_keyb.c. + * - Masahiro Adegawa + */ + if (scancode == 0x73) + scancode = 0x59; + else if (scancode == 0x7d) + scancode = 0x7c; + + if (!shift_lock && !shift_key && !ctrl_key) { + keychar = plain_map[scancode]; + } else if ((shift_lock || shift_key) && key_maps[1]) { + keychar = key_maps[1][scancode]; + } else if (ctrl_key && key_maps[4]) { + keychar = key_maps[4][scancode]; + } else { + keychar = 0x0020; + kdb_printf("Unknown state/scancode (%d)\n", scancode); + } + keychar &= 0x0fff; + if (keychar == '\t') + keychar = ' '; + switch (KTYP(keychar)) { + case KT_LETTER: + case KT_LATIN: + if (isprint(keychar)) + break; /* printable characters */ + /* drop through */ + case KT_SPEC: + if (keychar == K_ENTER) + break; + /* drop through */ + default: + return -1; /* ignore unprintables */ + } + + if ((scancode & 0x7f) == 0x1c) { + /* + * enter key. All done. Absorb the release scancode. + */ + while ((inb(KBD_STATUS_REG) & KBD_STAT_OBF) == 0) + ; + + /* + * Fetch the scancode + */ + scancode = inb(KBD_DATA_REG); + scanstatus = inb(KBD_STATUS_REG); + + while (scanstatus & KBD_STAT_MOUSE_OBF) { + scancode = inb(KBD_DATA_REG); + scanstatus = inb(KBD_STATUS_REG); + } + + if (scancode != 0x9c) { + /* + * Wasn't an enter-release, why not? + */ + kdb_printf("kdb: expected enter got 0x%x status 0x%x\n", + scancode, scanstatus); + } + + return 13; + } + + return keychar & 0xff; +} +EXPORT_SYMBOL_GPL(kdb_get_kbd_char); diff --git a/drivers/char/kdb_keyboard.h b/drivers/char/kdb_keyboard.h new file mode 100644 index 000000000000..5541668cce0a --- /dev/null +++ b/drivers/char/kdb_keyboard.h @@ -0,0 +1,143 @@ +/* + * include/linux/pc_keyb.h + * + * PC Keyboard And Keyboard Controller + * + * (c) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz> + */ + +/* + * Configuration Switches + */ + +#undef KBD_REPORT_ERR /* Report keyboard errors */ +#define KBD_REPORT_UNKN /* Report unknown scan codes */ +#define KBD_REPORT_TIMEOUTS /* Report keyboard timeouts */ +#undef KBD_IS_FOCUS_9000 /* We have the brain-damaged + * FOCUS-9000 keyboard */ +#undef INITIALIZE_MOUSE /* Define if your PS/2 mouse + * needs initialization. */ + +#define KBD_INIT_TIMEOUT 1000 /* Timeout in ms for initializing the + * keyboard */ +#define KBC_TIMEOUT 250 /* Timeout in ms for sending + * to keyboard controller */ +#define KBD_TIMEOUT 1000 /* Timeout in ms for keyboard + * command acknowledge */ + +/* + * Internal variables of the driver + */ + +extern unsigned char pckbd_read_mask; +extern unsigned char aux_device_present; + +/* + * Keyboard Controller Registers on normal PCs. + */ + +#define KBD_STATUS_REG 0x64 /* Status register (R) */ +#define KBD_CNTL_REG 0x64 /* Controller command register (W) */ +#define KBD_DATA_REG 0x60 /* Keyboard data register (R/W) */ + +/* + * Keyboard Controller Commands + */ + +#define KBD_CCMD_READ_MODE 0x20 /* Read mode bits */ +#define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */ +#define KBD_CCMD_GET_VERSION 0xA1 /* Get controller version */ +#define KBD_CCMD_MOUSE_DISABLE 0xA7 /* Disable mouse interface */ +#define KBD_CCMD_MOUSE_ENABLE 0xA8 /* Enable mouse interface */ +#define KBD_CCMD_TEST_MOUSE 0xA9 /* Mouse interface test */ +#define KBD_CCMD_SELF_TEST 0xAA /* Controller self test */ +#define KBD_CCMD_KBD_TEST 0xAB /* Keyboard interface test */ +#define KBD_CCMD_KBD_DISABLE 0xAD /* Keyboard interface disable */ +#define KBD_CCMD_KBD_ENABLE 0xAE /* Keyboard interface enable */ +#define KBD_CCMD_WRITE_AUX_OBUF 0xD3 /* Write to output buffer as if + initiated by the auxiliary device */ +#define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to + * the mouse */ + +/* + * Keyboard Commands + */ + +#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */ +#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */ +#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */ +#define KBD_CMD_DISABLE 0xF5 /* Disable scanning */ +#define KBD_CMD_RESET 0xFF /* Reset */ + +/* + * Keyboard Replies + */ + +#define KBD_REPLY_POR 0xAA /* Power on reset */ +#define KBD_REPLY_ACK 0xFA /* Command ACK */ +#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */ + +/* + * Status Register Bits + */ + +#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */ +#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */ +#define KBD_STAT_SELFTEST 0x04 /* Self test successful */ +#define KBD_STAT_CMD 0x08 /* Last write was a command + * write (0=data) */ +#define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */ +#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */ +#define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */ +#define KBD_STAT_PERR 0x80 /* Parity error */ + +#define AUX_STAT_OBF (KBD_STAT_OBF | KBD_STAT_MOUSE_OBF) + +/* + * Controller Mode Register Bits + */ + +#define KBD_MODE_KBD_INT 0x01 /* Keyboard data generate IRQ1 */ +#define KBD_MODE_MOUSE_INT 0x02 /* Mouse data generate IRQ12 */ +#define KBD_MODE_SYS 0x04 /* The system flag (?) */ +#define KBD_MODE_NO_KEYLOCK 0x08 /* The keylock doesn't affect + * the keyboard if set */ +#define KBD_MODE_DISABLE_KBD 0x10 /* Disable keyboard interface */ +#define KBD_MODE_DISABLE_MOUSE 0x20 /* Disable mouse interface */ +#define KBD_MODE_KCC 0x40 /* Scan code conversion to PC format */ +#define KBD_MODE_RFU 0x80 + +/* + * Mouse Commands + */ + +#define AUX_SET_RES 0xE8 /* Set resolution */ +#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */ +#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */ +#define AUX_GET_SCALE 0xE9 /* Get scaling factor */ +#define AUX_SET_STREAM 0xEA /* Set stream mode */ +#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */ +#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */ +#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */ +#define AUX_RESET 0xFF /* Reset aux device */ +#define AUX_ACK 0xFA /* Command byte ACK. */ + +#define AUX_BUF_SIZE 2048 /* This might be better divisible by + three to make overruns stay in sync + but then the read function would need + a lock etc - ick */ + +struct aux_queue { + unsigned long head; + unsigned long tail; + wait_queue_head_t proc_list; + struct fasync_struct *fasync; + unsigned char buf[AUX_BUF_SIZE]; +}; + + +/* How to access the keyboard macros on this platform. */ +#define kbd_read_input() inb(KBD_DATA_REG) +#define kbd_read_status() inb(KBD_STATUS_REG) +#define kbd_write_output(val) outb(val, KBD_DATA_REG) +#define kbd_write_command(val) outb(val, KBD_CNTL_REG) diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index f706b1dffdb3..1db54f62f9e1 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -1195,6 +1195,11 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) if (keycode < BTN_MISC && printk_ratelimit()) printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", keycode); + if (down) + set_bit(keycode, key_down); + else + clear_bit(keycode, key_down); + #ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ if (keycode == KEY_SYSRQ && (sysrq_down || (down == 1 && sysrq_alt))) { if (!sysrq_down) { @@ -1237,11 +1242,6 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) raw_mode = 1; } - if (down) - set_bit(keycode, key_down); - else - clear_bit(keycode, key_down); - if (rep && (!vc_kbd_mode(kbd, VC_REPEAT) || (tty && !L_ECHO(tty) && tty_chars_in_buffer(tty)))) { @@ -1410,6 +1410,23 @@ static const struct input_device_id kbd_ids[] = { MODULE_DEVICE_TABLE(input, kbd_ids); +#ifdef CONFIG_KGDB_KDB +void kbd_clear_keys(void) +{ + int i, j, k; + + for (i = 0; i < ARRAY_SIZE(key_down); i++) { + k = i * BITS_PER_LONG; + for (j = 0; j < BITS_PER_LONG; j++, k++) { + if (test_bit(k, key_down)) { + kbd_keycode(k, 0, 0); + } + } + } +} +#endif + + static struct input_handler kbd_handler = { .event = kbd_event, .connect = kbd_connect, @@ -1417,6 +1434,9 @@ static struct input_handler kbd_handler = { .start = kbd_start, .name = "kbd", .id_table = kbd_ids, +#ifdef CONFIG_KGDB_KDB + .dbg_clear_keys = kbd_clear_keys, +#endif }; int __init kbd_init(void) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 1b49fa055f4f..652c207f5c61 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -29,6 +29,7 @@ */ #include <linux/sysrq.h> #include <linux/fb.h> +#include <linux/kgdb.h> #include "drmP.h" #include "drm_crtc.h" #include "drm_fb_helper.h" @@ -233,6 +234,80 @@ int drm_fb_helper_parse_command_line(struct drm_device *dev) return 0; } +#define to_fb_helper(ops) (container_of((ops), struct drm_fb_helper, kdb_ops)) + +static int drm_fb_kdb_enter(struct dbg_kms_console_ops *ops) +{ + struct drm_fb_helper *helper = to_fb_helper(ops); + 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; +} + +/* 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; +} + +static int drm_fb_kdb_exit(struct dbg_kms_console_ops *ops) +{ + struct drm_fb_helper *helper = to_fb_helper(ops); + 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; +} + bool drm_fb_helper_force_kernel_mode(void) { int i = 0; @@ -321,9 +396,9 @@ static void drm_fb_helper_on(struct fb_info *info) !crtc->enabled) continue; - mutex_lock(&dev->mode_config.mutex); + dbg_safe_mutex_lock(&dev->mode_config.mutex); crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); - mutex_unlock(&dev->mode_config.mutex); + dbg_safe_mutex_unlock(&dev->mode_config.mutex); /* Found a CRTC on this fb, now find encoders */ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { @@ -331,9 +406,9 @@ static void drm_fb_helper_on(struct fb_info *info) struct drm_encoder_helper_funcs *encoder_funcs; encoder_funcs = encoder->helper_private; - mutex_lock(&dev->mode_config.mutex); + dbg_safe_mutex_lock(&dev->mode_config.mutex); encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); - mutex_unlock(&dev->mode_config.mutex); + dbg_safe_mutex_unlock(&dev->mode_config.mutex); } } } @@ -602,7 +677,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 !!! */ @@ -745,9 +820,9 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, modeset->y = var->yoffset; if (modeset->num_connectors) { - mutex_lock(&dev->mode_config.mutex); + dbg_safe_mutex_lock(&dev->mode_config.mutex); ret = crtc->funcs->set_config(modeset); - mutex_unlock(&dev->mode_config.mutex); + dbg_safe_mutex_unlock(&dev->mode_config.mutex); if (!ret) { info->var.xoffset = var->xoffset; info->var.yoffset = var->yoffset; @@ -924,6 +999,9 @@ int drm_fb_helper_single_fb_probe(struct drm_device *dev, /* Switch back to kernel console on panic */ /* multi card linked list maybe */ if (list_empty(&kernel_fb_helper_list)) { + fb_helper->kdb_ops.activate_console = drm_fb_kdb_enter; + fb_helper->kdb_ops.restore_console = drm_fb_kdb_exit; + dbg_kms_console_ops_register(&fb_helper->kdb_ops); printk(KERN_INFO "registered panic notifier\n"); atomic_notifier_chain_register(&panic_notifier_list, &paniced); @@ -938,6 +1016,7 @@ void drm_fb_helper_free(struct drm_fb_helper *helper) { list_del(&helper->kernel_fb_list); if (list_empty(&kernel_fb_helper_list)) { + dbg_kms_console_ops_unregister(&helper->kdb_ops); printk(KERN_INFO "unregistered panic notifier\n"); atomic_notifier_chain_unregister(&panic_notifier_list, &paniced); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 52cd9b006da2..a438fda2b50b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -949,6 +949,13 @@ intel_find_pll_g4x_dp(const intel_limit_t *limit, struct drm_crtc *crtc, void intel_wait_for_vblank(struct drm_device *dev) { + if (in_dbg_master()) { + /* When in the kernel debugger we cannot sleep */ + preempt_disable(); + mdelay(20); + preempt_enable(); + return; + } /* Wait for 20ms, i.e. one cycle at 50hz. */ msleep(20); } @@ -1166,6 +1173,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 (dev_priv->display.fbc_enabled(crtc)) { /* We can re-enable it in this case, but need to update pitch */ if (fb->pitch > dev_priv->cfb_pitch) @@ -1234,6 +1245,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 = obj->driver_private; + + 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) @@ -1275,17 +1378,17 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, obj = intel_fb->obj; obj_priv = obj->driver_private; - mutex_lock(&dev->struct_mutex); + dbg_safe_mutex_lock(&dev->struct_mutex); ret = intel_pin_and_fence_fb_obj(dev, obj); if (ret != 0) { - mutex_unlock(&dev->struct_mutex); + dbg_safe_mutex_unlock(&dev->struct_mutex); return ret; } ret = i915_gem_object_set_to_gtt_domain(obj, 1); if (ret != 0) { i915_gem_object_unpin(obj); - mutex_unlock(&dev->struct_mutex); + dbg_safe_mutex_unlock(&dev->struct_mutex); return ret; } @@ -1312,7 +1415,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, default: DRM_ERROR("Unknown color depth\n"); i915_gem_object_unpin(obj); - mutex_unlock(&dev->struct_mutex); + dbg_safe_mutex_unlock(&dev->struct_mutex); return -EINVAL; } if (IS_I965G(dev)) { @@ -1356,7 +1459,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, } intel_increase_pllclock(crtc, true); - mutex_unlock(&dev->struct_mutex); + dbg_safe_mutex_unlock(&dev->struct_mutex); if (!dev->primary->master) return 0; @@ -4243,6 +4346,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, diff --git a/drivers/input/input.c b/drivers/input/input.c index a31394c1eca8..5d95aef035c0 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -1663,6 +1663,21 @@ int input_register_handler(struct input_handler *handler) } EXPORT_SYMBOL(input_register_handler); +#ifdef CONFIG_KGDB_KDB +/* input_db_clear_keys - Clear any keyboards if they have a call back, + * after returning from the kernel debugger + */ +void input_dbg_clear_keys(void) +{ + struct input_handler *handler; + + list_for_each_entry(handler, &input_handler_list, node) + if (handler->dbg_clear_keys) + handler->dbg_clear_keys(); +} +EXPORT_SYMBOL_GPL(input_dbg_clear_keys); +#endif + /** * input_unregister_handler - unregisters an input handler * @handler: handler to be unregistered diff --git a/drivers/misc/kgdbts.c b/drivers/misc/kgdbts.c index fcb6ec1af173..72450237a0f4 100644 --- a/drivers/misc/kgdbts.c +++ b/drivers/misc/kgdbts.c @@ -295,6 +295,10 @@ static int check_and_rewind_pc(char *put_str, char *arg) /* On x86 a breakpoint stop requires it to be decremented */ if (addr + 1 == kgdbts_regs.ip) offset = -1; +#elif defined(CONFIG_SUPERH) + /* On SUPERH a breakpoint stop requires it to be decremented */ + if (addr + 2 == kgdbts_regs.pc) + offset = -2; #endif if (strcmp(arg, "silent") && instruction_pointer(&kgdbts_regs) + offset != addr) { @@ -305,6 +309,8 @@ static int check_and_rewind_pc(char *put_str, char *arg) #ifdef CONFIG_X86 /* On x86 adjust the instruction pointer if needed */ kgdbts_regs.ip += offset; +#elif defined(CONFIG_SUPERH) + kgdbts_regs.pc += offset; #endif return 0; } diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 63bcbe1a46f4..7ad8237b30e3 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -1889,8 +1889,8 @@ static int serial8250_get_poll_char(struct uart_port *port) struct uart_8250_port *up = (struct uart_8250_port *)port; unsigned char lsr = serial_inp(up, UART_LSR); - while (!(lsr & UART_LSR_DR)) - lsr = serial_inp(up, UART_LSR); + if (!(lsr & UART_LSR_DR)) + return NO_POLL_CHAR; return serial_inp(up, UART_RX); } diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c index ef7adc8135dd..b4111159386f 100644 --- a/drivers/serial/amba-pl011.c +++ b/drivers/serial/amba-pl011.c @@ -335,9 +335,9 @@ static int pl010_get_poll_char(struct uart_port *port) struct uart_amba_port *uap = (struct uart_amba_port *)port; unsigned int status; - do { - status = readw(uap->port.membase + UART01x_FR); - } while (status & UART01x_FR_RXFE); + status = readw(uap->port.membase + UART01x_FR); + if (status & UART01x_FR_RXFE) + return NO_POLL_CHAR; return readw(uap->port.membase + UART01x_DR); } diff --git a/drivers/serial/kgdboc.c b/drivers/serial/kgdboc.c index eadc1ab6bbce..05d16055423c 100644 --- a/drivers/serial/kgdboc.c +++ b/drivers/serial/kgdboc.c @@ -14,7 +14,10 @@ #include <linux/kernel.h> #include <linux/ctype.h> #include <linux/kgdb.h> +#include <linux/kdb.h> #include <linux/tty.h> +#include <linux/console.h> +#include <linux/input.h> #define MAX_CONFIG_LEN 40 @@ -22,6 +25,8 @@ static struct kgdb_io kgdboc_io_ops; /* -1 = init not run yet, 0 = unconfigured, 1 = configured. */ static int configured = -1; +static int kgdboc_use_kbd; /* 1 if we use a keyboard */ +static int kgdboc_use_kms; /* 1 if we use kernel mode switching */ static char config[MAX_CONFIG_LEN]; static struct kparam_string kps = { @@ -45,25 +50,85 @@ static int kgdboc_option_setup(char *opt) __setup("kgdboc=", kgdboc_option_setup); +static void cleanup_kgdboc(void) +{ +#ifdef CONFIG_KDB_KEYBOARD + int i; + + /* Unregister the keyboard poll hook, if registered */ + for (i = 0; i < kdb_poll_idx; i++) { + if (kdb_poll_funcs[i] == kdb_get_kbd_char) { + kdb_poll_idx--; + kdb_poll_funcs[i] = kdb_poll_funcs[kdb_poll_idx]; + kdb_poll_funcs[kdb_poll_idx] = NULL; + i--; + } + } +#endif /* CONFIG_KDB_KEYBOARD */ + + if (configured == 1) + kgdb_unregister_io_module(&kgdboc_io_ops); +} + static int configure_kgdboc(void) { struct tty_driver *p; int tty_line = 0; int err; + char *cptr = config; + struct console *cons; err = kgdboc_option_setup(config); if (err || !strlen(config) || isspace(config[0])) goto noconfig; err = -ENODEV; + kgdboc_io_ops.is_console = 0; + kgdboc_use_kbd = 0; + + kgdboc_use_kms = 0; + if (strncmp(cptr, "kms,", 4) == 0) { + cptr += 4; + kgdboc_use_kms = 1; + } +#ifdef CONFIG_KDB_KEYBOARD + kgdb_tty_driver = NULL; + + if (strncmp(cptr, "kbd", 3) == 0) { + if (kdb_poll_idx < KDB_POLL_FUNC_MAX) { + kdb_poll_funcs[kdb_poll_idx] = kdb_get_kbd_char; + kdb_poll_idx++; + kgdboc_use_kbd = 1; + if (cptr[3] == ',') + cptr += 4; + else + goto do_register; + } + } +#endif /* CONFIG_KDB_KEYBOARD */ - p = tty_find_polling_driver(config, &tty_line); + p = tty_find_polling_driver(cptr, &tty_line); if (!p) goto noconfig; + cons = console_drivers; + while (cons) { + int idx; + if (cons->device && cons->device(cons, &idx) == p && + idx == tty_line) { + kgdboc_io_ops.is_console = 1; + break; + } + cons = cons->next; + } + kgdb_tty_driver = p; kgdb_tty_line = tty_line; +#ifdef CONFIG_KDB_KEYBOARD +do_register: +#endif /* CONFIG_KDB_KEYBOARD */ + err = kgdb_register_io_module(&kgdboc_io_ops); if (err) goto noconfig; @@ -75,6 +140,7 @@ static int configure_kgdboc(void) noconfig: config[0] = 0; configured = 0; + cleanup_kgdboc(); return err; } @@ -88,20 +154,18 @@ static int __init init_kgdboc(void) return configure_kgdboc(); } -static void cleanup_kgdboc(void) -{ - if (configured == 1) - kgdb_unregister_io_module(&kgdboc_io_ops); -} - static int kgdboc_get_char(void) { + if (!kgdb_tty_driver) + return -1; return kgdb_tty_driver->ops->poll_get_char(kgdb_tty_driver, kgdb_tty_line); } static void kgdboc_put_char(u8 chr) { + if (!kgdb_tty_driver) + return; kgdb_tty_driver->ops->poll_put_char(kgdb_tty_driver, kgdb_tty_line, chr); } @@ -140,8 +204,19 @@ 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_kms_console_core && + dbg_kms_console_core->activate_console) { + if (dbg_kms_console_core->activate_console(dbg_kms_console_core)) { + printk(KERN_ERR "kgdboc: kernel mode switch error\n"); + } else { + dbg_restore_graphics = 1; + dbg_pre_vt_hook(); + } + } /* Increment the module count when the debugger is active */ if (!kgdb_connected) try_module_get(THIS_MODULE); @@ -152,6 +227,21 @@ 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_kms_console_core && + dbg_kms_console_core->restore_console) { + if (dbg_restore_graphics) { + if (dbg_kms_console_core->restore_console(dbg_kms_console_core)) + printk(KERN_ERR "kgdboc: graphics restore failed\n"); + dbg_restore_graphics = 0; + dbg_post_vt_hook(); + } + } + +#ifdef CONFIG_KDB_KEYBOARD + /* If using the kdb keyboard driver release all the keys. */ + if (kgdboc_use_kbd) + input_dbg_clear_keys(); +#endif /* CONFIG_KDB_KEYBOARD */ } static struct kgdb_io kgdboc_io_ops = { @@ -162,6 +252,19 @@ static struct kgdb_io kgdboc_io_ops = { .post_exception = kgdboc_post_exp_handler, }; +#ifdef CONFIG_KGDB_SERIAL_CONSOLE +/* This is only available if kgdboc is a built in for early debugging */ +void __init early_kgdboc_init(void) +{ + /* save the first character of the config string because the + * init routine can destroy it. + */ + char save_ch = config[0]; + init_kgdboc(); + config[0] = save_ch; +} +#endif /* CONFIG_KGDB_SERIAL_CONSOLE */ + module_init(init_kgdboc); module_exit(cleanup_kgdboc); module_param_call(kgdboc, param_set_kgdboc_var, param_get_string, &kps, 0644); diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index 37f0de9dd9ce..d29b3fefb0a8 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -126,7 +126,11 @@ static int sci_poll_get_char(struct uart_port *port) handle_error(port); continue; } - } while (!(status & SCxSR_RDxF(port))); + break; + } while (1); + + if (!(status & SCxSR_RDxF(port))) + return NO_POLL_CHAR; c = sci_in(port, SCxRDR); diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c index 2c7a66af4f52..978b3cee02d7 100644 --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c @@ -102,6 +102,8 @@ struct uart_sunzilog_port { #endif }; +static void sunzilog_putchar(struct uart_port *port, int ch); + #define ZILOG_CHANNEL_FROM_PORT(PORT) ((struct zilog_channel __iomem *)((PORT)->membase)) #define UART_ZILOG(PORT) ((struct uart_sunzilog_port *)(PORT)) @@ -996,6 +998,50 @@ static int sunzilog_verify_port(struct uart_port *port, struct serial_struct *se return -EINVAL; } +#ifdef CONFIG_CONSOLE_POLL +static int sunzilog_get_poll_char(struct uart_port *port) +{ + unsigned char ch, r1; + struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port; + struct zilog_channel __iomem *channel + = ZILOG_CHANNEL_FROM_PORT(&up->port); + + + r1 = read_zsreg(channel, R1); + if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) { + writeb(ERR_RES, &channel->control); + ZSDELAY(); + ZS_WSYNC(channel); + } + + ch = readb(&channel->control); + ZSDELAY(); + + /* This funny hack depends upon BRK_ABRT not interfering + * with the other bits we care about in R1. + */ + if (ch & BRK_ABRT) + r1 |= BRK_ABRT; + + if (!(ch & Rx_CH_AV)) + return NO_POLL_CHAR; + + ch = readb(&channel->data); + ZSDELAY(); + + ch &= up->parity_mask; + return ch; +} + +static void sunzilog_put_poll_char(struct uart_port *port, + unsigned char ch) +{ + struct uart_sunzilog_port *up = (struct uart_sunzilog_port *)port; + + sunzilog_putchar(&up->port, ch); +} +#endif /* CONFIG_CONSOLE_POLL */ + static struct uart_ops sunzilog_pops = { .tx_empty = sunzilog_tx_empty, .set_mctrl = sunzilog_set_mctrl, @@ -1013,6 +1059,10 @@ static struct uart_ops sunzilog_pops = { .request_port = sunzilog_request_port, .config_port = sunzilog_config_port, .verify_port = sunzilog_verify_port, +#ifdef CONFIG_CONSOLE_POLL + .poll_get_char = sunzilog_get_poll_char, + .poll_put_char = sunzilog_put_poll_char, +#endif }; static int uart_chip_count; diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 3681c6a88212..6f2ed5a15e0c 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -75,6 +75,7 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/crc32.h> /* For counting font checksums */ +#include <linux/kgdb.h> #include <asm/fb.h> #include <asm/irq.h> #include <asm/system.h> @@ -2318,6 +2319,12 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch) } } + if (in_dbg_master()) { + if (info->fbops->fb_blank) + info->fbops->fb_blank(blank, info); + return 0; + } + if (!fbcon_is_inactive(vc, info)) { if (ops->blank_state != blank) { ops->blank_state = blank; |