From f1befe71fa7a79ab733011b045639d8d809924ad Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 18 May 2010 12:24:51 +0100 Subject: agp/intel: Restrict GTT mapping to valid range on i915 and i945 References: Bug 15733 - Crash when accessing nonexistent GTT entries in i915 https://bugzilla.kernel.org/show_bug.cgi?id=15733 On G33 and above, the size of the GTT space is determined by the GMCH control register. Prior to this revision, the size is determined by the size of the aperture. So we must careful to map and fill the appropriate range depending on chipset. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/char/agp/intel-gtt.c | 46 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 7 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index e8ea6825822c..9344216183a4 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -1059,7 +1059,7 @@ static void intel_i9xx_setup_flush(void) } } -static int intel_i915_configure(void) +static int intel_i9xx_configure(void) { struct aper_size_info_fixed *current_size; u32 temp; @@ -1207,6 +1207,38 @@ static int intel_i9xx_fetch_size(void) return 0; } +static int intel_i915_get_gtt_size(void) +{ + int size; + + if (IS_G33) { + u16 gmch_ctrl; + + /* G33's GTT size defined in gmch_ctrl */ + pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl); + switch (gmch_ctrl & G33_PGETBL_SIZE_MASK) { + case G33_PGETBL_SIZE_1M: + size = 1024; + break; + case G33_PGETBL_SIZE_2M: + size = 2048; + break; + default: + dev_info(&agp_bridge->dev->dev, + "unknown page table size 0x%x, assuming 512KB\n", + (gmch_ctrl & G33_PGETBL_SIZE_MASK)); + size = 512; + } + } else { + /* On previous hardware, the GTT size was just what was + * required to map the aperture. + */ + size = agp_bridge->driver->fetch_size(); + } + + return KB(size); +} + /* The intel i915 automatically initializes the agp aperture during POST. * Use the memory already set aside for in the GTT. */ @@ -1216,7 +1248,7 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge) struct aper_size_info_fixed *size; int num_entries; u32 temp, temp2; - int gtt_map_size = 256 * 1024; + int gtt_map_size; size = agp_bridge->current_size; page_order = size->page_order; @@ -1226,8 +1258,8 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge) pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &temp); pci_read_config_dword(intel_private.pcidev, I915_PTEADDR, &temp2); - if (IS_G33) - gtt_map_size = 1024 * 1024; /* 1M on G33 */ + gtt_map_size = intel_i915_get_gtt_size(); + intel_private.gtt = ioremap(temp2, gtt_map_size); if (!intel_private.gtt) return -ENOMEM; @@ -1422,7 +1454,7 @@ static const struct agp_bridge_driver intel_915_driver = { .size_type = FIXED_APER_SIZE, .num_aperture_sizes = 4, .needs_scratch_page = true, - .configure = intel_i915_configure, + .configure = intel_i9xx_configure, .fetch_size = intel_i9xx_fetch_size, .cleanup = intel_i915_cleanup, .mask_memory = intel_i810_mask_memory, @@ -1455,7 +1487,7 @@ static const struct agp_bridge_driver intel_i965_driver = { .size_type = FIXED_APER_SIZE, .num_aperture_sizes = 4, .needs_scratch_page = true, - .configure = intel_i915_configure, + .configure = intel_i9xx_configure, .fetch_size = intel_i9xx_fetch_size, .cleanup = intel_i915_cleanup, .mask_memory = intel_i965_mask_memory, @@ -1488,7 +1520,7 @@ static const struct agp_bridge_driver intel_g33_driver = { .size_type = FIXED_APER_SIZE, .num_aperture_sizes = 4, .needs_scratch_page = true, - .configure = intel_i915_configure, + .configure = intel_i9xx_configure, .fetch_size = intel_i9xx_fetch_size, .cleanup = intel_i915_cleanup, .mask_memory = intel_i965_mask_memory, -- cgit v1.2.3 From 79905ad50bcf025deb81382413719ed600734941 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 1 Jun 2010 19:33:08 +0000 Subject: agp/uninorth: Fix oops caused by flushing too much This fixes a sporadic oops at boot on G5 Power Macs. The table_end variable has the address of the last byte of the table. Adding on PAGE_SIZE means we flush too much, and if the page after the table is not mapped for any reason, the kernel will oops. Instead we add on 1 because flush_dcache_range() interprets its second argument as the first byte past the range to be flushed. Signed-off-by: Paul Mackerras Signed-off-by: Benjamin Herrenschmidt --- drivers/char/agp/uninorth-agp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c index 95db71360d24..f845a8f718b3 100644 --- a/drivers/char/agp/uninorth-agp.c +++ b/drivers/char/agp/uninorth-agp.c @@ -415,7 +415,7 @@ static int uninorth_create_gatt_table(struct agp_bridge_data *bridge) bridge->gatt_table_real = (u32 *) table; /* Need to clear out any dirty data still sitting in caches */ flush_dcache_range((unsigned long)table, - (unsigned long)(table_end + PAGE_SIZE)); + (unsigned long)table_end + 1); bridge->gatt_table = vmap(pages, (1 << page_order), 0, PAGE_KERNEL_NCG); if (bridge->gatt_table == NULL) -- cgit v1.2.3 From 0047634d3daebca9e99a22eb89167bf77f35cdfa Mon Sep 17 00:00:00 2001 From: Amit Shah Date: Thu, 27 May 2010 13:24:39 +0530 Subject: virtio: console: Fix crash when hot-unplugging a port and read is blocked When removing a port we don't check if a program was blocked for read. This leads to a crash when SIGTERM is sent to the program after hot-unplugging the port. Signed-off-by: Amit Shah Signed-off-by: Rusty Russell --- drivers/char/virtio_console.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 8c99bf1b5e9f..e3fb5296cf25 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1099,6 +1099,13 @@ static int remove_port(struct port *port) { struct port_buffer *buf; + if (port->guest_connected) { + port->guest_connected = false; + port->host_connected = false; + wake_up_interruptible(&port->waitqueue); + send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 0); + } + spin_lock_irq(&port->portdev->ports_lock); list_del(&port->list); spin_unlock_irq(&port->portdev->ports_lock); @@ -1120,9 +1127,6 @@ static int remove_port(struct port *port) hvc_remove(port->cons.hvc); #endif } - if (port->guest_connected) - send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 0); - sysfs_remove_group(&port->dev->kobj, &port_attribute_group); device_destroy(pdrvdata.class, port->dev->devt); cdev_del(&port->cdev); -- cgit v1.2.3 From 60e5e0b84045ce0f6ab07a02c7fcd6627b53d2d3 Mon Sep 17 00:00:00 2001 From: Amit Shah Date: Thu, 27 May 2010 13:24:40 +0530 Subject: virtio: console: Fix crash when port is unplugged and blocked for write When a program that has a virtio port opened and blocked for a write operation, a port hot-unplug event will later led to a crash when SIGTERM was sent to the program. Fix that. Signed-off-by: Amit Shah Signed-off-by: Rusty Russell --- drivers/char/virtio_console.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/char') diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index e3fb5296cf25..942a9826bd23 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -529,6 +529,10 @@ static bool will_write_block(struct port *port) { bool ret; + if (!port->guest_connected) { + /* Port got hot-unplugged. Let's exit. */ + return false; + } if (!port->host_connected) return true; -- cgit v1.2.3 From 328be395a396b1333b56e04571365dc614c96e46 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 25 May 2010 11:37:17 +0200 Subject: TTY/n_gsm: potential double lock In gsm_dlci_data_kick() we call gsm_dlci_data_sweep() with the "gsm->tx_lock" held so we can't lock it again inside gsm_dlci_data_sweep(). I removed that lock from and added one to gsmld_write_wakeup() instead. The sweep function is only called from those two places. Signed-off-by: Dan Carpenter Acked-by: Alan Cox Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/char/n_gsm.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/n_gsm.c b/drivers/char/n_gsm.c index c4161d5e053d..e4089c432f15 100644 --- a/drivers/char/n_gsm.c +++ b/drivers/char/n_gsm.c @@ -904,9 +904,7 @@ static void gsm_dlci_data_sweep(struct gsm_mux *gsm) int len; /* Priority ordering: We should do priority with RR of the groups */ int i = 1; - unsigned long flags; - spin_lock_irqsave(&gsm->tx_lock, flags); while (i < NUM_DLCI) { struct gsm_dlci *dlci; @@ -927,7 +925,6 @@ static void gsm_dlci_data_sweep(struct gsm_mux *gsm) if (len == 0) i++; } - spin_unlock_irqrestore(&gsm->tx_lock, flags); } /** @@ -2230,12 +2227,16 @@ static int gsmld_open(struct tty_struct *tty) static void gsmld_write_wakeup(struct tty_struct *tty) { struct gsm_mux *gsm = tty->disc_data; + unsigned long flags; /* Queue poll */ clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); gsm_data_kick(gsm); - if (gsm->tx_bytes < TX_THRESH_LO) + if (gsm->tx_bytes < TX_THRESH_LO) { + spin_lock_irqsave(&gsm->tx_lock, flags); gsm_dlci_data_sweep(gsm); + spin_unlock_irqrestore(&gsm->tx_lock, flags); + } } /** -- cgit v1.2.3 From 962400e8fd29981a7b166e463dd143b6ac6a3e76 Mon Sep 17 00:00:00 2001 From: Frank Pan Date: Wed, 26 May 2010 15:37:43 +0800 Subject: tty: fix a little bug in scrup, vt.c The code uses vc->vc_cols instead of vc->vc_size_row by mistake, it will cause half of the region which is going to clear remain uncleared. The issue happens in background consoles, so it's hard to observe. Frank Pan Signed-off-by: Frank Pan Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/char/vt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 7cdb6ee569cd..1296c42ed5c6 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -304,7 +304,7 @@ static void scrup(struct vc_data *vc, unsigned int t, unsigned int b, int nr) d = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t); s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * (t + nr)); scr_memmovew(d, s, (b - t - nr) * vc->vc_size_row); - scr_memsetw(d + (b - t - nr) * vc->vc_cols, vc->vc_video_erase_char, + scr_memsetw(d + (b - t - nr) * vc->vc_size_row, vc->vc_video_erase_char, vc->vc_size_row * nr); } -- cgit v1.2.3 From 3fde85df5421eb01f563fef6f111ba73ab0d120e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 4 Jun 2010 12:20:46 +0200 Subject: vt_ioctl: return -EFAULT on copy_from_user errors copy_from_user() returns the number of bytes remaining but we want to return a negative error code here. Signed-off-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/char/vt_ioctl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c index 6aa10284104a..cb19dbc52136 100644 --- a/drivers/char/vt_ioctl.c +++ b/drivers/char/vt_ioctl.c @@ -1303,7 +1303,9 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, if (!perm) goto eperm; ret = copy_from_user(&ui, up, sizeof(struct unimapinit)); - if (!ret) + if (ret) + ret = -EFAULT; + else con_clear_unimap(vc, &ui); break; } -- cgit v1.2.3 From b7e5d1f04104d98895945ecb463d750320dcd6cf Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 4 Jun 2010 14:14:48 -0700 Subject: ramoops: add HAS_IOMEM dependency The driver fails to compile on s390: drivers/char/ramoops.c: In function 'ramoops_init': drivers/char/ramoops.c:122: error: implicit declaration of function 'ioremap' Since we won't make use of the driver anyway on s390 just let it depend on HAS_IOMEM. Signed-off-by: Heiko Carstens Cc: Marco Stornelli Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/char') diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index f09fc0e2062d..7cfcc629a7fd 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -1123,6 +1123,7 @@ source "drivers/s390/char/Kconfig" config RAMOOPS tristate "Log panic/oops to a RAM buffer" + depends on HAS_IOMEM default n help This enables panic and oops messages to be logged to a circular -- cgit v1.2.3 From 386f40c86d6c8d5b717ef20620af1a750d0dacb4 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 6 Jun 2010 20:44:04 -0700 Subject: Revert "tty: fix a little bug in scrup, vt.c" This reverts commit 962400e8fd29981a7b166e463dd143b6ac6a3e76, which was entirely bogus. The code used to multiply the character offset by "vc->vc_cols", and that's actually correct, because 'd' itself is an 'unsigned short'. So the pointer arithmetic already takes the size of a VGA character into account. Changing it to use vc_size_row (which is just "vc_cols" shifted up to take the size of the character into account) ends up multiplying with the VGA character size twice. This got reported as bugs for various other subsystems, because what it actually results in is writing the 16-bit vc_video_erase_char pattern (usually 0x0720: 0x07 is the default attribute, 0x20 is ASCII space) into some random other allocation. So Markus ended up reporting this as a ext4 bug, while to Torsten Kaiser it looked like a problem with KMS or libata. Jeff Chua saw it in different places. And finally - Justin Mattock had slab poisoning enabled, and saw it as a slab poison overwritten. And bisected and reverted this to verify the buggy commit. Reported-by: Markus Trippelsdorf Reported-by: Torsten Kaiser Reported-by: Jeff Chua Reported-by: Justin P. Mattock Reported-bisected-and-tested-by: Justin P. Mattock Acked-by: Dave Airlie Cc: Frank Pan Cc: Greg Kroah-Hartman Signed-off-by: Linus Torvalds --- drivers/char/vt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 1296c42ed5c6..7cdb6ee569cd 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -304,7 +304,7 @@ static void scrup(struct vc_data *vc, unsigned int t, unsigned int b, int nr) d = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t); s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * (t + nr)); scr_memmovew(d, s, (b - t - nr) * vc->vc_size_row); - scr_memsetw(d + (b - t - nr) * vc->vc_size_row, vc->vc_video_erase_char, + scr_memsetw(d + (b - t - nr) * vc->vc_cols, vc->vc_video_erase_char, vc->vc_size_row * nr); } -- cgit v1.2.3