From 832cc28d5bc676331e6376d940ae45d5937aa688 Mon Sep 17 00:00:00 2001 From: Florian Mickler Date: Mon, 13 Jul 2009 18:40:32 +0800 Subject: drm/i915: Set lvds dual channel according to register from vbios Vbios will set lvds register correctly based on current algorithm for lingle/dual Channel LVDS when system boot, so we can accept this configuration directly, regardless of LVDS enable status. It fixed freedesktop.org bug #22262 Signed-off-by: Florian Mickler Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 508838e..3371cb0 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -645,7 +645,7 @@ intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, int err = target; if (IS_I9XX(dev) && intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) && - (I915_READ(LVDS) & LVDS_PORT_EN) != 0) { + (I915_READ(LVDS)) != 0) { /* * For LVDS, if the panel is on, just rely on its current * settings for dual-channel. We haven't figured out how to -- cgit v0.10.2 From 8a90523639f49dc4b4fa7ae47bb9c8ed73ea8577 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Sat, 11 Jul 2009 16:48:03 -0400 Subject: drm/i915: refactor error detection & collection This patch refactors the existing error detection and collection code, placing most of it in i915_handle_error(). Additionally, we introduce a work queue for scheduling post-crash tasks such as generating a uevent. Using the uevent facility, userspace should be able to capture a post-mortem dump for diagnostics. Signed-off-by: Jesse Barnes Signed-off-by: Ben Gamari Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index d087528..b05b44d 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -229,6 +229,7 @@ typedef struct drm_i915_private { spinlock_t error_lock; struct drm_i915_error_state *first_error; + struct work_struct error_work; /* Register state */ u8 saveLBB; diff --git a/drivers/gpu/drm/i915/i915_gem_debugfs.c b/drivers/gpu/drm/i915/i915_gem_debugfs.c index 9a44bfc..cb3b974 100644 --- a/drivers/gpu/drm/i915/i915_gem_debugfs.c +++ b/drivers/gpu/drm/i915/i915_gem_debugfs.c @@ -343,6 +343,8 @@ static int i915_error_state(struct seq_file *m, void *unused) error = dev_priv->first_error; + seq_printf(m, "Time: %ld s %ld us\n", error->time.tv_sec, + error->time.tv_usec); seq_printf(m, "EIR: 0x%08x\n", error->eir); seq_printf(m, " PGTBL_ER: 0x%08x\n", error->pgtbl_er); seq_printf(m, " INSTPM: 0x%08x\n", error->instpm); diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 7ba23a6..f340b3f 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -290,6 +290,35 @@ irqreturn_t igdng_irq_handler(struct drm_device *dev) return ret; } +/** + * i915_error_work_func - do process context error handling work + * @work: work struct + * + * Fire an error uevent so userspace can see that a hang or error + * was detected. + */ +static void i915_error_work_func(struct work_struct *work) +{ + drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t, + error_work); + struct drm_device *dev = dev_priv->dev; + char *event_string = "ERROR=1"; + char *envp[] = { event_string, NULL }; + + DRM_DEBUG("generating error event\n"); + + kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, envp); +} + +/** + * i915_capture_error_state - capture an error record for later analysis + * @dev: drm device + * + * Should be called when an error is detected (either a hang or an error + * interrupt) to capture error state from the time of the error. Fills + * out a structure which becomes available in debugfs for user level tools + * to pick up. + */ static void i915_capture_error_state(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -325,12 +354,137 @@ static void i915_capture_error_state(struct drm_device *dev) error->acthd = I915_READ(ACTHD_I965); } + do_gettimeofday(&error->time); + dev_priv->first_error = error; out: spin_unlock_irqrestore(&dev_priv->error_lock, flags); } +/** + * i915_handle_error - handle an error interrupt + * @dev: drm device + * + * Do some basic checking of regsiter state at error interrupt time and + * dump it to the syslog. Also call i915_capture_error_state() to make + * sure we get a record and make it available in debugfs. Fire a uevent + * so userspace knows something bad happened (should trigger collection + * of a ring dump etc.). + */ +static void i915_handle_error(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 eir = I915_READ(EIR); + u32 pipea_stats = I915_READ(PIPEASTAT); + u32 pipeb_stats = I915_READ(PIPEBSTAT); + + i915_capture_error_state(dev); + + printk(KERN_ERR "render error detected, EIR: 0x%08x\n", + eir); + + if (IS_G4X(dev)) { + if (eir & (GM45_ERROR_MEM_PRIV | GM45_ERROR_CP_PRIV)) { + u32 ipeir = I915_READ(IPEIR_I965); + + printk(KERN_ERR " IPEIR: 0x%08x\n", + I915_READ(IPEIR_I965)); + printk(KERN_ERR " IPEHR: 0x%08x\n", + I915_READ(IPEHR_I965)); + printk(KERN_ERR " INSTDONE: 0x%08x\n", + I915_READ(INSTDONE_I965)); + printk(KERN_ERR " INSTPS: 0x%08x\n", + I915_READ(INSTPS)); + printk(KERN_ERR " INSTDONE1: 0x%08x\n", + I915_READ(INSTDONE1)); + printk(KERN_ERR " ACTHD: 0x%08x\n", + I915_READ(ACTHD_I965)); + I915_WRITE(IPEIR_I965, ipeir); + (void)I915_READ(IPEIR_I965); + } + if (eir & GM45_ERROR_PAGE_TABLE) { + u32 pgtbl_err = I915_READ(PGTBL_ER); + printk(KERN_ERR "page table error\n"); + printk(KERN_ERR " PGTBL_ER: 0x%08x\n", + pgtbl_err); + I915_WRITE(PGTBL_ER, pgtbl_err); + (void)I915_READ(PGTBL_ER); + } + } + + if (IS_I9XX(dev)) { + if (eir & I915_ERROR_PAGE_TABLE) { + u32 pgtbl_err = I915_READ(PGTBL_ER); + printk(KERN_ERR "page table error\n"); + printk(KERN_ERR " PGTBL_ER: 0x%08x\n", + pgtbl_err); + I915_WRITE(PGTBL_ER, pgtbl_err); + (void)I915_READ(PGTBL_ER); + } + } + + if (eir & I915_ERROR_MEMORY_REFRESH) { + printk(KERN_ERR "memory refresh error\n"); + printk(KERN_ERR "PIPEASTAT: 0x%08x\n", + pipea_stats); + printk(KERN_ERR "PIPEBSTAT: 0x%08x\n", + pipeb_stats); + /* pipestat has already been acked */ + } + if (eir & I915_ERROR_INSTRUCTION) { + printk(KERN_ERR "instruction error\n"); + printk(KERN_ERR " INSTPM: 0x%08x\n", + I915_READ(INSTPM)); + if (!IS_I965G(dev)) { + u32 ipeir = I915_READ(IPEIR); + + printk(KERN_ERR " IPEIR: 0x%08x\n", + I915_READ(IPEIR)); + printk(KERN_ERR " IPEHR: 0x%08x\n", + I915_READ(IPEHR)); + printk(KERN_ERR " INSTDONE: 0x%08x\n", + I915_READ(INSTDONE)); + printk(KERN_ERR " ACTHD: 0x%08x\n", + I915_READ(ACTHD)); + I915_WRITE(IPEIR, ipeir); + (void)I915_READ(IPEIR); + } else { + u32 ipeir = I915_READ(IPEIR_I965); + + printk(KERN_ERR " IPEIR: 0x%08x\n", + I915_READ(IPEIR_I965)); + printk(KERN_ERR " IPEHR: 0x%08x\n", + I915_READ(IPEHR_I965)); + printk(KERN_ERR " INSTDONE: 0x%08x\n", + I915_READ(INSTDONE_I965)); + printk(KERN_ERR " INSTPS: 0x%08x\n", + I915_READ(INSTPS)); + printk(KERN_ERR " INSTDONE1: 0x%08x\n", + I915_READ(INSTDONE1)); + printk(KERN_ERR " ACTHD: 0x%08x\n", + I915_READ(ACTHD_I965)); + I915_WRITE(IPEIR_I965, ipeir); + (void)I915_READ(IPEIR_I965); + } + } + + I915_WRITE(EIR, eir); + (void)I915_READ(EIR); + eir = I915_READ(EIR); + if (eir) { + /* + * some errors might have become stuck, + * mask them. + */ + DRM_ERROR("EIR stuck: 0x%08x, masking\n", eir); + I915_WRITE(EMR, I915_READ(EMR) | eir); + I915_WRITE(IIR, I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT); + } + + schedule_work(&dev_priv->error_work); +} + irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) { struct drm_device *dev = (struct drm_device *) arg; @@ -372,6 +526,9 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) pipea_stats = I915_READ(PIPEASTAT); pipeb_stats = I915_READ(PIPEBSTAT); + if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT) + i915_handle_error(dev); + /* * Clear the PIPE(A|B)STAT regs before the IIR */ @@ -409,80 +566,6 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) I915_READ(PORT_HOTPLUG_STAT); } - if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT) { - u32 eir = I915_READ(EIR); - - i915_capture_error_state(dev); - - printk(KERN_ERR "render error detected, EIR: 0x%08x\n", - eir); - if (eir & I915_ERROR_PAGE_TABLE) { - u32 pgtbl_err = I915_READ(PGTBL_ER); - printk(KERN_ERR "page table error\n"); - printk(KERN_ERR " PGTBL_ER: 0x%08x\n", - pgtbl_err); - I915_WRITE(PGTBL_ER, pgtbl_err); - (void)I915_READ(PGTBL_ER); - } - if (eir & I915_ERROR_MEMORY_REFRESH) { - printk(KERN_ERR "memory refresh error\n"); - printk(KERN_ERR "PIPEASTAT: 0x%08x\n", - pipea_stats); - printk(KERN_ERR "PIPEBSTAT: 0x%08x\n", - pipeb_stats); - /* pipestat has already been acked */ - } - if (eir & I915_ERROR_INSTRUCTION) { - printk(KERN_ERR "instruction error\n"); - printk(KERN_ERR " INSTPM: 0x%08x\n", - I915_READ(INSTPM)); - if (!IS_I965G(dev)) { - u32 ipeir = I915_READ(IPEIR); - - printk(KERN_ERR " IPEIR: 0x%08x\n", - I915_READ(IPEIR)); - printk(KERN_ERR " IPEHR: 0x%08x\n", - I915_READ(IPEHR)); - printk(KERN_ERR " INSTDONE: 0x%08x\n", - I915_READ(INSTDONE)); - printk(KERN_ERR " ACTHD: 0x%08x\n", - I915_READ(ACTHD)); - I915_WRITE(IPEIR, ipeir); - (void)I915_READ(IPEIR); - } else { - u32 ipeir = I915_READ(IPEIR_I965); - - printk(KERN_ERR " IPEIR: 0x%08x\n", - I915_READ(IPEIR_I965)); - printk(KERN_ERR " IPEHR: 0x%08x\n", - I915_READ(IPEHR_I965)); - printk(KERN_ERR " INSTDONE: 0x%08x\n", - I915_READ(INSTDONE_I965)); - printk(KERN_ERR " INSTPS: 0x%08x\n", - I915_READ(INSTPS)); - printk(KERN_ERR " INSTDONE1: 0x%08x\n", - I915_READ(INSTDONE1)); - printk(KERN_ERR " ACTHD: 0x%08x\n", - I915_READ(ACTHD_I965)); - I915_WRITE(IPEIR_I965, ipeir); - (void)I915_READ(IPEIR_I965); - } - } - - I915_WRITE(EIR, eir); - (void)I915_READ(EIR); - eir = I915_READ(EIR); - if (eir) { - /* - * some errors might have become stuck, - * mask them. - */ - DRM_ERROR("EIR stuck: 0x%08x, masking\n", eir); - I915_WRITE(EMR, I915_READ(EMR) | eir); - I915_WRITE(IIR, I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT); - } - } - I915_WRITE(IIR, iir); new_iir = I915_READ(IIR); /* Flush posted writes */ @@ -830,6 +913,7 @@ void i915_driver_irq_preinstall(struct drm_device * dev) atomic_set(&dev_priv->irq_received, 0); INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func); + INIT_WORK(&dev_priv->error_work, i915_error_work_func); if (IS_IGDNG(dev)) { igdng_irq_preinstall(dev); -- cgit v0.10.2 From 5e4d6fa72619aeea271d2ad704757717b06e291a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 12 Jul 2009 23:53:17 -0700 Subject: drm/i915: Allow frame buffers up to 4096x4096 on 915/945 class hardware The 915 and 945 scanout engines can handle frame buffers up to 4096 pixels wide. Pre-9xx hardware has an 8192 byte stride limit, and so we leave the existing 2048 max in place. I'm not sure why we limit the height to the same value; there's no intrinsic hardware limit in the scanout engine. Signed-off-by: Keith Packard Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3371cb0..984645e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3148,6 +3148,9 @@ void intel_modeset_init(struct drm_device *dev) if (IS_I965G(dev)) { dev->mode_config.max_width = 8192; dev->mode_config.max_height = 8192; + } else if (IS_I9XX(dev)) { + dev->mode_config.max_width = 4096; + dev->mode_config.max_height = 4096; } else { dev->mode_config.max_width = 2048; dev->mode_config.max_height = 2048; -- cgit v0.10.2 From ed8c754b292f02d0550596481527b7bf2b52d024 Mon Sep 17 00:00:00 2001 From: Tormod Volden Date: Mon, 13 Jul 2009 22:26:48 +0200 Subject: drm/i915: ignore lvds on AOpen Mini PC MP-915 This motherboard thinks it has an LVDS connected, so without this patch the screen goes blank on the connected VGA monitor. More information (for the non-KMS case) in fd.o bug #18004. Signed-off-by: Tormod Volden Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 9ab38ef..43c7d9a 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -780,6 +780,14 @@ static const struct dmi_system_id intel_no_lvds[] = { }, { .callback = intel_no_lvds_dmi_callback, + .ident = "AOpen Mini PC MP915", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"), + DMI_MATCH(DMI_BOARD_NAME, "i915GMx-F"), + }, + }, + { + .callback = intel_no_lvds_dmi_callback, .ident = "Aopen i945GTt-VFA", .matches = { DMI_MATCH(DMI_PRODUCT_VERSION, "AO00001JW"), -- cgit v0.10.2 From dff33cfcefa31c30b72c57f44586754ea9e8f3e2 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 14 Jul 2009 10:15:56 -0700 Subject: drm/i915: FIFO watermark calculation fixes I discovered several bugs in the FIFO code that was recently applied. Some of them fell into the "how did this ever work" category, since in some cases we were using the wrong FIFO size values, and the calculations ended up being way off. This patch fixes all the bugs I found, and works well on my GM45, 915GM and 855GM test machines; but as usual with these sorts of patches broader testing is definitely requested (in particular this patch affects 830, 845 and 865 for which I don't have test hardware). Overall, the patch clarifies the watermark calculation function by adding some comments and debug info, and making the variable names a bit clearer. The "get FIFO size" portion of the code has also been corrected, so we should be able to properly detect the FIFO allocations for each pipe, for use in the watermark calculation. Signed-off-by: Jesse Barnes Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 6c08584..897a116 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1618,7 +1618,7 @@ #define I830_FIFO_LINE_SIZE 32 #define I945_FIFO_SIZE 127 /* 945 & 965 */ #define I915_FIFO_SIZE 95 -#define I855GM_FIFO_SIZE 255 +#define I855GM_FIFO_SIZE 127 /* In cachelines */ #define I830_FIFO_SIZE 95 #define I915_MAX_WM 0x3f diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 984645e..3fa0d63 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1623,44 +1623,67 @@ static struct intel_watermark_params igd_cursor_hplloff_wm = { IGD_FIFO_LINE_SIZE }; static struct intel_watermark_params i945_wm_info = { - I915_FIFO_LINE_SIZE, + I945_FIFO_SIZE, I915_MAX_WM, 1, - 0, - IGD_FIFO_LINE_SIZE + 2, + I915_FIFO_LINE_SIZE }; static struct intel_watermark_params i915_wm_info = { - I945_FIFO_SIZE, + I915_FIFO_SIZE, I915_MAX_WM, 1, - 0, + 2, I915_FIFO_LINE_SIZE }; static struct intel_watermark_params i855_wm_info = { I855GM_FIFO_SIZE, I915_MAX_WM, 1, - 0, + 2, I830_FIFO_LINE_SIZE }; static struct intel_watermark_params i830_wm_info = { I830_FIFO_SIZE, I915_MAX_WM, 1, - 0, + 2, I830_FIFO_LINE_SIZE }; +/** + * intel_calculate_wm - calculate watermark level + * @clock_in_khz: pixel clock + * @wm: chip FIFO params + * @pixel_size: display pixel size + * @latency_ns: memory latency for the platform + * + * Calculate the watermark level (the level at which the display plane will + * start fetching from memory again). Each chip has a different display + * FIFO size and allocation, so the caller needs to figure that out and pass + * in the correct intel_watermark_params structure. + * + * As the pixel clock runs, the FIFO will be drained at a rate that depends + * on the pixel size. When it reaches the watermark level, it'll start + * fetching FIFO line sized based chunks from memory until the FIFO fills + * past the watermark point. If the FIFO drains completely, a FIFO underrun + * will occur, and a display engine hang could result. + */ static unsigned long intel_calculate_wm(unsigned long clock_in_khz, struct intel_watermark_params *wm, int pixel_size, unsigned long latency_ns) { - unsigned long bytes_required, wm_size; + unsigned long entries_required, wm_size; + + entries_required = (clock_in_khz * pixel_size * latency_ns) / 1000000; + entries_required /= wm->cacheline_size; + + DRM_DEBUG("FIFO entries required for mode: %d\n", entries_required); - bytes_required = (clock_in_khz * pixel_size * latency_ns) / 1000000; - bytes_required /= wm->cacheline_size; - wm_size = wm->fifo_size - bytes_required - wm->guard_size; + wm_size = wm->fifo_size - (entries_required + wm->guard_size); + + DRM_DEBUG("FIFO watermark level: %d\n", wm_size); if (wm_size > wm->max_wm) wm_size = wm->max_wm; @@ -1799,8 +1822,37 @@ static void igd_enable_cxsr(struct drm_device *dev, unsigned long clock, return; } -const static int latency_ns = 5000; /* default for non-igd platforms */ +const static int latency_ns = 3000; /* default for non-igd platforms */ + +static int intel_get_fifo_size(struct drm_device *dev, int plane) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t dsparb = I915_READ(DSPARB); + int size; + + if (IS_I9XX(dev)) { + if (plane == 0) + size = dsparb & 0x7f; + else + size = ((dsparb >> DSPARB_CSTART_SHIFT) & 0x7f) - + (dsparb & 0x7f); + } else if (IS_I85X(dev)) { + if (plane == 0) + size = dsparb & 0x1ff; + else + size = ((dsparb >> DSPARB_BEND_SHIFT) & 0x1ff) - + (dsparb & 0x1ff); + size >>= 1; /* Convert to cachelines */ + } else { + size = dsparb & 0x7f; + size >>= 1; /* Convert to cachelines */ + } + + DRM_DEBUG("FIFO size - (0x%08x) %s: %d\n", dsparb, plane ? "B" : "A", + size); + return size; +} static void i965_update_wm(struct drm_device *dev) { @@ -1817,101 +1869,87 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock, int planeb_clock, int sr_hdisplay, int pixel_size) { struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t fwater_lo = I915_READ(FW_BLC) & MM_FIFO_WATERMARK; - uint32_t fwater_hi = I915_READ(FW_BLC2) & LM_FIFO_WATERMARK; - int bsize, asize, cwm, bwm = 1, awm = 1, srwm = 1; - uint32_t dsparb = I915_READ(DSPARB); - int planea_entries, planeb_entries; - struct intel_watermark_params *wm_params; + uint32_t fwater_lo; + uint32_t fwater_hi; + int total_size, cacheline_size, cwm, srwm = 1; + int planea_wm, planeb_wm; + struct intel_watermark_params planea_params, planeb_params; unsigned long line_time_us; int sr_clock, sr_entries = 0; + /* Create copies of the base settings for each pipe */ if (IS_I965GM(dev) || IS_I945GM(dev)) - wm_params = &i945_wm_info; + planea_params = planeb_params = i945_wm_info; else if (IS_I9XX(dev)) - wm_params = &i915_wm_info; + planea_params = planeb_params = i915_wm_info; else - wm_params = &i855_wm_info; - - planea_entries = intel_calculate_wm(planea_clock, wm_params, - pixel_size, latency_ns); - planeb_entries = intel_calculate_wm(planeb_clock, wm_params, - pixel_size, latency_ns); + planea_params = planeb_params = i855_wm_info; - DRM_DEBUG("FIFO entries - A: %d, B: %d\n", planea_entries, - planeb_entries); + /* Grab a couple of global values before we overwrite them */ + total_size = planea_params.fifo_size; + cacheline_size = planea_params.cacheline_size; - if (IS_I9XX(dev)) { - asize = dsparb & 0x7f; - bsize = (dsparb >> DSPARB_CSTART_SHIFT) & 0x7f; - } else { - asize = dsparb & 0x1ff; - bsize = (dsparb >> DSPARB_BEND_SHIFT) & 0x1ff; - } - DRM_DEBUG("FIFO size - A: %d, B: %d\n", asize, bsize); + /* Update per-plane FIFO sizes */ + planea_params.fifo_size = intel_get_fifo_size(dev, 0); + planeb_params.fifo_size = intel_get_fifo_size(dev, 1); - /* Two extra entries for padding */ - awm = asize - (planea_entries + 2); - bwm = bsize - (planeb_entries + 2); - - /* Sanity check against potentially bad FIFO allocations */ - if (awm <= 0) { - /* pipe is on but has too few FIFO entries */ - if (planea_entries != 0) - DRM_DEBUG("plane A needs more FIFO entries\n"); - awm = 1; - } - if (bwm <= 0) { - if (planeb_entries != 0) - DRM_DEBUG("plane B needs more FIFO entries\n"); - bwm = 1; - } + planea_wm = intel_calculate_wm(planea_clock, &planea_params, + pixel_size, latency_ns); + planeb_wm = intel_calculate_wm(planeb_clock, &planeb_params, + pixel_size, latency_ns); + DRM_DEBUG("FIFO watermarks - A: %d, B: %d\n", planea_wm, planeb_wm); /* * Overlay gets an aggressive default since video jitter is bad. */ cwm = 2; - /* Calc sr entries for one pipe configs */ + /* Calc sr entries for one plane configs */ if (!planea_clock || !planeb_clock) { + /* self-refresh has much higher latency */ + const static int sr_latency_ns = 6000; + sr_clock = planea_clock ? planea_clock : planeb_clock; - line_time_us = (sr_hdisplay * 1000) / sr_clock; - sr_entries = (((latency_ns / line_time_us) + 1) * pixel_size * - sr_hdisplay) / 1000; - sr_entries = roundup(sr_entries / wm_params->cacheline_size, 1); - if (sr_entries < wm_params->fifo_size) - srwm = wm_params->fifo_size - sr_entries; + line_time_us = ((sr_hdisplay * 1000) / sr_clock); + + /* Use ns/us then divide to preserve precision */ + sr_entries = (((sr_latency_ns / line_time_us) + 1) * + pixel_size * sr_hdisplay) / 1000; + sr_entries = roundup(sr_entries / cacheline_size, 1); + DRM_DEBUG("self-refresh entries: %d\n", sr_entries); + srwm = total_size - sr_entries; + if (srwm < 0) + srwm = 1; } DRM_DEBUG("Setting FIFO watermarks - A: %d, B: %d, C: %d, SR %d\n", - awm, bwm, cwm, srwm); + planea_wm, planeb_wm, cwm, srwm); - fwater_lo = fwater_lo | ((bwm & 0x3f) << 16) | (awm & 0x3f); - fwater_hi = fwater_hi | (cwm & 0x1f); + fwater_lo = ((planeb_wm & 0x3f) << 16) | (planea_wm & 0x3f); + fwater_hi = (cwm & 0x1f); + + /* Set request length to 8 cachelines per fetch */ + fwater_lo = fwater_lo | (1 << 24) | (1 << 8); + fwater_hi = fwater_hi | (1 << 8); I915_WRITE(FW_BLC, fwater_lo); I915_WRITE(FW_BLC2, fwater_hi); if (IS_I9XX(dev)) - I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN | (srwm & 0x3f)); + I915_WRITE(FW_BLC_SELF, (srwm & 0x3f)); } static void i830_update_wm(struct drm_device *dev, int planea_clock, int pixel_size) { struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t dsparb = I915_READ(DSPARB); uint32_t fwater_lo = I915_READ(FW_BLC) & MM_FIFO_WATERMARK; - unsigned int asize, awm; - int planea_entries; - - planea_entries = intel_calculate_wm(planea_clock, &i830_wm_info, - pixel_size, latency_ns); - - asize = dsparb & 0x7f; + int planea_wm; - awm = asize - planea_entries; + i830_wm_info.fifo_size = intel_get_fifo_size(dev, 0); - fwater_lo = fwater_lo | awm; + planea_wm = intel_calculate_wm(planea_clock, &i830_wm_info, + pixel_size, latency_ns); + fwater_lo = fwater_lo | planea_wm; I915_WRITE(FW_BLC, fwater_lo); } @@ -1984,7 +2022,7 @@ static void intel_update_watermarks(struct drm_device *dev) if (enabled <= 0) return; - /* Single pipe configs can enable self refresh */ + /* Single plane configs can enable self refresh */ if (enabled == 1 && IS_IGD(dev)) igd_enable_cxsr(dev, sr_clock, pixel_size); else if (IS_IGD(dev)) -- cgit v0.10.2 From 390c4dd448b1a5f04ea497c20f5ff664f8eeed01 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 16 Jul 2009 13:01:01 -0700 Subject: drm/i915: handle FIFO oversubsription correctly If you're pushing a plane hard (i.e. you need most or all of the FIFO entries just to cover your frame refresh latency), the watermark level may end up being negative. So fix up the signed vs. unsigned math in the calculation function to handle this correctly, giving all available FIFO entries to such a configuration. Reported-by: Eric Anholt Tested-by: Eric Anholt Signed-off-by: Jesse Barnes Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3fa0d63..890f710 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1674,7 +1674,7 @@ static unsigned long intel_calculate_wm(unsigned long clock_in_khz, int pixel_size, unsigned long latency_ns) { - unsigned long entries_required, wm_size; + long entries_required, wm_size; entries_required = (clock_in_khz * pixel_size * latency_ns) / 1000000; entries_required /= wm->cacheline_size; @@ -1685,9 +1685,10 @@ static unsigned long intel_calculate_wm(unsigned long clock_in_khz, DRM_DEBUG("FIFO watermark level: %d\n", wm_size); - if (wm_size > wm->max_wm) + /* Don't promote wm_size to unsigned... */ + if (wm_size > (long)wm->max_wm) wm_size = wm->max_wm; - if (wm_size == 0) + if (wm_size <= 0) wm_size = wm->default_wm; return wm_size; } -- cgit v0.10.2 From 2a2430f4542467502d39660bfd66b0004fd8d6a9 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 16 Jul 2009 13:01:02 -0700 Subject: drm/i915: correct self-refresh calculation in "everything off" case If no planes are enabled, the self-refresh calculation may end up doing a divide by zero. This patch should prevent that by making sure at least one of the CRTCs had a valid hdisplay value. Reported-by: Eric Anholt Tested-by: Eric Anholt Signed-off-by: Jesse Barnes Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 890f710..a58bfad 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1906,7 +1906,7 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock, cwm = 2; /* Calc sr entries for one plane configs */ - if (!planea_clock || !planeb_clock) { + if (sr_hdisplay && (!planea_clock || !planeb_clock)) { /* self-refresh has much higher latency */ const static int sr_latency_ns = 6000; @@ -1921,6 +1921,8 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock, srwm = total_size - sr_entries; if (srwm < 0) srwm = 1; + if (IS_I9XX(dev)) + I915_WRITE(FW_BLC_SELF, (srwm & 0x3f)); } DRM_DEBUG("Setting FIFO watermarks - A: %d, B: %d, C: %d, SR %d\n", @@ -1935,8 +1937,6 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock, I915_WRITE(FW_BLC, fwater_lo); I915_WRITE(FW_BLC2, fwater_hi); - if (IS_I9XX(dev)) - I915_WRITE(FW_BLC_SELF, (srwm & 0x3f)); } static void i830_update_wm(struct drm_device *dev, int planea_clock, -- cgit v0.10.2 From eb9069119d1c4bc856b4c1339abcad0105691e71 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Wed, 15 Jul 2009 19:47:24 +0800 Subject: [ARM] pxa: fix gpio issue in zylonite WARNING: at drivers/gpio/gpiolib.c:83 gpio_ensure_requested+0x58/0xbc() autorequest GPIO-71 Modules linked in: [] (unwind_backtrace+0x0/0xe8) from [] (warn_slowpath_common+0x48/0x78) [] (warn_slowpath_common+0x48/0x78) from [] (warn_slowpath_fmt+0x28/0x38) [] (warn_slowpath_fmt+0x28/0x38) from [] (gpio_ensure_requested+0x58/0xbc) [] (gpio_ensure_requested+0x58/0xbc) from [] (gpio_direction_input+0x80/0xf4) [] (gpio_direction_input+0x80/0xf4) from [] (zylonite_pxa300_init+0x108/0x214) [] (zylonite_pxa300_init+0x108/0x214) from [] (zylonite_init+0x8/0x84) [] (zylonite_init+0x8/0x84) from [] (customize_machine+0x18/0x24) [] (customize_machine+0x18/0x24) from [] (do_one_initcall+0x30/0x1b0) [] (do_one_initcall+0x30/0x1b0) from [] (kernel_init+0xa4/0x11c) [] (kernel_init+0xa4/0x11c) from [] (kernel_thread_exit+0x0/0x8) ---[ end trace 1b75b31a2719ed1c ]--- This issue is caused by using gpio pin without request. Add gpio_request() into zylonite. To simplify the code, error checking is omitted since this is being performed early. Signed-off-by: Haojian Zhuang Signed-off-by: Eric Miao diff --git a/arch/arm/mach-pxa/zylonite_pxa300.c b/arch/arm/mach-pxa/zylonite_pxa300.c index cefd1c0..8409544 100644 --- a/arch/arm/mach-pxa/zylonite_pxa300.c +++ b/arch/arm/mach-pxa/zylonite_pxa300.c @@ -197,10 +197,12 @@ static void __init zylonite_detect_lcd_panel(void) for (i = 0; i < NUM_LCD_DETECT_PINS; i++) { id = id << 1; gpio = mfp_to_gpio(lcd_detect_pins[i]); + gpio_request(gpio, "LCD_ID_PINS"); gpio_direction_input(gpio); if (gpio_get_value(gpio)) id = id | 0x1; + gpio_free(gpio); } /* lcd id, flush out bit 1 */ diff --git a/arch/arm/mach-pxa/zylonite_pxa320.c b/arch/arm/mach-pxa/zylonite_pxa320.c index cc5a228..60d08f2 100644 --- a/arch/arm/mach-pxa/zylonite_pxa320.c +++ b/arch/arm/mach-pxa/zylonite_pxa320.c @@ -176,10 +176,12 @@ static void __init zylonite_detect_lcd_panel(void) for (i = 0; i < NUM_LCD_DETECT_PINS; i++) { id = id << 1; gpio = mfp_to_gpio(lcd_detect_pins[i]); + gpio_request(gpio, "LCD_ID_PINS"); gpio_direction_input(gpio); if (gpio_get_value(gpio)) id = id | 0x1; + gpio_free(gpio); } /* lcd id, flush out bit 1 */ -- cgit v0.10.2 From ecf763c5677faee04d47333e6ed8e9539a427770 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 16 Jul 2009 19:37:29 +0200 Subject: [ARM] pxa: add STUART MFP config for PalmTX,T5,LD Signed-off-by: Marek Vasut Signed-off-by: Eric Miao diff --git a/arch/arm/mach-pxa/palmld.c b/arch/arm/mach-pxa/palmld.c index ed70f28..169fcc1 100644 --- a/arch/arm/mach-pxa/palmld.c +++ b/arch/arm/mach-pxa/palmld.c @@ -128,6 +128,10 @@ static unsigned long palmld_pin_config[] __initdata = { GPIO38_GPIO, /* wifi ready */ GPIO81_GPIO, /* wifi reset */ + /* FFUART */ + GPIO34_FFUART_RXD, + GPIO39_FFUART_TXD, + /* HDD */ GPIO98_GPIO, /* HDD reset */ GPIO115_GPIO, /* HDD power */ diff --git a/arch/arm/mach-pxa/palmt5.c b/arch/arm/mach-pxa/palmt5.c index aae64a1..33f726f 100644 --- a/arch/arm/mach-pxa/palmt5.c +++ b/arch/arm/mach-pxa/palmt5.c @@ -111,6 +111,10 @@ static unsigned long palmt5_pin_config[] __initdata = { /* PWM */ GPIO16_PWM0_OUT, + /* FFUART */ + GPIO34_FFUART_RXD, + GPIO39_FFUART_TXD, + /* MISC */ GPIO10_GPIO, /* hotsync button */ GPIO90_GPIO, /* power detect */ diff --git a/arch/arm/mach-pxa/palmtx.c b/arch/arm/mach-pxa/palmtx.c index 6c15d84..83d0208 100644 --- a/arch/arm/mach-pxa/palmtx.c +++ b/arch/arm/mach-pxa/palmtx.c @@ -127,6 +127,10 @@ static unsigned long palmtx_pin_config[] __initdata = { GPIO76_LCD_PCLK, GPIO77_LCD_BIAS, + /* FFUART */ + GPIO34_FFUART_RXD, + GPIO39_FFUART_TXD, + /* MISC. */ GPIO10_GPIO, /* hotsync button */ GPIO12_GPIO, /* power detect */ -- cgit v0.10.2 From 2ded9e2747d0a390d281bb5b16ff7f640ec85f78 Mon Sep 17 00:00:00 2001 From: "ling.ma@intel.com" Date: Thu, 16 Jul 2009 17:23:09 +0800 Subject: drm/i915: hdmi detection according by reading edid According to investigations from windows team ,hw team, and our test results on all 4x platofrms available (gm45, g45b, q45, g45a, g45c, g41a, and g41), we find currently Hot plug live status and Hot plug interrupt detection are not reliable, sometime the results from the two approaches are contradicts. So we chose edid detection for hdmi output. Signed-off-by: Ma Ling Reviewed-by: Ian Romanick Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 9e30daa..1842290 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -130,16 +130,17 @@ static bool intel_hdmi_mode_fixup(struct drm_encoder *encoder, } static enum drm_connector_status -intel_hdmi_edid_detect(struct drm_connector *connector) +intel_hdmi_detect(struct drm_connector *connector) { struct intel_output *intel_output = to_intel_output(connector); struct intel_hdmi_priv *hdmi_priv = intel_output->dev_priv; struct edid *edid = NULL; enum drm_connector_status status = connector_status_disconnected; + hdmi_priv->has_hdmi_sink = false; edid = drm_get_edid(&intel_output->base, intel_output->ddc_bus); - hdmi_priv->has_hdmi_sink = false; + if (edid) { if (edid->input & DRM_EDID_INPUT_DIGITAL) { status = connector_status_connected; @@ -148,65 +149,8 @@ intel_hdmi_edid_detect(struct drm_connector *connector) intel_output->base.display_info.raw_edid = NULL; kfree(edid); } - return status; -} - -static enum drm_connector_status -igdng_hdmi_detect(struct drm_connector *connector) -{ - struct intel_output *intel_output = to_intel_output(connector); - struct intel_hdmi_priv *hdmi_priv = intel_output->dev_priv; - - /* FIXME hotplug detect */ - - hdmi_priv->has_hdmi_sink = false; - return intel_hdmi_edid_detect(connector); -} -static enum drm_connector_status -intel_hdmi_detect(struct drm_connector *connector) -{ - struct drm_device *dev = connector->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_output *intel_output = to_intel_output(connector); - struct intel_hdmi_priv *hdmi_priv = intel_output->dev_priv; - u32 temp, bit; - - if (IS_IGDNG(dev)) - return igdng_hdmi_detect(connector); - - temp = I915_READ(PORT_HOTPLUG_EN); - - switch (hdmi_priv->sdvox_reg) { - case SDVOB: - temp |= HDMIB_HOTPLUG_INT_EN; - break; - case SDVOC: - temp |= HDMIC_HOTPLUG_INT_EN; - break; - default: - return connector_status_unknown; - } - - I915_WRITE(PORT_HOTPLUG_EN, temp); - - POSTING_READ(PORT_HOTPLUG_EN); - - switch (hdmi_priv->sdvox_reg) { - case SDVOB: - bit = HDMIB_HOTPLUG_INT_STATUS; - break; - case SDVOC: - bit = HDMIC_HOTPLUG_INT_STATUS; - break; - default: - return connector_status_unknown; - } - - if ((I915_READ(PORT_HOTPLUG_STAT) & bit) != 0) - return intel_hdmi_edid_detect(connector); - else - return connector_status_disconnected; + return status; } static int intel_hdmi_get_modes(struct drm_connector *connector) -- cgit v0.10.2 From 1d3e216f1d303878d7204de94dee251bc2702175 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 21 Jul 2009 17:09:52 +0300 Subject: [ARM] pxa/em-x270: fix compile failure when CONFIG_APM_EMULATION=n If CONFIG_APM_EMULATION=n em-x270 build fails with linker error: arch/arm/mach-pxa/built-in.o: In function `em_x270_battery_critical': em-x270.c:(.text+0x12c0): undefined reference to `apm_queue_event' arch/arm/mach-pxa/built-in.o: In function `em_x270_battery_low': em-x270.c:(.text+0x12c8): undefined reference to `apm_queue_event' make: *** [.tmp_vmlinux1] Error 1 Fix it. Signed-off-by: Mike Rapoport Signed-off-by: Eric Miao diff --git a/arch/arm/mach-pxa/em-x270.c b/arch/arm/mach-pxa/em-x270.c index 63b10d9..9cd0946 100644 --- a/arch/arm/mach-pxa/em-x270.c +++ b/arch/arm/mach-pxa/em-x270.c @@ -1141,12 +1141,16 @@ struct power_supply_info em_x270_psy_info = { static void em_x270_battery_low(void) { +#if defined(CONFIG_APM_EMULATION) apm_queue_event(APM_LOW_BATTERY); +#endif } static void em_x270_battery_critical(void) { +#if defined(CONFIG_APM_EMULATION) apm_queue_event(APM_CRITICAL_SUSPEND); +#endif } struct da9030_battery_info em_x270_batterty_info = { -- cgit v0.10.2 From 3174c88af4b6b2e81cacfaa2bb90cc7abe36f1cc Mon Sep 17 00:00:00 2001 From: Hartley Sweeten Date: Mon, 20 Jul 2009 18:12:23 +0100 Subject: [ARM] 5611/1: ep93xx: update ts72xx nor flash support Update the NOR flash support for TS-7200. The TS-7200 models all have 16-bit NOR flash. Update the platform init to support this. Remove the private TS72XX_NOR_* defines and use the common ep93xx defines for the external chip select physical base address instead. Move the NOR flash registration into a static __init function. When the NAND flash support is updated this function will also be used to register the NAND flash for the TS-7250 and TS-7260. Tested-by: Matthieu Crapet Signed-off-by: H Hartley Sweeten Signed-off-by: Russell King diff --git a/arch/arm/mach-ep93xx/include/mach/ts72xx.h b/arch/arm/mach-ep93xx/include/mach/ts72xx.h index 34ddec0..4117344 100644 --- a/arch/arm/mach-ep93xx/include/mach/ts72xx.h +++ b/arch/arm/mach-ep93xx/include/mach/ts72xx.h @@ -41,9 +41,6 @@ #define TS72XX_OPTIONS2_TS9420_BOOT 0x02 -#define TS72XX_NOR_PHYS_BASE 0x60000000 -#define TS72XX_NOR2_PHYS_BASE 0x62000000 - #define TS72XX_NAND1_DATA_PHYS_BASE 0x60000000 #define TS72XX_NAND2_DATA_PHYS_BASE 0x70000000 #define TS72XX_NAND_DATA_VIRT_BASE 0xfebfc000 diff --git a/arch/arm/mach-ep93xx/ts72xx.c b/arch/arm/mach-ep93xx/ts72xx.c index 7ee024d..aaf1371 100644 --- a/arch/arm/mach-ep93xx/ts72xx.c +++ b/arch/arm/mach-ep93xx/ts72xx.c @@ -112,13 +112,16 @@ static void __init ts72xx_map_io(void) } } +/************************************************************************* + * NOR flash (TS-7200 only) + *************************************************************************/ static struct physmap_flash_data ts72xx_flash_data = { - .width = 1, + .width = 2, }; static struct resource ts72xx_flash_resource = { - .start = TS72XX_NOR_PHYS_BASE, - .end = TS72XX_NOR_PHYS_BASE + SZ_16M - 1, + .start = EP93XX_CS6_PHYS_BASE, + .end = EP93XX_CS6_PHYS_BASE + SZ_16M - 1, .flags = IORESOURCE_MEM, }; @@ -132,6 +135,12 @@ static struct platform_device ts72xx_flash = { .resource = &ts72xx_flash_resource, }; +static void __init ts72xx_register_flash(void) +{ + if (board_is_ts7200()) + platform_device_register(&ts72xx_flash); +} + static unsigned char ts72xx_rtc_readbyte(unsigned long addr) { __raw_writeb(addr, TS72XX_RTC_INDEX_VIRT_BASE); @@ -165,8 +174,7 @@ static struct ep93xx_eth_data ts72xx_eth_data = { static void __init ts72xx_init_machine(void) { ep93xx_init_devices(); - if (board_is_ts7200()) - platform_device_register(&ts72xx_flash); + ts72xx_register_flash(); platform_device_register(&ts72xx_rtc_device); ep93xx_register_eth(&ts72xx_eth_data, 1); -- cgit v0.10.2 From 7194e6f9c083e87171ddfc8b746f05e007f58132 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 24 Jul 2009 17:05:00 +0300 Subject: UBI: fix double free on error path If we fail in 'ubi_eba_init_scan()', we free 'ubi->volumes[i]->eba_tbl' in there, but also later free it in 'free_internal_volumes()'. Fix this by assigning NULL to 'ubi->volumes[i]->eba_tbl' after it is freed. Signed-off-by: Adrian Hunter Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index 0f2034c..e4d9ef0 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -1254,6 +1254,7 @@ out_free: if (!ubi->volumes[i]) continue; kfree(ubi->volumes[i]->eba_tbl); + ubi->volumes[i]->eba_tbl = NULL; } return err; } -- cgit v0.10.2 From 32bc4820287a1a03982979515949e8ea56eac641 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 24 Jul 2009 19:16:04 +0300 Subject: UBI: compatible fallback in absense of sequence numbers Fall back onto thinking everything's OK if either of the sequence numbers we are asked to compare is zero, which is what was used before sequence numbers were introduced. [ Artem: modified the patch to be applicable to upstream UBI, added big comment ] Signed-off-by: Adrian Hunter Signed-off-by: Phil Carmody Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c index a423131..b847745 100644 --- a/drivers/mtd/ubi/scan.c +++ b/drivers/mtd/ubi/scan.c @@ -781,11 +781,22 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, return -EINVAL; } + /* + * Make sure that all PEBs have the same image sequence number. + * This allows us to detect situations when users flash UBI + * images incorrectly, so that the flash has the new UBI image + * and leftovers from the old one. This feature was added + * relatively recently, and the sequence number was always + * zero, because old UBI implementations always set it to zero. + * For this reasons, we do not panic if some PEBs have zero + * sequence number, while other PEBs have non-zero sequence + * number. + */ image_seq = be32_to_cpu(ech->image_seq); if (!si->image_seq_set) { ubi->image_seq = image_seq; si->image_seq_set = 1; - } else if (ubi->image_seq != image_seq) { + } else if (ubi->image_seq && ubi->image_seq != image_seq) { ubi_err("bad image sequence number %d in PEB %d, " "expected %d", image_seq, pnum, ubi->image_seq); ubi_dbg_dump_ec_hdr(ech); -- cgit v0.10.2 From 81566a060bb8f989cc369ea28837b05bd4adcedb Mon Sep 17 00:00:00 2001 From: Jaswinder Singh Rajput Date: Wed, 8 Jul 2009 20:00:15 +0530 Subject: ARM: includecheck fix: misc.c fix the following 'make includecheck' warning: arch/arm/boot/compressed/misc.c: linux/compiler.h is included more than once. Signed-off-by: Jaswinder Singh Rajput Signed-off-by: Russell King diff --git a/arch/arm/boot/compressed/misc.c b/arch/arm/boot/compressed/misc.c index 9e6e512..17153b5 100644 --- a/arch/arm/boot/compressed/misc.c +++ b/arch/arm/boot/compressed/misc.c @@ -29,7 +29,6 @@ unsigned int __machine_arch_type; static void putstr(const char *ptr); -#include #include #ifdef CONFIG_DEBUG_ICEDCC -- cgit v0.10.2 From feecaf73bb437cf72a44bd71598c6532d357f78e Mon Sep 17 00:00:00 2001 From: Jaswinder Singh Rajput Date: Wed, 8 Jul 2009 20:01:39 +0530 Subject: ARM: includecheck fix: atomic.h fix the following 'make includecheck' warning: arch/arm/include/asm/atomic.h: asm/system.h is included more than once. Signed-off-by: Jaswinder Singh Rajput Signed-off-by: Russell King diff --git a/arch/arm/include/asm/atomic.h b/arch/arm/include/asm/atomic.h index 9e07fe5..9ed2377 100644 --- a/arch/arm/include/asm/atomic.h +++ b/arch/arm/include/asm/atomic.h @@ -159,8 +159,6 @@ static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr) #else /* ARM_ARCH_6 */ -#include - #ifdef CONFIG_SMP #error SMP not supported on pre-ARMv6 CPUs #endif -- cgit v0.10.2 From 44e96d452173ed22a7ba2291c7d566bf4b406f62 Mon Sep 17 00:00:00 2001 From: Jaswinder Singh Rajput Date: Wed, 8 Jul 2009 20:03:08 +0530 Subject: ARM: includecheck fix: board-dm355-evm.c fix the following 'make includecheck' warning: arch/arm/mach-davinci/board-dm355-evm.c: mach/common.h is included more than once. Signed-off-by: Jaswinder Singh Rajput Acked-by: Kevin Hilman Signed-off-by: Russell King diff --git a/arch/arm/mach-davinci/board-dm355-evm.c b/arch/arm/mach-davinci/board-dm355-evm.c index 5ac2f56..d6ab64c 100644 --- a/arch/arm/mach-davinci/board-dm355-evm.c +++ b/arch/arm/mach-davinci/board-dm355-evm.c @@ -37,7 +37,6 @@ #include #include #include -#include #define DAVINCI_ASYNC_EMIF_CONTROL_BASE 0x01e10000 #define DAVINCI_ASYNC_EMIF_DATA_CE0_BASE 0x02000000 -- cgit v0.10.2 From 7f25b0ac2dde2de399d6cfe42d9ec7066e665f2f Mon Sep 17 00:00:00 2001 From: Jaswinder Singh Rajput Date: Wed, 8 Jul 2009 20:04:33 +0530 Subject: ARM: includecheck fix: board-dm355-leopard.c fix the following 'make includecheck' warning: arch/arm/mach-davinci/board-dm355-leopard.c: mach/common.h is included more than once. Signed-off-by: Jaswinder Singh Rajput Acked-by: Kevin Hilman Signed-off-by: Russell King diff --git a/arch/arm/mach-davinci/board-dm355-leopard.c b/arch/arm/mach-davinci/board-dm355-leopard.c index 28c9008..84ad5d1 100644 --- a/arch/arm/mach-davinci/board-dm355-leopard.c +++ b/arch/arm/mach-davinci/board-dm355-leopard.c @@ -36,7 +36,6 @@ #include #include #include -#include #define DAVINCI_ASYNC_EMIF_CONTROL_BASE 0x01e10000 #define DAVINCI_ASYNC_EMIF_DATA_CE0_BASE 0x02000000 -- cgit v0.10.2 From 6608168486973a33d24d27b25fc94d4743c1a1e5 Mon Sep 17 00:00:00 2001 From: Jaswinder Singh Rajput Date: Wed, 8 Jul 2009 20:05:34 +0530 Subject: ARM: includecheck fix: board-dm644x-evm.c fix the following 'make includecheck' warning: arch/arm/mach-davinci/board-dm644x-evm.c: mach/common.h is included more than once. Signed-off-by: Jaswinder Singh Rajput Acked-by: Kevin Hilman Signed-off-by: Russell King diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c index d9d4045..56c8cd0 100644 --- a/arch/arm/mach-davinci/board-dm644x-evm.c +++ b/arch/arm/mach-davinci/board-dm644x-evm.c @@ -45,7 +45,6 @@ #include #include #include -#include #define DM644X_EVM_PHY_MASK (0x2) #define DM644X_EVM_MDIO_FREQUENCY (2200000) /* PHY bus frequency */ -- cgit v0.10.2 From 78eacf0b0373f524509da261b771f8baa28806b5 Mon Sep 17 00:00:00 2001 From: Jaswinder Singh Rajput Date: Wed, 8 Jul 2009 20:06:42 +0530 Subject: ARM: includecheck fix: board-dm646x-evm.c fix the following 'make includecheck' warning: arch/arm/mach-davinci/board-dm646x-evm.c: mach/common.h is included more than once. Signed-off-by: Jaswinder Singh Rajput Acked-by: Kevin Hilman Signed-off-by: Russell King diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c index e17de63..8657e72 100644 --- a/arch/arm/mach-davinci/board-dm646x-evm.c +++ b/arch/arm/mach-davinci/board-dm646x-evm.c @@ -47,7 +47,6 @@ #include #include #include -#include #define DM646X_EVM_PHY_MASK (0x2) #define DM646X_EVM_MDIO_FREQUENCY (2200000) /* PHY bus frequency */ -- cgit v0.10.2 From 7a33aed825c4d2bafea748384e3331661fc3a180 Mon Sep 17 00:00:00 2001 From: Jaswinder Singh Rajput Date: Wed, 8 Jul 2009 20:07:26 +0530 Subject: ARM: includecheck fix: board-sffsdr.c fix the following 'make includecheck' warning: arch/arm/mach-davinci/board-sffsdr.c: mach/common.h is included more than once. Signed-off-by: Jaswinder Singh Rajput Acked-by: Kevin Hilman Acked-by: Philip Balister Signed-off-by: Russell King diff --git a/arch/arm/mach-davinci/board-sffsdr.c b/arch/arm/mach-davinci/board-sffsdr.c index 748a8e4..7acdfd8a 100644 --- a/arch/arm/mach-davinci/board-sffsdr.c +++ b/arch/arm/mach-davinci/board-sffsdr.c @@ -52,7 +52,6 @@ #include #include #include -#include #define SFFSDR_PHY_MASK (0x2) #define SFFSDR_MDIO_FREQUENCY (2200000) /* PHY bus frequency */ -- cgit v0.10.2 From 52cbbd41f7afeceba4be2e4062138781aacd440c Mon Sep 17 00:00:00 2001 From: Jaswinder Singh Rajput Date: Wed, 8 Jul 2009 20:10:02 +0530 Subject: ARM: includecheck fix: mach-omap1/mcbsp.c fix the following 'make includecheck' warning: arch/arm/mach-omap1/mcbsp.c: mach/irqs.h is included more than once. Signed-off-by: Jaswinder Singh Rajput Acked-by: Eduardo Valentin Acked-by: Kevin Hilman Signed-off-by: Russell King diff --git a/arch/arm/mach-omap1/mcbsp.c b/arch/arm/mach-omap1/mcbsp.c index a2d7814..505d98c 100644 --- a/arch/arm/mach-omap1/mcbsp.c +++ b/arch/arm/mach-omap1/mcbsp.c @@ -19,7 +19,6 @@ #include #include -#include #include #include #include -- cgit v0.10.2 From efda2b4c8a643290867d9f5816e36f71a5acee7d Mon Sep 17 00:00:00 2001 From: Jaswinder Singh Rajput Date: Wed, 8 Jul 2009 20:11:05 +0530 Subject: ARM: includecheck fix: mach-omap2/mcbsp.c fix the following 'make includecheck' warning: arch/arm/mach-omap2/mcbsp.c: mach/irqs.h is included more than once. Signed-off-by: Jaswinder Singh Rajput Acked-by: Eduardo Valentin Acked-by: Kevin Hilman Signed-off-by: Russell King diff --git a/arch/arm/mach-omap2/mcbsp.c b/arch/arm/mach-omap2/mcbsp.c index a5c0f04..99b6e15 100644 --- a/arch/arm/mach-omap2/mcbsp.c +++ b/arch/arm/mach-omap2/mcbsp.c @@ -19,7 +19,6 @@ #include #include -#include #include #include #include -- cgit v0.10.2 From 2e6e2c143cdefc2624722659766d1f3c098d79e1 Mon Sep 17 00:00:00 2001 From: Jaswinder Singh Rajput Date: Wed, 8 Jul 2009 20:12:07 +0530 Subject: ARM: includecheck fix: plat-s3c64xx/pm.c fix the following 'make includecheck' warning: arch/arm/plat-s3c64xx/pm.c: plat/regs-gpio.h is included more than once. Signed-off-by: Jaswinder Singh Rajput Acked-by: Ben Dooks Signed-off-by: Russell King diff --git a/arch/arm/plat-s3c64xx/pm.c b/arch/arm/plat-s3c64xx/pm.c index 07a6516..47632fc 100644 --- a/arch/arm/plat-s3c64xx/pm.c +++ b/arch/arm/plat-s3c64xx/pm.c @@ -117,8 +117,6 @@ void s3c_pm_save_core(void) * this. */ -#include - static void s3c64xx_cpu_suspend(void) { unsigned long tmp; -- cgit v0.10.2 From 40e03b581a8a0b638bc1e9b957ae0536a4a00ad3 Mon Sep 17 00:00:00 2001 From: Jaswinder Singh Rajput Date: Wed, 8 Jul 2009 20:13:24 +0530 Subject: ARM: includecheck fix: plat-stmp3xxx/pinmux.c fix the following 'make includecheck' warning: arch/arm/plat-stmp3xxx/pinmux.c: linux/sysdev.h is included more than once. Signed-off-by: Jaswinder Singh Rajput Acked-by: dmitry pervushin Signed-off-by: Russell King diff --git a/arch/arm/plat-stmp3xxx/pinmux.c b/arch/arm/plat-stmp3xxx/pinmux.c index d412003..6d6b1a4 100644 --- a/arch/arm/plat-stmp3xxx/pinmux.c +++ b/arch/arm/plat-stmp3xxx/pinmux.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include -- cgit v0.10.2 From c640e1cb45cb9ff6b02f5f130a4f2a58ab9ebe55 Mon Sep 17 00:00:00 2001 From: Tomas Cech Date: Mon, 27 Jul 2009 14:16:31 +0100 Subject: ARM: 5623/1: Treo680: ir shutdown typo fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit correct GPIO freed in treo680_irda_shutdown() Signed-off-by: Tomáš ?ech Signed-off-by: Russell King diff --git a/arch/arm/mach-pxa/treo680.c b/arch/arm/mach-pxa/treo680.c index a06f19e..753ec4d 100644 --- a/arch/arm/mach-pxa/treo680.c +++ b/arch/arm/mach-pxa/treo680.c @@ -409,7 +409,7 @@ err1: static void treo680_irda_shutdown(struct device *dev) { - gpio_free(GPIO_NR_TREO680_AMP_EN); + gpio_free(GPIO_NR_TREO680_IR_EN); } static struct pxaficp_platform_data treo680_ficp_info = { -- cgit v0.10.2 From 8666f8deec75a8dce15edd35ec33d29ef79cdb08 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 24 Jul 2009 17:30:50 +0200 Subject: mx27 defconfig update - enable MX27_3DS and MX27LITE Board - enable MXC nand driver - enable UBI support Signed-off-by: Sascha Hauer diff --git a/arch/arm/configs/mx27_defconfig b/arch/arm/configs/mx27_defconfig index 083516c..75263a8 100644 --- a/arch/arm/configs/mx27_defconfig +++ b/arch/arm/configs/mx27_defconfig @@ -1,15 +1,15 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.30-rc1 -# Wed Apr 8 10:18:06 2009 +# Linux kernel version: 2.6.31-rc4 +# Fri Jul 24 16:08:06 2009 # CONFIG_ARM=y +CONFIG_HAVE_PWM=y CONFIG_SYS_SUPPORTS_APM_EMULATION=y CONFIG_GENERIC_GPIO=y CONFIG_GENERIC_TIME=y CONFIG_GENERIC_CLOCKEVENTS=y CONFIG_MMU=y -# CONFIG_NO_IOPORT is not set CONFIG_GENERIC_HARDIRQS=y CONFIG_STACKTRACE_SUPPORT=y CONFIG_HAVE_LATENCYTOP_SUPPORT=y @@ -18,14 +18,13 @@ CONFIG_TRACE_IRQFLAGS_SUPPORT=y CONFIG_HARDIRQS_SW_RESEND=y CONFIG_GENERIC_IRQ_PROBE=y CONFIG_RWSEM_GENERIC_SPINLOCK=y -# CONFIG_ARCH_HAS_ILOG2_U32 is not set -# CONFIG_ARCH_HAS_ILOG2_U64 is not set CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_ARCH_MTD_XIP=y CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y CONFIG_VECTORS_BASE=0xffff0000 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_CONSTRUCTORS=y # # General setup @@ -85,7 +84,12 @@ CONFIG_TIMERFD=y CONFIG_EVENTFD=y CONFIG_SHMEM=y CONFIG_AIO=y + +# +# Performance Counters +# CONFIG_VM_EVENT_COUNTERS=y +# CONFIG_STRIP_ASM_SYMS is not set # CONFIG_COMPAT_BRK is not set CONFIG_SLAB=y # CONFIG_SLUB is not set @@ -99,6 +103,12 @@ CONFIG_KPROBES=y CONFIG_KRETPROBES=y CONFIG_HAVE_KPROBES=y CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_CLK=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set # CONFIG_SLOW_WORK is not set CONFIG_HAVE_GENERIC_DMA_COHERENT=y CONFIG_SLABINFO=y @@ -111,7 +121,7 @@ CONFIG_MODULE_UNLOAD=y # CONFIG_MODVERSIONS is not set # CONFIG_MODULE_SRCVERSION_ALL is not set CONFIG_BLOCK=y -# CONFIG_LBD is not set +CONFIG_LBDAF=y # CONFIG_BLK_DEV_BSG is not set # CONFIG_BLK_DEV_INTEGRITY is not set @@ -138,13 +148,14 @@ CONFIG_FREEZER=y # CONFIG_ARCH_VERSATILE is not set # CONFIG_ARCH_AT91 is not set # CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_GEMINI is not set # CONFIG_ARCH_EBSA110 is not set # CONFIG_ARCH_EP93XX is not set -# CONFIG_ARCH_GEMINI is not set # CONFIG_ARCH_FOOTBRIDGE is not set +CONFIG_ARCH_MXC=y +# CONFIG_ARCH_STMP3XXX is not set # CONFIG_ARCH_NETX is not set # CONFIG_ARCH_H720X is not set -# CONFIG_ARCH_IMX is not set # CONFIG_ARCH_IOP13XX is not set # CONFIG_ARCH_IOP32X is not set # CONFIG_ARCH_IOP33X is not set @@ -153,25 +164,25 @@ CONFIG_FREEZER=y # CONFIG_ARCH_IXP4XX is not set # CONFIG_ARCH_L7200 is not set # CONFIG_ARCH_KIRKWOOD is not set -# CONFIG_ARCH_KS8695 is not set -# CONFIG_ARCH_NS9XXX is not set # CONFIG_ARCH_LOKI is not set # CONFIG_ARCH_MV78XX0 is not set -CONFIG_ARCH_MXC=y # CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_NS9XXX is not set +# CONFIG_ARCH_W90X900 is not set # CONFIG_ARCH_PNX4008 is not set # CONFIG_ARCH_PXA is not set -# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_MSM is not set # CONFIG_ARCH_RPC is not set # CONFIG_ARCH_SA1100 is not set # CONFIG_ARCH_S3C2410 is not set # CONFIG_ARCH_S3C64XX is not set # CONFIG_ARCH_SHARK is not set # CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_U300 is not set # CONFIG_ARCH_DAVINCI is not set # CONFIG_ARCH_OMAP is not set -# CONFIG_ARCH_MSM is not set -# CONFIG_ARCH_W90X900 is not set # # Freescale MXC Implementations @@ -188,6 +199,8 @@ CONFIG_MACH_MX27=y CONFIG_MACH_MX27ADS=y CONFIG_MACH_PCM038=y CONFIG_MACH_PCM970_BASEBOARD=y +CONFIG_MACH_MX27_3DS=y +CONFIG_MACH_MX27LITE=y CONFIG_MXC_IRQ_PRIOR=y CONFIG_MXC_PWM=y @@ -213,7 +226,6 @@ CONFIG_ARM_THUMB=y # CONFIG_CPU_DCACHE_DISABLE is not set # CONFIG_CPU_DCACHE_WRITETHROUGH is not set # CONFIG_CPU_CACHE_ROUND_ROBIN is not set -# CONFIG_OUTER_CACHE is not set CONFIG_COMMON_CLKDEV=y # @@ -238,7 +250,6 @@ CONFIG_PREEMPT=y CONFIG_HZ=100 CONFIG_AEABI=y CONFIG_OABI_COMPAT=y -CONFIG_ARCH_FLATMEM_HAS_HOLES=y # CONFIG_ARCH_SPARSEMEM_DEFAULT is not set # CONFIG_ARCH_SELECT_MEMORY_MODEL is not set # CONFIG_HIGHMEM is not set @@ -253,10 +264,11 @@ CONFIG_SPLIT_PTLOCK_CPUS=4096 # CONFIG_PHYS_ADDR_T_64BIT is not set CONFIG_ZONE_DMA_FLAG=0 CONFIG_VIRT_TO_BUS=y -CONFIG_UNEVICTABLE_LRU=y CONFIG_HAVE_MLOCK=y CONFIG_HAVE_MLOCKED_PAGE_BIT=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 CONFIG_ALIGNMENT_TRAP=y +# CONFIG_UACCESS_WITH_MEMCPY is not set # # Boot options @@ -361,6 +373,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic" # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set # CONFIG_PHONET is not set +# CONFIG_IEEE802154 is not set # CONFIG_NET_SCHED is not set # CONFIG_DCB is not set @@ -474,7 +487,16 @@ CONFIG_MTD_PHYSMAP=y # CONFIG_MTD_DOC2000 is not set # CONFIG_MTD_DOC2001 is not set # CONFIG_MTD_DOC2001PLUS is not set -# CONFIG_MTD_NAND is not set +CONFIG_MTD_NAND=y +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +# CONFIG_MTD_NAND_ECC_SMC is not set +# CONFIG_MTD_NAND_MUSEUM_IDS is not set +# CONFIG_MTD_NAND_GPIO is not set +CONFIG_MTD_NAND_IDS=y +# CONFIG_MTD_NAND_DISKONCHIP is not set +# CONFIG_MTD_NAND_NANDSIM is not set +# CONFIG_MTD_NAND_PLATFORM is not set +CONFIG_MTD_NAND_MXC=y # CONFIG_MTD_ONENAND is not set # @@ -485,7 +507,15 @@ CONFIG_MTD_PHYSMAP=y # # UBI - Unsorted block images # -# CONFIG_MTD_UBI is not set +CONFIG_MTD_UBI=y +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_MTD_UBI_BEB_RESERVE=1 +# CONFIG_MTD_UBI_GLUEBI is not set + +# +# UBI debugging options +# +# CONFIG_MTD_UBI_DEBUG is not set # CONFIG_PARPORT is not set CONFIG_BLK_DEV=y # CONFIG_BLK_DEV_COW_COMMON is not set @@ -494,7 +524,21 @@ CONFIG_BLK_DEV=y # CONFIG_BLK_DEV_RAM is not set # CONFIG_CDROM_PKTCDVD is not set # CONFIG_ATA_OVER_ETH is not set -# CONFIG_MISC_DEVICES is not set +# CONFIG_MG_DISK is not set +CONFIG_MISC_DEVICES=y +# CONFIG_ICS932S401 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_ISL29003 is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +CONFIG_EEPROM_AT24=y +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +# CONFIG_EEPROM_93CX6 is not set CONFIG_HAVE_IDE=y # CONFIG_IDE is not set @@ -508,7 +552,6 @@ CONFIG_HAVE_IDE=y # CONFIG_ATA is not set # CONFIG_MD is not set CONFIG_NETDEVICES=y -CONFIG_COMPAT_NET_DEV_OPS=y # CONFIG_DUMMY is not set # CONFIG_BONDING is not set # CONFIG_MACVLAN is not set @@ -534,6 +577,8 @@ CONFIG_NET_ETHERNET=y # CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set # CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set # CONFIG_B44 is not set +# CONFIG_KS8842 is not set +# CONFIG_KS8851 is not set CONFIG_FEC=y # CONFIG_FEC2 is not set # CONFIG_NETDEV_1000 is not set @@ -580,6 +625,11 @@ CONFIG_INPUT_EVDEV=y # CONFIG_INPUT_TABLET is not set CONFIG_INPUT_TOUCHSCREEN=y # CONFIG_TOUCHSCREEN_ADS7846 is not set +# CONFIG_TOUCHSCREEN_AD7877 is not set +# CONFIG_TOUCHSCREEN_AD7879_I2C is not set +# CONFIG_TOUCHSCREEN_AD7879_SPI is not set +# CONFIG_TOUCHSCREEN_AD7879 is not set +# CONFIG_TOUCHSCREEN_EETI is not set # CONFIG_TOUCHSCREEN_FUJITSU is not set # CONFIG_TOUCHSCREEN_GUNZE is not set # CONFIG_TOUCHSCREEN_ELO is not set @@ -592,6 +642,7 @@ CONFIG_INPUT_TOUCHSCREEN=y # CONFIG_TOUCHSCREEN_TOUCHWIN is not set # CONFIG_TOUCHSCREEN_TOUCHIT213 is not set # CONFIG_TOUCHSCREEN_TSC2007 is not set +# CONFIG_TOUCHSCREEN_W90X900 is not set # CONFIG_INPUT_MISC is not set # @@ -644,6 +695,7 @@ CONFIG_I2C_HELPER_AUTO=y # # I2C system bus drivers (mostly embedded / system-on-chip) # +# CONFIG_I2C_DESIGNWARE is not set # CONFIG_I2C_GPIO is not set CONFIG_I2C_IMX=y # CONFIG_I2C_OCORES is not set @@ -668,7 +720,6 @@ CONFIG_I2C_IMX=y # CONFIG_SENSORS_PCF8574 is not set # CONFIG_PCF8575 is not set # CONFIG_SENSORS_PCA9539 is not set -# CONFIG_SENSORS_MAX6875 is not set # CONFIG_SENSORS_TSL2550 is not set # CONFIG_I2C_DEBUG_CORE is not set # CONFIG_I2C_DEBUG_ALGO is not set @@ -719,6 +770,7 @@ CONFIG_W1=y # # CONFIG_W1_MASTER_DS2482 is not set CONFIG_W1_MASTER_MXC=y +# CONFIG_W1_MASTER_DS1WM is not set # CONFIG_W1_MASTER_GPIO is not set # @@ -753,54 +805,16 @@ CONFIG_SSB_POSSIBLE=y # CONFIG_TPS65010 is not set # CONFIG_TWL4030_CORE is not set # CONFIG_MFD_TMIO is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC6387XB is not set # CONFIG_MFD_TC6393XB is not set # CONFIG_PMIC_DA903X is not set # CONFIG_MFD_WM8400 is not set # CONFIG_MFD_WM8350_I2C is not set # CONFIG_MFD_PCF50633 is not set - -# -# Multimedia devices -# - -# -# Multimedia core support -# -CONFIG_VIDEO_DEV=y -CONFIG_VIDEO_V4L2_COMMON=y -CONFIG_VIDEO_ALLOW_V4L1=y -CONFIG_VIDEO_V4L1_COMPAT=y -# CONFIG_DVB_CORE is not set -CONFIG_VIDEO_MEDIA=y - -# -# Multimedia drivers -# -# CONFIG_MEDIA_ATTACH is not set -CONFIG_MEDIA_TUNER=y -# CONFIG_MEDIA_TUNER_CUSTOMISE is not set -CONFIG_MEDIA_TUNER_SIMPLE=y -CONFIG_MEDIA_TUNER_TDA8290=y -CONFIG_MEDIA_TUNER_TDA9887=y -CONFIG_MEDIA_TUNER_TEA5761=y -CONFIG_MEDIA_TUNER_TEA5767=y -CONFIG_MEDIA_TUNER_MT20XX=y -CONFIG_MEDIA_TUNER_XC2028=y -CONFIG_MEDIA_TUNER_XC5000=y -CONFIG_MEDIA_TUNER_MC44S803=y -CONFIG_VIDEO_V4L2=y -CONFIG_VIDEO_V4L1=y -CONFIG_VIDEO_CAPTURE_DRIVERS=y -# CONFIG_VIDEO_ADV_DEBUG is not set -# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set -CONFIG_VIDEO_HELPER_CHIPS_AUTO=y -# CONFIG_VIDEO_VIVI is not set -# CONFIG_VIDEO_CPIA is not set -# CONFIG_VIDEO_SAA5246A is not set -# CONFIG_VIDEO_SAA5249 is not set -# CONFIG_SOC_CAMERA is not set -# CONFIG_RADIO_ADAPTERS is not set -# CONFIG_DAB is not set +# CONFIG_AB3100_CORE is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_MEDIA_SUPPORT is not set # # Graphics support @@ -917,6 +931,7 @@ CONFIG_RTC_DRV_PCF8563=y # CONFIG_RTC_DRV_S35390A is not set # CONFIG_RTC_DRV_FM3130 is not set # CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set # # SPI RTC drivers @@ -962,12 +977,15 @@ CONFIG_RTC_DRV_PCF8563=y # CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set # CONFIG_FS_POSIX_ACL is not set -CONFIG_FILE_LOCKING=y # CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set # CONFIG_OCFS2_FS is not set # CONFIG_BTRFS_FS is not set +CONFIG_FILE_LOCKING=y +CONFIG_FSNOTIFY=y # CONFIG_DNOTIFY is not set # CONFIG_INOTIFY is not set +CONFIG_INOTIFY_USER=y # CONFIG_QUOTA is not set # CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS is not set @@ -1021,6 +1039,12 @@ CONFIG_JFFS2_ZLIB=y # CONFIG_JFFS2_LZO is not set CONFIG_JFFS2_RTIME=y # CONFIG_JFFS2_RUBIN is not set +CONFIG_UBIFS_FS=y +# CONFIG_UBIFS_FS_XATTR is not set +# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set +CONFIG_UBIFS_FS_LZO=y +CONFIG_UBIFS_FS_ZLIB=y +# CONFIG_UBIFS_FS_DEBUG is not set # CONFIG_CRAMFS is not set # CONFIG_SQUASHFS is not set # CONFIG_VXFS_FS is not set @@ -1119,25 +1143,11 @@ CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_NOP_TRACER=y CONFIG_HAVE_FUNCTION_TRACER=y CONFIG_RING_BUFFER=y +CONFIG_EVENT_TRACING=y +CONFIG_CONTEXT_SWITCH_TRACER=y CONFIG_TRACING=y CONFIG_TRACING_SUPPORT=y - -# -# Tracers -# -# CONFIG_FUNCTION_TRACER is not set -# CONFIG_IRQSOFF_TRACER is not set -# CONFIG_PREEMPT_TRACER is not set -# CONFIG_SCHED_TRACER is not set -# CONFIG_CONTEXT_SWITCH_TRACER is not set -# CONFIG_EVENT_TRACER is not set -# CONFIG_BOOT_TRACER is not set -# CONFIG_TRACE_BRANCH_PROFILING is not set -# CONFIG_STACK_TRACER is not set -# CONFIG_KMEMTRACE is not set -# CONFIG_WORKQUEUE_TRACER is not set -# CONFIG_BLK_DEV_IO_TRACE is not set -# CONFIG_FTRACE_STARTUP_TEST is not set +# CONFIG_FTRACE is not set # CONFIG_DYNAMIC_DEBUG is not set # CONFIG_SAMPLES is not set CONFIG_HAVE_ARCH_KGDB=y @@ -1151,16 +1161,104 @@ CONFIG_ARM_UNWIND=y # CONFIG_SECURITY is not set # CONFIG_SECURITYFS is not set # CONFIG_SECURITY_FILE_CAPABILITIES is not set -# CONFIG_CRYPTO is not set +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +# CONFIG_CRYPTO_FIPS is not set +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +# CONFIG_CRYPTO_MANAGER is not set +# CONFIG_CRYPTO_MANAGER2 is not set +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_CRYPTD is not set +# CONFIG_CRYPTO_AUTHENC is not set +# CONFIG_CRYPTO_TEST is not set + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_SEQIV is not set + +# +# Block modes +# +# CONFIG_CRYPTO_CBC is not set +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +# CONFIG_CRYPTO_ECB is not set +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_XTS is not set + +# +# Hash modes +# +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_XCBC is not set + +# +# Digest +# +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_MD4 is not set +# CONFIG_CRYPTO_MD5 is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_DES is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_TWOFISH is not set + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=y +# CONFIG_CRYPTO_ZLIB is not set +CONFIG_CRYPTO_LZO=y + +# +# Random Number Generation +# +# CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_HW=y CONFIG_BINARY_PRINTF=y # # Library routines # CONFIG_BITREVERSE=y +CONFIG_RATIONAL=y CONFIG_GENERIC_FIND_LAST_BIT=y # CONFIG_CRC_CCITT is not set -# CONFIG_CRC16 is not set +CONFIG_CRC16=y # CONFIG_CRC_T10DIF is not set # CONFIG_CRC_ITU_T is not set CONFIG_CRC32=y @@ -1168,6 +1266,8 @@ CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y CONFIG_HAS_IOMEM=y CONFIG_HAS_IOPORT=y CONFIG_HAS_DMA=y -- cgit v0.10.2 From 42469ff014812880d7324285d165841f4b1814e7 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 24 Jul 2009 17:31:03 +0200 Subject: mx3 defconfig update - enable PCM043, MX31LILLY, ARMADILLO5X0 and MX35_3DS boards - enable MXC nand driver - enable UBI support - disable cs89x0 support which broke all boards which do not have this chip Signed-off-by: Sascha Hauer diff --git a/arch/arm/configs/mx3_defconfig b/arch/arm/configs/mx3_defconfig index 20ada52..a4f9a2a 100644 --- a/arch/arm/configs/mx3_defconfig +++ b/arch/arm/configs/mx3_defconfig @@ -1,15 +1,15 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.30-rc1 -# Wed Apr 8 11:06:37 2009 +# Linux kernel version: 2.6.31-rc4 +# Tue Jul 28 14:11:34 2009 # CONFIG_ARM=y +CONFIG_HAVE_PWM=y CONFIG_SYS_SUPPORTS_APM_EMULATION=y CONFIG_GENERIC_GPIO=y CONFIG_GENERIC_TIME=y CONFIG_GENERIC_CLOCKEVENTS=y CONFIG_MMU=y -# CONFIG_NO_IOPORT is not set CONFIG_GENERIC_HARDIRQS=y CONFIG_STACKTRACE_SUPPORT=y CONFIG_HAVE_LATENCYTOP_SUPPORT=y @@ -18,14 +18,13 @@ CONFIG_TRACE_IRQFLAGS_SUPPORT=y CONFIG_HARDIRQS_SW_RESEND=y CONFIG_GENERIC_IRQ_PROBE=y CONFIG_RWSEM_GENERIC_SPINLOCK=y -# CONFIG_ARCH_HAS_ILOG2_U32 is not set -# CONFIG_ARCH_HAS_ILOG2_U64 is not set CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_ARCH_MTD_XIP=y CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y CONFIG_VECTORS_BASE=0xffff0000 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_CONSTRUCTORS=y # # General setup @@ -86,7 +85,12 @@ CONFIG_TIMERFD=y CONFIG_EVENTFD=y CONFIG_SHMEM=y CONFIG_AIO=y + +# +# Performance Counters +# CONFIG_VM_EVENT_COUNTERS=y +# CONFIG_STRIP_ASM_SYMS is not set CONFIG_COMPAT_BRK=y CONFIG_SLAB=y # CONFIG_SLUB is not set @@ -97,6 +101,11 @@ CONFIG_HAVE_OPROFILE=y # CONFIG_KPROBES is not set CONFIG_HAVE_KPROBES=y CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_CLK=y + +# +# GCOV-based kernel profiling +# # CONFIG_SLOW_WORK is not set CONFIG_HAVE_GENERIC_DMA_COHERENT=y CONFIG_SLABINFO=y @@ -109,7 +118,7 @@ CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODVERSIONS=y # CONFIG_MODULE_SRCVERSION_ALL is not set CONFIG_BLOCK=y -# CONFIG_LBD is not set +CONFIG_LBDAF=y # CONFIG_BLK_DEV_BSG is not set # CONFIG_BLK_DEV_INTEGRITY is not set @@ -136,13 +145,14 @@ CONFIG_FREEZER=y # CONFIG_ARCH_VERSATILE is not set # CONFIG_ARCH_AT91 is not set # CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_GEMINI is not set # CONFIG_ARCH_EBSA110 is not set # CONFIG_ARCH_EP93XX is not set -# CONFIG_ARCH_GEMINI is not set # CONFIG_ARCH_FOOTBRIDGE is not set +CONFIG_ARCH_MXC=y +# CONFIG_ARCH_STMP3XXX is not set # CONFIG_ARCH_NETX is not set # CONFIG_ARCH_H720X is not set -# CONFIG_ARCH_IMX is not set # CONFIG_ARCH_IOP13XX is not set # CONFIG_ARCH_IOP32X is not set # CONFIG_ARCH_IOP33X is not set @@ -151,25 +161,25 @@ CONFIG_FREEZER=y # CONFIG_ARCH_IXP4XX is not set # CONFIG_ARCH_L7200 is not set # CONFIG_ARCH_KIRKWOOD is not set -# CONFIG_ARCH_KS8695 is not set -# CONFIG_ARCH_NS9XXX is not set # CONFIG_ARCH_LOKI is not set # CONFIG_ARCH_MV78XX0 is not set -CONFIG_ARCH_MXC=y # CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_NS9XXX is not set +# CONFIG_ARCH_W90X900 is not set # CONFIG_ARCH_PNX4008 is not set # CONFIG_ARCH_PXA is not set -# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_MSM is not set # CONFIG_ARCH_RPC is not set # CONFIG_ARCH_SA1100 is not set # CONFIG_ARCH_S3C2410 is not set # CONFIG_ARCH_S3C64XX is not set # CONFIG_ARCH_SHARK is not set # CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_U300 is not set # CONFIG_ARCH_DAVINCI is not set # CONFIG_ARCH_OMAP is not set -# CONFIG_ARCH_MSM is not set -# CONFIG_ARCH_W90X900 is not set # # Freescale MXC Implementations @@ -178,6 +188,7 @@ CONFIG_ARCH_MXC=y # CONFIG_ARCH_MX2 is not set CONFIG_ARCH_MX3=y CONFIG_ARCH_MX31=y +CONFIG_ARCH_MX35=y # # MX3 platforms: @@ -185,12 +196,19 @@ CONFIG_ARCH_MX31=y CONFIG_MACH_MX31ADS=y CONFIG_MACH_MX31ADS_WM1133_EV1=y CONFIG_MACH_PCM037=y +CONFIG_MACH_PCM037_EET=y CONFIG_MACH_MX31LITE=y CONFIG_MACH_MX31_3DS=y CONFIG_MACH_MX31MOBOARD=y +CONFIG_MACH_MX31LILLY=y CONFIG_MACH_QONG=y +CONFIG_MACH_PCM043=y +CONFIG_MACH_ARMADILLO5X0=y +CONFIG_MACH_MX35_3DS=y CONFIG_MXC_IRQ_PRIOR=y CONFIG_MXC_PWM=y +CONFIG_ARCH_HAS_RNGA=y +CONFIG_ARCH_MXC_IOMUX_V3=y # # Processor Type @@ -218,6 +236,7 @@ CONFIG_ARM_THUMB=y # CONFIG_CPU_BPREDICT_DISABLE is not set CONFIG_OUTER_CACHE=y CONFIG_CACHE_L2X0=y +# CONFIG_ARM_ERRATA_411920 is not set CONFIG_COMMON_CLKDEV=y # @@ -242,7 +261,6 @@ CONFIG_PREEMPT=y CONFIG_HZ=100 CONFIG_AEABI=y CONFIG_OABI_COMPAT=y -CONFIG_ARCH_FLATMEM_HAS_HOLES=y # CONFIG_ARCH_SPARSEMEM_DEFAULT is not set # CONFIG_ARCH_SELECT_MEMORY_MODEL is not set # CONFIG_HIGHMEM is not set @@ -257,10 +275,11 @@ CONFIG_SPLIT_PTLOCK_CPUS=4 # CONFIG_PHYS_ADDR_T_64BIT is not set CONFIG_ZONE_DMA_FLAG=0 CONFIG_VIRT_TO_BUS=y -CONFIG_UNEVICTABLE_LRU=y CONFIG_HAVE_MLOCK=y CONFIG_HAVE_MLOCKED_PAGE_BIT=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 CONFIG_ALIGNMENT_TRAP=y +# CONFIG_UACCESS_WITH_MEMCPY is not set # # Boot options @@ -362,6 +381,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic" # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set # CONFIG_PHONET is not set +# CONFIG_IEEE802154 is not set # CONFIG_NET_SCHED is not set # CONFIG_DCB is not set @@ -465,7 +485,16 @@ CONFIG_MTD_PHYSMAP=y # CONFIG_MTD_DOC2000 is not set # CONFIG_MTD_DOC2001 is not set # CONFIG_MTD_DOC2001PLUS is not set -# CONFIG_MTD_NAND is not set +CONFIG_MTD_NAND=y +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +# CONFIG_MTD_NAND_ECC_SMC is not set +# CONFIG_MTD_NAND_MUSEUM_IDS is not set +# CONFIG_MTD_NAND_GPIO is not set +CONFIG_MTD_NAND_IDS=y +# CONFIG_MTD_NAND_DISKONCHIP is not set +# CONFIG_MTD_NAND_NANDSIM is not set +# CONFIG_MTD_NAND_PLATFORM is not set +CONFIG_MTD_NAND_MXC=y # CONFIG_MTD_ONENAND is not set # @@ -476,10 +505,30 @@ CONFIG_MTD_PHYSMAP=y # # UBI - Unsorted block images # -# CONFIG_MTD_UBI is not set +CONFIG_MTD_UBI=y +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_MTD_UBI_BEB_RESERVE=1 +# CONFIG_MTD_UBI_GLUEBI is not set + +# +# UBI debugging options +# +# CONFIG_MTD_UBI_DEBUG is not set # CONFIG_PARPORT is not set # CONFIG_BLK_DEV is not set -# CONFIG_MISC_DEVICES is not set +CONFIG_MISC_DEVICES=y +# CONFIG_ICS932S401 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_ISL29003 is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +CONFIG_EEPROM_AT24=y +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +# CONFIG_EEPROM_93CX6 is not set CONFIG_HAVE_IDE=y # CONFIG_IDE is not set @@ -493,7 +542,6 @@ CONFIG_HAVE_IDE=y # CONFIG_ATA is not set # CONFIG_MD is not set CONFIG_NETDEVICES=y -CONFIG_COMPAT_NET_DEV_OPS=y # CONFIG_DUMMY is not set # CONFIG_BONDING is not set # CONFIG_MACVLAN is not set @@ -528,7 +576,7 @@ CONFIG_MII=y # CONFIG_ETHOC is not set # CONFIG_SMC911X is not set CONFIG_SMSC911X=y -# CONFIG_DNET is not set +CONFIG_DNET=y # CONFIG_IBM_NEW_EMAC_ZMII is not set # CONFIG_IBM_NEW_EMAC_RGMII is not set # CONFIG_IBM_NEW_EMAC_TAH is not set @@ -537,8 +585,10 @@ CONFIG_SMSC911X=y # CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set # CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set # CONFIG_B44 is not set -CONFIG_CS89x0=y -CONFIG_CS89x0_NONISA_IRQ=y +# CONFIG_CS89x0 is not set +# CONFIG_KS8842 is not set +CONFIG_FEC=y +# CONFIG_FEC2 is not set # CONFIG_NETDEV_1000 is not set # CONFIG_NETDEV_10000 is not set @@ -609,6 +659,7 @@ CONFIG_I2C_HELPER_AUTO=y # # I2C system bus drivers (mostly embedded / system-on-chip) # +# CONFIG_I2C_DESIGNWARE is not set # CONFIG_I2C_GPIO is not set CONFIG_I2C_IMX=y # CONFIG_I2C_OCORES is not set @@ -633,7 +684,6 @@ CONFIG_I2C_IMX=y # CONFIG_SENSORS_PCF8574 is not set # CONFIG_PCF8575 is not set # CONFIG_SENSORS_PCA9539 is not set -# CONFIG_SENSORS_MAX6875 is not set # CONFIG_SENSORS_TSL2550 is not set # CONFIG_I2C_DEBUG_CORE is not set # CONFIG_I2C_DEBUG_ALGO is not set @@ -669,6 +719,7 @@ CONFIG_W1=y # # CONFIG_W1_MASTER_DS2482 is not set CONFIG_W1_MASTER_MXC=y +# CONFIG_W1_MASTER_DS1WM is not set # CONFIG_W1_MASTER_GPIO is not set # @@ -703,6 +754,8 @@ CONFIG_SSB_POSSIBLE=y # CONFIG_TPS65010 is not set # CONFIG_TWL4030_CORE is not set # CONFIG_MFD_TMIO is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC6387XB is not set # CONFIG_MFD_TC6393XB is not set # CONFIG_PMIC_DA903X is not set # CONFIG_MFD_WM8400 is not set @@ -711,10 +764,8 @@ CONFIG_MFD_WM8350_CONFIG_MODE_0=y CONFIG_MFD_WM8352_CONFIG_MODE_0=y CONFIG_MFD_WM8350_I2C=y # CONFIG_MFD_PCF50633 is not set - -# -# Multimedia devices -# +# CONFIG_AB3100_CORE is not set +CONFIG_MEDIA_SUPPORT=y # # Multimedia core support @@ -758,8 +809,10 @@ CONFIG_SOC_CAMERA_MT9T031=y CONFIG_SOC_CAMERA_MT9V022=y CONFIG_SOC_CAMERA_TW9910=y # CONFIG_SOC_CAMERA_PLATFORM is not set -# CONFIG_SOC_CAMERA_OV772X is not set +CONFIG_SOC_CAMERA_OV772X=y +CONFIG_MX3_VIDEO=y CONFIG_VIDEO_MX3=y +# CONFIG_VIDEO_SH_MOBILE_CEU is not set # CONFIG_RADIO_ADAPTERS is not set # CONFIG_DAB is not set @@ -847,8 +900,11 @@ CONFIG_REGULATOR=y # CONFIG_REGULATOR_DEBUG is not set # CONFIG_REGULATOR_FIXED_VOLTAGE is not set # CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set +# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set # CONFIG_REGULATOR_BQ24022 is not set +# CONFIG_REGULATOR_MAX1586 is not set CONFIG_REGULATOR_WM8350=y +# CONFIG_REGULATOR_LP3971 is not set # CONFIG_UIO is not set # CONFIG_STAGING is not set @@ -861,10 +917,12 @@ CONFIG_REGULATOR_WM8350=y # CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set # CONFIG_FS_POSIX_ACL is not set -CONFIG_FILE_LOCKING=y # CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set # CONFIG_OCFS2_FS is not set # CONFIG_BTRFS_FS is not set +CONFIG_FILE_LOCKING=y +CONFIG_FSNOTIFY=y # CONFIG_DNOTIFY is not set CONFIG_INOTIFY=y CONFIG_INOTIFY_USER=y @@ -921,6 +979,12 @@ CONFIG_JFFS2_ZLIB=y # CONFIG_JFFS2_LZO is not set CONFIG_JFFS2_RTIME=y # CONFIG_JFFS2_RUBIN is not set +CONFIG_UBIFS_FS=y +# CONFIG_UBIFS_FS_XATTR is not set +# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set +CONFIG_UBIFS_FS_LZO=y +CONFIG_UBIFS_FS_ZLIB=y +# CONFIG_UBIFS_FS_DEBUG is not set # CONFIG_CRAMFS is not set # CONFIG_SQUASHFS is not set # CONFIG_VXFS_FS is not set @@ -937,6 +1001,7 @@ CONFIG_NFS_FS=y CONFIG_NFS_V3=y # CONFIG_NFS_V3_ACL is not set CONFIG_NFS_V4=y +# CONFIG_NFS_V4_1 is not set CONFIG_ROOT_NFS=y # CONFIG_NFSD is not set CONFIG_LOCKD=y @@ -979,22 +1044,7 @@ CONFIG_FRAME_WARN=1024 CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_HAVE_FUNCTION_TRACER=y CONFIG_TRACING_SUPPORT=y - -# -# Tracers -# -# CONFIG_FUNCTION_TRACER is not set -# CONFIG_IRQSOFF_TRACER is not set -# CONFIG_PREEMPT_TRACER is not set -# CONFIG_SCHED_TRACER is not set -# CONFIG_CONTEXT_SWITCH_TRACER is not set -# CONFIG_EVENT_TRACER is not set -# CONFIG_BOOT_TRACER is not set -# CONFIG_TRACE_BRANCH_PROFILING is not set -# CONFIG_STACK_TRACER is not set -# CONFIG_KMEMTRACE is not set -# CONFIG_WORKQUEUE_TRACER is not set -# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_FTRACE is not set # CONFIG_SAMPLES is not set CONFIG_HAVE_ARCH_KGDB=y CONFIG_ARM_UNWIND=y @@ -1094,9 +1144,9 @@ CONFIG_CRYPTO_DES=y # # Compression # -# CONFIG_CRYPTO_DEFLATE is not set +CONFIG_CRYPTO_DEFLATE=y # CONFIG_CRYPTO_ZLIB is not set -# CONFIG_CRYPTO_LZO is not set +CONFIG_CRYPTO_LZO=y # # Random Number Generation @@ -1109,9 +1159,10 @@ CONFIG_CRYPTO_HW=y # Library routines # CONFIG_BITREVERSE=y +CONFIG_RATIONAL=y CONFIG_GENERIC_FIND_LAST_BIT=y # CONFIG_CRC_CCITT is not set -# CONFIG_CRC16 is not set +CONFIG_CRC16=y # CONFIG_CRC_T10DIF is not set # CONFIG_CRC_ITU_T is not set CONFIG_CRC32=y @@ -1119,6 +1170,8 @@ CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y CONFIG_HAS_IOMEM=y CONFIG_HAS_IOPORT=y CONFIG_HAS_DMA=y -- cgit v0.10.2 From cdaa052b05e26d96a990af5d253fd2af5db2b1fc Mon Sep 17 00:00:00 2001 From: Zhao Yakui Date: Tue, 28 Jul 2009 10:54:13 +0800 Subject: drm/I915: Fix offset to DVO timings in LVDS data Now the DVO timing in LVDS data entry is obtained by using the following step: a. get the entry size for every LVDS panel data b. Get the LVDS fp entry for the preferred panel type c. get the DVO timing by using entry->dvo_timing In our driver the entry->dvo_timing is related with the size of lvds_fp_timing. For example: the size is 46. But it seems that the size of lvds_fp_timing varies on the differnt platform. In such case we will get the incorrect DVO timing entry because of the incorrect DVO offset in LVDS panel data entry. This also removes a hack on new IGDNG to get proper DVO timing. Calculate the DVO timing offset in LVDS data entry to get the DVO timing a. get the DVO timing offset in the LVDS fp data entry by using the pointer definition in LVDS data ptr b. get the LVDS data entry c. get the DVO timing by adding the DVO timing offset to data entry https://bugs.freedesktop.org/show_bug.cgi?id=22787 Signed-off-by: Zhao Yakui Tested-by: Zhenyu Wang Acked-by: Jesse Barnes Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 7cc4471..5c7a62a 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -97,14 +97,13 @@ static void parse_lfp_panel_data(struct drm_i915_private *dev_priv, struct bdb_header *bdb) { - struct drm_device *dev = dev_priv->dev; struct bdb_lvds_options *lvds_options; struct bdb_lvds_lfp_data *lvds_lfp_data; struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs; struct bdb_lvds_lfp_data_entry *entry; struct lvds_dvo_timing *dvo_timing; struct drm_display_mode *panel_fixed_mode; - int lfp_data_size; + int lfp_data_size, dvo_timing_offset; /* Defaults if we can't find VBT info */ dev_priv->lvds_dither = 0; @@ -133,14 +132,16 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv, entry = (struct bdb_lvds_lfp_data_entry *) ((uint8_t *)lvds_lfp_data->data + (lfp_data_size * lvds_options->panel_type)); + dvo_timing_offset = lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset - + lvds_lfp_data_ptrs->ptr[0].fp_timing_offset; - /* On IGDNG mobile, LVDS data block removes panel fitting registers. - So dec 2 dword from dvo_timing offset */ - if (IS_IGDNG(dev)) - dvo_timing = (struct lvds_dvo_timing *) - ((u8 *)&entry->dvo_timing - 8); - else - dvo_timing = &entry->dvo_timing; + /* + * the size of fp_timing varies on the different platform. + * So calculate the DVO timing relative offset in LVDS data + * entry to get the DVO timing entry + */ + dvo_timing = (struct lvds_dvo_timing *) + ((unsigned char *)entry + dvo_timing_offset); panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL); -- cgit v0.10.2 From 24f119c769bacac5729297b682fec7811a983cc6 Mon Sep 17 00:00:00 2001 From: Zhenyu Wang Date: Fri, 24 Jul 2009 01:00:28 +0800 Subject: drm/i915: disable VGA plane reliably This does VGA disable like DDX driver. SR01 bit 5 should be set before VGA plane disable through control register, otherwise we might get random crash and lockups. Signed-off-by: Zhenyu Wang Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a58bfad..b06364e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -998,6 +998,29 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, return 0; } +/* Disable the VGA plane that we never use */ +static void i915_disable_vga (struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u8 sr1; + u32 vga_reg; + + if (IS_IGDNG(dev)) + vga_reg = CPU_VGACNTRL; + else + vga_reg = VGACNTRL; + + if (I915_READ(vga_reg) & VGA_DISP_DISABLE) + return; + + I915_WRITE8(VGA_SR_INDEX, 1); + sr1 = I915_READ8(VGA_SR_DATA); + I915_WRITE8(VGA_SR_DATA, sr1 | (1 << 5)); + udelay(100); + + I915_WRITE(vga_reg, VGA_DISP_DISABLE); +} + static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode) { struct drm_device *dev = crtc->dev; @@ -1200,8 +1223,7 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode) case DRM_MODE_DPMS_OFF: DRM_DEBUG("crtc %d dpms off\n", pipe); - /* Disable the VGA plane that we never use */ - I915_WRITE(CPU_VGACNTRL, VGA_DISP_DISABLE); + i915_disable_vga(dev); /* Disable display plane */ temp = I915_READ(dspcntr_reg); @@ -1342,7 +1364,7 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode) //intel_crtc_dpms_video(crtc, FALSE); TODO /* Disable the VGA plane that we never use */ - I915_WRITE(VGACNTRL, VGA_DISP_DISABLE); + i915_disable_vga(dev); /* Disable display plane */ temp = I915_READ(dspcntr_reg); -- cgit v0.10.2 From 249c0e64c24bf455a4e4815f72750f2b16cedd94 Mon Sep 17 00:00:00 2001 From: Zhenyu Wang Date: Fri, 24 Jul 2009 01:00:29 +0800 Subject: drm/i915: fix issue in display pipe setup on IGDNG During pipe DPMS off, instead of busy waiting pipe off, insert delays during wait and don't loop after enough tries which matches spec requirement. Also try to match DPMS on path by disable FDI TX PLL in DPMS off. Disable PF by writing PF_WIN_SZ which really trigger the update. Signed-off-by: Zhenyu Wang Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 897a116..7c77c4c 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1848,6 +1848,8 @@ #define PFA_CTL_1 0x68080 #define PFB_CTL_1 0x68880 #define PF_ENABLE (1<<31) +#define PFA_WIN_SZ 0x68074 +#define PFB_WIN_SZ 0x68874 /* legacy palette */ #define LGC_PALETTE_A 0x4a000 diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b06364e..15a8c39 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1038,6 +1038,7 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode) int fdi_rx_imr_reg = (pipe == 0) ? FDI_RXA_IMR : FDI_RXB_IMR; int transconf_reg = (pipe == 0) ? TRANSACONF : TRANSBCONF; int pf_ctl_reg = (pipe == 0) ? PFA_CTL_1 : PFB_CTL_1; + int pf_win_size = (pipe == 0) ? PFA_WIN_SZ : PFB_WIN_SZ; int cpu_htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B; int cpu_hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B; int cpu_hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B; @@ -1051,7 +1052,7 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode) int trans_vblank_reg = (pipe == 0) ? TRANS_VBLANK_A : TRANS_VBLANK_B; int trans_vsync_reg = (pipe == 0) ? TRANS_VSYNC_A : TRANS_VSYNC_B; u32 temp; - int tries = 5, j; + int tries = 5, j, n; /* XXX: When our outputs are all unaware of DPMS modes other than off * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC. @@ -1239,19 +1240,21 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode) if ((temp & PIPEACONF_ENABLE) != 0) { I915_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE); I915_READ(pipeconf_reg); + n = 0; /* wait for cpu pipe off, pipe state */ - while ((I915_READ(pipeconf_reg) & I965_PIPECONF_ACTIVE) != 0) - ; + while ((I915_READ(pipeconf_reg) & I965_PIPECONF_ACTIVE) != 0) { + n++; + if (n < 60) { + udelay(500); + continue; + } else { + DRM_DEBUG("pipe %d off delay\n", pipe); + break; + } + } } else DRM_DEBUG("crtc %d is disabled\n", pipe); - /* IGDNG-A : disable cpu panel fitter ? */ - temp = I915_READ(pf_ctl_reg); - if ((temp & PF_ENABLE) != 0) { - I915_WRITE(pf_ctl_reg, temp & ~PF_ENABLE); - I915_READ(pf_ctl_reg); - } - /* disable CPU FDI tx and PCH FDI rx */ temp = I915_READ(fdi_tx_reg); I915_WRITE(fdi_tx_reg, temp & ~FDI_TX_ENABLE); @@ -1261,6 +1264,8 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode) I915_WRITE(fdi_rx_reg, temp & ~FDI_RX_ENABLE); I915_READ(fdi_rx_reg); + udelay(100); + /* still set train pattern 1 */ temp = I915_READ(fdi_tx_reg); temp &= ~FDI_LINK_TRAIN_NONE; @@ -1272,14 +1277,25 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode) temp |= FDI_LINK_TRAIN_PATTERN_1; I915_WRITE(fdi_rx_reg, temp); + udelay(100); + /* disable PCH transcoder */ temp = I915_READ(transconf_reg); if ((temp & TRANS_ENABLE) != 0) { I915_WRITE(transconf_reg, temp & ~TRANS_ENABLE); I915_READ(transconf_reg); + n = 0; /* wait for PCH transcoder off, transcoder state */ - while ((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) != 0) - ; + while ((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) != 0) { + n++; + if (n < 60) { + udelay(500); + continue; + } else { + DRM_DEBUG("transcoder %d off delay\n", pipe); + break; + } + } } /* disable PCH DPLL */ @@ -1297,6 +1313,22 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode) I915_READ(fdi_rx_reg); } + /* Disable CPU FDI TX PLL */ + temp = I915_READ(fdi_tx_reg); + if ((temp & FDI_TX_PLL_ENABLE) != 0) { + I915_WRITE(fdi_tx_reg, temp & ~FDI_TX_PLL_ENABLE); + I915_READ(fdi_tx_reg); + udelay(100); + } + + /* Disable PF */ + temp = I915_READ(pf_ctl_reg); + if ((temp & PF_ENABLE) != 0) { + I915_WRITE(pf_ctl_reg, temp & ~PF_ENABLE); + I915_READ(pf_ctl_reg); + } + I915_WRITE(pf_win_size, 0); + /* Wait for the clocks to turn off. */ udelay(150); break; -- cgit v0.10.2 From eebc863e469cd91d96c4e3636450596ae29f0502 Mon Sep 17 00:00:00 2001 From: Zhenyu Wang Date: Fri, 24 Jul 2009 01:00:30 +0800 Subject: drm/i915: Fix channel ending action for DP aux transaction We should use current channel 'status' bits to clear DP aux channel's done and error bits, instead of using the channel setting bits, that will set send/busy bit again to initiate new transaction. This also includes also some minor cleanup. Signed-off-by: Zhenyu Wang Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 6770ae8..afec65c 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -236,7 +236,7 @@ intel_dp_aux_ch(struct intel_output *intel_output, } /* Clear done status and any errors */ - I915_WRITE(ch_ctl, (ctl | + I915_WRITE(ch_ctl, (status | DP_AUX_CH_CTL_DONE | DP_AUX_CH_CTL_TIME_OUT_ERROR | DP_AUX_CH_CTL_RECEIVE_ERROR)); @@ -295,7 +295,7 @@ intel_dp_aux_native_write(struct intel_output *intel_output, return -1; msg[0] = AUX_NATIVE_WRITE << 4; msg[1] = address >> 8; - msg[2] = address; + msg[2] = address & 0xff; msg[3] = send_bytes - 1; memcpy(&msg[4], send, send_bytes); msg_bytes = send_bytes + 4; @@ -387,8 +387,8 @@ intel_dp_i2c_init(struct intel_output *intel_output, const char *name) memset(&dp_priv->adapter, '\0', sizeof (dp_priv->adapter)); dp_priv->adapter.owner = THIS_MODULE; dp_priv->adapter.class = I2C_CLASS_DDC; - strncpy (dp_priv->adapter.name, name, sizeof dp_priv->adapter.name - 1); - dp_priv->adapter.name[sizeof dp_priv->adapter.name - 1] = '\0'; + strncpy (dp_priv->adapter.name, name, sizeof(dp_priv->adapter.name) - 1); + dp_priv->adapter.name[sizeof(dp_priv->adapter.name) - 1] = '\0'; dp_priv->adapter.algo_data = &dp_priv->algo; dp_priv->adapter.dev.parent = &intel_output->base.kdev; -- cgit v0.10.2 From 5eb08b69f510fadaba77eb9a1bda0f7299c4ebcc Mon Sep 17 00:00:00 2001 From: Zhenyu Wang Date: Fri, 24 Jul 2009 01:00:31 +0800 Subject: drm/i915: enable DisplayPort support on IGDNG Signed-off-by: Zhenyu Wang Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 7c77c4c..4518a94 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1444,6 +1444,7 @@ #define DP_CLOCK_OUTPUT_ENABLE (1 << 13) #define DP_SCRAMBLING_DISABLE (1 << 12) +#define DP_SCRAMBLING_DISABLE_IGDNG (1 << 7) /** limit RGB values to avoid confusing TVs */ #define DP_COLOR_RANGE_16_235 (1 << 8) @@ -2210,4 +2211,28 @@ #define PCH_PP_OFF_DELAYS 0xc720c #define PCH_PP_DIVISOR 0xc7210 +#define PCH_DP_B 0xe4100 +#define PCH_DPB_AUX_CH_CTL 0xe4110 +#define PCH_DPB_AUX_CH_DATA1 0xe4114 +#define PCH_DPB_AUX_CH_DATA2 0xe4118 +#define PCH_DPB_AUX_CH_DATA3 0xe411c +#define PCH_DPB_AUX_CH_DATA4 0xe4120 +#define PCH_DPB_AUX_CH_DATA5 0xe4124 + +#define PCH_DP_C 0xe4200 +#define PCH_DPC_AUX_CH_CTL 0xe4210 +#define PCH_DPC_AUX_CH_DATA1 0xe4214 +#define PCH_DPC_AUX_CH_DATA2 0xe4218 +#define PCH_DPC_AUX_CH_DATA3 0xe421c +#define PCH_DPC_AUX_CH_DATA4 0xe4220 +#define PCH_DPC_AUX_CH_DATA5 0xe4224 + +#define PCH_DP_D 0xe4300 +#define PCH_DPD_AUX_CH_CTL 0xe4310 +#define PCH_DPD_AUX_CH_DATA1 0xe4314 +#define PCH_DPD_AUX_CH_DATA2 0xe4318 +#define PCH_DPD_AUX_CH_DATA3 0xe431c +#define PCH_DPD_AUX_CH_DATA4 0xe4320 +#define PCH_DPD_AUX_CH_DATA5 0xe4324 + #endif /* _I915_REG_H_ */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 15a8c39..34c5046 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -268,6 +268,9 @@ intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, static bool intel_find_pll_g4x_dp(const intel_limit_t *, struct drm_crtc *crtc, int target, int refclk, intel_clock_t *best_clock); +static bool +intel_find_pll_igdng_dp(const intel_limit_t *, struct drm_crtc *crtc, + int target, int refclk, intel_clock_t *best_clock); static const intel_limit_t intel_limits_i8xx_dvo = { .dot = { .min = I8XX_DOT_MIN, .max = I8XX_DOT_MAX }, @@ -752,6 +755,30 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, } static bool +intel_find_pll_igdng_dp(const intel_limit_t *limit, struct drm_crtc *crtc, + int target, int refclk, intel_clock_t *best_clock) +{ + struct drm_device *dev = crtc->dev; + intel_clock_t clock; + if (target < 200000) { + clock.n = 1; + clock.p1 = 2; + clock.p2 = 10; + clock.m1 = 12; + clock.m2 = 9; + } else { + clock.n = 2; + clock.p1 = 1; + clock.p2 = 10; + clock.m1 = 14; + clock.m2 = 8; + } + intel_clock(dev, refclk, &clock); + memcpy(best_clock, &clock, sizeof(intel_clock_t)); + return true; +} + +static bool intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, int target, int refclk, intel_clock_t *best_clock) { @@ -763,6 +790,10 @@ intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, int err_most = 47; found = false; + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) + return intel_find_pll_igdng_dp(limit, crtc, target, + refclk, best_clock); + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP) @@ -2136,6 +2167,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, int lvds_reg = LVDS; u32 temp; int sdvo_pixel_multiply; + int target_clock; drm_vblank_pre_modeset(dev, pipe); @@ -2218,11 +2250,18 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, } /* FDI link */ - if (IS_IGDNG(dev)) + if (IS_IGDNG(dev)) { + /* DP over FDI requires target mode clock + instead of link clock */ + if (is_dp) + target_clock = mode->clock; + else + target_clock = adjusted_mode->clock; igdng_compute_m_n(3, 4, /* lane num 4 */ - adjusted_mode->clock, + target_clock, 270000, /* lane clock */ &m_n); + } if (IS_IGD(dev)) fp = (1 << clock.n) << 16 | clock.m1 << 8 | clock.m2; @@ -3050,6 +3089,8 @@ static void intel_setup_outputs(struct drm_device *dev) found = 0; if (!found) intel_hdmi_init(dev, HDMIB); + if (!found && (I915_READ(PCH_DP_B) & DP_DETECTED)) + intel_dp_init(dev, PCH_DP_B); } if (I915_READ(HDMIC) & PORT_DETECTED) @@ -3058,6 +3099,12 @@ static void intel_setup_outputs(struct drm_device *dev) if (I915_READ(HDMID) & PORT_DETECTED) intel_hdmi_init(dev, HDMID); + if (I915_READ(PCH_DP_C) & DP_DETECTED) + intel_dp_init(dev, PCH_DP_C); + + if (I915_READ(PCH_DP_D) & DP_DETECTED) + intel_dp_init(dev, PCH_DP_D); + } else if (IS_I9XX(dev)) { int found; u32 reg; diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index afec65c..0715911 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -206,7 +206,12 @@ intel_dp_aux_ch(struct intel_output *intel_output, * and would like to run at 2MHz. So, take the * hrawclk value and divide by 2 and use that */ - aux_clock_divider = intel_hrawclk(dev) / 2; + /* IGDNG: input clock fixed at 125Mhz, so aux_bit_clk always 62 */ + if (IS_IGDNG(dev)) + aux_clock_divider = 62; + else + aux_clock_divider = intel_hrawclk(dev) / 2; + /* Must try at least 3 times according to DP spec */ for (try = 0; try < 5; try++) { /* Load the send data into the aux channel data registers */ @@ -493,22 +498,40 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, intel_dp_compute_m_n(3, lane_count, mode->clock, adjusted_mode->clock, &m_n); - if (intel_crtc->pipe == 0) { - I915_WRITE(PIPEA_GMCH_DATA_M, - ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) | - m_n.gmch_m); - I915_WRITE(PIPEA_GMCH_DATA_N, - m_n.gmch_n); - I915_WRITE(PIPEA_DP_LINK_M, m_n.link_m); - I915_WRITE(PIPEA_DP_LINK_N, m_n.link_n); + if (IS_IGDNG(dev)) { + if (intel_crtc->pipe == 0) { + I915_WRITE(TRANSA_DATA_M1, + ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) | + m_n.gmch_m); + I915_WRITE(TRANSA_DATA_N1, m_n.gmch_n); + I915_WRITE(TRANSA_DP_LINK_M1, m_n.link_m); + I915_WRITE(TRANSA_DP_LINK_N1, m_n.link_n); + } else { + I915_WRITE(TRANSB_DATA_M1, + ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) | + m_n.gmch_m); + I915_WRITE(TRANSB_DATA_N1, m_n.gmch_n); + I915_WRITE(TRANSB_DP_LINK_M1, m_n.link_m); + I915_WRITE(TRANSB_DP_LINK_N1, m_n.link_n); + } } else { - I915_WRITE(PIPEB_GMCH_DATA_M, - ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) | - m_n.gmch_m); - I915_WRITE(PIPEB_GMCH_DATA_N, - m_n.gmch_n); - I915_WRITE(PIPEB_DP_LINK_M, m_n.link_m); - I915_WRITE(PIPEB_DP_LINK_N, m_n.link_n); + if (intel_crtc->pipe == 0) { + I915_WRITE(PIPEA_GMCH_DATA_M, + ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) | + m_n.gmch_m); + I915_WRITE(PIPEA_GMCH_DATA_N, + m_n.gmch_n); + I915_WRITE(PIPEA_DP_LINK_M, m_n.link_m); + I915_WRITE(PIPEA_DP_LINK_N, m_n.link_n); + } else { + I915_WRITE(PIPEB_GMCH_DATA_M, + ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) | + m_n.gmch_m); + I915_WRITE(PIPEB_GMCH_DATA_N, + m_n.gmch_n); + I915_WRITE(PIPEB_DP_LINK_M, m_n.link_m); + I915_WRITE(PIPEB_DP_LINK_N, m_n.link_n); + } } } @@ -935,6 +958,12 @@ intel_dp_link_down(struct intel_output *intel_output, uint32_t DP) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_dp_priv *dp_priv = intel_output->dev_priv; + DP &= ~DP_LINK_TRAIN_MASK; + I915_WRITE(dp_priv->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE); + POSTING_READ(dp_priv->output_reg); + + udelay(17000); + I915_WRITE(dp_priv->output_reg, DP & ~DP_PORT_EN); POSTING_READ(dp_priv->output_reg); } @@ -978,6 +1007,24 @@ intel_dp_check_link_status(struct intel_output *intel_output) intel_dp_link_train(intel_output, dp_priv->DP, dp_priv->link_configuration); } +static enum drm_connector_status +igdng_dp_detect(struct drm_connector *connector) +{ + struct intel_output *intel_output = to_intel_output(connector); + struct intel_dp_priv *dp_priv = intel_output->dev_priv; + enum drm_connector_status status; + + status = connector_status_disconnected; + if (intel_dp_aux_native_read(intel_output, + 0x000, dp_priv->dpcd, + sizeof (dp_priv->dpcd)) == sizeof (dp_priv->dpcd)) + { + if (dp_priv->dpcd[0] != 0) + status = connector_status_connected; + } + return status; +} + /** * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect DP connection. * @@ -996,6 +1043,9 @@ intel_dp_detect(struct drm_connector *connector) dp_priv->has_audio = false; + if (IS_IGDNG(dev)) + return igdng_dp_detect(connector); + temp = I915_READ(PORT_HOTPLUG_EN); I915_WRITE(PORT_HOTPLUG_EN, @@ -1106,6 +1156,7 @@ intel_dp_init(struct drm_device *dev, int output_reg) struct drm_connector *connector; struct intel_output *intel_output; struct intel_dp_priv *dp_priv; + const char *name = NULL; intel_output = kcalloc(sizeof(struct intel_output) + sizeof(struct intel_dp_priv), 1, GFP_KERNEL); @@ -1139,9 +1190,22 @@ intel_dp_init(struct drm_device *dev, int output_reg) drm_sysfs_connector_add(connector); /* Set up the DDC bus. */ - intel_dp_i2c_init(intel_output, - (output_reg == DP_B) ? "DPDDC-B" : - (output_reg == DP_C) ? "DPDDC-C" : "DPDDC-D"); + switch (output_reg) { + case DP_B: + case PCH_DP_B: + name = "DPDDC-B"; + break; + case DP_C: + case PCH_DP_C: + name = "DPDDC-C"; + break; + case DP_D: + case PCH_DP_D: + name = "DPDDC-D"; + break; + } + + intel_dp_i2c_init(intel_output, name); intel_output->ddc_bus = &dp_priv->adapter; intel_output->hot_plug = intel_dp_hot_plug; -- cgit v0.10.2 From 32f9d658aee5be09ebdd28fc730630e61d0b46db Mon Sep 17 00:00:00 2001 From: Zhenyu Wang Date: Fri, 24 Jul 2009 01:00:32 +0800 Subject: drm/i915: Add eDP support on IGDNG mobile chip This adds embedded DisplayPort support on next mobile chip which aims to replace origin LVDS port. VBT's driver feature block has been used to determine the type of current internal panel for eDP or LVDS. Currently no panel fitting support for eDP and backlight control would be added in future. Signed-off-by: Zhenyu Wang Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index b05b44d..5f3a259 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -219,6 +219,7 @@ typedef struct drm_i915_private { unsigned int lvds_vbt:1; unsigned int int_crt_support:1; unsigned int lvds_use_ssc:1; + unsigned int edp_support:1; int lvds_ssc_freq; struct drm_i915_fence_reg fence_regs[16]; /* assume 965 */ @@ -889,6 +890,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); IS_I915GM(dev))) #define SUPPORTS_INTEGRATED_HDMI(dev) (IS_G4X(dev) || IS_IGDNG(dev)) #define SUPPORTS_INTEGRATED_DP(dev) (IS_G4X(dev) || IS_IGDNG(dev)) +#define SUPPORTS_EDP(dev) (IS_IGDNG_M(dev)) #define I915_HAS_HOTPLUG(dev) (IS_I945G(dev) || IS_I945GM(dev) || IS_I965G(dev)) /* dsparb controlled by hw only */ #define DSPARB_HWCONTROL(dev) (IS_G4X(dev) || IS_IGDNG(dev)) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 4518a94..2955083 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1395,6 +1395,7 @@ #define TV_V_CHROMA_42 0x684a8 /* Display Port */ +#define DP_A 0x64000 /* eDP */ #define DP_B 0x64100 #define DP_C 0x64200 #define DP_D 0x64300 @@ -1437,9 +1438,17 @@ /* Mystic DPCD version 1.1 special mode */ #define DP_ENHANCED_FRAMING (1 << 18) +/* eDP */ +#define DP_PLL_FREQ_270MHZ (0 << 16) +#define DP_PLL_FREQ_160MHZ (1 << 16) +#define DP_PLL_FREQ_MASK (3 << 16) + /** locked once port is enabled */ #define DP_PORT_REVERSAL (1 << 15) +/* eDP */ +#define DP_PLL_ENABLE (1 << 14) + /** sends the clock on lane 15 of the PEG for debug */ #define DP_CLOCK_OUTPUT_ENABLE (1 << 13) @@ -1464,6 +1473,13 @@ * is 20 bytes in each direction, hence the 5 fixed * data registers */ +#define DPA_AUX_CH_CTL 0x64010 +#define DPA_AUX_CH_DATA1 0x64014 +#define DPA_AUX_CH_DATA2 0x64018 +#define DPA_AUX_CH_DATA3 0x6401c +#define DPA_AUX_CH_DATA4 0x64020 +#define DPA_AUX_CH_DATA5 0x64024 + #define DPB_AUX_CH_CTL 0x64110 #define DPB_AUX_CH_DATA1 0x64114 #define DPB_AUX_CH_DATA2 0x64118 diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 5c7a62a..300aee3 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -296,6 +296,25 @@ parse_sdvo_device_mapping(struct drm_i915_private *dev_priv, } return; } + +static void +parse_driver_features(struct drm_i915_private *dev_priv, + struct bdb_header *bdb) +{ + struct drm_device *dev = dev_priv->dev; + struct bdb_driver_features *driver; + + /* set default for chips without eDP */ + if (!SUPPORTS_EDP(dev)) { + dev_priv->edp_support = 0; + return; + } + + driver = find_section(bdb, BDB_DRIVER_FEATURES); + if (driver && driver->lvds_config == BDB_DRIVER_FEATURE_EDP) + dev_priv->edp_support = 1; +} + /** * intel_init_bios - initialize VBIOS settings & find VBT * @dev: DRM device @@ -346,6 +365,8 @@ intel_init_bios(struct drm_device *dev) parse_lfp_panel_data(dev_priv, bdb); parse_sdvo_panel_data(dev_priv, bdb); parse_sdvo_device_mapping(dev_priv, bdb); + parse_driver_features(dev_priv, bdb); + pci_unmap_rom(pdev, bios); return 0; diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h index fe72e1c..0f8e5f6 100644 --- a/drivers/gpu/drm/i915/intel_bios.h +++ b/drivers/gpu/drm/i915/intel_bios.h @@ -381,6 +381,51 @@ struct bdb_sdvo_lvds_options { } __attribute__((packed)); +#define BDB_DRIVER_FEATURE_NO_LVDS 0 +#define BDB_DRIVER_FEATURE_INT_LVDS 1 +#define BDB_DRIVER_FEATURE_SDVO_LVDS 2 +#define BDB_DRIVER_FEATURE_EDP 3 + +struct bdb_driver_features { + u8 boot_dev_algorithm:1; + u8 block_display_switch:1; + u8 allow_display_switch:1; + u8 hotplug_dvo:1; + u8 dual_view_zoom:1; + u8 int15h_hook:1; + u8 sprite_in_clone:1; + u8 primary_lfp_id:1; + + u16 boot_mode_x; + u16 boot_mode_y; + u8 boot_mode_bpp; + u8 boot_mode_refresh; + + u16 enable_lfp_primary:1; + u16 selective_mode_pruning:1; + u16 dual_frequency:1; + u16 render_clock_freq:1; /* 0: high freq; 1: low freq */ + u16 nt_clone_support:1; + u16 power_scheme_ui:1; /* 0: CUI; 1: 3rd party */ + u16 sprite_display_assign:1; /* 0: secondary; 1: primary */ + u16 cui_aspect_scaling:1; + u16 preserve_aspect_ratio:1; + u16 sdvo_device_power_down:1; + u16 crt_hotplug:1; + u16 lvds_config:2; + u16 tv_hotplug:1; + u16 hdmi_config:2; + + u8 static_display:1; + u8 reserved2:7; + u16 legacy_crt_max_x; + u16 legacy_crt_max_y; + u8 legacy_crt_max_refresh; + + u8 hdmi_termination; + u8 custom_vbt_version; +} __attribute__((packed)); + bool intel_init_bios(struct drm_device *dev); /* diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 34c5046..a9f1307 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -34,6 +34,8 @@ #include "drm_crtc_helper.h" +#define HAS_eDP (intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP)) + bool intel_pipe_has_type (struct drm_crtc *crtc, int type); static void intel_update_watermarks(struct drm_device *dev); @@ -601,6 +603,23 @@ bool intel_pipe_has_type (struct drm_crtc *crtc, int type) return false; } +struct drm_connector * +intel_pipe_get_output (struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_mode_config *mode_config = &dev->mode_config; + struct drm_connector *l_entry, *ret = NULL; + + list_for_each_entry(l_entry, &mode_config->connector_list, head) { + if (l_entry->encoder && + l_entry->encoder->crtc == crtc) { + ret = l_entry; + break; + } + } + return ret; +} + #define INTELPllInvalid(s) do { /* DRM_DEBUG(s); */ return false; } while (0) /** * Returns whether the given set of divisors are valid for a given refclk with @@ -790,6 +809,10 @@ intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, int err_most = 47; found = false; + /* eDP has only 2 clock choice, no n/m/p setting */ + if (HAS_eDP) + return true; + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) return intel_find_pll_igdng_dp(limit, crtc, target, refclk, best_clock); @@ -1052,6 +1075,67 @@ static void i915_disable_vga (struct drm_device *dev) I915_WRITE(vga_reg, VGA_DISP_DISABLE); } +static void igdng_disable_pll_edp (struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 dpa_ctl; + + DRM_DEBUG("\n"); + dpa_ctl = I915_READ(DP_A); + dpa_ctl &= ~DP_PLL_ENABLE; + I915_WRITE(DP_A, dpa_ctl); +} + +static void igdng_enable_pll_edp (struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 dpa_ctl; + + dpa_ctl = I915_READ(DP_A); + dpa_ctl |= DP_PLL_ENABLE; + I915_WRITE(DP_A, dpa_ctl); + udelay(200); +} + + +static void igdng_set_pll_edp (struct drm_crtc *crtc, int clock) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 dpa_ctl; + + DRM_DEBUG("eDP PLL enable for clock %d\n", clock); + dpa_ctl = I915_READ(DP_A); + dpa_ctl &= ~DP_PLL_FREQ_MASK; + + if (clock < 200000) { + u32 temp; + dpa_ctl |= DP_PLL_FREQ_160MHZ; + /* workaround for 160Mhz: + 1) program 0x4600c bits 15:0 = 0x8124 + 2) program 0x46010 bit 0 = 1 + 3) program 0x46034 bit 24 = 1 + 4) program 0x64000 bit 14 = 1 + */ + temp = I915_READ(0x4600c); + temp &= 0xffff0000; + I915_WRITE(0x4600c, temp | 0x8124); + + temp = I915_READ(0x46010); + I915_WRITE(0x46010, temp | 1); + + temp = I915_READ(0x46034); + I915_WRITE(0x46034, temp | (1 << 24)); + } else { + dpa_ctl |= DP_PLL_FREQ_270MHZ; + } + I915_WRITE(DP_A, dpa_ctl); + + udelay(500); +} + static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode) { struct drm_device *dev = crtc->dev; @@ -1093,27 +1177,32 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode) case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: DRM_DEBUG("crtc %d dpms on\n", pipe); - /* enable PCH DPLL */ - temp = I915_READ(pch_dpll_reg); - if ((temp & DPLL_VCO_ENABLE) == 0) { - I915_WRITE(pch_dpll_reg, temp | DPLL_VCO_ENABLE); - I915_READ(pch_dpll_reg); - } - - /* enable PCH FDI RX PLL, wait warmup plus DMI latency */ - temp = I915_READ(fdi_rx_reg); - I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE | - FDI_SEL_PCDCLK | - FDI_DP_PORT_WIDTH_X4); /* default 4 lanes */ - I915_READ(fdi_rx_reg); - udelay(200); + if (HAS_eDP) { + /* enable eDP PLL */ + igdng_enable_pll_edp(crtc); + } else { + /* enable PCH DPLL */ + temp = I915_READ(pch_dpll_reg); + if ((temp & DPLL_VCO_ENABLE) == 0) { + I915_WRITE(pch_dpll_reg, temp | DPLL_VCO_ENABLE); + I915_READ(pch_dpll_reg); + } - /* Enable CPU FDI TX PLL, always on for IGDNG */ - temp = I915_READ(fdi_tx_reg); - if ((temp & FDI_TX_PLL_ENABLE) == 0) { - I915_WRITE(fdi_tx_reg, temp | FDI_TX_PLL_ENABLE); - I915_READ(fdi_tx_reg); - udelay(100); + /* enable PCH FDI RX PLL, wait warmup plus DMI latency */ + temp = I915_READ(fdi_rx_reg); + I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE | + FDI_SEL_PCDCLK | + FDI_DP_PORT_WIDTH_X4); /* default 4 lanes */ + I915_READ(fdi_rx_reg); + udelay(200); + + /* Enable CPU FDI TX PLL, always on for IGDNG */ + temp = I915_READ(fdi_tx_reg); + if ((temp & FDI_TX_PLL_ENABLE) == 0) { + I915_WRITE(fdi_tx_reg, temp | FDI_TX_PLL_ENABLE); + I915_READ(fdi_tx_reg); + udelay(100); + } } /* Enable CPU pipe */ @@ -1132,122 +1221,126 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode) I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); } - /* enable CPU FDI TX and PCH FDI RX */ - temp = I915_READ(fdi_tx_reg); - temp |= FDI_TX_ENABLE; - temp |= FDI_DP_PORT_WIDTH_X4; /* default */ - temp &= ~FDI_LINK_TRAIN_NONE; - temp |= FDI_LINK_TRAIN_PATTERN_1; - I915_WRITE(fdi_tx_reg, temp); - I915_READ(fdi_tx_reg); + if (!HAS_eDP) { + /* enable CPU FDI TX and PCH FDI RX */ + temp = I915_READ(fdi_tx_reg); + temp |= FDI_TX_ENABLE; + temp |= FDI_DP_PORT_WIDTH_X4; /* default */ + temp &= ~FDI_LINK_TRAIN_NONE; + temp |= FDI_LINK_TRAIN_PATTERN_1; + I915_WRITE(fdi_tx_reg, temp); + I915_READ(fdi_tx_reg); - temp = I915_READ(fdi_rx_reg); - temp &= ~FDI_LINK_TRAIN_NONE; - temp |= FDI_LINK_TRAIN_PATTERN_1; - I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENABLE); - I915_READ(fdi_rx_reg); + temp = I915_READ(fdi_rx_reg); + temp &= ~FDI_LINK_TRAIN_NONE; + temp |= FDI_LINK_TRAIN_PATTERN_1; + I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENABLE); + I915_READ(fdi_rx_reg); - udelay(150); + udelay(150); - /* Train FDI. */ - /* umask FDI RX Interrupt symbol_lock and bit_lock bit - for train result */ - temp = I915_READ(fdi_rx_imr_reg); - temp &= ~FDI_RX_SYMBOL_LOCK; - temp &= ~FDI_RX_BIT_LOCK; - I915_WRITE(fdi_rx_imr_reg, temp); - I915_READ(fdi_rx_imr_reg); - udelay(150); + /* Train FDI. */ + /* umask FDI RX Interrupt symbol_lock and bit_lock bit + for train result */ + temp = I915_READ(fdi_rx_imr_reg); + temp &= ~FDI_RX_SYMBOL_LOCK; + temp &= ~FDI_RX_BIT_LOCK; + I915_WRITE(fdi_rx_imr_reg, temp); + I915_READ(fdi_rx_imr_reg); + udelay(150); - temp = I915_READ(fdi_rx_iir_reg); - DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp); + temp = I915_READ(fdi_rx_iir_reg); + DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp); - if ((temp & FDI_RX_BIT_LOCK) == 0) { - for (j = 0; j < tries; j++) { - temp = I915_READ(fdi_rx_iir_reg); - DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp); - if (temp & FDI_RX_BIT_LOCK) - break; - udelay(200); - } - if (j != tries) + if ((temp & FDI_RX_BIT_LOCK) == 0) { + for (j = 0; j < tries; j++) { + temp = I915_READ(fdi_rx_iir_reg); + DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp); + if (temp & FDI_RX_BIT_LOCK) + break; + udelay(200); + } + if (j != tries) + I915_WRITE(fdi_rx_iir_reg, + temp | FDI_RX_BIT_LOCK); + else + DRM_DEBUG("train 1 fail\n"); + } else { I915_WRITE(fdi_rx_iir_reg, temp | FDI_RX_BIT_LOCK); - else - DRM_DEBUG("train 1 fail\n"); - } else { - I915_WRITE(fdi_rx_iir_reg, - temp | FDI_RX_BIT_LOCK); - DRM_DEBUG("train 1 ok 2!\n"); - } - temp = I915_READ(fdi_tx_reg); - temp &= ~FDI_LINK_TRAIN_NONE; - temp |= FDI_LINK_TRAIN_PATTERN_2; - I915_WRITE(fdi_tx_reg, temp); - - temp = I915_READ(fdi_rx_reg); - temp &= ~FDI_LINK_TRAIN_NONE; - temp |= FDI_LINK_TRAIN_PATTERN_2; - I915_WRITE(fdi_rx_reg, temp); + DRM_DEBUG("train 1 ok 2!\n"); + } + temp = I915_READ(fdi_tx_reg); + temp &= ~FDI_LINK_TRAIN_NONE; + temp |= FDI_LINK_TRAIN_PATTERN_2; + I915_WRITE(fdi_tx_reg, temp); + + temp = I915_READ(fdi_rx_reg); + temp &= ~FDI_LINK_TRAIN_NONE; + temp |= FDI_LINK_TRAIN_PATTERN_2; + I915_WRITE(fdi_rx_reg, temp); - udelay(150); + udelay(150); - temp = I915_READ(fdi_rx_iir_reg); - DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp); + temp = I915_READ(fdi_rx_iir_reg); + DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp); - if ((temp & FDI_RX_SYMBOL_LOCK) == 0) { - for (j = 0; j < tries; j++) { - temp = I915_READ(fdi_rx_iir_reg); - DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp); - if (temp & FDI_RX_SYMBOL_LOCK) - break; - udelay(200); - } - if (j != tries) { + if ((temp & FDI_RX_SYMBOL_LOCK) == 0) { + for (j = 0; j < tries; j++) { + temp = I915_READ(fdi_rx_iir_reg); + DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp); + if (temp & FDI_RX_SYMBOL_LOCK) + break; + udelay(200); + } + if (j != tries) { + I915_WRITE(fdi_rx_iir_reg, + temp | FDI_RX_SYMBOL_LOCK); + DRM_DEBUG("train 2 ok 1!\n"); + } else + DRM_DEBUG("train 2 fail\n"); + } else { I915_WRITE(fdi_rx_iir_reg, temp | FDI_RX_SYMBOL_LOCK); - DRM_DEBUG("train 2 ok 1!\n"); - } else - DRM_DEBUG("train 2 fail\n"); - } else { - I915_WRITE(fdi_rx_iir_reg, temp | FDI_RX_SYMBOL_LOCK); - DRM_DEBUG("train 2 ok 2!\n"); - } - DRM_DEBUG("train done\n"); + DRM_DEBUG("train 2 ok 2!\n"); + } + DRM_DEBUG("train done\n"); - /* set transcoder timing */ - I915_WRITE(trans_htot_reg, I915_READ(cpu_htot_reg)); - I915_WRITE(trans_hblank_reg, I915_READ(cpu_hblank_reg)); - I915_WRITE(trans_hsync_reg, I915_READ(cpu_hsync_reg)); + /* set transcoder timing */ + I915_WRITE(trans_htot_reg, I915_READ(cpu_htot_reg)); + I915_WRITE(trans_hblank_reg, I915_READ(cpu_hblank_reg)); + I915_WRITE(trans_hsync_reg, I915_READ(cpu_hsync_reg)); - I915_WRITE(trans_vtot_reg, I915_READ(cpu_vtot_reg)); - I915_WRITE(trans_vblank_reg, I915_READ(cpu_vblank_reg)); - I915_WRITE(trans_vsync_reg, I915_READ(cpu_vsync_reg)); + I915_WRITE(trans_vtot_reg, I915_READ(cpu_vtot_reg)); + I915_WRITE(trans_vblank_reg, I915_READ(cpu_vblank_reg)); + I915_WRITE(trans_vsync_reg, I915_READ(cpu_vsync_reg)); - /* enable PCH transcoder */ - temp = I915_READ(transconf_reg); - I915_WRITE(transconf_reg, temp | TRANS_ENABLE); - I915_READ(transconf_reg); + /* enable PCH transcoder */ + temp = I915_READ(transconf_reg); + I915_WRITE(transconf_reg, temp | TRANS_ENABLE); + I915_READ(transconf_reg); - while ((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) == 0) - ; + while ((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) == 0) + ; - /* enable normal */ + /* enable normal */ - temp = I915_READ(fdi_tx_reg); - temp &= ~FDI_LINK_TRAIN_NONE; - I915_WRITE(fdi_tx_reg, temp | FDI_LINK_TRAIN_NONE | - FDI_TX_ENHANCE_FRAME_ENABLE); - I915_READ(fdi_tx_reg); + temp = I915_READ(fdi_tx_reg); + temp &= ~FDI_LINK_TRAIN_NONE; + I915_WRITE(fdi_tx_reg, temp | FDI_LINK_TRAIN_NONE | + FDI_TX_ENHANCE_FRAME_ENABLE); + I915_READ(fdi_tx_reg); - temp = I915_READ(fdi_rx_reg); - temp &= ~FDI_LINK_TRAIN_NONE; - I915_WRITE(fdi_rx_reg, temp | FDI_LINK_TRAIN_NONE | - FDI_RX_ENHANCE_FRAME_ENABLE); - I915_READ(fdi_rx_reg); + temp = I915_READ(fdi_rx_reg); + temp &= ~FDI_LINK_TRAIN_NONE; + I915_WRITE(fdi_rx_reg, temp | FDI_LINK_TRAIN_NONE | + FDI_RX_ENHANCE_FRAME_ENABLE); + I915_READ(fdi_rx_reg); - /* wait one idle pattern time */ - udelay(100); + /* wait one idle pattern time */ + udelay(100); + + } intel_crtc_load_lut(crtc); @@ -1286,6 +1379,10 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode) } else DRM_DEBUG("crtc %d is disabled\n", pipe); + if (HAS_eDP) { + igdng_disable_pll_edp(crtc); + } + /* disable CPU FDI tx and PCH FDI rx */ temp = I915_READ(fdi_tx_reg); I915_WRITE(fdi_tx_reg, temp & ~FDI_TX_ENABLE); @@ -2152,6 +2249,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, u32 dpll = 0, fp = 0, dspcntr, pipeconf; bool ok, is_sdvo = false, is_dvo = false; bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false; + bool is_edp = false; struct drm_mode_config *mode_config = &dev->mode_config; struct drm_connector *connector; const intel_limit_t *limit; @@ -2199,6 +2297,9 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, case INTEL_OUTPUT_DISPLAYPORT: is_dp = true; break; + case INTEL_OUTPUT_EDP: + is_edp = true; + break; } num_outputs++; @@ -2251,16 +2352,27 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, /* FDI link */ if (IS_IGDNG(dev)) { - /* DP over FDI requires target mode clock - instead of link clock */ - if (is_dp) + int lane, link_bw; + /* eDP doesn't require FDI link, so just set DP M/N + according to current link config */ + if (is_edp) { + struct drm_connector *edp; target_clock = mode->clock; - else - target_clock = adjusted_mode->clock; - igdng_compute_m_n(3, 4, /* lane num 4 */ - target_clock, - 270000, /* lane clock */ - &m_n); + edp = intel_pipe_get_output(crtc); + intel_edp_link_config(to_intel_output(edp), + &lane, &link_bw); + } else { + /* DP over FDI requires target mode clock + instead of link clock */ + if (is_dp) + target_clock = mode->clock; + else + target_clock = adjusted_mode->clock; + lane = 4; + link_bw = 270000; + } + igdng_compute_m_n(3, lane, target_clock, + link_bw, &m_n); } if (IS_IGD(dev)) @@ -2382,29 +2494,15 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, dpll_reg = pch_dpll_reg; } - if (dpll & DPLL_VCO_ENABLE) { + if (is_edp) { + igdng_disable_pll_edp(crtc); + } else if ((dpll & DPLL_VCO_ENABLE)) { I915_WRITE(fp_reg, fp); I915_WRITE(dpll_reg, dpll & ~DPLL_VCO_ENABLE); I915_READ(dpll_reg); udelay(150); } - if (IS_IGDNG(dev)) { - /* enable PCH clock reference source */ - /* XXX need to change the setting for other outputs */ - u32 temp; - temp = I915_READ(PCH_DREF_CONTROL); - temp &= ~DREF_NONSPREAD_SOURCE_MASK; - temp |= DREF_NONSPREAD_CK505_ENABLE; - temp &= ~DREF_SSC_SOURCE_MASK; - temp |= DREF_SSC_SOURCE_ENABLE; - temp &= ~DREF_SSC1_ENABLE; - /* if no eDP, disable source output to CPU */ - temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK; - temp |= DREF_CPU_SOURCE_OUTPUT_DISABLE; - I915_WRITE(PCH_DREF_CONTROL, temp); - } - /* The LVDS pin pair needs to be on before the DPLLs are enabled. * This is an exception to the general rule that mode_set doesn't turn * things on. @@ -2436,23 +2534,25 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, if (is_dp) intel_dp_set_m_n(crtc, mode, adjusted_mode); - I915_WRITE(fp_reg, fp); - I915_WRITE(dpll_reg, dpll); - I915_READ(dpll_reg); - /* Wait for the clocks to stabilize. */ - udelay(150); - - if (IS_I965G(dev) && !IS_IGDNG(dev)) { - sdvo_pixel_multiply = adjusted_mode->clock / mode->clock; - I915_WRITE(dpll_md_reg, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) | - ((sdvo_pixel_multiply - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT)); - } else { - /* write it again -- the BIOS does, after all */ + if (!is_edp) { + I915_WRITE(fp_reg, fp); I915_WRITE(dpll_reg, dpll); + I915_READ(dpll_reg); + /* Wait for the clocks to stabilize. */ + udelay(150); + + if (IS_I965G(dev) && !IS_IGDNG(dev)) { + sdvo_pixel_multiply = adjusted_mode->clock / mode->clock; + I915_WRITE(dpll_md_reg, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) | + ((sdvo_pixel_multiply - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT)); + } else { + /* write it again -- the BIOS does, after all */ + I915_WRITE(dpll_reg, dpll); + } + I915_READ(dpll_reg); + /* Wait for the clocks to stabilize. */ + udelay(150); } - I915_READ(dpll_reg); - /* Wait for the clocks to stabilize. */ - udelay(150); I915_WRITE(htot_reg, (adjusted_mode->crtc_hdisplay - 1) | ((adjusted_mode->crtc_htotal - 1) << 16)); @@ -2482,10 +2582,14 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, I915_WRITE(link_m1_reg, m_n.link_m); I915_WRITE(link_n1_reg, m_n.link_n); - /* enable FDI RX PLL too */ - temp = I915_READ(fdi_rx_reg); - I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE); - udelay(200); + if (is_edp) { + igdng_set_pll_edp(crtc, adjusted_mode->clock); + } else { + /* enable FDI RX PLL too */ + temp = I915_READ(fdi_rx_reg); + I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE); + udelay(200); + } } I915_WRITE(pipeconf_reg, pipeconf); @@ -3083,6 +3187,9 @@ static void intel_setup_outputs(struct drm_device *dev) if (IS_IGDNG(dev)) { int found; + if (IS_MOBILE(dev) && (I915_READ(DP_A) & DP_DETECTED)) + intel_dp_init(dev, DP_A); + if (I915_READ(HDMIB) & PORT_DETECTED) { /* check SDVOB */ /* found = intel_sdvo_init(dev, HDMIB); */ @@ -3179,6 +3286,10 @@ static void intel_setup_outputs(struct drm_device *dev) (1 << 1)); clone_mask = (1 << INTEL_OUTPUT_DISPLAYPORT); break; + case INTEL_OUTPUT_EDP: + crtc_mask = (1 << 1); + clone_mask = (1 << INTEL_OUTPUT_EDP); + break; } encoder->possible_crtcs = crtc_mask; encoder->possible_clones = intel_connector_clones(dev, clone_mask); diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 0715911..a6ff15a 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -40,6 +40,8 @@ #define DP_LINK_CONFIGURATION_SIZE 9 +#define IS_eDP(i) ((i)->type == INTEL_OUTPUT_EDP) + struct intel_dp_priv { uint32_t output_reg; uint32_t DP; @@ -63,6 +65,19 @@ intel_dp_link_train(struct intel_output *intel_output, uint32_t DP, static void intel_dp_link_down(struct intel_output *intel_output, uint32_t DP); +void +intel_edp_link_config (struct intel_output *intel_output, + int *lane_num, int *link_bw) +{ + struct intel_dp_priv *dp_priv = intel_output->dev_priv; + + *lane_num = dp_priv->lane_count; + if (dp_priv->link_bw == DP_LINK_BW_1_62) + *link_bw = 162000; + else if (dp_priv->link_bw == DP_LINK_BW_2_7) + *link_bw = 270000; +} + static int intel_dp_max_lane_count(struct intel_output *intel_output) { @@ -206,9 +221,10 @@ intel_dp_aux_ch(struct intel_output *intel_output, * and would like to run at 2MHz. So, take the * hrawclk value and divide by 2 and use that */ - /* IGDNG: input clock fixed at 125Mhz, so aux_bit_clk always 62 */ - if (IS_IGDNG(dev)) - aux_clock_divider = 62; + if (IS_eDP(intel_output)) + aux_clock_divider = 225; /* eDP input clock at 450Mhz */ + else if (IS_IGDNG(dev)) + aux_clock_divider = 62; /* IGDNG: input clock fixed at 125Mhz */ else aux_clock_divider = intel_hrawclk(dev) / 2; @@ -579,8 +595,38 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, if (intel_crtc->pipe == 1) dp_priv->DP |= DP_PIPEB_SELECT; + + if (IS_eDP(intel_output)) { + /* don't miss out required setting for eDP */ + dp_priv->DP |= DP_PLL_ENABLE; + if (adjusted_mode->clock < 200000) + dp_priv->DP |= DP_PLL_FREQ_160MHZ; + else + dp_priv->DP |= DP_PLL_FREQ_270MHZ; + } } +static void igdng_edp_backlight_on (struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 pp; + + DRM_DEBUG("\n"); + pp = I915_READ(PCH_PP_CONTROL); + pp |= EDP_BLC_ENABLE; + I915_WRITE(PCH_PP_CONTROL, pp); +} + +static void igdng_edp_backlight_off (struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 pp; + + DRM_DEBUG("\n"); + pp = I915_READ(PCH_PP_CONTROL); + pp &= ~EDP_BLC_ENABLE; + I915_WRITE(PCH_PP_CONTROL, pp); +} static void intel_dp_dpms(struct drm_encoder *encoder, int mode) @@ -592,11 +638,17 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode) uint32_t dp_reg = I915_READ(dp_priv->output_reg); if (mode != DRM_MODE_DPMS_ON) { - if (dp_reg & DP_PORT_EN) + if (dp_reg & DP_PORT_EN) { intel_dp_link_down(intel_output, dp_priv->DP); + if (IS_eDP(intel_output)) + igdng_edp_backlight_off(dev); + } } else { - if (!(dp_reg & DP_PORT_EN)) + if (!(dp_reg & DP_PORT_EN)) { intel_dp_link_train(intel_output, dp_priv->DP, dp_priv->link_configuration); + if (IS_eDP(intel_output)) + igdng_edp_backlight_on(dev); + } } dp_priv->dpms_mode = mode; } @@ -958,12 +1010,23 @@ intel_dp_link_down(struct intel_output *intel_output, uint32_t DP) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_dp_priv *dp_priv = intel_output->dev_priv; + DRM_DEBUG("\n"); + + if (IS_eDP(intel_output)) { + DP &= ~DP_PLL_ENABLE; + I915_WRITE(dp_priv->output_reg, DP); + POSTING_READ(dp_priv->output_reg); + udelay(100); + } + DP &= ~DP_LINK_TRAIN_MASK; I915_WRITE(dp_priv->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE); POSTING_READ(dp_priv->output_reg); udelay(17000); + if (IS_eDP(intel_output)) + DP |= DP_LINK_TRAIN_OFF; I915_WRITE(dp_priv->output_reg, DP & ~DP_PORT_EN); POSTING_READ(dp_priv->output_reg); } @@ -1089,11 +1152,27 @@ intel_dp_detect(struct drm_connector *connector) static int intel_dp_get_modes(struct drm_connector *connector) { struct intel_output *intel_output = to_intel_output(connector); + struct drm_device *dev = intel_output->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int ret; /* We should parse the EDID data and find out if it has an audio sink */ - return intel_ddc_get_modes(intel_output); + ret = intel_ddc_get_modes(intel_output); + if (ret) + return ret; + + /* if eDP has no EDID, try to use fixed panel mode from VBT */ + if (IS_eDP(intel_output)) { + if (dev_priv->panel_fixed_mode != NULL) { + struct drm_display_mode *mode; + mode = drm_mode_duplicate(dev, dev_priv->panel_fixed_mode); + drm_mode_probed_add(connector, mode); + return 1; + } + } + return 0; } static void @@ -1170,7 +1249,10 @@ intel_dp_init(struct drm_device *dev, int output_reg) DRM_MODE_CONNECTOR_DisplayPort); drm_connector_helper_add(connector, &intel_dp_connector_helper_funcs); - intel_output->type = INTEL_OUTPUT_DISPLAYPORT; + if (output_reg == DP_A) + intel_output->type = INTEL_OUTPUT_EDP; + else + intel_output->type = INTEL_OUTPUT_DISPLAYPORT; connector->interlace_allowed = true; connector->doublescan_allowed = 0; @@ -1191,6 +1273,9 @@ intel_dp_init(struct drm_device *dev, int output_reg) /* Set up the DDC bus. */ switch (output_reg) { + case DP_A: + name = "DPDDC-A"; + break; case DP_B: case PCH_DP_B: name = "DPDDC-B"; @@ -1206,9 +1291,22 @@ intel_dp_init(struct drm_device *dev, int output_reg) } intel_dp_i2c_init(intel_output, name); + intel_output->ddc_bus = &dp_priv->adapter; intel_output->hot_plug = intel_dp_hot_plug; + if (output_reg == DP_A) { + /* initialize panel mode from VBT if available for eDP */ + if (dev_priv->lfp_lvds_vbt_mode) { + dev_priv->panel_fixed_mode = + drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode); + if (dev_priv->panel_fixed_mode) { + dev_priv->panel_fixed_mode->type |= + DRM_MODE_TYPE_PREFERRED; + } + } + } + /* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written * 0xd. Failure to do so will result in spurious interrupts being * generated on the port when a cable is not attached. diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 004541c..d6f92ea 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -55,6 +55,7 @@ #define INTEL_OUTPUT_TVOUT 5 #define INTEL_OUTPUT_HDMI 6 #define INTEL_OUTPUT_DISPLAYPORT 7 +#define INTEL_OUTPUT_EDP 8 #define INTEL_DVO_CHIP_NONE 0 #define INTEL_DVO_CHIP_LVDS 1 @@ -121,6 +122,8 @@ extern void intel_dp_init(struct drm_device *dev, int dp_reg); void intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); +extern void intel_edp_link_config (struct intel_output *, int *, int *); + extern void intel_crtc_load_lut(struct drm_crtc *crtc); extern void intel_encoder_prepare (struct drm_encoder *encoder); diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 43c7d9a..3f445a8 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -892,6 +892,10 @@ void intel_lvds_init(struct drm_device *dev) if (IS_IGDNG(dev)) { if ((I915_READ(PCH_LVDS) & LVDS_DETECTED) == 0) return; + if (dev_priv->edp_support) { + DRM_DEBUG("disable LVDS for eDP support\n"); + return; + } gpio = PCH_GPIOC; } -- cgit v0.10.2 From 67941da28d59cca6817d35823fcb1e3e4eed030e Mon Sep 17 00:00:00 2001 From: Zhenyu Wang Date: Fri, 24 Jul 2009 01:00:33 +0800 Subject: drm/i915: fix VGA detect on IGDNG Check FORCE_DETECT bit to be clear for the finish of hotplug detect process. Also check possible mono monitor which should also be marked as connected. Signed-off-by: Zhenyu Wang Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index d6a1a6e..4cf8e2e 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -156,6 +156,9 @@ static bool intel_igdng_crt_detect_hotplug(struct drm_connector *connector) temp = adpa = I915_READ(PCH_ADPA); + adpa &= ~ADPA_DAC_ENABLE; + I915_WRITE(PCH_ADPA, adpa); + adpa &= ~ADPA_CRT_HOTPLUG_MASK; adpa |= (ADPA_CRT_HOTPLUG_PERIOD_128 | @@ -169,13 +172,14 @@ static bool intel_igdng_crt_detect_hotplug(struct drm_connector *connector) DRM_DEBUG("pch crt adpa 0x%x", adpa); I915_WRITE(PCH_ADPA, adpa); - /* This might not be needed as not specified in spec...*/ - udelay(1000); + while ((I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) != 0) + ; /* Check the status to see if both blue and green are on now */ adpa = I915_READ(PCH_ADPA); - if ((adpa & ADPA_CRT_HOTPLUG_MONITOR_MASK) == - ADPA_CRT_HOTPLUG_MONITOR_COLOR) + adpa &= ADPA_CRT_HOTPLUG_MONITOR_MASK; + if ((adpa == ADPA_CRT_HOTPLUG_MONITOR_COLOR) || + (adpa == ADPA_CRT_HOTPLUG_MONITOR_MONO)) ret = true; else ret = false; -- cgit v0.10.2 From f360132626b11d0dc60814033873ca0e3111677c Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 22 Jul 2009 12:54:59 -0700 Subject: drm/i915: fix 845G FIFO size & burst length I had one report of flicker due to FIFO underruns on 845G. Scott was kind enough to test a few patches and report success with this one. Looks like 845G measures FIFO size slightly differently than other chips, and we were also clobbering the FIFO burst length. Fixing both of those issues gives him a healthy machine again. Note that we still only adjust plane A's watermark in the 830/845 case. If someone is willing to test we could support a bigger variety of dual-head 830/845 configurations with a bit more code. Fixes fdo bug #19304 (again). Reported-by: Scott Hansen Tested-by: Scott Hansen Signed-off-by: Jesse Barnes Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a9f1307..1da7b0b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2026,6 +2026,9 @@ static int intel_get_fifo_size(struct drm_device *dev, int plane) size = ((dsparb >> DSPARB_BEND_SHIFT) & 0x1ff) - (dsparb & 0x1ff); size >>= 1; /* Convert to cachelines */ + } else if (IS_845G(dev)) { + size = dsparb & 0x7f; + size >>= 2; /* Convert to cachelines */ } else { size = dsparb & 0x7f; size >>= 1; /* Convert to cachelines */ @@ -2125,14 +2128,16 @@ static void i830_update_wm(struct drm_device *dev, int planea_clock, int pixel_size) { struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t fwater_lo = I915_READ(FW_BLC) & MM_FIFO_WATERMARK; + uint32_t fwater_lo = I915_READ(FW_BLC) & ~0xfff; int planea_wm; i830_wm_info.fifo_size = intel_get_fifo_size(dev, 0); planea_wm = intel_calculate_wm(planea_clock, &i830_wm_info, pixel_size, latency_ns); - fwater_lo = fwater_lo | planea_wm; + fwater_lo |= (3<<8) | planea_wm; + + DRM_DEBUG("Setting FIFO watermarks - A: %d\n", planea_wm); I915_WRITE(FW_BLC, fwater_lo); } -- cgit v0.10.2 From bcae2ca81c4a085e3e0e8941b7c64f9aeb6fc05c Mon Sep 17 00:00:00 2001 From: "ling.ma@intel.com" Date: Mon, 20 Jul 2009 13:20:23 +0800 Subject: drm/i915: Set preferred mode for integrated TV according to TV format In order to get best possible quality image we chose 640x480 for NTSC, PAL and 480p, 1280x720 for 720p, 1920x1080 for 1080i/p TV format respectively. Signed-off-by: Ma Ling Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index a43c98e..da4ab4d 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1490,6 +1490,27 @@ static struct input_res { {"1920x1080", 1920, 1080}, }; +/* + * Chose preferred mode according to line number of TV format + */ +static void +intel_tv_chose_preferred_modes(struct drm_connector *connector, + struct drm_display_mode *mode_ptr) +{ + struct intel_output *intel_output = to_intel_output(connector); + const struct tv_mode *tv_mode = intel_tv_mode_find(intel_output); + + if (tv_mode->nbr_end < 480 && mode_ptr->vdisplay == 480) + mode_ptr->type |= DRM_MODE_TYPE_PREFERRED; + else if (tv_mode->nbr_end > 480) { + if (tv_mode->progressive == true && tv_mode->nbr_end < 720) { + if (mode_ptr->vdisplay == 720) + mode_ptr->type |= DRM_MODE_TYPE_PREFERRED; + } else if (mode_ptr->vdisplay == 1080) + mode_ptr->type |= DRM_MODE_TYPE_PREFERRED; + } +} + /** * Stub get_modes function. * @@ -1544,6 +1565,7 @@ intel_tv_get_modes(struct drm_connector *connector) mode_ptr->clock = (int) tmp; mode_ptr->type = DRM_MODE_TYPE_DRIVER; + intel_tv_chose_preferred_modes(connector, mode_ptr); drm_mode_probed_add(connector, mode_ptr); count++; } -- cgit v0.10.2 From fb7a46f3cc7d7dcf7c5edb3a38c84e3f730d7adb Mon Sep 17 00:00:00 2001 From: "ling.ma@intel.com" Date: Thu, 23 Jul 2009 17:11:34 +0800 Subject: drm/i915: Choose real sdvo output according to result from detection Baed on Eric's idea in order to handle multiple sdvo encoders we implement another approach to dynamically chose real one encoder after detection, which is contrasted with patch - drm/i915:Construct all possible sdvo outputs for sdvo encoder. Signed-off-by: Ma Ling Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 4f0c309..b68746f 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -55,6 +55,12 @@ struct intel_sdvo_priv { /* Pixel clock limitations reported by the SDVO device, in kHz */ int pixel_clock_min, pixel_clock_max; + /* + * For multiple function SDVO device, + * this is for current attached outputs. + */ + uint16_t attached_output; + /** * This is set if we're going to treat the device as TV-out. * @@ -114,6 +120,9 @@ struct intel_sdvo_priv { u32 save_SDVOX; }; +static bool +intel_sdvo_output_setup(struct intel_output *intel_output, uint16_t flags); + /** * Writes the SDVOB or SDVOC with the given value, but always writes both * SDVOB and SDVOC to work around apparent hardware issues (according to @@ -1435,6 +1444,39 @@ void intel_sdvo_set_hotplug(struct drm_connector *connector, int on) intel_sdvo_read_response(intel_output, &response, 2); } +static bool +intel_sdvo_multifunc_encoder(struct intel_output *intel_output) +{ + struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; + int caps = 0; + + if (sdvo_priv->caps.output_flags & + (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1)) + caps++; + if (sdvo_priv->caps.output_flags & + (SDVO_OUTPUT_RGB0 | SDVO_OUTPUT_RGB1)) + caps++; + if (sdvo_priv->caps.output_flags & + (SDVO_OUTPUT_SVID0 | SDVO_OUTPUT_SVID0)) + caps++; + if (sdvo_priv->caps.output_flags & + (SDVO_OUTPUT_CVBS0 | SDVO_OUTPUT_CVBS1)) + caps++; + if (sdvo_priv->caps.output_flags & + (SDVO_OUTPUT_YPRPB0 | SDVO_OUTPUT_YPRPB1)) + caps++; + + if (sdvo_priv->caps.output_flags & + (SDVO_OUTPUT_SCART0 | SDVO_OUTPUT_SCART1)) + caps++; + + if (sdvo_priv->caps.output_flags & + (SDVO_OUTPUT_LVDS0 | SDVO_OUTPUT_LVDS1)) + caps++; + + return (caps > 1); +} + static void intel_sdvo_hdmi_sink_detect(struct drm_connector *connector) { @@ -1453,23 +1495,31 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector) static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connector) { - u8 response[2]; + uint16_t response; u8 status; struct intel_output *intel_output = to_intel_output(connector); + struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0); status = intel_sdvo_read_response(intel_output, &response, 2); - DRM_DEBUG("SDVO response %d %d\n", response[0], response[1]); + DRM_DEBUG("SDVO response %d %d\n", response & 0xff, response >> 8); if (status != SDVO_CMD_STATUS_SUCCESS) return connector_status_unknown; - if ((response[0] != 0) || (response[1] != 0)) { - intel_sdvo_hdmi_sink_detect(connector); - return connector_status_connected; - } else + if (response == 0) return connector_status_disconnected; + + if (intel_sdvo_multifunc_encoder(intel_output) && + sdvo_priv->attached_output != response) { + if (sdvo_priv->controlled_output != response && + intel_sdvo_output_setup(intel_output, response) != true) + return connector_status_unknown; + sdvo_priv->attached_output = response; + } + intel_sdvo_hdmi_sink_detect(connector); + return connector_status_connected; } static void intel_sdvo_get_ddc_modes(struct drm_connector *connector) @@ -1866,16 +1916,101 @@ intel_sdvo_get_slave_addr(struct drm_device *dev, int output_device) return 0x72; } +static bool +intel_sdvo_output_setup(struct intel_output *intel_output, uint16_t flags) +{ + struct drm_connector *connector = &intel_output->base; + struct drm_encoder *encoder = &intel_output->enc; + struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; + bool ret = true, registered = false; + + sdvo_priv->is_tv = false; + intel_output->needs_tv_clock = false; + sdvo_priv->is_lvds = false; + + if (device_is_registered(&connector->kdev)) { + drm_sysfs_connector_remove(connector); + registered = true; + } + + if (flags & + (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1)) { + if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS0) + sdvo_priv->controlled_output = SDVO_OUTPUT_TMDS0; + else + sdvo_priv->controlled_output = SDVO_OUTPUT_TMDS1; + + encoder->encoder_type = DRM_MODE_ENCODER_TMDS; + connector->connector_type = DRM_MODE_CONNECTOR_DVID; + + if (intel_sdvo_get_supp_encode(intel_output, + &sdvo_priv->encode) && + intel_sdvo_get_digital_encoding_mode(intel_output) && + sdvo_priv->is_hdmi) { + /* enable hdmi encoding mode if supported */ + intel_sdvo_set_encode(intel_output, SDVO_ENCODE_HDMI); + intel_sdvo_set_colorimetry(intel_output, + SDVO_COLORIMETRY_RGB256); + connector->connector_type = DRM_MODE_CONNECTOR_HDMIA; + } + } else if (flags & SDVO_OUTPUT_SVID0) { + + sdvo_priv->controlled_output = SDVO_OUTPUT_SVID0; + encoder->encoder_type = DRM_MODE_ENCODER_TVDAC; + connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO; + sdvo_priv->is_tv = true; + intel_output->needs_tv_clock = true; + } else if (flags & SDVO_OUTPUT_RGB0) { + + sdvo_priv->controlled_output = SDVO_OUTPUT_RGB0; + encoder->encoder_type = DRM_MODE_ENCODER_DAC; + connector->connector_type = DRM_MODE_CONNECTOR_VGA; + } else if (flags & SDVO_OUTPUT_RGB1) { + + sdvo_priv->controlled_output = SDVO_OUTPUT_RGB1; + encoder->encoder_type = DRM_MODE_ENCODER_DAC; + connector->connector_type = DRM_MODE_CONNECTOR_VGA; + } else if (flags & SDVO_OUTPUT_LVDS0) { + + sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS0; + encoder->encoder_type = DRM_MODE_ENCODER_LVDS; + connector->connector_type = DRM_MODE_CONNECTOR_LVDS; + sdvo_priv->is_lvds = true; + } else if (flags & SDVO_OUTPUT_LVDS1) { + + sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS1; + encoder->encoder_type = DRM_MODE_ENCODER_LVDS; + connector->connector_type = DRM_MODE_CONNECTOR_LVDS; + sdvo_priv->is_lvds = true; + } else { + + unsigned char bytes[2]; + + sdvo_priv->controlled_output = 0; + memcpy(bytes, &sdvo_priv->caps.output_flags, 2); + DRM_DEBUG_KMS(I915_SDVO, + "%s: Unknown SDVO output type (0x%02x%02x)\n", + SDVO_NAME(sdvo_priv), + bytes[0], bytes[1]); + ret = false; + } + + if (ret && registered) + ret = drm_sysfs_connector_add(connector) == 0 ? true : false; + + + return ret; + +} + bool intel_sdvo_init(struct drm_device *dev, int output_device) { struct drm_connector *connector; struct intel_output *intel_output; struct intel_sdvo_priv *sdvo_priv; - int connector_type; u8 ch[0x40]; int i; - int encoder_type; intel_output = kcalloc(sizeof(struct intel_output)+sizeof(struct intel_sdvo_priv), 1, GFP_KERNEL); if (!intel_output) { @@ -1925,88 +2060,28 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) intel_output->ddc_bus->algo = &intel_sdvo_i2c_bit_algo; /* In defaut case sdvo lvds is false */ - sdvo_priv->is_lvds = false; intel_sdvo_get_capabilities(intel_output, &sdvo_priv->caps); - if (sdvo_priv->caps.output_flags & - (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1)) { - if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS0) - sdvo_priv->controlled_output = SDVO_OUTPUT_TMDS0; - else - sdvo_priv->controlled_output = SDVO_OUTPUT_TMDS1; - - encoder_type = DRM_MODE_ENCODER_TMDS; - connector_type = DRM_MODE_CONNECTOR_DVID; - - if (intel_sdvo_get_supp_encode(intel_output, - &sdvo_priv->encode) && - intel_sdvo_get_digital_encoding_mode(intel_output) && - sdvo_priv->is_hdmi) { - /* enable hdmi encoding mode if supported */ - intel_sdvo_set_encode(intel_output, SDVO_ENCODE_HDMI); - intel_sdvo_set_colorimetry(intel_output, - SDVO_COLORIMETRY_RGB256); - connector_type = DRM_MODE_CONNECTOR_HDMIA; - } - } - else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_SVID0) - { - sdvo_priv->controlled_output = SDVO_OUTPUT_SVID0; - encoder_type = DRM_MODE_ENCODER_TVDAC; - connector_type = DRM_MODE_CONNECTOR_SVIDEO; - sdvo_priv->is_tv = true; - intel_output->needs_tv_clock = true; - } - else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB0) - { - sdvo_priv->controlled_output = SDVO_OUTPUT_RGB0; - encoder_type = DRM_MODE_ENCODER_DAC; - connector_type = DRM_MODE_CONNECTOR_VGA; - } - else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB1) - { - sdvo_priv->controlled_output = SDVO_OUTPUT_RGB1; - encoder_type = DRM_MODE_ENCODER_DAC; - connector_type = DRM_MODE_CONNECTOR_VGA; - } - else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_LVDS0) - { - sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS0; - encoder_type = DRM_MODE_ENCODER_LVDS; - connector_type = DRM_MODE_CONNECTOR_LVDS; - sdvo_priv->is_lvds = true; - } - else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_LVDS1) - { - sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS1; - encoder_type = DRM_MODE_ENCODER_LVDS; - connector_type = DRM_MODE_CONNECTOR_LVDS; - sdvo_priv->is_lvds = true; - } - else - { - unsigned char bytes[2]; - - sdvo_priv->controlled_output = 0; - memcpy (bytes, &sdvo_priv->caps.output_flags, 2); - DRM_DEBUG_KMS(I915_SDVO, - "%s: Unknown SDVO output type (0x%02x%02x)\n", - SDVO_NAME(sdvo_priv), - bytes[0], bytes[1]); - encoder_type = DRM_MODE_ENCODER_NONE; - connector_type = DRM_MODE_CONNECTOR_Unknown; + if (intel_sdvo_output_setup(intel_output, + sdvo_priv->caps.output_flags) != true) { + DRM_DEBUG("SDVO output failed to setup on SDVO%c\n", + output_device == SDVOB ? 'B' : 'C'); goto err_i2c; } + connector = &intel_output->base; drm_connector_init(dev, connector, &intel_sdvo_connector_funcs, - connector_type); + connector->connector_type); + drm_connector_helper_add(connector, &intel_sdvo_connector_helper_funcs); connector->interlace_allowed = 0; connector->doublescan_allowed = 0; connector->display_info.subpixel_order = SubPixelHorizontalRGB; - drm_encoder_init(dev, &intel_output->enc, &intel_sdvo_enc_funcs, encoder_type); + drm_encoder_init(dev, &intel_output->enc, + &intel_sdvo_enc_funcs, intel_output->enc.encoder_type); + drm_encoder_helper_add(&intel_output->enc, &intel_sdvo_helper_funcs); drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc); -- cgit v0.10.2 From 0c997c0eaac8c68fa23719617484dae29bddaedd Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 22 Jul 2009 00:33:06 +0200 Subject: S3C24XX: GPIO: Fix pin range check in s3c_gpiolib_getchip In the s3c_gpiolib_getchip implementation for s3c24xx the check whether a pin is in the gpio banks range is reversed. Thus the function returns NULL for valid pins and the gpio chip if its not valid. As a result gpio states are not saved/restored properly during suspend/resume. Signed-off-by: Ben Dooks diff --git a/arch/arm/mach-s3c2410/include/mach/gpio-core.h b/arch/arm/mach-s3c2410/include/mach/gpio-core.h index 8fe1920..f8b879a 100644 --- a/arch/arm/mach-s3c2410/include/mach/gpio-core.h +++ b/arch/arm/mach-s3c2410/include/mach/gpio-core.h @@ -28,7 +28,7 @@ static inline struct s3c_gpio_chip *s3c_gpiolib_getchip(unsigned int pin) return NULL; chip = &s3c24xx_gpios[pin/32]; - return (S3C2410_GPIO_OFFSET(pin) > chip->chip.ngpio) ? chip : NULL; + return (S3C2410_GPIO_OFFSET(pin) < chip->chip.ngpio) ? chip : NULL; } #endif /* __ASM_ARCH_GPIO_CORE_H */ -- cgit v0.10.2 From 1d91e1a296244690461a7c36d71710dfbabbc219 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 15 Jul 2009 13:03:34 +0100 Subject: S3C64XX: Fix get_rate() for ARMCLK If the requested clock is faster than the parent clock then the parent clock is the closest we can get to the request so we need to return that instead of the requested clock. Signed-off-by: Mark Brown Signed-off-by: Ben Dooks diff --git a/arch/arm/plat-s3c64xx/s3c6400-clock.c b/arch/arm/plat-s3c64xx/s3c6400-clock.c index 1debc1f..f8165e6 100644 --- a/arch/arm/plat-s3c64xx/s3c6400-clock.c +++ b/arch/arm/plat-s3c64xx/s3c6400-clock.c @@ -153,7 +153,7 @@ static unsigned long s3c64xx_clk_arm_round_rate(struct clk *clk, u32 div; if (parent < rate) - return rate; + return parent; div = (parent / rate) - 1; if (div > armclk_mask) -- cgit v0.10.2 From 9b71de49b030ad8fd4d13d38571b5c42dc9ed8dd Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 15 Jul 2009 13:03:35 +0100 Subject: S3C64XX: Fix ARMCLK configuration The value of armclk_mask needs to be inverted for use as a mask on the register value when updating ARM_RATIO. This is critical for cpufreq support, without it attempts to scale the frequency of the core trash pretty much the entire clock tree. Signed-off-by: Mark Brown Signed-off-by: Ben Dooks diff --git a/arch/arm/plat-s3c64xx/s3c6400-clock.c b/arch/arm/plat-s3c64xx/s3c6400-clock.c index f8165e6..febac19 100644 --- a/arch/arm/plat-s3c64xx/s3c6400-clock.c +++ b/arch/arm/plat-s3c64xx/s3c6400-clock.c @@ -175,7 +175,7 @@ static int s3c64xx_clk_arm_set_rate(struct clk *clk, unsigned long rate) div = clk_get_rate(clk->parent) / rate; val = __raw_readl(S3C_CLK_DIV0); - val &= armclk_mask; + val &= ~armclk_mask; val |= (div - 1); __raw_writel(val, S3C_CLK_DIV0); -- cgit v0.10.2 From e624859e7eb6ae2930df3923af73406dc6ccdad8 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 27 Jul 2009 22:11:59 +0100 Subject: ARM: 5624/1: Document cache aliasing region Augment the memory.txt file for ARM to list the cache aliasing region ffff4000-fffffff. Signed-off-by: Linus Walleij Signed-off-by: Russell King diff --git a/Documentation/arm/memory.txt b/Documentation/arm/memory.txt index 43cb100..9d58c7c5 100644 --- a/Documentation/arm/memory.txt +++ b/Documentation/arm/memory.txt @@ -21,6 +21,8 @@ ffff8000 ffffffff copy_user_page / clear_user_page use. For SA11xx and Xscale, this is used to setup a minicache mapping. +ffff4000 ffffffff cache aliasing on ARMv6 and later CPUs. + ffff1000 ffff7fff Reserved. Platforms must not use this address range. -- cgit v0.10.2 From 3ef7143d2287b21e09e00a25a8cb4fbdcf0c6c4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 29 Jul 2009 19:31:30 +0100 Subject: ARM: 5627/1: Fix restoring of lr at the end of mcount MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After ftrace_trace_function is called r1 is probably clobbered so don't try to use its value for restoring. This was introduced in v2.6.29~38^2~7 Signed-off-by: Uwe Kleine-König Signed-off-by: Russell King diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index 366e509..8c3de1a 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -148,7 +148,7 @@ trace: sub r0, r0, #MCOUNT_INSN_SIZE mov lr, pc mov pc, r2 - mov lr, r1 @ restore lr + ldr lr, [fp, #-4] @ restore lr ldmia sp!, {r0-r3, pc} #endif /* CONFIG_DYNAMIC_FTRACE */ -- cgit v0.10.2 From 320145fac91955ee35a6af7e1c2b42388a17b3d8 Mon Sep 17 00:00:00 2001 From: Yegor Yefremov Date: Thu, 9 Jul 2009 08:48:03 +0100 Subject: ARM: 5597/1: [PCI] reset all internal hardware prior PCI initialization Make software reset to avoid freeze if PCI bus was messed up Signed-off-by: Yegor Yefremov Acked-by: Andrew Victor Signed-off-by: Russell King diff --git a/arch/arm/mach-ks8695/pci.c b/arch/arm/mach-ks8695/pci.c index f5ebcc0..7849966 100644 --- a/arch/arm/mach-ks8695/pci.c +++ b/arch/arm/mach-ks8695/pci.c @@ -245,6 +245,9 @@ static int ks8695_pci_fault(unsigned long addr, unsigned int fsr, struct pt_regs static void __init ks8695_pci_preinit(void) { + /* make software reset to avoid freeze if PCI bus was messed up */ + __raw_writel(0x80000000, KS8695_PCI_VA + KS8695_PBCS); + /* stage 1 initialization, subid, subdevice = 0x0001 */ __raw_writel(0x00010001, KS8695_PCI_VA + KS8695_CRCSID); -- cgit v0.10.2 From 2b8d33f714477d1719f96459370037993520de84 Mon Sep 17 00:00:00 2001 From: "ling.ma@intel.com" Date: Wed, 29 Jul 2009 11:31:18 +0800 Subject: drm/i915: Return disconnected for SDVO DVI when there's no digital EDID. The patch fixed a bug on MP965-D. When VGA is connected to a DVI-I connector, it incorrectly shows sdvo dvi as connected. Signed-off-by: Ma Ling [anholt: hand-resolved against previous commit and fixed up commit message] Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index b68746f..5371d93 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -31,6 +31,7 @@ #include "drm.h" #include "drm_crtc.h" #include "intel_drv.h" +#include "drm_edid.h" #include "i915_drm.h" #include "i915_drv.h" #include "intel_sdvo_regs.h" @@ -1477,20 +1478,35 @@ intel_sdvo_multifunc_encoder(struct intel_output *intel_output) return (caps > 1); } -static void -intel_sdvo_hdmi_sink_detect(struct drm_connector *connector) +enum drm_connector_status +intel_sdvo_hdmi_sink_detect(struct drm_connector *connector, u16 response) { struct intel_output *intel_output = to_intel_output(connector); struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; + enum drm_connector_status status = connector_status_connected; struct edid *edid = NULL; edid = drm_get_edid(&intel_output->base, intel_output->ddc_bus); if (edid != NULL) { - sdvo_priv->is_hdmi = drm_detect_hdmi_monitor(edid); + /* Don't report the output as connected if it's a DVI-I + * connector with a non-digital EDID coming out. + */ + if (response & (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1)) { + if (edid->input & DRM_EDID_INPUT_DIGITAL) + sdvo_priv->is_hdmi = + drm_detect_hdmi_monitor(edid); + else + status = connector_status_disconnected; + } + kfree(edid); intel_output->base.display_info.raw_edid = NULL; - } + + } else if (response & (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1)) + status = connector_status_disconnected; + + return status; } static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connector) @@ -1518,8 +1534,7 @@ static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connect return connector_status_unknown; sdvo_priv->attached_output = response; } - intel_sdvo_hdmi_sink_detect(connector); - return connector_status_connected; + return intel_sdvo_hdmi_sink_detect(connector, response); } static void intel_sdvo_get_ddc_modes(struct drm_connector *connector) -- cgit v0.10.2 From 0c2e39525b3b53a97a0202c5f35058147e53977e Mon Sep 17 00:00:00 2001 From: "ling.ma@intel.com" Date: Fri, 17 Jul 2009 11:44:30 +0800 Subject: drm/i915: Add support for dual-channel LVDS on 8xx. This corresponds to a fix to UMS back in 2007. Fixes fd.o bug #20115. Signed-off-by: Ma Ling Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1da7b0b..d6fce21 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -90,7 +90,7 @@ struct intel_limit { #define I8XX_P2_SLOW 4 #define I8XX_P2_FAST 2 #define I8XX_P2_LVDS_SLOW 14 -#define I8XX_P2_LVDS_FAST 14 /* No fast option */ +#define I8XX_P2_LVDS_FAST 7 #define I8XX_P2_SLOW_LIMIT 165000 #define I9XX_DOT_MIN 20000 -- cgit v0.10.2 From 165f5f64199f972a21f21effc125d89ed2488e58 Mon Sep 17 00:00:00 2001 From: Peter Korsgaard Date: Wed, 1 Jul 2009 17:47:08 +0200 Subject: ARM: S3C: PWM fix for low duty cycle The pwm hardware only checks the compare register after a decrement, so the pin never toggles if tcmp = tcnt. This happens when a very low duty cycle is requested. Fix it by always ensuring that tcmp < tcnt. Signed-off-by: Peter Korsgaard Signed-off-by: Ben Dooks diff --git a/arch/arm/plat-s3c24xx/pwm.c b/arch/arm/plat-s3c24xx/pwm.c index 0120b76..82a6d4d 100644 --- a/arch/arm/plat-s3c24xx/pwm.c +++ b/arch/arm/plat-s3c24xx/pwm.c @@ -246,6 +246,10 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) tcmp = duty_ns / tin_ns; tcmp = tcnt - tcmp; + /* the pwm hw only checks the compare register after a decrement, + so the pin never toggles if tcmp = tcnt */ + if (tcmp == tcnt) + tcmp--; pwm_dbg(pwm, "tin_ns=%lu, tcmp=%ld/%lu\n", tin_ns, tcmp, tcnt); -- cgit v0.10.2 From 8fe70a5f7167e02bbc18086970f0e92a5e55b80d Mon Sep 17 00:00:00 2001 From: Ramax Lo Date: Thu, 9 Jul 2009 16:28:33 +0800 Subject: ARM: S3C24XX: serial: Fix section mismatch warnings During kernel build process, the following warning was found: WARNING: drivers/serial/built-in.o(.data+0x304): Section mismatch in reference from the variable s3c2440_serial_drv to the function .devexit.text:s3c24xx_serial_remove() The variable s3c2440_serial_drv references the function __devexit s3c24xx_serial_remove() If the reference is valid then annotate the variable with __exit* (see linux/init.h) or name the variable: *driver, *_template, *_timer, *_sht, *_ops, *_probe, *_probe_one, *_console, The same warning happened for s3c241x platform. We rename variables to avoid these warnings. These changes also apply to s3c2400 & s3c24a0 for consistency. Signed-off-by: Ramax Lo Signed-off-by: Ben Dooks diff --git a/drivers/serial/s3c2400.c b/drivers/serial/s3c2400.c index fb00ed5..fed1a9a 100644 --- a/drivers/serial/s3c2400.c +++ b/drivers/serial/s3c2400.c @@ -76,7 +76,7 @@ static int s3c2400_serial_probe(struct platform_device *dev) return s3c24xx_serial_probe(dev, &s3c2400_uart_inf); } -static struct platform_driver s3c2400_serial_drv = { +static struct platform_driver s3c2400_serial_driver = { .probe = s3c2400_serial_probe, .remove = __devexit_p(s3c24xx_serial_remove), .driver = { @@ -85,16 +85,16 @@ static struct platform_driver s3c2400_serial_drv = { }, }; -s3c24xx_console_init(&s3c2400_serial_drv, &s3c2400_uart_inf); +s3c24xx_console_init(&s3c2400_serial_driver, &s3c2400_uart_inf); static inline int s3c2400_serial_init(void) { - return s3c24xx_serial_init(&s3c2400_serial_drv, &s3c2400_uart_inf); + return s3c24xx_serial_init(&s3c2400_serial_driver, &s3c2400_uart_inf); } static inline void s3c2400_serial_exit(void) { - platform_driver_unregister(&s3c2400_serial_drv); + platform_driver_unregister(&s3c2400_serial_driver); } module_init(s3c2400_serial_init); diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c index b5d7cbc..c99f082 100644 --- a/drivers/serial/s3c2410.c +++ b/drivers/serial/s3c2410.c @@ -88,7 +88,7 @@ static int s3c2410_serial_probe(struct platform_device *dev) return s3c24xx_serial_probe(dev, &s3c2410_uart_inf); } -static struct platform_driver s3c2410_serial_drv = { +static struct platform_driver s3c2410_serial_driver = { .probe = s3c2410_serial_probe, .remove = __devexit_p(s3c24xx_serial_remove), .driver = { @@ -97,16 +97,16 @@ static struct platform_driver s3c2410_serial_drv = { }, }; -s3c24xx_console_init(&s3c2410_serial_drv, &s3c2410_uart_inf); +s3c24xx_console_init(&s3c2410_serial_driver, &s3c2410_uart_inf); static int __init s3c2410_serial_init(void) { - return s3c24xx_serial_init(&s3c2410_serial_drv, &s3c2410_uart_inf); + return s3c24xx_serial_init(&s3c2410_serial_driver, &s3c2410_uart_inf); } static void __exit s3c2410_serial_exit(void) { - platform_driver_unregister(&s3c2410_serial_drv); + platform_driver_unregister(&s3c2410_serial_driver); } module_init(s3c2410_serial_init); diff --git a/drivers/serial/s3c2412.c b/drivers/serial/s3c2412.c index 11dcb90..6e057d8 100644 --- a/drivers/serial/s3c2412.c +++ b/drivers/serial/s3c2412.c @@ -121,7 +121,7 @@ static int s3c2412_serial_probe(struct platform_device *dev) return s3c24xx_serial_probe(dev, &s3c2412_uart_inf); } -static struct platform_driver s3c2412_serial_drv = { +static struct platform_driver s3c2412_serial_driver = { .probe = s3c2412_serial_probe, .remove = __devexit_p(s3c24xx_serial_remove), .driver = { @@ -130,16 +130,16 @@ static struct platform_driver s3c2412_serial_drv = { }, }; -s3c24xx_console_init(&s3c2412_serial_drv, &s3c2412_uart_inf); +s3c24xx_console_init(&s3c2412_serial_driver, &s3c2412_uart_inf); static inline int s3c2412_serial_init(void) { - return s3c24xx_serial_init(&s3c2412_serial_drv, &s3c2412_uart_inf); + return s3c24xx_serial_init(&s3c2412_serial_driver, &s3c2412_uart_inf); } static inline void s3c2412_serial_exit(void) { - platform_driver_unregister(&s3c2412_serial_drv); + platform_driver_unregister(&s3c2412_serial_driver); } module_init(s3c2412_serial_init); diff --git a/drivers/serial/s3c2440.c b/drivers/serial/s3c2440.c index 06c5b0c..69ff5d3 100644 --- a/drivers/serial/s3c2440.c +++ b/drivers/serial/s3c2440.c @@ -151,7 +151,7 @@ static int s3c2440_serial_probe(struct platform_device *dev) return s3c24xx_serial_probe(dev, &s3c2440_uart_inf); } -static struct platform_driver s3c2440_serial_drv = { +static struct platform_driver s3c2440_serial_driver = { .probe = s3c2440_serial_probe, .remove = __devexit_p(s3c24xx_serial_remove), .driver = { @@ -160,16 +160,16 @@ static struct platform_driver s3c2440_serial_drv = { }, }; -s3c24xx_console_init(&s3c2440_serial_drv, &s3c2440_uart_inf); +s3c24xx_console_init(&s3c2440_serial_driver, &s3c2440_uart_inf); static int __init s3c2440_serial_init(void) { - return s3c24xx_serial_init(&s3c2440_serial_drv, &s3c2440_uart_inf); + return s3c24xx_serial_init(&s3c2440_serial_driver, &s3c2440_uart_inf); } static void __exit s3c2440_serial_exit(void) { - platform_driver_unregister(&s3c2440_serial_drv); + platform_driver_unregister(&s3c2440_serial_driver); } module_init(s3c2440_serial_init); diff --git a/drivers/serial/s3c24a0.c b/drivers/serial/s3c24a0.c index 786a067..26c49e1 100644 --- a/drivers/serial/s3c24a0.c +++ b/drivers/serial/s3c24a0.c @@ -92,7 +92,7 @@ static int s3c24a0_serial_probe(struct platform_device *dev) return s3c24xx_serial_probe(dev, &s3c24a0_uart_inf); } -static struct platform_driver s3c24a0_serial_drv = { +static struct platform_driver s3c24a0_serial_driver = { .probe = s3c24a0_serial_probe, .remove = __devexit_p(s3c24xx_serial_remove), .driver = { @@ -101,16 +101,16 @@ static struct platform_driver s3c24a0_serial_drv = { }, }; -s3c24xx_console_init(&s3c24a0_serial_drv, &s3c24a0_uart_inf); +s3c24xx_console_init(&s3c24a0_serial_driver, &s3c24a0_uart_inf); static int __init s3c24a0_serial_init(void) { - return s3c24xx_serial_init(&s3c24a0_serial_drv, &s3c24a0_uart_inf); + return s3c24xx_serial_init(&s3c24a0_serial_driver, &s3c24a0_uart_inf); } static void __exit s3c24a0_serial_exit(void) { - platform_driver_unregister(&s3c24a0_serial_drv); + platform_driver_unregister(&s3c24a0_serial_driver); } module_init(s3c24a0_serial_init); -- cgit v0.10.2 From 909db80297ba65699a77d877f7bf618ba960f6fc Mon Sep 17 00:00:00 2001 From: Ramax Lo Date: Fri, 10 Jul 2009 19:30:56 +0800 Subject: ARM: S3C64XX: serial: Fix section mismatch warning Rename the structure to avoid the following warning: WARNING: vmlinux.o(.data+0x11ef4): Section mismatch in reference from the variable s3c6400_serial_drv to the function .devexit.text:s3c24xx_serial_remove() The variable s3c6400_serial_drv references the function __devexit s3c24xx_serial_remove() If the reference is valid then annotate the variable with __exit* (see linux/init.h) or name the variable: *driver, *_template, *_timer, *_sht, *_ops, *_probe, *_probe_one, *_console, Signed-off-by: Ramax Lo Signed-off-by: Ben Dooks diff --git a/drivers/serial/s3c6400.c b/drivers/serial/s3c6400.c index 48f1a37..4be92ab 100644 --- a/drivers/serial/s3c6400.c +++ b/drivers/serial/s3c6400.c @@ -122,7 +122,7 @@ static int s3c6400_serial_probe(struct platform_device *dev) return s3c24xx_serial_probe(dev, &s3c6400_uart_inf); } -static struct platform_driver s3c6400_serial_drv = { +static struct platform_driver s3c6400_serial_driver = { .probe = s3c6400_serial_probe, .remove = __devexit_p(s3c24xx_serial_remove), .driver = { @@ -131,16 +131,16 @@ static struct platform_driver s3c6400_serial_drv = { }, }; -s3c24xx_console_init(&s3c6400_serial_drv, &s3c6400_uart_inf); +s3c24xx_console_init(&s3c6400_serial_driver, &s3c6400_uart_inf); static int __init s3c6400_serial_init(void) { - return s3c24xx_serial_init(&s3c6400_serial_drv, &s3c6400_uart_inf); + return s3c24xx_serial_init(&s3c6400_serial_driver, &s3c6400_uart_inf); } static void __exit s3c6400_serial_exit(void) { - platform_driver_unregister(&s3c6400_serial_drv); + platform_driver_unregister(&s3c6400_serial_driver); } module_init(s3c6400_serial_init); -- cgit v0.10.2 From 6606bb97e146a387932efee263745b7240a11193 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Fri, 31 Jul 2009 11:03:58 -0400 Subject: Btrfs: fix btrfs_remove_from_free_space corner case Yan Zheng hit a problem where we tried to remove some free space but failed because we couldn't find the free space entry. This is because the free space was held within a bitmap that had a starting offset well before the actual offset of the free space, and there were free space extents that were in the same range as that offset, so tree_search_offset returned with NULL because we couldn't find a free space extent that had that offset. This is fixed by making sure that if we fail to find the entry, we re-search again with bitmap_only set to 1 and do an offset_to_bitmap so we can get the appropriate bitmap. A similar problem happens in btrfs_alloc_from_bitmap for the clustering code, but that is not as bad since we will just go and redo our cluster allocation. Also this adds some debugging checks to make sure that the free space we are trying to remove from the bitmap is in fact there. This can probably go away after a while, but since this code is only used by the tree-logging stuff it would be nice to run with it for a while to make sure there are no problems. Signed-off-by: Josef Bacik Signed-off-by: Chris Mason diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c index af99b78..5edcee3 100644 --- a/fs/btrfs/free-space-cache.c +++ b/fs/btrfs/free-space-cache.c @@ -414,11 +414,29 @@ static noinline int remove_from_bitmap(struct btrfs_block_group_cache *block_gro u64 *offset, u64 *bytes) { u64 end; + u64 search_start, search_bytes; + int ret; again: end = bitmap_info->offset + (u64)(BITS_PER_BITMAP * block_group->sectorsize) - 1; + /* + * XXX - this can go away after a few releases. + * + * since the only user of btrfs_remove_free_space is the tree logging + * stuff, and the only way to test that is under crash conditions, we + * want to have this debug stuff here just in case somethings not + * working. Search the bitmap for the space we are trying to use to + * make sure its actually there. If its not there then we need to stop + * because something has gone wrong. + */ + search_start = *offset; + search_bytes = *bytes; + ret = search_bitmap(block_group, bitmap_info, &search_start, + &search_bytes); + BUG_ON(ret < 0 || search_start != *offset); + if (*offset > bitmap_info->offset && *offset + *bytes > end) { bitmap_clear_bits(block_group, bitmap_info, *offset, end - *offset + 1); @@ -430,6 +448,7 @@ again: } if (*bytes) { + struct rb_node *next = rb_next(&bitmap_info->offset_index); if (!bitmap_info->bytes) { unlink_free_space(block_group, bitmap_info); kfree(bitmap_info->bitmap); @@ -438,16 +457,36 @@ again: recalculate_thresholds(block_group); } - bitmap_info = tree_search_offset(block_group, - offset_to_bitmap(block_group, - *offset), - 1, 0); - if (!bitmap_info) + /* + * no entry after this bitmap, but we still have bytes to + * remove, so something has gone wrong. + */ + if (!next) return -EINVAL; + bitmap_info = rb_entry(next, struct btrfs_free_space, + offset_index); + + /* + * if the next entry isn't a bitmap we need to return to let the + * extent stuff do its work. + */ if (!bitmap_info->bitmap) return -EAGAIN; + /* + * Ok the next item is a bitmap, but it may not actually hold + * the information for the rest of this free space stuff, so + * look for it, and if we don't find it return so we can try + * everything over again. + */ + search_start = *offset; + search_bytes = *bytes; + ret = search_bitmap(block_group, bitmap_info, &search_start, + &search_bytes); + if (ret < 0 || search_start != *offset) + return -EAGAIN; + goto again; } else if (!bitmap_info->bytes) { unlink_free_space(block_group, bitmap_info); @@ -644,8 +683,17 @@ int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group, again: info = tree_search_offset(block_group, offset, 0, 0); if (!info) { - WARN_ON(1); - goto out_lock; + /* + * oops didn't find an extent that matched the space we wanted + * to remove, look for a bitmap instead + */ + info = tree_search_offset(block_group, + offset_to_bitmap(block_group, offset), + 1, 0); + if (!info) { + WARN_ON(1); + goto out_lock; + } } if (info->bytes < bytes && rb_next(&info->offset_index)) { @@ -957,8 +1005,15 @@ static u64 btrfs_alloc_from_bitmap(struct btrfs_block_group_cache *block_group, if (cluster->block_group != block_group) goto out; - entry = tree_search_offset(block_group, search_start, 0, 0); - + /* + * search_start is the beginning of the bitmap, but at some point it may + * be a good idea to point to the actual start of the free area in the + * bitmap, so do the offset_to_bitmap trick anyway, and set bitmap_only + * to 1 to make sure we get the bitmap entry + */ + entry = tree_search_offset(block_group, + offset_to_bitmap(block_group, search_start), + 1, 0); if (!entry || !entry->bitmap) goto out; -- cgit v0.10.2 From 013f1b12f4fc479f697acae2f31bad220162cd03 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Fri, 31 Jul 2009 14:57:55 -0400 Subject: Btrfs: make sure the async caching thread advances the key The async caching thread can end up looping forever if a given search puts it at the last key in a leaf. It will end up calling btrfs_next_leaf and then checking if it needs to politely drop the read semaphore. Most of the time this looping isn't noticed because it is able to make progress the next time around. But, during log replay, we wait on the async caching thread to finish, and the async thread is waiting on the commit, and no progress is really made. The fix used here is to copy the key out of the next leaf, that way our search lands there properly. Signed-off-by: Chris Mason diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index dc84dae..72a2b9c 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -265,10 +265,6 @@ static int caching_kthread(void *data) atomic_inc(&block_group->space_info->caching_threads); last = max_t(u64, block_group->key.objectid, BTRFS_SUPER_INFO_OFFSET); -again: - /* need to make sure the commit_root doesn't disappear */ - down_read(&fs_info->extent_commit_sem); - /* * We don't want to deadlock with somebody trying to allocate a new * extent for the extent root while also trying to search the extent @@ -282,6 +278,10 @@ again: key.objectid = last; key.offset = 0; btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY); +again: + /* need to make sure the commit_root doesn't disappear */ + down_read(&fs_info->extent_commit_sem); + ret = btrfs_search_slot(NULL, fs_info->extent_root, &key, path, 0, 0); if (ret < 0) goto err; @@ -304,6 +304,19 @@ again: if (need_resched() || btrfs_transaction_in_commit(fs_info)) { + leaf = path->nodes[0]; + + /* this shouldn't happen, but if the + * leaf is empty just move on. + */ + if (btrfs_header_nritems(leaf) == 0) + break; + /* + * we need to copy the key out so that + * we are sure the next search advances + * us forward in the btree. + */ + btrfs_item_key_to_cpu(leaf, &key, 0); btrfs_release_path(fs_info->extent_root, path); up_read(&fs_info->extent_commit_sem); schedule_timeout(1); -- cgit v0.10.2 From 7699ad35ed06044c4fc1be162553880f98658616 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Mon, 15 Jun 2009 01:10:18 -0400 Subject: mtd: let include/linux/mtd/partitions.h stand on its own When declaring static MTD partitions in board specific code, only including should suffice without gcc nagging us with: In file included from arch/arm/mach-kirkwood/sheevaplug-setup.c:14: include/linux/mtd/partitions.h:50: warning: 'struct mtd_info' declared inside parameter list include/linux/mtd/partitions.h:50: warning: its scope is only this definition or declaration, which is probably not what you want include/linux/mtd/partitions.h:51: warning: 'struct mtd_info' declared inside parameter list include/linux/mtd/partitions.h:61: warning: 'struct mtd_info' declared inside parameter list include/linux/mtd/partitions.h:67: warning: 'struct mtd_info' declared inside parameter list Signed-off-by: Nicolas Pitre Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h index af6dcb9..b70313d 100644 --- a/include/linux/mtd/partitions.h +++ b/include/linux/mtd/partitions.h @@ -47,6 +47,8 @@ struct mtd_partition { #define MTDPART_SIZ_FULL (0) +struct mtd_info; + int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *, int); int del_mtd_partitions(struct mtd_info *); -- cgit v0.10.2 From 6afc4fdb3e94ba60cd566cb878b60c6c01979277 Mon Sep 17 00:00:00 2001 From: Saeed Bishara Date: Tue, 28 Jul 2009 04:56:43 -0700 Subject: mtd: fix the conversion from dev to mtd_info The patch fixes a bug when converting dev to mtd_info by using the drvdata of the dev, the previous code used container_of(dev, struct mtd_info, dev), but won't work for the mtdXro devices as they created without being contained inside mtd_info structure. Signed-off-by: Saeed Bishara Signed-off-by: David Woodhouse diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index fac54a3..00ebf7a 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -65,8 +65,8 @@ static void mtd_release(struct device *dev) static int mtd_cls_suspend(struct device *dev, pm_message_t state) { struct mtd_info *mtd = dev_to_mtd(dev); - - if (mtd->suspend) + + if (mtd && mtd->suspend) return mtd->suspend(mtd); else return 0; @@ -76,7 +76,7 @@ static int mtd_cls_resume(struct device *dev) { struct mtd_info *mtd = dev_to_mtd(dev); - if (mtd->resume) + if (mtd && mtd->resume) mtd->resume(mtd); return 0; } @@ -298,6 +298,7 @@ int add_mtd_device(struct mtd_info *mtd) mtd->dev.class = &mtd_class; mtd->dev.devt = MTD_DEVT(i); dev_set_name(&mtd->dev, "mtd%d", i); + dev_set_drvdata(&mtd->dev, mtd); if (device_register(&mtd->dev) != 0) { mtd_table[i] = NULL; break; diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 5675b63..0f32a9b 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -251,7 +251,7 @@ struct mtd_info { static inline struct mtd_info *dev_to_mtd(struct device *dev) { - return dev ? container_of(dev, struct mtd_info, dev) : NULL; + return dev ? dev_get_drvdata(dev) : NULL; } static inline uint32_t mtd_div_by_eb(uint64_t sz, struct mtd_info *mtd) -- cgit v0.10.2 From 8022c13c27b822cf22f13df10b42aae89cd56bf0 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Fri, 10 Jul 2009 17:02:17 +0300 Subject: mtd: blkdevs: do not forget to get MTD devices Nowadays MTD devices have to be "get" before they can be used. This has to be done with 'get_mtd_device()'. The 'blktrans_open()' function did not do this and instead used 'try_module_get()'. Fix this. Since 'get_mtd_device()' already gets the module, extra 'try_module_get()' is not needed. This fixes oops when one tries to use mtdblock on top of gluebi. Reported-by: Holger Brunck Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index c3f6265..7baba40 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -144,7 +144,7 @@ static int blktrans_open(struct block_device *bdev, fmode_t mode) struct mtd_blktrans_ops *tr = dev->tr; int ret = -ENODEV; - if (!try_module_get(dev->mtd->owner)) + if (!get_mtd_device(NULL, dev->mtd->index)) goto out; if (!try_module_get(tr->owner)) @@ -158,7 +158,7 @@ static int blktrans_open(struct block_device *bdev, fmode_t mode) ret = 0; if (tr->open && (ret = tr->open(dev))) { dev->mtd->usecount--; - module_put(dev->mtd->owner); + put_mtd_device(dev->mtd); out_tr: module_put(tr->owner); } @@ -177,7 +177,7 @@ static int blktrans_release(struct gendisk *disk, fmode_t mode) if (!ret) { dev->mtd->usecount--; - module_put(dev->mtd->owner); + put_mtd_device(dev->mtd); module_put(tr->owner); } -- cgit v0.10.2 From 00acf4a80779611a7ea77ff5b5ffab886ed5cc42 Mon Sep 17 00:00:00 2001 From: Mika Korhonen Date: Thu, 11 Jun 2009 14:05:07 +0300 Subject: mtd: OneNAND: fix incorrect bufferram offset Fixes the case where CONFIG_MTD_ONENAND_2X_PROGRAM is set and the real page size differs from mtd_info.writesize. Signed-off-by: Mika Korhonen Acked-by: Kyungmin Park Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c index 38d656b..6fac1f4 100644 --- a/drivers/mtd/onenand/omap2.c +++ b/drivers/mtd/onenand/omap2.c @@ -266,7 +266,7 @@ static inline int omap2_onenand_bufferram_offset(struct mtd_info *mtd, int area) if (ONENAND_CURRENT_BUFFERRAM(this)) { if (area == ONENAND_DATARAM) - return mtd->writesize; + return this->writesize; if (area == ONENAND_SPARERAM) return mtd->oobsize; } -- cgit v0.10.2 From 3cae1cc149c40c14424162496eb5a7c8db1cd4fb Mon Sep 17 00:00:00 2001 From: Mika Korhonen Date: Thu, 25 Jun 2009 15:32:19 +0300 Subject: mtd: OneNAND: OMAP2/3: free GPMC CS on module removal GPMC CS was not freed in omap2_onenand_remove() preventing the module from reloading after removal. Signed-off-by: Mika Korhonen Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c index 6fac1f4..0108ed4 100644 --- a/drivers/mtd/onenand/omap2.c +++ b/drivers/mtd/onenand/omap2.c @@ -770,6 +770,7 @@ static int __devexit omap2_onenand_remove(struct platform_device *pdev) } iounmap(c->onenand.base); release_mem_region(c->phys_base, ONENAND_IO_SIZE); + gpmc_cs_free(c->gpmc_cs); kfree(c); return 0; -- cgit v0.10.2 From 2bf961b7ccd69e108ac435c67e2b0522b403c578 Mon Sep 17 00:00:00 2001 From: Subrata Modak Date: Wed, 1 Jul 2009 19:22:47 +0530 Subject: mtd: remove 'SBC8240 Wind River' Device Driver Code This driver is causing build errors and is no longer needed -- it is obsoleted by physmap_of. Signed-off-by: Subrata Modak Tested-on-PPC64-by: Subrata Modak Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index 0b98654..7a58bd5 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -284,13 +284,6 @@ config MTD_L440GX BE VERY CAREFUL. -config MTD_SBC8240 - tristate "Flash device on SBC8240" - depends on MTD_JEDECPROBE && 8260 - help - Flash access on the SBC8240 board from Wind River. See - - config MTD_TQM8XXL tristate "CFI Flash device mapped on TQM8XXL" depends on MTD_CFI && TQM8xxL diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile index 8bae7f9..5beb066 100644 --- a/drivers/mtd/maps/Makefile +++ b/drivers/mtd/maps/Makefile @@ -50,7 +50,6 @@ obj-$(CONFIG_MTD_UCLINUX) += uclinux.o obj-$(CONFIG_MTD_NETtel) += nettel.o obj-$(CONFIG_MTD_SCB2_FLASH) += scb2_flash.o obj-$(CONFIG_MTD_H720X) += h720x-flash.o -obj-$(CONFIG_MTD_SBC8240) += sbc8240.o obj-$(CONFIG_MTD_IXP4XX) += ixp4xx.o obj-$(CONFIG_MTD_IXP2000) += ixp2000.o obj-$(CONFIG_MTD_WRSBC8260) += wr_sbc82xx_flash.o diff --git a/drivers/mtd/maps/sbc8240.c b/drivers/mtd/maps/sbc8240.c index d5374cd..e69de29 100644 --- a/drivers/mtd/maps/sbc8240.c +++ b/drivers/mtd/maps/sbc8240.c @@ -1,250 +0,0 @@ -/* - * Handle mapping of the flash memory access routines on the SBC8240 board. - * - * Carolyn Smith, Tektronix, Inc. - * - * This code is GPLed - */ - -/* - * The SBC8240 has 2 flash banks. - * Bank 0 is a 512 KiB AMD AM29F040B; 8 x 64 KiB sectors. - * It contains the U-Boot code (7 sectors) and the environment (1 sector). - * Bank 1 is 4 x 1 MiB AMD AM29LV800BT; 15 x 64 KiB sectors, 1 x 32 KiB sector, - * 2 x 8 KiB sectors, 1 x 16 KiB sectors. - * Both parts are JEDEC compatible. - */ - -#include -#include -#include -#include - -#include -#include -#include - -#ifdef CONFIG_MTD_PARTITIONS -#include -#endif - -#define DEBUG - -#ifdef DEBUG -# define debugk(fmt,args...) printk(fmt ,##args) -#else -# define debugk(fmt,args...) -#endif - - -#define WINDOW_ADDR0 0xFFF00000 /* 512 KiB */ -#define WINDOW_SIZE0 0x00080000 -#define BUSWIDTH0 1 - -#define WINDOW_ADDR1 0xFF000000 /* 4 MiB */ -#define WINDOW_SIZE1 0x00400000 -#define BUSWIDTH1 8 - -#define MSG_PREFIX "sbc8240:" /* prefix for our printk()'s */ -#define MTDID "sbc8240-%d" /* for mtdparts= partitioning */ - - -static struct map_info sbc8240_map[2] = { - { - .name = "sbc8240 Flash Bank #0", - .size = WINDOW_SIZE0, - .bankwidth = BUSWIDTH0, - }, - { - .name = "sbc8240 Flash Bank #1", - .size = WINDOW_SIZE1, - .bankwidth = BUSWIDTH1, - } -}; - -#define NUM_FLASH_BANKS ARRAY_SIZE(sbc8240_map) - -/* - * The following defines the partition layout of SBC8240 boards. - * - * See include/linux/mtd/partitions.h for definition of the - * mtd_partition structure. - * - * The *_max_flash_size is the maximum possible mapped flash size - * which is not necessarily the actual flash size. It must correspond - * to the value specified in the mapping definition defined by the - * "struct map_desc *_io_desc" for the corresponding machine. - */ - -#ifdef CONFIG_MTD_PARTITIONS - -static struct mtd_partition sbc8240_uboot_partitions [] = { - /* Bank 0 */ - { - .name = "U-boot", /* U-Boot Firmware */ - .offset = 0, - .size = 0x00070000, /* 7 x 64 KiB sectors */ - .mask_flags = MTD_WRITEABLE, /* force read-only */ - }, - { - .name = "environment", /* U-Boot environment */ - .offset = 0x00070000, - .size = 0x00010000, /* 1 x 64 KiB sector */ - }, -}; - -static struct mtd_partition sbc8240_fs_partitions [] = { - { - .name = "jffs", /* JFFS filesystem */ - .offset = 0, - .size = 0x003C0000, /* 4 * 15 * 64KiB */ - }, - { - .name = "tmp32", - .offset = 0x003C0000, - .size = 0x00020000, /* 4 * 32KiB */ - }, - { - .name = "tmp8a", - .offset = 0x003E0000, - .size = 0x00008000, /* 4 * 8KiB */ - }, - { - .name = "tmp8b", - .offset = 0x003E8000, - .size = 0x00008000, /* 4 * 8KiB */ - }, - { - .name = "tmp16", - .offset = 0x003F0000, - .size = 0x00010000, /* 4 * 16KiB */ - } -}; - -/* trivial struct to describe partition information */ -struct mtd_part_def -{ - int nums; - unsigned char *type; - struct mtd_partition* mtd_part; -}; - -static struct mtd_info *sbc8240_mtd[NUM_FLASH_BANKS]; -static struct mtd_part_def sbc8240_part_banks[NUM_FLASH_BANKS]; - - -#endif /* CONFIG_MTD_PARTITIONS */ - - -static int __init init_sbc8240_mtd (void) -{ - static struct _cjs { - u_long addr; - u_long size; - } pt[NUM_FLASH_BANKS] = { - { - .addr = WINDOW_ADDR0, - .size = WINDOW_SIZE0 - }, - { - .addr = WINDOW_ADDR1, - .size = WINDOW_SIZE1 - }, - }; - - int devicesfound = 0; - int i,j; - - for (i = 0; i < NUM_FLASH_BANKS; i++) { - printk (KERN_NOTICE MSG_PREFIX - "Probing 0x%08lx at 0x%08lx\n", pt[i].size, pt[i].addr); - - sbc8240_map[i].map_priv_1 = - (unsigned long) ioremap (pt[i].addr, pt[i].size); - if (!sbc8240_map[i].map_priv_1) { - printk (MSG_PREFIX "failed to ioremap\n"); - for (j = 0; j < i; j++) { - iounmap((void *) sbc8240_map[j].map_priv_1); - sbc8240_map[j].map_priv_1 = 0; - } - return -EIO; - } - simple_map_init(&sbc8240_mtd[i]); - - sbc8240_mtd[i] = do_map_probe("jedec_probe", &sbc8240_map[i]); - - if (sbc8240_mtd[i]) { - sbc8240_mtd[i]->module = THIS_MODULE; - devicesfound++; - } else { - if (sbc8240_map[i].map_priv_1) { - iounmap((void *) sbc8240_map[i].map_priv_1); - sbc8240_map[i].map_priv_1 = 0; - } - } - } - - if (!devicesfound) { - printk(KERN_NOTICE MSG_PREFIX - "No suppported flash chips found!\n"); - return -ENXIO; - } - -#ifdef CONFIG_MTD_PARTITIONS - sbc8240_part_banks[0].mtd_part = sbc8240_uboot_partitions; - sbc8240_part_banks[0].type = "static image"; - sbc8240_part_banks[0].nums = ARRAY_SIZE(sbc8240_uboot_partitions); - sbc8240_part_banks[1].mtd_part = sbc8240_fs_partitions; - sbc8240_part_banks[1].type = "static file system"; - sbc8240_part_banks[1].nums = ARRAY_SIZE(sbc8240_fs_partitions); - - for (i = 0; i < NUM_FLASH_BANKS; i++) { - - if (!sbc8240_mtd[i]) continue; - if (sbc8240_part_banks[i].nums == 0) { - printk (KERN_NOTICE MSG_PREFIX - "No partition info available, registering whole device\n"); - add_mtd_device(sbc8240_mtd[i]); - } else { - printk (KERN_NOTICE MSG_PREFIX - "Using %s partition definition\n", sbc8240_part_banks[i].mtd_part->name); - add_mtd_partitions (sbc8240_mtd[i], - sbc8240_part_banks[i].mtd_part, - sbc8240_part_banks[i].nums); - } - } -#else - printk(KERN_NOTICE MSG_PREFIX - "Registering %d flash banks at once\n", devicesfound); - - for (i = 0; i < devicesfound; i++) { - add_mtd_device(sbc8240_mtd[i]); - } -#endif /* CONFIG_MTD_PARTITIONS */ - - return devicesfound == 0 ? -ENXIO : 0; -} - -static void __exit cleanup_sbc8240_mtd (void) -{ - int i; - - for (i = 0; i < NUM_FLASH_BANKS; i++) { - if (sbc8240_mtd[i]) { - del_mtd_device (sbc8240_mtd[i]); - map_destroy (sbc8240_mtd[i]); - } - if (sbc8240_map[i].map_priv_1) { - iounmap ((void *) sbc8240_map[i].map_priv_1); - sbc8240_map[i].map_priv_1 = 0; - } - } -} - -module_init (init_sbc8240_mtd); -module_exit (cleanup_sbc8240_mtd); - -MODULE_LICENSE ("GPL"); -MODULE_AUTHOR ("Carolyn Smith "); -MODULE_DESCRIPTION ("MTD map driver for SBC8240 boards"); - -- cgit v0.10.2 From d676c11727815761e41a81b00c054b4bec452ae5 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Tue, 14 Jul 2009 22:04:29 +0200 Subject: mtd: mtdblock: introduce mtdblks_lock The mtdblks array and its content are prone to race conditions. Introduce the mutex mtdblks_lock in order to solve this. [Amended by Artem Bityutskiy] Signed-off-by: Matthias Kaehlcke Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c index 208c6fa..77db5ce 100644 --- a/drivers/mtd/mtdblock.c +++ b/drivers/mtd/mtdblock.c @@ -29,6 +29,8 @@ static struct mtdblk_dev { enum { STATE_EMPTY, STATE_CLEAN, STATE_DIRTY } cache_state; } *mtdblks[MAX_MTD_DEVICES]; +static struct mutex mtdblks_lock; + /* * Cache stuff... * @@ -270,15 +272,19 @@ static int mtdblock_open(struct mtd_blktrans_dev *mbd) DEBUG(MTD_DEBUG_LEVEL1,"mtdblock_open\n"); + mutex_lock(&mtdblks_lock); if (mtdblks[dev]) { mtdblks[dev]->count++; + mutex_unlock(&mtdblks_lock); return 0; } /* OK, it's not open. Create cache info for it */ mtdblk = kzalloc(sizeof(struct mtdblk_dev), GFP_KERNEL); - if (!mtdblk) + if (!mtdblk) { + mutex_unlock(&mtdblks_lock); return -ENOMEM; + } mtdblk->count = 1; mtdblk->mtd = mtd; @@ -291,6 +297,7 @@ static int mtdblock_open(struct mtd_blktrans_dev *mbd) } mtdblks[dev] = mtdblk; + mutex_unlock(&mtdblks_lock); DEBUG(MTD_DEBUG_LEVEL1, "ok\n"); @@ -304,6 +311,8 @@ static int mtdblock_release(struct mtd_blktrans_dev *mbd) DEBUG(MTD_DEBUG_LEVEL1, "mtdblock_release\n"); + mutex_lock(&mtdblks_lock); + mutex_lock(&mtdblk->cache_mutex); write_cached_data(mtdblk); mutex_unlock(&mtdblk->cache_mutex); @@ -316,6 +325,9 @@ static int mtdblock_release(struct mtd_blktrans_dev *mbd) vfree(mtdblk->cache_data); kfree(mtdblk); } + + mutex_unlock(&mtdblks_lock); + DEBUG(MTD_DEBUG_LEVEL1, "ok\n"); return 0; @@ -376,6 +388,8 @@ static struct mtd_blktrans_ops mtdblock_tr = { static int __init init_mtdblock(void) { + mutex_init(&mtdblks_lock); + return register_mtd_blktrans(&mtdblock_tr); } -- cgit v0.10.2 From 57ca7deb062abf56168d15f000c16e25f88a9cf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20Grafstr=C3=B6m?= Date: Tue, 4 Aug 2009 13:11:47 +0200 Subject: jffs2: Fix return value from jffs2_do_readpage_nolock() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes "kernel BUG at fs/jffs2/file.c:251!". This pseudocode hopefully illustrates the scenario that triggers it: jffs2_write_begin { jffs2_do_readpage_nolock { jffs2_read_inode_range { jffs2_read_dnode { Data CRC 33c102e9 != calculated CRC 0ef77e7b for node at 005d42e4 return -EIO; } } ClearPageUptodate(pg); return 0; } } jffs2_write_end { BUG_ON(!PageUptodate(pg)); } Signed-off-by: Anders Grafström Signed-off-by: David Woodhouse diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c index 5edc2bf..23c9475 100644 --- a/fs/jffs2/file.c +++ b/fs/jffs2/file.c @@ -99,7 +99,7 @@ static int jffs2_do_readpage_nolock (struct inode *inode, struct page *pg) kunmap(pg); D2(printk(KERN_DEBUG "readpage finished\n")); - return 0; + return ret; } int jffs2_do_readpage_unlock(struct inode *inode, struct page *pg) -- cgit v0.10.2 From 6502fbfaf81b09b3f474bb7b3796257e9450273e Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 4 Aug 2009 11:24:24 -0400 Subject: drm/radeon: Add support for RS880 chips These are new AMD IGP chips Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/r600_cp.c b/drivers/gpu/drm/radeon/r600_cp.c index 146f357..20f1790 100644 --- a/drivers/gpu/drm/radeon/r600_cp.c +++ b/drivers/gpu/drm/radeon/r600_cp.c @@ -384,8 +384,9 @@ static void r600_cp_load_microcode(drm_radeon_private_t *dev_priv) DRM_INFO("Loading RV670 PFP Microcode\n"); for (i = 0; i < PFP_UCODE_SIZE; i++) RADEON_WRITE(R600_CP_PFP_UCODE_DATA, RV670_pfp_microcode[i]); - } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780)) { - DRM_INFO("Loading RS780 CP Microcode\n"); + } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780) || + ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS880)) { + DRM_INFO("Loading RS780/RS880 CP Microcode\n"); for (i = 0; i < PM4_UCODE_SIZE; i++) { RADEON_WRITE(R600_CP_ME_RAM_DATA, RS780_cp_microcode[i][0]); @@ -396,7 +397,7 @@ static void r600_cp_load_microcode(drm_radeon_private_t *dev_priv) } RADEON_WRITE(R600_CP_PFP_UCODE_ADDR, 0); - DRM_INFO("Loading RS780 PFP Microcode\n"); + DRM_INFO("Loading RS780/RS880 PFP Microcode\n"); for (i = 0; i < PFP_UCODE_SIZE; i++) RADEON_WRITE(R600_CP_PFP_UCODE_DATA, RS780_pfp_microcode[i]); } @@ -783,6 +784,7 @@ static void r600_gfx_init(struct drm_device *dev, break; case CHIP_RV610: case CHIP_RS780: + case CHIP_RS880: case CHIP_RV620: dev_priv->r600_max_pipes = 1; dev_priv->r600_max_tile_pipes = 1; @@ -917,7 +919,8 @@ static void r600_gfx_init(struct drm_device *dev, ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV630) || ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV610) || ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV620) || - ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780)) + ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780) || + ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS880)) RADEON_WRITE(R600_DB_DEBUG, R600_PREZ_MUST_WAIT_FOR_POSTZ_DONE); else RADEON_WRITE(R600_DB_DEBUG, 0); @@ -935,7 +938,8 @@ static void r600_gfx_init(struct drm_device *dev, sq_ms_fifo_sizes = RADEON_READ(R600_SQ_MS_FIFO_SIZES); if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV610) || ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV620) || - ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780)) { + ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780) || + ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS880)) { sq_ms_fifo_sizes = (R600_CACHE_FIFO_SIZE(0xa) | R600_FETCH_FIFO_HIWATER(0xa) | R600_DONE_FIFO_HIWATER(0xe0) | @@ -978,7 +982,8 @@ static void r600_gfx_init(struct drm_device *dev, R600_NUM_ES_STACK_ENTRIES(0)); } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV610) || ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV620) || - ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780)) { + ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780) || + ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS880)) { /* no vertex cache */ sq_config &= ~R600_VC_ENABLE; @@ -1035,7 +1040,8 @@ static void r600_gfx_init(struct drm_device *dev, if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV610) || ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV620) || - ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780)) + ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780) || + ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS880)) RADEON_WRITE(R600_VGT_CACHE_INVALIDATION, R600_CACHE_INVALIDATION(R600_TC_ONLY)); else RADEON_WRITE(R600_VGT_CACHE_INVALIDATION, R600_CACHE_INVALIDATION(R600_VC_AND_TC)); @@ -1078,6 +1084,7 @@ static void r600_gfx_init(struct drm_device *dev, break; case CHIP_RV610: case CHIP_RS780: + case CHIP_RS880: case CHIP_RV620: gs_prim_buffer_depth = 32; break; @@ -1123,6 +1130,7 @@ static void r600_gfx_init(struct drm_device *dev, switch (dev_priv->flags & RADEON_FAMILY_MASK) { case CHIP_RV610: case CHIP_RS780: + case CHIP_RS880: case CHIP_RV620: tc_cntl = R600_TC_L2_SIZE(8); break; diff --git a/drivers/gpu/drm/radeon/radeon_drv.h b/drivers/gpu/drm/radeon/radeon_drv.h index 127d045..3933f82 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.h +++ b/drivers/gpu/drm/radeon/radeon_drv.h @@ -143,6 +143,7 @@ enum radeon_family { CHIP_RV635, CHIP_RV670, CHIP_RS780, + CHIP_RS880, CHIP_RV770, CHIP_RV730, CHIP_RV710, diff --git a/include/drm/drm_pciids.h b/include/drm/drm_pciids.h index 9d4c004..8535084 100644 --- a/include/drm/drm_pciids.h +++ b/include/drm/drm_pciids.h @@ -370,6 +370,11 @@ {0x1002, 0x9614, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS780|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x9615, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS780|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x9616, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS780|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9710, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS880|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9711, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS880|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9712, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS880|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9713, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS880|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9714, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS880|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0, 0, 0} #define r128_PCI_IDS \ -- cgit v0.10.2 From 685aaca751271b2c5191901931a19ccaceeae1ce Mon Sep 17 00:00:00 2001 From: "Jory A. Pratt" Date: Mon, 3 Aug 2009 09:32:34 -0700 Subject: Input: i8042 - add Asus G1S to noloop exception list The synaptic touchpad on the Asus G1S is not properly detected when rebooting machine or on cold boot from time to time. Adding the Asus G1S to the noloop exception table resolves the issue. # dmidecode 2.10 SMBIOS 2.4 present. Handle 0x0001, DMI type 1, 27 bytes System Information Manufacturer: ASUSTeK Computer Inc. Product Name: G1S Version: 1.0 Wake-up Type: Power Switch SKU Number: Family: Signed-off-by: Jory A. Pratt Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 924e8ed..ae04d8a4 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -78,6 +78,14 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { }, }, { + .ident = "ASUS G1S", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer Inc."), + DMI_MATCH(DMI_BOARD_NAME, "G1S"), + DMI_MATCH(DMI_BOARD_VERSION, "1.0"), + }, + }, + { /* AUX LOOP command does not raise AUX IRQ */ .ident = "ASUS P65UP5", .matches = { -- cgit v0.10.2 From f532959b77e5e567c84c914cb7c7b07d2582448b Mon Sep 17 00:00:00 2001 From: Fenghua Yu Date: Tue, 4 Aug 2009 15:09:37 -0700 Subject: intel-iommu: Correct sglist size calculation. In domain_sg_mapping(), use aligned_nrpages() instead of hand-coded rounding code for calculating the size of each sg elem. This means that on IA64 we correctly round up to the MM page size, not just to the VT-d page size. Also remove the incorrect mm_to_dma_pfn() when intel_map_sg() calls domain_sg_mapping() -- the 'size' variable is in VT-d pages already. Signed-off-by: Fenghua Yu Signed-off-by: David Woodhouse diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index ebc9b8d..11b317a 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c @@ -1648,6 +1648,14 @@ static int domain_context_mapped(struct pci_dev *pdev) tmp->devfn); } +/* Returns a number of VTD pages, but aligned to MM page size */ +static inline unsigned long aligned_nrpages(unsigned long host_addr, + size_t size) +{ + host_addr &= ~PAGE_MASK; + return PAGE_ALIGN(host_addr + size) >> VTD_PAGE_SHIFT; +} + static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn, struct scatterlist *sg, unsigned long phys_pfn, unsigned long nr_pages, int prot) @@ -1675,7 +1683,7 @@ static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn, uint64_t tmp; if (!sg_res) { - sg_res = (sg->offset + sg->length + VTD_PAGE_SIZE - 1) >> VTD_PAGE_SHIFT; + sg_res = aligned_nrpages(sg->offset, sg->length); sg->dma_address = ((dma_addr_t)iov_pfn << VTD_PAGE_SHIFT) + sg->offset; sg->dma_length = sg->length; pteval = page_to_phys(sg_page(sg)) | prot; @@ -2415,14 +2423,6 @@ error: return ret; } -/* Returns a number of VTD pages, but aligned to MM page size */ -static inline unsigned long aligned_nrpages(unsigned long host_addr, - size_t size) -{ - host_addr &= ~PAGE_MASK; - return PAGE_ALIGN(host_addr + size) >> VTD_PAGE_SHIFT; -} - /* This takes a number of _MM_ pages, not VTD pages */ static struct iova *intel_alloc_iova(struct device *dev, struct dmar_domain *domain, @@ -2875,7 +2875,7 @@ static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int ne start_vpfn = mm_to_dma_pfn(iova->pfn_lo); - ret = domain_sg_mapping(domain, start_vpfn, sglist, mm_to_dma_pfn(size), prot); + ret = domain_sg_mapping(domain, start_vpfn, sglist, size, prot); if (unlikely(ret)) { /* clear the page */ dma_pte_clear_range(domain, start_vpfn, -- cgit v0.10.2 From 33041ec049d39a6e0463c7edc7b6f631d24559e3 Mon Sep 17 00:00:00 2001 From: Fenghua Yu Date: Tue, 4 Aug 2009 15:10:59 -0700 Subject: intel-iommu: Mask physical address to correct page size in intel_map_single() The physical address passed to domain_pfn_mapping() should be rounded down to the start of the MM page, not the VT-d page. This issue causes kernel panic on PAGE_SIZE>VTD_PAGE_SIZE platforms e.g. ia64 platforms. Signed-off-by: Fenghua Yu Signed-off-by: David Woodhouse diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index 11b317a..af7ff9b 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c @@ -2551,6 +2551,7 @@ static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr, int prot = 0; int ret; struct intel_iommu *iommu; + unsigned long paddr_pfn = paddr >> PAGE_SHIFT; BUG_ON(dir == DMA_NONE); @@ -2585,7 +2586,7 @@ static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr, * is not a big problem */ ret = domain_pfn_mapping(domain, mm_to_dma_pfn(iova->pfn_lo), - paddr >> VTD_PAGE_SHIFT, size, prot); + mm_to_dma_pfn(paddr_pfn), size, prot); if (ret) goto error; -- cgit v0.10.2 From 7d5b005652bc5ae3e1e0efc53fd0e25a643ec506 Mon Sep 17 00:00:00 2001 From: Alok Kataria Date: Tue, 4 Aug 2009 15:34:22 -0700 Subject: x86: Fix VMI && stack protector With CONFIG_STACK_PROTECTOR turned on, VMI doesn't boot with more than one processor. The problem is with the gs value not being initialized correctly when registering the secondary processor for VMI's case. The patch below initializes the gs value for the AP to __KERNEL_STACK_CANARY. Without this the secondary processor keeps on taking a GP on every gs access. Signed-off-by: Alok N Kataria Cc: # for v2.6.30.x LKML-Reference: <1249425262.18955.40.camel@ank32.eng.vmware.com> Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/vmi_32.c b/arch/x86/kernel/vmi_32.c index b263423..95a7289 100644 --- a/arch/x86/kernel/vmi_32.c +++ b/arch/x86/kernel/vmi_32.c @@ -441,7 +441,7 @@ vmi_startup_ipi_hook(int phys_apicid, unsigned long start_eip, ap.ds = __USER_DS; ap.es = __USER_DS; ap.fs = __KERNEL_PERCPU; - ap.gs = 0; + ap.gs = __KERNEL_STACK_CANARY; ap.eflags = 0; -- cgit v0.10.2 From e125e7b6944898831b56739a5448e705578bf7e2 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Thu, 2 Jul 2009 21:45:47 +0200 Subject: KVM: Fix KVM_GET_MSR_INDEX_LIST So far, KVM copied the emulated_msrs (only MSR_IA32_MISC_ENABLE) to a wrong address in user space due to broken pointer arithmetic. This caused subtle corruption up there (missing MSR_IA32_MISC_ENABLE had probably no practical relevance). Moreover, the size check for the user-provided kvm_msr_list forgot about emulated MSRs. Cc: stable@kernel.org Signed-off-by: Jan Kiszka Signed-off-by: Avi Kivity diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index fe5474a..7bc3114 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1079,14 +1079,13 @@ long kvm_arch_dev_ioctl(struct file *filp, if (copy_to_user(user_msr_list, &msr_list, sizeof msr_list)) goto out; r = -E2BIG; - if (n < num_msrs_to_save) + if (n < msr_list.nmsrs) goto out; r = -EFAULT; if (copy_to_user(user_msr_list->indices, &msrs_to_save, num_msrs_to_save * sizeof(u32))) goto out; - if (copy_to_user(user_msr_list->indices - + num_msrs_to_save * sizeof(u32), + if (copy_to_user(user_msr_list->indices + num_msrs_to_save, &emulated_msrs, ARRAY_SIZE(emulated_msrs) * sizeof(u32))) goto out; -- cgit v0.10.2 From 0ff77873b1318fc2d77a85e70690d3cd6cafbd41 Mon Sep 17 00:00:00 2001 From: Marcelo Tosatti Date: Thu, 2 Jul 2009 20:02:15 -0300 Subject: KVM: PIT: fix kpit_elapsed division by zero Fix division by zero triggered by latch count command on uninitialized counter. Cc: stable@kernel.org Signed-off-by: Marcelo Tosatti Signed-off-by: Avi Kivity diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c index 4d6f0d2..21f68e0 100644 --- a/arch/x86/kvm/i8254.c +++ b/arch/x86/kvm/i8254.c @@ -104,6 +104,9 @@ static s64 __kpit_elapsed(struct kvm *kvm) ktime_t remaining; struct kvm_kpit_state *ps = &kvm->arch.vpit->pit_state; + if (!ps->pit_timer.period) + return 0; + /* * The Counter does not stop when it reaches zero. In * Modes 0, 1, 4, and 5 the Counter ``wraps around'' to -- cgit v0.10.2 From d6289b9365c3f622a8cfe62c4fb054bb70b5061a Mon Sep 17 00:00:00 2001 From: Marcelo Tosatti Date: Mon, 22 Jun 2009 15:27:56 -0300 Subject: KVM: x86: verify MTRR/PAT validity Do not allow invalid memory types in MTRR/PAT (generating a #GP otherwise). Signed-off-by: Marcelo Tosatti Signed-off-by: Avi Kivity diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 7bc3114..3d45290 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -704,11 +704,48 @@ static bool msr_mtrr_valid(unsigned msr) return false; } +static bool valid_pat_type(unsigned t) +{ + return t < 8 && (1 << t) & 0xf3; /* 0, 1, 4, 5, 6, 7 */ +} + +static bool valid_mtrr_type(unsigned t) +{ + return t < 8 && (1 << t) & 0x73; /* 0, 1, 4, 5, 6 */ +} + +static bool mtrr_valid(struct kvm_vcpu *vcpu, u32 msr, u64 data) +{ + int i; + + if (!msr_mtrr_valid(msr)) + return false; + + if (msr == MSR_IA32_CR_PAT) { + for (i = 0; i < 8; i++) + if (!valid_pat_type((data >> (i * 8)) & 0xff)) + return false; + return true; + } else if (msr == MSR_MTRRdefType) { + if (data & ~0xcff) + return false; + return valid_mtrr_type(data & 0xff); + } else if (msr >= MSR_MTRRfix64K_00000 && msr <= MSR_MTRRfix4K_F8000) { + for (i = 0; i < 8 ; i++) + if (!valid_mtrr_type((data >> (i * 8)) & 0xff)) + return false; + return true; + } + + /* variable MTRRs */ + return valid_mtrr_type(data & 0xff); +} + static int set_msr_mtrr(struct kvm_vcpu *vcpu, u32 msr, u64 data) { u64 *p = (u64 *)&vcpu->arch.mtrr_state.fixed_ranges; - if (!msr_mtrr_valid(msr)) + if (!mtrr_valid(vcpu, msr, data)) return 1; if (msr == MSR_MTRRdefType) { -- cgit v0.10.2 From 4b656b1202498184a0ecef86b3b89ff613b9c6ab Mon Sep 17 00:00:00 2001 From: Marcelo Tosatti Date: Tue, 21 Jul 2009 12:47:45 -0300 Subject: KVM: SVM: force new asid on vcpu migration If a migrated vcpu matches the asid_generation value of the target pcpu, there will be no TLB flush via TLB_CONTROL_FLUSH_ALL_ASID. The check for vcpu.cpu in pre_svm_run is meaningless since svm_vcpu_load already updated it on schedule in. Such vcpu will VMRUN with stale TLB entries. Based on original patch from Joerg Roedel (http://patchwork.kernel.org/patch/10021/) Signed-off-by: Marcelo Tosatti Acked-by: Joerg Roedel Signed-off-by: Avi Kivity diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 71510e0..b1f658a 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -711,6 +711,7 @@ static void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu) svm->vmcb->control.tsc_offset += delta; vcpu->cpu = cpu; kvm_migrate_timers(vcpu); + svm->asid_generation = 0; } for (i = 0; i < NR_HOST_SAVE_USER_MSRS; i++) @@ -1031,7 +1032,6 @@ static void new_asid(struct vcpu_svm *svm, struct svm_cpu_data *svm_data) svm->vmcb->control.tlb_ctl = TLB_CONTROL_FLUSH_ALL_ASID; } - svm->vcpu.cpu = svm_data->cpu; svm->asid_generation = svm_data->asid_generation; svm->vmcb->control.asid = svm_data->next_asid++; } @@ -2300,8 +2300,8 @@ static void pre_svm_run(struct vcpu_svm *svm) struct svm_cpu_data *svm_data = per_cpu(svm_data, cpu); svm->vmcb->control.tlb_ctl = TLB_CONTROL_DO_NOTHING; - if (svm->vcpu.cpu != cpu || - svm->asid_generation != svm_data->asid_generation) + /* FIXME: handle wraparound of asid_generation */ + if (svm->asid_generation != svm_data->asid_generation) new_asid(svm, svm_data); } -- cgit v0.10.2 From 025dbbf36a7680bffe54d9dcbf0a8bc01a7cbd10 Mon Sep 17 00:00:00 2001 From: Marcelo Tosatti Date: Wed, 22 Jul 2009 13:05:49 -0300 Subject: KVM: MMU: handle n_free_mmu_pages > n_alloc_mmu_pages in kvm_mmu_change_mmu_pages kvm_mmu_change_mmu_pages mishandles the case where n_alloc_mmu_pages is smaller then n_free_mmu_pages, by not checking if the result of the subtraction is negative. Its a valid condition which can happen if a large number of pages has been recently freed. Signed-off-by: Marcelo Tosatti Signed-off-by: Avi Kivity diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 7030b5f..49a10d0 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -1407,24 +1407,25 @@ static int kvm_mmu_zap_page(struct kvm *kvm, struct kvm_mmu_page *sp) */ void kvm_mmu_change_mmu_pages(struct kvm *kvm, unsigned int kvm_nr_mmu_pages) { + int used_pages; + + used_pages = kvm->arch.n_alloc_mmu_pages - kvm->arch.n_free_mmu_pages; + used_pages = max(0, used_pages); + /* * If we set the number of mmu pages to be smaller be than the * number of actived pages , we must to free some mmu pages before we * change the value */ - if ((kvm->arch.n_alloc_mmu_pages - kvm->arch.n_free_mmu_pages) > - kvm_nr_mmu_pages) { - int n_used_mmu_pages = kvm->arch.n_alloc_mmu_pages - - kvm->arch.n_free_mmu_pages; - - while (n_used_mmu_pages > kvm_nr_mmu_pages) { + if (used_pages > kvm_nr_mmu_pages) { + while (used_pages > kvm_nr_mmu_pages) { struct kvm_mmu_page *page; page = container_of(kvm->arch.active_mmu_pages.prev, struct kvm_mmu_page, link); kvm_mmu_zap_page(kvm, page); - n_used_mmu_pages--; + used_pages--; } kvm->arch.n_free_mmu_pages = 0; } -- cgit v0.10.2 From 34f0c1ad27a74bd5eb0f99ea43ab6a4658d6419d Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Wed, 22 Jul 2009 23:53:26 +0200 Subject: KVM: VMX: Fix locking order in handle_invalid_guest_state Release and re-acquire preemption and IRQ lock in the same order as vcpu_enter_guest does. Signed-off-by: Jan Kiszka Signed-off-by: Marcelo Tosatti Signed-off-by: Avi Kivity diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 356a0ce..6bf58c0 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -3157,8 +3157,8 @@ static void handle_invalid_guest_state(struct kvm_vcpu *vcpu, struct vcpu_vmx *vmx = to_vmx(vcpu); enum emulation_result err = EMULATE_DONE; - preempt_enable(); local_irq_enable(); + preempt_enable(); while (!guest_state_valid(vcpu)) { err = emulate_instruction(vcpu, kvm_run, 0, 0, 0); @@ -3177,8 +3177,8 @@ static void handle_invalid_guest_state(struct kvm_vcpu *vcpu, schedule(); } - local_irq_disable(); preempt_disable(); + local_irq_disable(); vmx->invalid_state_emulation_result = err; } -- cgit v0.10.2 From 263799a3616242201e20fd2025fe84047b1379b1 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Tue, 21 Jul 2009 10:43:07 +0200 Subject: KVM: VMX: Fix locking imbalance on emulation failure We have to disable preemption and IRQs on every exit from handle_invalid_guest_state, otherwise we generate at least a preempt_disable imbalance. Signed-off-by: Jan Kiszka Signed-off-by: Marcelo Tosatti Signed-off-by: Avi Kivity diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 6bf58c0..29f9129 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -3168,7 +3168,7 @@ static void handle_invalid_guest_state(struct kvm_vcpu *vcpu, if (err != EMULATE_DONE) { kvm_report_emulation_failure(vcpu, "emulation failure"); - return; + break; } if (signal_pending(current)) -- cgit v0.10.2 From d3bc2f91b4761a8d9f96bea167fef2f8c00dea54 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Thu, 16 Jul 2009 17:17:37 +0200 Subject: KVM: s390: fix wait_queue handling There are two waitqueues in kvm for wait handling: vcpu->wq for virt/kvm/kvm_main.c and vpcu->arch.local_int.wq for the s390 specific wait code. the wait handling in kvm_s390_handle_wait was broken by using different wait_queues for add_wait queue and remove_wait_queue. There are two options to fix the problem: o move all the s390 specific code to vcpu->wq and remove vcpu->arch.local_int.wq o move all the s390 specific code to vcpu->arch.local_int.wq This patch chooses the 2nd variant for two reasons: o s390 does not use kvm_vcpu_block but implements its own enabled wait handling. Having a separate wait_queue make it clear, that our wait mechanism is different o the patch is much smaller Report-by: Julia Lawall Signed-off-by: Christian Borntraeger Signed-off-by: Marcelo Tosatti Signed-off-by: Avi Kivity diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index f04f530..4d61341 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c @@ -386,7 +386,7 @@ no_timer: } __unset_cpu_idle(vcpu); __set_current_state(TASK_RUNNING); - remove_wait_queue(&vcpu->wq, &wait); + remove_wait_queue(&vcpu->arch.local_int.wq, &wait); spin_unlock_bh(&vcpu->arch.local_int.lock); spin_unlock(&vcpu->arch.local_int.float_int->lock); hrtimer_try_to_cancel(&vcpu->arch.ckc_timer); -- cgit v0.10.2 From 5116d8f6b977970ebefc1932c0f313163a6ec91f Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Sun, 26 Jul 2009 17:10:01 +0300 Subject: KVM: fix ack not being delivered when msi present kvm_notify_acked_irq does not check irq type, so that it sometimes interprets msi vector as irq. As a result, ack notifiers are not called, which typially hangs the guest. The fix is to track and check irq type. Signed-off-by: Michael S. Tsirkin Signed-off-by: Avi Kivity diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 16713dc..3060bdc3 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -110,6 +110,7 @@ struct kvm_memory_slot { struct kvm_kernel_irq_routing_entry { u32 gsi; + u32 type; int (*set)(struct kvm_kernel_irq_routing_entry *e, struct kvm *kvm, int level); union { diff --git a/virt/kvm/irq_comm.c b/virt/kvm/irq_comm.c index a8bd466..ddc17f0 100644 --- a/virt/kvm/irq_comm.c +++ b/virt/kvm/irq_comm.c @@ -160,7 +160,8 @@ void kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin) unsigned gsi = pin; list_for_each_entry(e, &kvm->irq_routing, link) - if (e->irqchip.irqchip == irqchip && + if (e->type == KVM_IRQ_ROUTING_IRQCHIP && + e->irqchip.irqchip == irqchip && e->irqchip.pin == pin) { gsi = e->gsi; break; @@ -259,6 +260,7 @@ static int setup_routing_entry(struct kvm_kernel_irq_routing_entry *e, int delta; e->gsi = ue->gsi; + e->type = ue->type; switch (ue->type) { case KVM_IRQ_ROUTING_IRQCHIP: delta = 0; -- cgit v0.10.2 From 114cfab222233f50f46d7162cf7d99fdc6c271e5 Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Wed, 5 Aug 2009 13:25:21 +0300 Subject: perf report: Make --sort comm,dso,symbol the default If you're doing performance testing, you're interested in the symbols anyway so lets make "--sort comm,dso,symbol" the default sort option. Signed-off-by: Pekka Enberg Acked-by: Peter Zijlstra Cc: acme@redhat.com LKML-Reference: <1249467921-10450-1-git-send-email-penberg@cs.helsinki.fi> Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index ce4f286..8cb58d6 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -31,7 +31,7 @@ static char const *input_name = "perf.data"; static char *vmlinux = NULL; -static char default_sort_order[] = "comm,dso"; +static char default_sort_order[] = "comm,dso,symbol"; static char *sort_order = default_sort_order; static char *dso_list_str, *comm_list_str, *sym_list_str, *col_width_list_str; @@ -1424,7 +1424,7 @@ print_entries: if (sort_order == default_sort_order && parent_pattern == default_parent_pattern) { fprintf(fp, "#\n"); - fprintf(fp, "# (For more details, try: perf report --sort comm,dso,symbol)\n"); + fprintf(fp, "# (For a higher level overview, try: perf report --sort comm,dso)\n"); fprintf(fp, "#\n"); } fprintf(fp, "\n"); -- cgit v0.10.2 From c428dcc9b9f967945992a2f8529e8c50a31d7913 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 17 Jun 2009 15:04:19 +1000 Subject: KVM: Make KVM_HPAGES_PER_HPAGE unsigned long to avoid build error on powerpc Eliminates this compiler warning: arch/powerpc/kvm/../../../virt/kvm/kvm_main.c:1178: error: integer overflow in expression Signed-off-by: Stephen Rothwell Signed-off-by: Avi Kivity diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h index dfdf13c..fddc3ed 100644 --- a/arch/powerpc/include/asm/kvm_host.h +++ b/arch/powerpc/include/asm/kvm_host.h @@ -34,7 +34,7 @@ #define KVM_COALESCED_MMIO_PAGE_OFFSET 1 /* We don't currently support large pages. */ -#define KVM_PAGES_PER_HPAGE (1<<31) +#define KVM_PAGES_PER_HPAGE (1UL << 31) struct kvm; struct kvm_run; -- cgit v0.10.2 From e9cbde8c158629cc96a26b2323c4a243536c1951 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Mon, 6 Jul 2009 12:49:39 +0300 Subject: KVM: ia64: fix build failures due to ia64/unsigned long mismatches Signed-off-by: Avi Kivity diff --git a/arch/ia64/kvm/mmio.c b/arch/ia64/kvm/mmio.c index 21f63ff..9bf55af 100644 --- a/arch/ia64/kvm/mmio.c +++ b/arch/ia64/kvm/mmio.c @@ -247,7 +247,8 @@ void emulate_io_inst(struct kvm_vcpu *vcpu, u64 padr, u64 ma) vcpu_get_fpreg(vcpu, inst.M9.f2, &v); /* Write high word. FIXME: this is a kludge! */ v.u.bits[1] &= 0x3ffff; - mmio_access(vcpu, padr + 8, &v.u.bits[1], 8, ma, IOREQ_WRITE); + mmio_access(vcpu, padr + 8, (u64 *)&v.u.bits[1], 8, + ma, IOREQ_WRITE); data = v.u.bits[0]; size = 3; } else if (inst.M10.major == 7 && inst.M10.x6 == 0x3B) { @@ -265,7 +266,8 @@ void emulate_io_inst(struct kvm_vcpu *vcpu, u64 padr, u64 ma) /* Write high word.FIXME: this is a kludge! */ v.u.bits[1] &= 0x3ffff; - mmio_access(vcpu, padr + 8, &v.u.bits[1], 8, ma, IOREQ_WRITE); + mmio_access(vcpu, padr + 8, (u64 *)&v.u.bits[1], + 8, ma, IOREQ_WRITE); data = v.u.bits[0]; size = 3; } else if (inst.M10.major == 7 && inst.M10.x6 == 0x31) { diff --git a/arch/ia64/kvm/vcpu.c b/arch/ia64/kvm/vcpu.c index 46b02cb..cc406d0 100644 --- a/arch/ia64/kvm/vcpu.c +++ b/arch/ia64/kvm/vcpu.c @@ -461,7 +461,7 @@ void setreg(unsigned long regnum, unsigned long val, u64 vcpu_get_gr(struct kvm_vcpu *vcpu, unsigned long reg) { struct kvm_pt_regs *regs = vcpu_regs(vcpu); - u64 val; + unsigned long val; if (!reg) return 0; @@ -469,7 +469,7 @@ u64 vcpu_get_gr(struct kvm_vcpu *vcpu, unsigned long reg) return val; } -void vcpu_set_gr(struct kvm_vcpu *vcpu, u64 reg, u64 value, int nat) +void vcpu_set_gr(struct kvm_vcpu *vcpu, unsigned long reg, u64 value, int nat) { struct kvm_pt_regs *regs = vcpu_regs(vcpu); long sof = (regs->cr_ifs) & 0x7f; @@ -1072,7 +1072,7 @@ void kvm_ttag(struct kvm_vcpu *vcpu, INST64 inst) vcpu_set_gr(vcpu, inst.M46.r1, tag, 0); } -int vcpu_tpa(struct kvm_vcpu *vcpu, u64 vadr, u64 *padr) +int vcpu_tpa(struct kvm_vcpu *vcpu, u64 vadr, unsigned long *padr) { struct thash_data *data; union ia64_isr visr, pt_isr; diff --git a/arch/ia64/kvm/vcpu.h b/arch/ia64/kvm/vcpu.h index 042af92..360724d 100644 --- a/arch/ia64/kvm/vcpu.h +++ b/arch/ia64/kvm/vcpu.h @@ -686,14 +686,15 @@ static inline int highest_inservice_irq(struct kvm_vcpu *vcpu) return highest_bits((int *)&(VMX(vcpu, insvc[0]))); } -extern void vcpu_get_fpreg(struct kvm_vcpu *vcpu, u64 reg, +extern void vcpu_get_fpreg(struct kvm_vcpu *vcpu, unsigned long reg, struct ia64_fpreg *val); -extern void vcpu_set_fpreg(struct kvm_vcpu *vcpu, u64 reg, +extern void vcpu_set_fpreg(struct kvm_vcpu *vcpu, unsigned long reg, struct ia64_fpreg *val); -extern u64 vcpu_get_gr(struct kvm_vcpu *vcpu, u64 reg); -extern void vcpu_set_gr(struct kvm_vcpu *vcpu, u64 reg, u64 val, int nat); -extern u64 vcpu_get_psr(struct kvm_vcpu *vcpu); -extern void vcpu_set_psr(struct kvm_vcpu *vcpu, u64 val); +extern u64 vcpu_get_gr(struct kvm_vcpu *vcpu, unsigned long reg); +extern void vcpu_set_gr(struct kvm_vcpu *vcpu, unsigned long reg, + u64 val, int nat); +extern unsigned long vcpu_get_psr(struct kvm_vcpu *vcpu); +extern void vcpu_set_psr(struct kvm_vcpu *vcpu, unsigned long val); extern u64 vcpu_thash(struct kvm_vcpu *vcpu, u64 vadr); extern void vcpu_bsw0(struct kvm_vcpu *vcpu); extern void thash_vhpt_insert(struct kvm_vcpu *v, u64 pte, -- cgit v0.10.2 From 2cdbc46d7b2cb0acb68c3ecad93b000552121fa6 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 5 Aug 2009 14:05:16 +0200 Subject: perf: Auto-detect libbfd Since the C++ demangling isn't needed for everybody and bfd/iberty aren't widely/easily available on all machines, make it optional. It also allows you to forcefully disable demangling by using NO_DEMANGLE=1 and otherwise tries to detect libbfd/libiberty combinations that result in a compiling demangler. Reported-by: Jens Axboe Signed-off-by: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Kyle McMartin LKML-Reference: <20090801082048.GX12579@kernel.dk> Signed-off-by: Ingo Molnar diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 4b20fa4..ff905ac 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -345,7 +345,6 @@ BUILTIN_OBJS += builtin-stat.o BUILTIN_OBJS += builtin-top.o PERFLIBS = $(LIB_FILE) -EXTLIBS = -lbfd -liberty # # Platform specific tweaks @@ -374,6 +373,23 @@ ifeq ($(uname_S),Darwin) PTHREAD_LIBS = endif +ifdef NO_DEMANGLE + BASIC_CFLAGS += -DNO_DEMANGLE +else + + has_bfd := $(shell sh -c "(echo '\#include '; echo '\#include '; echo '\#ifndef DMGL_PARAMS'; echo '\#define DMGL_PARAMS (1 << 0)'; echo '\#define DMGL_ANSI (1 << 1)'; echo '\#endif'; echo 'int main(int argc, char **argv) { bfd_demangle(NULL, argv[0], DMGL_PARAMS | DMGL_ANSI); return 0; }') | gcc -x c - -lbfd > /dev/null 2>&1 && echo y") + + has_bfd_iberty := $(shell sh -c "(echo '\#include '; echo '\#include '; echo '\#ifndef DMGL_PARAMS'; echo '\#define DMGL_PARAMS (1 << 0)'; echo '\#define DMGL_ANSI (1 << 1)'; echo '\#endif'; echo 'int main(int argc, char **argv) { bfd_demangle(NULL, argv[0], DMGL_PARAMS | DMGL_ANSI); return 0; }') | gcc -x c - -lbfd -liberty > /dev/null 2>&1 && echo y") + + ifeq ($(has_bfd),y) + EXTLIBS += -lbfd + else ifeq ($(has_bfd_iberty),y) + EXTLIBS += -lbfd -liberty + else + BASIC_CFLAGS += -DNO_DEMANGLE + endif +endif + ifndef CC_LD_DYNPATH ifdef NO_R_TO_GCC_LINKER # Some gcc does not accept and pass -R to the linker to specify diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index b4fe057..0580b94 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -6,7 +6,16 @@ #include #include #include + +#ifndef NO_DEMANGLE #include +#else +static inline +char *bfd_demangle(void __used *v, const char __used *c, int __used i) +{ + return NULL; +} +#endif const char *sym_hist_filter; -- cgit v0.10.2 From 386c0b702b1ea81c0f54f5c9832a3d4a52270f14 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 5 Aug 2009 10:04:53 -0300 Subject: perf report: Add missing command line options to man page Signed-off-by: Arnaldo Carvalho de Melo Cc: Peter Zijlstra LKML-Reference: <20090805130453.GC10688@ghostprotocols.net> Signed-off-by: Ingo Molnar diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 1dbc1ee..6be696b 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt @@ -29,13 +29,67 @@ OPTIONS Select the PMU event. Selection can be a symbolic event name (use 'perf list' to list all events) or a raw PMU event (eventsel+umask) in the form of rNNN where NNN is a - hexadecimal event descriptor. + hexadecimal event descriptor. -a:: - system-wide collection + System-wide collection. -l:: - scale counter values + Scale counter values. + +-p:: +--pid=:: + Record events on existing pid. + +-r:: +--realtime=:: + Collect data with this RT SCHED_FIFO priority. +-A:: +--append:: + Append to the output file to do incremental profiling. + +-f:: +--force:: + Overwrite existing data file. + +-c:: +--count=:: + Event period to sample. + +-o:: +--output=:: + Output file name. + +-i:: +--inherit:: + Child tasks inherit counters. +-F:: +--freq=:: + Profile at this frequency. + +-m:: +--mmap-pages=:: + Number of mmap data pages. + +-g:: +--call-graph:: + Do call-graph (stack chain/backtrace) recording. + +-v:: +--verbose:: + Be more verbose (show counter open errors, etc). + +-s:: +--stat:: + Per thread counts. + +-d:: +--data:: + Sample addresses. + +-n:: +--no-samples:: + Don't sample. SEE ALSO -------- -- cgit v0.10.2 From 0bf52b981770cbf006323bab5177f2858a196766 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Tue, 4 Aug 2009 21:16:58 +0000 Subject: net: Fix spinlock use in alloc_netdev_mq() -tip testing found this lockdep warning: [ 2.272010] calling net_dev_init+0x0/0x164 @ 1 [ 2.276033] device class 'net': registering [ 2.280191] INFO: trying to register non-static key. [ 2.284005] the code is fine but needs lockdep annotation. [ 2.284005] turning off the locking correctness validator. [ 2.284005] Pid: 1, comm: swapper Not tainted 2.6.31-rc5-tip #1145 [ 2.284005] Call Trace: [ 2.284005] [<7958eb4e>] ? printk+0xf/0x11 [ 2.284005] [<7904f83c>] __lock_acquire+0x11b/0x622 [ 2.284005] [<7908c9b7>] ? alloc_debug_processing+0xf9/0x144 [ 2.284005] [<7904e2be>] ? mark_held_locks+0x3a/0x52 [ 2.284005] [<7908dbc4>] ? kmem_cache_alloc+0xa8/0x13f [ 2.284005] [<7904e475>] ? trace_hardirqs_on_caller+0xa2/0xc3 [ 2.284005] [<7904fdf6>] lock_acquire+0xb3/0xd0 [ 2.284005] [<79489678>] ? alloc_netdev_mq+0xf5/0x1ad [ 2.284005] [<79591514>] _spin_lock_bh+0x2d/0x5d [ 2.284005] [<79489678>] ? alloc_netdev_mq+0xf5/0x1ad [ 2.284005] [<79489678>] alloc_netdev_mq+0xf5/0x1ad [ 2.284005] [<793a38f2>] ? loopback_setup+0x0/0x74 [ 2.284005] [<798eecd0>] loopback_net_init+0x20/0x5d [ 2.284005] [<79483efb>] register_pernet_device+0x23/0x4b [ 2.284005] [<798f5c9f>] net_dev_init+0x115/0x164 [ 2.284005] [<7900104f>] do_one_initcall+0x4a/0x11a [ 2.284005] [<798f5b8a>] ? net_dev_init+0x0/0x164 [ 2.284005] [<79066f6d>] ? register_irq_proc+0x8c/0xa8 [ 2.284005] [<798cc29a>] do_basic_setup+0x42/0x52 [ 2.284005] [<798cc30a>] kernel_init+0x60/0xa1 [ 2.284005] [<798cc2aa>] ? kernel_init+0x0/0xa1 [ 2.284005] [<79003e03>] kernel_thread_helper+0x7/0x10 [ 2.284078] device: 'lo': device_add [ 2.288248] initcall net_dev_init+0x0/0x164 returned 0 after 11718 usecs [ 2.292010] calling neigh_init+0x0/0x66 @ 1 [ 2.296010] initcall neigh_init+0x0/0x66 returned 0 after 0 usecs it's using an zero-initialized spinlock. This is a side-effect of: dev_unicast_init(dev); in alloc_netdev_mq() making use of dev->addr_list_lock. The device has just been allocated freshly, it's not accessible anywhere yet so no locking is needed at all - in fact it's wrong to lock it here (the lock isnt initialized yet). This bug was introduced via: | commit a6ac65db2329e7685299666f5f7b6093c7b0f3a0 | Date: Thu Jul 30 01:06:12 2009 +0000 | | net: restore the original spinlock to protect unicast list Signed-off-by: Ingo Molnar Acked-by: Jiri Pirko Tested-by: Mark Brown Signed-off-by: David S. Miller diff --git a/net/core/dev.c b/net/core/dev.c index 43e61ba..6a94475 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -4007,9 +4007,7 @@ static void dev_unicast_flush(struct net_device *dev) static void dev_unicast_init(struct net_device *dev) { - netif_addr_lock_bh(dev); __hw_addr_init(&dev->uc); - netif_addr_unlock_bh(dev); } -- cgit v0.10.2 From 9c9fe1f841745184bbc5460c6f3909fded3b929b Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 3 Aug 2009 16:09:16 -0700 Subject: drm/i915: Use our own workqueue to avoid wedging the system along with the GPU. Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 8c47831..50d1f78 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1186,6 +1186,13 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) if (ret) goto out_iomapfree; + dev_priv->wq = create_workqueue("i915"); + if (dev_priv->wq == NULL) { + DRM_ERROR("Failed to create our workqueue.\n"); + ret = -ENOMEM; + goto out_iomapfree; + } + /* enable GEM by default */ dev_priv->has_gem = 1; @@ -1211,7 +1218,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) if (!I915_NEED_GFX_HWS(dev)) { ret = i915_init_phys_hws(dev); if (ret != 0) - goto out_iomapfree; + goto out_workqueue_free; } i915_get_mem_freq(dev); @@ -1245,7 +1252,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) ret = i915_load_modeset_init(dev, prealloc_size, agp_size); if (ret < 0) { DRM_ERROR("failed to init modeset\n"); - goto out_rmmap; + goto out_workqueue_free; } } @@ -1256,6 +1263,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) return 0; +out_workqueue_free: + destroy_workqueue(dev_priv->wq); out_iomapfree: io_mapping_free(dev_priv->mm.gtt_mapping); out_rmmap: @@ -1269,6 +1278,8 @@ int i915_driver_unload(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + destroy_workqueue(dev_priv->wq); + io_mapping_free(dev_priv->mm.gtt_mapping); if (dev_priv->mm.gtt_mtrr >= 0) { mtrr_del(dev_priv->mm.gtt_mtrr, dev->agp->base, diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 5f3a259..7537f57 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -231,6 +231,7 @@ typedef struct drm_i915_private { spinlock_t error_lock; struct drm_i915_error_state *first_error; struct work_struct error_work; + struct workqueue_struct *wq; /* Register state */ u8 saveLBB; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 5bf4203..140bee1 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1570,7 +1570,7 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv, } if (was_empty && !dev_priv->mm.suspended) - schedule_delayed_work(&dev_priv->mm.retire_work, HZ); + queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ); return seqno; } @@ -1719,7 +1719,7 @@ i915_gem_retire_work_handler(struct work_struct *work) i915_gem_retire_requests(dev); if (!dev_priv->mm.suspended && !list_empty(&dev_priv->mm.request_list)) - schedule_delayed_work(&dev_priv->mm.retire_work, HZ); + queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ); mutex_unlock(&dev->struct_mutex); } diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index f340b3f..83aee80 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -482,7 +482,7 @@ static void i915_handle_error(struct drm_device *dev) I915_WRITE(IIR, I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT); } - schedule_work(&dev_priv->error_work); + queue_work(dev_priv->wq, &dev_priv->error_work); } irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) @@ -560,7 +560,8 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) DRM_DEBUG("hotplug event received, stat 0x%08x\n", hotplug_status); if (hotplug_status & dev_priv->hotplug_supported_mask) - schedule_work(&dev_priv->hotplug_work); + queue_work(dev_priv->wq, + &dev_priv->hotplug_work); I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); I915_READ(PORT_HOTPLUG_STAT); -- cgit v0.10.2 From 819e0064634f580ab618189e657ea58341d214b7 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Sun, 26 Jul 2009 00:50:38 +0200 Subject: drm/i915: Fix read outside array bounds in restoring the SWF10 range. dev_priv->saveSWF1 is a 16 element array, but this reads up to index 22, and restored values from the wrong registers. Signed-off-by: Roel Kluin Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 9e1d16e..1d04e19 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -598,7 +598,7 @@ int i915_restore_state(struct drm_device *dev) for (i = 0; i < 16; i++) { I915_WRITE(SWF00 + (i << 2), dev_priv->saveSWF0[i]); - I915_WRITE(SWF10 + (i << 2), dev_priv->saveSWF1[i+7]); + I915_WRITE(SWF10 + (i << 2), dev_priv->saveSWF1[i]); } for (i = 0; i < 3; i++) I915_WRITE(SWF30 + (i << 2), dev_priv->saveSWF2[i]); -- cgit v0.10.2 From 0a51810aa058a0a4ac76dd6f87f4d10bee774e2e Mon Sep 17 00:00:00 2001 From: Andrew Victor Date: Tue, 4 Aug 2009 19:55:56 +0100 Subject: ARM: 5637/1: [KS8695] Don't reference CLOCK_TICK_RATE in drivers Stop referencing CLOCK_TICK_RATE in the KS8695 drivers, rather refer to a KS8695_CLOCK_RATE. Issue pointed out by Russell King on arm-linux-kernel mailing list. Signed-off-by: Andrew Victor Signed-off-by: Russell King diff --git a/arch/arm/mach-ks8695/include/mach/hardware.h b/arch/arm/mach-ks8695/include/mach/hardware.h index 1d640d0..e0f911d 100644 --- a/arch/arm/mach-ks8695/include/mach/hardware.h +++ b/arch/arm/mach-ks8695/include/mach/hardware.h @@ -17,6 +17,11 @@ #include /* + * Clocks are derived from MCLK, which is 25Mhz + */ +#define KS8695_CLOCK_RATE 25000000 + +/* * Physical RAM address. */ #define KS8695_SDRAM_PA 0x00000000 diff --git a/arch/arm/mach-ks8695/include/mach/timex.h b/arch/arm/mach-ks8695/include/mach/timex.h index 4682e35..10f7163 100644 --- a/arch/arm/mach-ks8695/include/mach/timex.h +++ b/arch/arm/mach-ks8695/include/mach/timex.h @@ -14,7 +14,8 @@ #ifndef __ASM_ARCH_TIMEX_H #define __ASM_ARCH_TIMEX_H -/* timers are derived from MCLK, which is 25MHz */ -#define CLOCK_TICK_RATE 25000000 +#include + +#define CLOCK_TICK_RATE KS8695_CLOCK_RATE #endif diff --git a/drivers/serial/serial_ks8695.c b/drivers/serial/serial_ks8695.c index 998e89d..e066563 100644 --- a/drivers/serial/serial_ks8695.c +++ b/drivers/serial/serial_ks8695.c @@ -549,7 +549,7 @@ static struct uart_port ks8695uart_ports[SERIAL_KS8695_NR] = { .mapbase = KS8695_UART_VA, .iotype = SERIAL_IO_MEM, .irq = KS8695_IRQ_UART_TX, - .uartclk = CLOCK_TICK_RATE * 16, + .uartclk = KS8695_CLOCK_RATE * 16, .fifosize = 16, .ops = &ks8695uart_pops, .flags = ASYNC_BOOT_AUTOCONF, diff --git a/drivers/watchdog/ks8695_wdt.c b/drivers/watchdog/ks8695_wdt.c index 00b03eb..e1c8276 100644 --- a/drivers/watchdog/ks8695_wdt.c +++ b/drivers/watchdog/ks8695_wdt.c @@ -66,7 +66,7 @@ static inline void ks8695_wdt_stop(void) static inline void ks8695_wdt_start(void) { unsigned long tmcon; - unsigned long tval = wdt_time * CLOCK_TICK_RATE; + unsigned long tval = wdt_time * KS8695_CLOCK_RATE; spin_lock(&ks8695_lock); /* disable timer0 */ @@ -103,7 +103,7 @@ static inline void ks8695_wdt_reload(void) static int ks8695_wdt_settimeout(int new_time) { /* - * All counting occurs at SLOW_CLOCK / 128 = 0.256 Hz + * All counting occurs at KS8695_CLOCK_RATE / 128 = 0.256 Hz * * Since WDV is a 16-bit counter, the maximum period is * 65536 / 0.256 = 256 seconds. -- cgit v0.10.2 From 65a5053b764a42d33b334ba55810bb5b56eb92df Mon Sep 17 00:00:00 2001 From: Hartley Sweeten Date: Tue, 4 Aug 2009 23:20:45 +0100 Subject: ARM: 5638/1: arch/arm/kernel/signal.c: use correct address space for CRUNCH preserve_crunch_context() calls __copy_to_user() which expects the destination address to be in __user space. setup_sigframe() properly passes the destination address. restore_crunch_context() calls __copy_from_user() which expects the source address to be in __user space. restore_sigframe() properly passes the source address. This fixes {preserve/restore}_crunch_context() to accept the address as __user space and resolves the following sparse warnings: arch/arm/kernel/signal.c:146:31: warning: incorrect type in argument 1 (different address spaces) expected void [noderef] *to got struct crunch_sigframe *frame arch/arm/kernel/signal.c:156:38: warning: incorrect type in argument 2 (different address spaces) expected void const [noderef] *from got struct crunch_sigframe *frame arch/arm/kernel/signal.c:250:48: warning: incorrect type in argument 1 (different address spaces) expected struct crunch_sigframe *frame got struct crunch_sigframe [noderef] * arch/arm/kernel/signal.c:365:49: warning: incorrect type in argument 1 (different address spaces) expected struct crunch_sigframe *frame got struct crunch_sigframe [noderef] * Signed-off-by: H Hartley Sweeten Signed-off-by: Russell King diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 93bb424..f6bc5d4 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -133,7 +133,7 @@ sys_sigaction(int sig, const struct old_sigaction __user *act, } #ifdef CONFIG_CRUNCH -static int preserve_crunch_context(struct crunch_sigframe *frame) +static int preserve_crunch_context(struct crunch_sigframe __user *frame) { char kbuf[sizeof(*frame) + 8]; struct crunch_sigframe *kframe; @@ -146,7 +146,7 @@ static int preserve_crunch_context(struct crunch_sigframe *frame) return __copy_to_user(frame, kframe, sizeof(*frame)); } -static int restore_crunch_context(struct crunch_sigframe *frame) +static int restore_crunch_context(struct crunch_sigframe __user *frame) { char kbuf[sizeof(*frame) + 8]; struct crunch_sigframe *kframe; -- cgit v0.10.2 From c0c60c4b9ab45bb02b20796401dd6a90770fd0ee Mon Sep 17 00:00:00 2001 From: Hartley Sweeten Date: Tue, 4 Aug 2009 23:38:06 +0100 Subject: ARM: 5639/1: arm: clkdev.c should include should be included to get the base API prototypes. This fixes the following sparse warnings: arch/arm/common/clkdev.c:65:12: warning: symbol 'clk_get_sys' was not declared. Should it be static? arch/arm/common/clkdev.c:79:12: warning: symbol 'clk_get' was not declared. Should it be static? arch/arm/common/clkdev.c:87:6: warning: symbol 'clk_put' was not declared. Should it be static? Signed-off-by: H Hartley Sweeten Signed-off-by: Russell King diff --git a/arch/arm/common/clkdev.c b/arch/arm/common/clkdev.c index f37afd9..aae5bc0 100644 --- a/arch/arm/common/clkdev.c +++ b/arch/arm/common/clkdev.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include -- cgit v0.10.2 From 0f2541d299d233eddddee4345795e0c46264fd56 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 5 Aug 2009 12:02:48 -0400 Subject: ring-buffer: fix check of try_to_discard result The function ring_buffer_discard_commit inversed the code path of the result of try_to_discard. It should skip incrementing the entry counter if try_to_discard succeeded. But instead, it increments the entry conder if it succeeded to discard, and does not increment it if it fails. The result of this bug is that filtering will make the stat counters incorrect. Signed-off-by: Steven Rostedt diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index bf27bb7..2fd1752 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -1785,7 +1785,7 @@ void ring_buffer_discard_commit(struct ring_buffer *buffer, */ RB_WARN_ON(buffer, !local_read(&cpu_buffer->committing)); - if (!rb_try_to_discard(cpu_buffer, event)) + if (rb_try_to_discard(cpu_buffer, event)) goto out; /* -- cgit v0.10.2 From 464e85eb0e63096bd52e4c3e2a6fb8357fb95828 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 5 Aug 2009 15:26:37 -0400 Subject: ring-buffer: do not disable ring buffer on oops_in_progress The commit: commit e0fdace10e75dac67d906213b780ff1b1a4cc360 Author: David Miller Date: Fri Aug 1 01:11:22 2008 -0700 debug_locks: set oops_in_progress if we will log messages. Otherwise lock debugging messages on runqueue locks can deadlock the system due to the wakeups performed by printk(). Signed-off-by: David S. Miller Signed-off-by: Ingo Molnar Will permanently set oops_in_progress on any lockdep failure. When this triggers it will cause any read from the ring buffer to permanently disable the ring buffer (not to mention no locking of printk). This patch removes the check. It keeps the print in NMI which makes sense. This is probably OK, since the ring buffer should not cause something to set oops_in_progress anyway. Signed-off-by: Steven Rostedt diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 2fd1752..2606cee 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -2486,7 +2486,7 @@ static inline int rb_ok_to_lock(void) * buffer too. A one time deal is all you get from reading * the ring buffer from an NMI. */ - if (likely(!in_nmi() && !oops_in_progress)) + if (likely(!in_nmi())) return 1; tracing_off_permanent(); -- cgit v0.10.2 From 3f6e968ef4e1d8d93d8a8505461b0e50a9e97ad8 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 5 Aug 2009 22:00:14 -0400 Subject: tracing: do not use functions starting with .L in recordmcount.pl On Wed, 5 Aug 2009, Ingo Molnar wrote: > * Dave Airlie wrote: > > > Hey, > > > > So I spent 3-4 hrs today (I'm stupid yes) tracking down a .o > > breakage by blaming rawhide gcc/binutils as I was using make > > V=1and seeing only the compiler chain running, > > Hm, is this that powerpc related build bug you just reported? Well we tracked it down and it is powerpc64 specific. Seems that in drivers/hwmon/lm93.c there's a function called: LM93_IN_FROM_REG() But PPC64 has function descriptors and the real function names (the ones you see in objdump) start with a '.'. Thus this in objdump you have: Disassembly of section .text: 0000000000000000 <.LM93_IN_FROM_REG>: 0: 7c 08 02 a6 mflr r0 4: fb 81 ff e0 std r28,-32(r1) The function name used is .LM93_IN_FROM_REG. But gcc considers symbols that start with ".L" as a special symbol that is used inside the assembly stage. The nm passed into recordmcount uses the --synthetic option which shows the ".L" symbols (my runs outside of the build did not include the --synthetic option, so my older patch worked). We see the function as a local. Now to capture all the locations that use "mcount" we need to have a reference to link into the object file a list of mcount callers. We need a reference that will not disappear. We try to use a global function and if that does not work, we use a local function as a reference. But to relink the section back into the object, we need to make it global. In this case, we run objcopy using --globalize-symbol and --localize-symbol to convert the symbol into a global symbol, link the mcount list, then convert it back to a local symbol. This works great except for this case. .L* symbols can not be converted into a global symbol, and the mcount section referencing it will remain unresolved. Reported-by: Dave Airlie LKML-Reference: Signed-off-by: Steven Rostedt diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl index d29baa2..4889c44 100755 --- a/scripts/recordmcount.pl +++ b/scripts/recordmcount.pl @@ -414,7 +414,10 @@ while () { $offset = hex $1; } else { # if we already have a function, and this is weak, skip it - if (!defined($ref_func) && !defined($weak{$text})) { + if (!defined($ref_func) && !defined($weak{$text}) && + # PPC64 can have symbols that start with .L and + # gcc considers these special. Don't use them! + $text !~ /^\.L/) { $ref_func = $text; $offset = hex $1; } -- cgit v0.10.2 From 1bbf20835c4e088667a090ce6523a0f70b62dc76 Mon Sep 17 00:00:00 2001 From: Darren Hart Date: Wed, 5 Aug 2009 12:05:21 -0700 Subject: rtmutex: Avoid deadlock in rt_mutex_start_proxy_lock() In the event of a lock steal or owner died, rt_mutex_start_proxy_lock() will give the rt_mutex to the waiting task, but it fails to release the wait_lock. This leads to subsequent deadlocks when other tasks try to acquire the rt_mutex. I also removed a few extra blank lines that really spaced this routine out. I must have been high on the \n when I wrote this originally... Signed-off-by: Darren Hart Cc: Peter Zijlstra Cc: Steven Rostedt Cc: Dinakar Guniguntala Cc: John Stultz LKML-Reference: <4A79D7F1.4000405@us.ibm.com> Signed-off-by: Ingo Molnar diff --git a/kernel/rtmutex.c b/kernel/rtmutex.c index fcd107a..29bd4ba 100644 --- a/kernel/rtmutex.c +++ b/kernel/rtmutex.c @@ -1039,16 +1039,14 @@ int rt_mutex_start_proxy_lock(struct rt_mutex *lock, if (!rt_mutex_owner(lock) || try_to_steal_lock(lock, task)) { /* We got the lock for task. */ debug_rt_mutex_lock(lock); - rt_mutex_set_owner(lock, task, 0); - + spin_unlock(&lock->wait_lock); rt_mutex_deadlock_account_lock(lock, task); return 1; } ret = task_blocks_on_rt_mutex(lock, waiter, task, detect_deadlock); - if (ret && !waiter->task) { /* * Reset the return value. We might have -- cgit v0.10.2 From af6af30c0fcd77e621638e53ef8b176bca8bd3b4 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 5 Aug 2009 20:41:04 +0200 Subject: ftrace: Fix perf-tracepoint OOPS Not all tracepoints are created equal, in specific the ftrace tracepoints are created with TRACE_EVENT_FORMAT() which does not generate the needed bits to tie them into perf counters. For those events, don't create the 'id' file and fail ->profile_enable when their ID is specified through other means. Reported-by: Chris Mason Signed-off-by: Peter Zijlstra Cc: Steven Rostedt LKML-Reference: <1249497664.5890.4.camel@laptop> [ v2: fix build error in the !CONFIG_EVENT_PROFILE case ] Signed-off-by: Ingo Molnar diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h index 5c093ff..d7cd193 100644 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h @@ -119,11 +119,9 @@ struct ftrace_event_call { void *filter; void *mod; -#ifdef CONFIG_EVENT_PROFILE - atomic_t profile_count; - int (*profile_enable)(struct ftrace_event_call *); - void (*profile_disable)(struct ftrace_event_call *); -#endif + atomic_t profile_count; + int (*profile_enable)(struct ftrace_event_call *); + void (*profile_disable)(struct ftrace_event_call *); }; #define MAX_FILTER_PRED 32 diff --git a/kernel/trace/trace_event_profile.c b/kernel/trace/trace_event_profile.c index 5b5895a..11ba5bb 100644 --- a/kernel/trace/trace_event_profile.c +++ b/kernel/trace/trace_event_profile.c @@ -14,7 +14,7 @@ int ftrace_profile_enable(int event_id) mutex_lock(&event_mutex); list_for_each_entry(event, &ftrace_events, list) { - if (event->id == event_id) { + if (event->id == event_id && event->profile_enable) { ret = event->profile_enable(event); break; } diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 23d2972..e75276a 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -940,7 +940,7 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events, entry = trace_create_file("enable", 0644, call->dir, call, enable); - if (call->id) + if (call->id && call->profile_enable) entry = trace_create_file("id", 0444, call->dir, call, id); -- cgit v0.10.2 From 985fe845aea9cd56fd351800302270444556e45a Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Wed, 29 Jul 2009 18:55:53 +0200 Subject: drm/radeon/kms: Fix caching mode selection for GTT object GTT object can either be cached,uncached or wc just let core ttm pick the best mode according to how the bo driver and GTT memory type was initialized. Signed-off-by: Jerome Glisse Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index dd9ac2f..e98cae3 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -106,7 +106,7 @@ static inline uint32_t radeon_object_flags_from_domain(uint32_t domain) flags |= TTM_PL_FLAG_VRAM | TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED; } if (domain & RADEON_GEM_DOMAIN_GTT) { - flags |= TTM_PL_FLAG_TT | TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED; + flags |= TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING; } if (domain & RADEON_GEM_DOMAIN_CPU) { flags |= TTM_PL_FLAG_SYSTEM | TTM_PL_MASK_CACHING; -- cgit v0.10.2 From 194934785a846e0a7b1b674b7b475a9d0125d2f8 Mon Sep 17 00:00:00 2001 From: TJ Date: Mon, 3 Aug 2009 13:39:09 -0700 Subject: Input: wistron_btns - support Prestigio Wifi RF kill button The Prestigio 157, an old no-name clone laptop uses input keys very similar to the Wistron 1557/MS2141 with the addition of BIOS-controlled wireless radio frequency kill switch. This patch adds support for the RF kill switch control and adds manual identification of the model. The Prestigio does not expose any recognisable identity via dmidecode and so requires manual selection at module init using force=1 keymap=prestigio Signed-off-by: TJ Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c index 26e17a9..27ee976 100644 --- a/drivers/input/misc/wistron_btns.c +++ b/drivers/input/misc/wistron_btns.c @@ -611,6 +611,20 @@ static struct key_entry keymap_wistron_generic[] __initdata = { { KE_END, 0 } }; +static struct key_entry keymap_prestigio[] __initdata = { + { KE_KEY, 0x11, {KEY_PROG1} }, + { KE_KEY, 0x12, {KEY_PROG2} }, + { KE_WIFI, 0x30 }, + { KE_KEY, 0x22, {KEY_REWIND} }, + { KE_KEY, 0x23, {KEY_FORWARD} }, + { KE_KEY, 0x24, {KEY_PLAYPAUSE} }, + { KE_KEY, 0x25, {KEY_STOPCD} }, + { KE_KEY, 0x31, {KEY_MAIL} }, + { KE_KEY, 0x36, {KEY_WWW} }, + { KE_END, 0 } +}; + + /* * If your machine is not here (which is currently rather likely), please send * a list of buttons and their key codes (reported when loading this module @@ -971,6 +985,8 @@ static int __init select_keymap(void) if (keymap_name != NULL) { if (strcmp (keymap_name, "1557/MS2141") == 0) keymap = keymap_wistron_ms2141; + else if (strcmp (keymap_name, "prestigio") == 0) + keymap = keymap_prestigio; else if (strcmp (keymap_name, "generic") == 0) keymap = keymap_wistron_generic; else { -- cgit v0.10.2 From d82f1c35348cebe2fb2d4a4d31ce0ab0769e3d93 Mon Sep 17 00:00:00 2001 From: Eric Miao Date: Wed, 5 Aug 2009 01:24:41 -0700 Subject: Input: matrix_keypad - make matrix keymap size dynamic Remove assumption on the shift and size of rows/columns form matrix_keypad driver. Signed-off-by: Eric Miao Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c index e9b2e7cb..541b981 100644 --- a/drivers/input/keyboard/matrix_keypad.c +++ b/drivers/input/keyboard/matrix_keypad.c @@ -27,6 +27,7 @@ struct matrix_keypad { const struct matrix_keypad_platform_data *pdata; struct input_dev *input_dev; unsigned short *keycodes; + unsigned int row_shift; uint32_t last_key_state[MATRIX_MAX_COLS]; struct delayed_work work; @@ -136,7 +137,7 @@ static void matrix_keypad_scan(struct work_struct *work) if ((bits_changed & (1 << row)) == 0) continue; - code = (row << 4) + col; + code = MATRIX_SCAN_CODE(row, col, keypad->row_shift); input_event(input_dev, EV_MSC, MSC_SCAN, code); input_report_key(input_dev, keypad->keycodes[code], @@ -317,6 +318,7 @@ static int __devinit matrix_keypad_probe(struct platform_device *pdev) struct matrix_keypad *keypad; struct input_dev *input_dev; unsigned short *keycodes; + unsigned int row_shift; int i; int err; @@ -332,14 +334,11 @@ static int __devinit matrix_keypad_probe(struct platform_device *pdev) return -EINVAL; } - if (!keymap_data->max_keymap_size) { - dev_err(&pdev->dev, "invalid keymap data supplied\n"); - return -EINVAL; - } + row_shift = get_count_order(pdata->num_col_gpios); keypad = kzalloc(sizeof(struct matrix_keypad), GFP_KERNEL); - keycodes = kzalloc(keymap_data->max_keymap_size * - sizeof(keypad->keycodes), + keycodes = kzalloc((pdata->num_row_gpios << row_shift) * + sizeof(*keycodes), GFP_KERNEL); input_dev = input_allocate_device(); if (!keypad || !keycodes || !input_dev) { @@ -350,6 +349,7 @@ static int __devinit matrix_keypad_probe(struct platform_device *pdev) keypad->input_dev = input_dev; keypad->pdata = pdata; keypad->keycodes = keycodes; + keypad->row_shift = row_shift; keypad->stopped = true; INIT_DELAYED_WORK(&keypad->work, matrix_keypad_scan); spin_lock_init(&keypad->lock); @@ -363,7 +363,7 @@ static int __devinit matrix_keypad_probe(struct platform_device *pdev) input_dev->keycode = keycodes; input_dev->keycodesize = sizeof(*keycodes); - input_dev->keycodemax = keymap_data->max_keymap_size; + input_dev->keycodemax = pdata->num_row_gpios << keypad->row_shift; for (i = 0; i < keymap_data->keymap_size; i++) { unsigned int key = keymap_data->keymap[i]; @@ -371,7 +371,7 @@ static int __devinit matrix_keypad_probe(struct platform_device *pdev) unsigned int col = KEY_COL(key); unsigned short code = KEY_VAL(key); - keycodes[(row << 4) + col] = code; + keycodes[MATRIX_SCAN_CODE(row, col, row_shift)] = code; __set_bit(code, input_dev->keybit); } __clear_bit(KEY_RESERVED, input_dev->keybit); diff --git a/include/linux/input/matrix_keypad.h b/include/linux/input/matrix_keypad.h index 7964516..15d5903 100644 --- a/include/linux/input/matrix_keypad.h +++ b/include/linux/input/matrix_keypad.h @@ -15,12 +15,13 @@ #define KEY_COL(k) (((k) >> 16) & 0xff) #define KEY_VAL(k) ((k) & 0xffff) +#define MATRIX_SCAN_CODE(row, col, row_shift) (((row) << (row_shift)) + (col)) + /** * struct matrix_keymap_data - keymap for matrix keyboards * @keymap: pointer to array of uint32 values encoded with KEY() macro * representing keymap * @keymap_size: number of entries (initialized) in this keymap - * @max_keymap_size: maximum size of keymap supported by the device * * This structure is supposed to be used by platform code to supply * keymaps to drivers that implement matrix-like keypads/keyboards. @@ -28,14 +29,13 @@ struct matrix_keymap_data { const uint32_t *keymap; unsigned int keymap_size; - unsigned int max_keymap_size; }; /** * struct matrix_keypad_platform_data - platform-dependent keypad data * @keymap_data: pointer to &matrix_keymap_data - * @row_gpios: array of gpio numbers reporesenting rows - * @col_gpios: array of gpio numbers reporesenting colums + * @row_gpios: pointer to array of gpio numbers representing rows + * @col_gpios: pointer to array of gpio numbers reporesenting colums * @num_row_gpios: actual number of row gpios used by device * @num_col_gpios: actual number of col gpios used by device * @col_scan_delay_us: delay, measured in microseconds, that is @@ -48,8 +48,9 @@ struct matrix_keymap_data { struct matrix_keypad_platform_data { const struct matrix_keymap_data *keymap_data; - unsigned int row_gpios[MATRIX_MAX_ROWS]; - unsigned int col_gpios[MATRIX_MAX_COLS]; + const unsigned int *row_gpios; + const unsigned int *col_gpios; + unsigned int num_row_gpios; unsigned int num_col_gpios; -- cgit v0.10.2 From 53a27b39ff4d2492f84b1fdc2f0047175f0b0b93 Mon Sep 17 00:00:00 2001 From: Marcelo Tosatti Date: Wed, 5 Aug 2009 15:43:58 -0300 Subject: KVM: MMU: limit rmap chain length Otherwise the host can spend too long traversing an rmap chain, which happens under a spinlock. Cc: stable@kernel.org Signed-off-by: Marcelo Tosatti Signed-off-by: Avi Kivity diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 49a10d0..0ef5bb2 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -489,16 +489,20 @@ static unsigned long *gfn_to_rmap(struct kvm *kvm, gfn_t gfn, int lpage) * * If rmapp bit zero is one, (then rmap & ~1) points to a struct kvm_rmap_desc * containing more mappings. + * + * Returns the number of rmap entries before the spte was added or zero if + * the spte was not added. + * */ -static void rmap_add(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn, int lpage) +static int rmap_add(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn, int lpage) { struct kvm_mmu_page *sp; struct kvm_rmap_desc *desc; unsigned long *rmapp; - int i; + int i, count = 0; if (!is_rmap_pte(*spte)) - return; + return count; gfn = unalias_gfn(vcpu->kvm, gfn); sp = page_header(__pa(spte)); sp->gfns[spte - sp->spt] = gfn; @@ -515,8 +519,10 @@ static void rmap_add(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn, int lpage) } else { rmap_printk("rmap_add: %p %llx many->many\n", spte, *spte); desc = (struct kvm_rmap_desc *)(*rmapp & ~1ul); - while (desc->shadow_ptes[RMAP_EXT-1] && desc->more) + while (desc->shadow_ptes[RMAP_EXT-1] && desc->more) { desc = desc->more; + count += RMAP_EXT; + } if (desc->shadow_ptes[RMAP_EXT-1]) { desc->more = mmu_alloc_rmap_desc(vcpu); desc = desc->more; @@ -525,6 +531,7 @@ static void rmap_add(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn, int lpage) ; desc->shadow_ptes[i] = spte; } + return count; } static void rmap_desc_remove_entry(unsigned long *rmapp, @@ -754,6 +761,19 @@ static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp) return young; } +#define RMAP_RECYCLE_THRESHOLD 1000 + +static void rmap_recycle(struct kvm_vcpu *vcpu, gfn_t gfn, int lpage) +{ + unsigned long *rmapp; + + gfn = unalias_gfn(vcpu->kvm, gfn); + rmapp = gfn_to_rmap(vcpu->kvm, gfn, lpage); + + kvm_unmap_rmapp(vcpu->kvm, rmapp); + kvm_flush_remote_tlbs(vcpu->kvm); +} + int kvm_age_hva(struct kvm *kvm, unsigned long hva) { return kvm_handle_hva(kvm, hva, kvm_age_rmapp); @@ -1741,6 +1761,7 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *shadow_pte, { int was_rmapped = 0; int was_writeble = is_writeble_pte(*shadow_pte); + int rmap_count; pgprintk("%s: spte %llx access %x write_fault %d" " user_fault %d gfn %lx\n", @@ -1782,9 +1803,11 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *shadow_pte, page_header_update_slot(vcpu->kvm, shadow_pte, gfn); if (!was_rmapped) { - rmap_add(vcpu, shadow_pte, gfn, largepage); + rmap_count = rmap_add(vcpu, shadow_pte, gfn, largepage); if (!is_rmap_pte(*shadow_pte)) kvm_release_pfn_clean(pfn); + if (rmap_count > RMAP_RECYCLE_THRESHOLD) + rmap_recycle(vcpu, gfn, largepage); } else { if (was_writeble) kvm_release_pfn_dirty(pfn); -- cgit v0.10.2 From c5b1525533c484238015c48c78f86d49a1bfb86b Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Thu, 6 Aug 2009 13:31:56 +0800 Subject: intel-iommu: Fix enabling snooping feature by mistake Two defects work together result in KVM device passthrough randomly can't work: 1. iommu_snooping is not initialized to zero when vm_iommu_init() called. So it is possible to get a random value. 2. One line added by commit 2c2e2c38("IOMMU Identity Mapping Support") change the code path, let it bypass domain_update_iommu_cap(), as well as missing the increment of domain iommu reference count. The latter is also likely to cause a leak of domains on repeated VMM assignment and deassignment. Signed-off-by: Sheng Yang Signed-off-by: David Woodhouse diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index af7ff9b..2314ad7 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c @@ -1505,7 +1505,6 @@ static int domain_context_mapping_one(struct dmar_domain *domain, int segment, } set_bit(num, iommu->domain_ids); - set_bit(iommu->seq_id, &domain->iommu_bmp); iommu->domains[num] = domain; id = num; } @@ -3409,6 +3408,7 @@ static int md_domain_init(struct dmar_domain *domain, int guest_width) domain->iommu_count = 0; domain->iommu_coherency = 0; + domain->iommu_snooping = 0; domain->max_addr = 0; /* always allocate the top pgd */ -- cgit v0.10.2 From e0d82a0a4e9841b787e6431ccfbb515546c55dc2 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Thu, 6 Aug 2009 21:16:44 +1000 Subject: perf_counter/powerpc: Check oprofile_cpu_type for NULL before using it If the current CPU doesn't support performance counters, cur_cpu_spec->oprofile_cpu_type can be NULL. The current perf_counter modules don't test for that case and would thus crash at boot time. Bug reported by David Woodhouse. Reported-by: David Woodhouse Signed-off-by: Benjamin Herrenschmidt Cc: Peter Zijlstra Signed-off-by: Paul Mackerras LKML-Reference: <19066.48028.446975.501454@cargo.ozlabs.ibm.com> Signed-off-by: Ingo Molnar diff --git a/arch/powerpc/kernel/mpc7450-pmu.c b/arch/powerpc/kernel/mpc7450-pmu.c index c244133..cc466d0 100644 --- a/arch/powerpc/kernel/mpc7450-pmu.c +++ b/arch/powerpc/kernel/mpc7450-pmu.c @@ -407,7 +407,8 @@ struct power_pmu mpc7450_pmu = { static int init_mpc7450_pmu(void) { - if (strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc/7450")) + if (!cur_cpu_spec->oprofile_cpu_type || + strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc/7450")) return -ENODEV; return register_power_pmu(&mpc7450_pmu); diff --git a/arch/powerpc/kernel/power4-pmu.c b/arch/powerpc/kernel/power4-pmu.c index db90b0c..3c90a3d 100644 --- a/arch/powerpc/kernel/power4-pmu.c +++ b/arch/powerpc/kernel/power4-pmu.c @@ -606,7 +606,8 @@ static struct power_pmu power4_pmu = { static int init_power4_pmu(void) { - if (strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power4")) + if (!cur_cpu_spec->oprofile_cpu_type || + strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power4")) return -ENODEV; return register_power_pmu(&power4_pmu); diff --git a/arch/powerpc/kernel/power5+-pmu.c b/arch/powerpc/kernel/power5+-pmu.c index f4adca8..31918af 100644 --- a/arch/powerpc/kernel/power5+-pmu.c +++ b/arch/powerpc/kernel/power5+-pmu.c @@ -678,8 +678,9 @@ static struct power_pmu power5p_pmu = { static int init_power5p_pmu(void) { - if (strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power5+") - && strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power5++")) + if (!cur_cpu_spec->oprofile_cpu_type || + (strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power5+") + && strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power5++"))) return -ENODEV; return register_power_pmu(&power5p_pmu); diff --git a/arch/powerpc/kernel/power5-pmu.c b/arch/powerpc/kernel/power5-pmu.c index 29b2c6c..867f6f6 100644 --- a/arch/powerpc/kernel/power5-pmu.c +++ b/arch/powerpc/kernel/power5-pmu.c @@ -618,7 +618,8 @@ static struct power_pmu power5_pmu = { static int init_power5_pmu(void) { - if (strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power5")) + if (!cur_cpu_spec->oprofile_cpu_type || + strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power5")) return -ENODEV; return register_power_pmu(&power5_pmu); diff --git a/arch/powerpc/kernel/power6-pmu.c b/arch/powerpc/kernel/power6-pmu.c index 09ae5bf..fa21890 100644 --- a/arch/powerpc/kernel/power6-pmu.c +++ b/arch/powerpc/kernel/power6-pmu.c @@ -537,7 +537,8 @@ static struct power_pmu power6_pmu = { static int init_power6_pmu(void) { - if (strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power6")) + if (!cur_cpu_spec->oprofile_cpu_type || + strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power6")) return -ENODEV; return register_power_pmu(&power6_pmu); diff --git a/arch/powerpc/kernel/power7-pmu.c b/arch/powerpc/kernel/power7-pmu.c index 5a9f5cb..388cf57 100644 --- a/arch/powerpc/kernel/power7-pmu.c +++ b/arch/powerpc/kernel/power7-pmu.c @@ -366,7 +366,8 @@ static struct power_pmu power7_pmu = { static int init_power7_pmu(void) { - if (strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power7")) + if (!cur_cpu_spec->oprofile_cpu_type || + strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power7")) return -ENODEV; return register_power_pmu(&power7_pmu); diff --git a/arch/powerpc/kernel/ppc970-pmu.c b/arch/powerpc/kernel/ppc970-pmu.c index 833097a..75dccb7 100644 --- a/arch/powerpc/kernel/ppc970-pmu.c +++ b/arch/powerpc/kernel/ppc970-pmu.c @@ -488,8 +488,9 @@ static struct power_pmu ppc970_pmu = { static int init_ppc970_pmu(void) { - if (strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/970") - && strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/970MP")) + if (!cur_cpu_spec->oprofile_cpu_type || + (strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/970") + && strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/970MP"))) return -ENODEV; return register_power_pmu(&ppc970_pmu); -- cgit v0.10.2 From 469535a598f28c13a2a42037e1b778f671af1d16 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 30 Jul 2009 19:19:18 +0200 Subject: ring-buffer: Fix advance of reader in rb_buffer_peek() When calling rb_buffer_peek() from ring_buffer_consume() and a padding event is returned, the function rb_advance_reader() is called twice. This may lead to missing samples or under high workloads to the warning below. This patch fixes this. If a padding event is returned by rb_buffer_peek() it will be consumed by the calling function now. Also, I simplified some code in ring_buffer_consume(). ------------[ cut here ]------------ WARNING: at /dev/shm/.source/linux/kernel/trace/ring_buffer.c:2289 rb_advance_reader+0x2e/0xc5() Hardware name: Anaheim Modules linked in: Pid: 29, comm: events/2 Tainted: G W 2.6.31-rc3-oprofile-x86_64-standard-00059-g5050dc2 #1 Call Trace: [] ? rb_advance_reader+0x2e/0xc5 [] warn_slowpath_common+0x77/0x8f [] warn_slowpath_null+0xf/0x11 [] rb_advance_reader+0x2e/0xc5 [] ring_buffer_consume+0xa0/0xd2 [] op_cpu_buffer_read_entry+0x21/0x9e [] ? __find_get_block+0x4b/0x165 [] sync_buffer+0xa5/0x401 [] ? __find_get_block+0x4b/0x165 [] ? wq_sync_buffer+0x0/0x78 [] wq_sync_buffer+0x5b/0x78 [] worker_thread+0x113/0x1ac [] ? autoremove_wake_function+0x0/0x38 [] ? worker_thread+0x0/0x1ac [] kthread+0x88/0x92 [] child_rip+0xa/0x20 [] ? kthread+0x0/0x92 [] ? child_rip+0x0/0x20 ---[ end trace f561c0a58fcc89bd ]--- Cc: Steven Rostedt Cc: Signed-off-by: Robert Richter Signed-off-by: Ingo Molnar diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 2606cee..d4d3580 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -2383,7 +2383,6 @@ rb_buffer_peek(struct ring_buffer *buffer, int cpu, u64 *ts) * the box. Return the padding, and we will release * the current locks, and try again. */ - rb_advance_reader(cpu_buffer); return event; case RINGBUF_TYPE_TIME_EXTEND: @@ -2519,6 +2518,8 @@ ring_buffer_peek(struct ring_buffer *buffer, int cpu, u64 *ts) if (dolock) spin_lock(&cpu_buffer->reader_lock); event = rb_buffer_peek(buffer, cpu, ts); + if (event && event->type_len == RINGBUF_TYPE_PADDING) + rb_advance_reader(cpu_buffer); if (dolock) spin_unlock(&cpu_buffer->reader_lock); local_irq_restore(flags); @@ -2590,12 +2591,9 @@ ring_buffer_consume(struct ring_buffer *buffer, int cpu, u64 *ts) spin_lock(&cpu_buffer->reader_lock); event = rb_buffer_peek(buffer, cpu, ts); - if (!event) - goto out_unlock; - - rb_advance_reader(cpu_buffer); + if (event) + rb_advance_reader(cpu_buffer); - out_unlock: if (dolock) spin_unlock(&cpu_buffer->reader_lock); local_irq_restore(flags); -- cgit v0.10.2 From 4d1e00a8af426500edfb8643fa6c375b89f1f804 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 5 Aug 2009 19:02:49 -0300 Subject: perf symbol: Fix symbol parsing in certain cases: use the build-id as a symlink In some cases distros have binaries and debuginfo in weird places: [root@doppio tuna]# ls -la /usr/lib64/{xulrunner-1.9.1/xulrunner-stub,firefox-3.5.2/firefox} -rwxr-xr-x 1 root root 90024 2009-08-03 19:45 /usr/lib64/firefox-3.5.2/firefox -rwxr-xr-x 1 root root 90024 2009-08-03 18:23 /usr/lib64/xulrunner-1.9.1/xulrunner-stub [root@doppio tuna]# sha1sum /usr/lib64/{xulrunner-1.9.1/xulrunner-stub,firefox-3.5.2/firefox} 19a858077d263d5de22c9c5da250d3e4396ae739 /usr/lib64/xulrunner-1.9.1/xulrunner-stub 19a858077d263d5de22c9c5da250d3e4396ae739 /usr/lib64/firefox-3.5.2/firefox [root@doppio tuna]# rpm -qf /usr/lib64/{xulrunner-1.9.1/xulrunner-stub,firefox-3.5.2/firefox} xulrunner-1.9.1.2-1.fc11.x86_64 firefox-3.5.2-2.fc11.x86_64 [root@doppio tuna]# ls -la /usr/lib/debug/{usr/lib64/xulrunner-1.9.1/xulrunner-stub,usr/lib64/firefox-3.5.2/firefox}.debug ls: cannot access /usr/lib/debug/usr/lib64/firefox-3.5.2/firefox.debug: No such file or directory -rwxr-xr-x 1 root root 403608 2009-08-03 18:22 /usr/lib/debug/usr/lib64/xulrunner-1.9.1/xulrunner-stub.debug Seemingly we don't have a .symtab when we actually can find it if we use the .note.gnu.build-id ELF section put in place by some distros. Use it and find the symbols we need. Signed-off-by: Arnaldo Carvalho de Melo Acked-by: Peter Zijlstra LKML-Reference: Signed-off-by: Ingo Molnar diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 0580b94..16ddca2 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -661,10 +661,69 @@ out_close: return err; } +#define BUILD_ID_SIZE 128 + +static char *dso__read_build_id(struct dso *self, int verbose) +{ + int i; + GElf_Ehdr ehdr; + GElf_Shdr shdr; + Elf_Data *build_id_data; + Elf_Scn *sec; + char *build_id = NULL, *bid; + unsigned char *raw; + Elf *elf; + int fd = open(self->name, O_RDONLY); + + if (fd < 0) + goto out; + + elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); + if (elf == NULL) { + if (verbose) + fprintf(stderr, "%s: cannot read %s ELF file.\n", + __func__, self->name); + goto out_close; + } + + if (gelf_getehdr(elf, &ehdr) == NULL) { + if (verbose) + fprintf(stderr, "%s: cannot get elf header.\n", __func__); + goto out_elf_end; + } + + sec = elf_section_by_name(elf, &ehdr, &shdr, ".note.gnu.build-id", NULL); + if (sec == NULL) + goto out_elf_end; + + build_id_data = elf_getdata(sec, NULL); + if (build_id_data == NULL) + goto out_elf_end; + build_id = malloc(BUILD_ID_SIZE); + if (build_id == NULL) + goto out_elf_end; + raw = build_id_data->d_buf + 16; + bid = build_id; + + for (i = 0; i < 20; ++i) { + sprintf(bid, "%02x", *raw); + ++raw; + bid += 2; + } + if (verbose) + printf("%s(%s): %s\n", __func__, self->name, build_id); +out_elf_end: + elf_end(elf); +out_close: + close(fd); +out: + return build_id; +} + int dso__load(struct dso *self, symbol_filter_t filter, int verbose) { - int size = strlen(self->name) + sizeof("/usr/lib/debug%s.debug"); - char *name = malloc(size); + int size = PATH_MAX; + char *name = malloc(size), *build_id = NULL; int variant = 0; int ret = -1; int fd; @@ -686,7 +745,18 @@ more: case 1: /* Ubuntu */ snprintf(name, size, "/usr/lib/debug%s", self->name); break; - case 2: /* Sane people */ + case 2: + build_id = dso__read_build_id(self, verbose); + if (build_id != NULL) { + snprintf(name, size, + "/usr/lib/debug/.build-id/%.2s/%s.debug", + build_id, build_id + 2); + free(build_id); + break; + } + variant++; + /* Fall thru */ + case 3: /* Sane people */ snprintf(name, size, "%s", self->name); break; -- cgit v0.10.2 From 9424edc2da097c8589fcc24a72552d33e54be161 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 5 Aug 2009 14:05:16 +0200 Subject: perf: Auto-detect libelf Adds autodetection for libelf as well, and simplifies the libbfd code. Furthermore, fail make with an error when libelf is not found and warn about the lack of libbfd. Also provide an option to build a 32bit version even though you might be running a 64bit kernel. Signed-off-by: Peter Zijlstra Signed-off-by: Ingo Molnar diff --git a/tools/perf/Makefile b/tools/perf/Makefile index ff905ac..1916e44 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -158,8 +158,10 @@ uname_P := $(shell sh -c 'uname -p 2>/dev/null || echo not') uname_V := $(shell sh -c 'uname -v 2>/dev/null || echo not') # If we're on a 64-bit kernel, use -m64 -ifneq ($(patsubst %64,%,$(uname_M)),$(uname_M)) - M64 := -m64 +ifndef NO_64BIT + ifneq ($(patsubst %64,%,$(uname_M)),$(uname_M)) + M64 := -m64 + endif endif # CFLAGS and LDFLAGS are for the users to override from the command line. @@ -373,19 +375,24 @@ ifeq ($(uname_S),Darwin) PTHREAD_LIBS = endif +ifneq ($(shell sh -c "(echo '\#include '; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ_MMAP, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o /dev/null $(ALL_LDFLAGS) > /dev/null 2>&1 && echo y"), y) + msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel); +endif + ifdef NO_DEMANGLE BASIC_CFLAGS += -DNO_DEMANGLE else - has_bfd := $(shell sh -c "(echo '\#include '; echo '\#include '; echo '\#ifndef DMGL_PARAMS'; echo '\#define DMGL_PARAMS (1 << 0)'; echo '\#define DMGL_ANSI (1 << 1)'; echo '\#endif'; echo 'int main(int argc, char **argv) { bfd_demangle(NULL, argv[0], DMGL_PARAMS | DMGL_ANSI); return 0; }') | gcc -x c - -lbfd > /dev/null 2>&1 && echo y") + has_bfd := $(shell sh -c "(echo '\#include '; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) -lbfd > /dev/null 2>&1 && echo y") - has_bfd_iberty := $(shell sh -c "(echo '\#include '; echo '\#include '; echo '\#ifndef DMGL_PARAMS'; echo '\#define DMGL_PARAMS (1 << 0)'; echo '\#define DMGL_ANSI (1 << 1)'; echo '\#endif'; echo 'int main(int argc, char **argv) { bfd_demangle(NULL, argv[0], DMGL_PARAMS | DMGL_ANSI); return 0; }') | gcc -x c - -lbfd -liberty > /dev/null 2>&1 && echo y") + has_bfd_iberty := $(shell sh -c "(echo '\#include '; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) -lbfd -liberty > /dev/null 2>&1 && echo y") ifeq ($(has_bfd),y) EXTLIBS += -lbfd else ifeq ($(has_bfd_iberty),y) EXTLIBS += -lbfd -liberty else + msg := $(warning No bfd.h/libbfd found, install binutils-dev[el] to gain symbol demangling) BASIC_CFLAGS += -DNO_DEMANGLE endif endif -- cgit v0.10.2 From 1054598cab8674438675085fae459e960eb10799 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 6 Aug 2009 18:06:26 +0200 Subject: perf_counter: Fix double list iteration in per task precise stats Brice Goglin reported this crash with per task precise stats: > I finally managed to test the threaded perfcounter statistics (thanks a > lot for implementing it). I am running 2.6.31-rc5 (with the AMD > magny-cours patches but I don't think they matter here). I am trying to > measure local/remote memory accesses per thread during the well-known > stream benchmark. It's compiled with OpenMP using 16 threads on a > quad-socket quad-core barcelona machine. > > Command line is: > /mnt/scratch/bgoglin/cpunode/linux-2.6.31/tools/perf/perf record -f -s > -e r1000001e0 -e r1000002e0 -e r1000004e0 -e r1000008e0 ./stream > > It seems to work fine with a single -e on the command line > while it crashes when there are at least 2 of them. > It seems to work fine without -s as well. A silly copy-paste resulted in a messed up iteration which would cause the OOPS. Reported-by: Brice Goglin Signed-off-by: Peter Zijlstra Tested-by: Brice Goglin LKML-Reference: <1249574786.32113.550.camel@twins> Signed-off-by: Ingo Molnar diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c index 199ed47..673c1aa 100644 --- a/kernel/perf_counter.c +++ b/kernel/perf_counter.c @@ -1104,7 +1104,7 @@ static void perf_counter_sync_stat(struct perf_counter_context *ctx, __perf_counter_sync_stat(counter, next_counter); counter = list_next_entry(counter, event_entry); - next_counter = list_next_entry(counter, event_entry); + next_counter = list_next_entry(next_counter, event_entry); } } -- cgit v0.10.2 From 7dbdee2e9a2ac42ea5135801bcc9d1a8e3f672aa Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Thu, 6 Aug 2009 19:53:18 -0400 Subject: tracing: Fix recordmcount.pl to handle sections with only weak functions Roland Dreier found that a section that contained only a weak function in one of the staging drivers and this caused recordmcount.pl to spit out a warning and fail. Although it is strange that a driver would have a weak function, and this function only be used in one place, it should not be something to make recordmcount.pl fail. This patch fixes the issue in a simple manner: if only weak functions exist in a section, then that section will not be recorded. Reported-by: Roland Dreier Signed-off-by: Steven Rostedt Signed-off-by: Ingo Molnar diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl index 4889c44..911ba7f 100755 --- a/scripts/recordmcount.pl +++ b/scripts/recordmcount.pl @@ -393,7 +393,7 @@ while () { $read_function = 0; } # print out any recorded offsets - update_funcs() if ($text_found); + update_funcs() if (defined($ref_func)); # reset all markers and arrays $text_found = 0; @@ -444,7 +444,7 @@ while () { } # dump out anymore offsets that may have been found -update_funcs() if ($text_found); +update_funcs() if (defined($ref_func)); # If we did not find any mcount callers, we are done (do nothing). if (!$opened) { -- cgit v0.10.2 From 677c1dd706d9cc384730cbd52baf821923d8be9b Mon Sep 17 00:00:00 2001 From: Hendrik Brueckner Date: Fri, 7 Aug 2009 10:39:24 +0200 Subject: [S390] kernel: Storing machine flags early in lowcore Currently, the machine_flags are stored late in the startup initialization which results in failing machine type checks (e.g. for MACHINE_IS_VM). To allow these checks, store the machine flags in the lowcore when the machine type has been detected. Moving the machine_flags to the lowcore has been introduced with git commit 25097bf153391f7be4c591d47061b3dc4990dac2 Signed-off-by: Hendrik Brueckner Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index 8d15314..cae14c4 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c @@ -208,6 +208,9 @@ static noinline __init void detect_machine_type(void) machine_flags |= MACHINE_FLAG_KVM; else machine_flags |= MACHINE_FLAG_VM; + + /* Store machine flags for setting up lowcore early */ + S390_lowcore.machine_flags = machine_flags; } static __init void early_pgm_check_handler(void) -- cgit v0.10.2 From 53cb780adbe69df90c8dc23e992ce40455e687c3 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Fri, 7 Aug 2009 10:39:25 +0200 Subject: [S390] KVM: Read buffer overflow Check whether index is within bounds before testing the element. Signed-off-by: Roel Kluin Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/kvm/sigp.c b/arch/s390/kvm/sigp.c index 3667883..0ef81d6 100644 --- a/arch/s390/kvm/sigp.c +++ b/arch/s390/kvm/sigp.c @@ -169,7 +169,7 @@ static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address, unsigned long *reg) { struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int; - struct kvm_s390_local_interrupt *li; + struct kvm_s390_local_interrupt *li = NULL; struct kvm_s390_interrupt_info *inti; int rc; u8 tmp; @@ -189,9 +189,10 @@ static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address, return 2; /* busy */ spin_lock(&fi->lock); - li = fi->local_int[cpu_addr]; + if (cpu_addr < KVM_MAX_VCPUS) + li = fi->local_int[cpu_addr]; - if ((cpu_addr >= KVM_MAX_VCPUS) || (li == NULL)) { + if (li == NULL) { rc = 1; /* incorrect state */ *reg &= SIGP_STAT_INCORRECT_STATE; kfree(inti); -- cgit v0.10.2 From 9795447f71324d8f14c19ed68b43c883135c3f59 Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Fri, 7 Aug 2009 16:37:10 +0800 Subject: lockdep: Fix file mode of lock_stat /proc/lock_stat is writable. Signed-off-by: Li Zefan Cc: Peter Zijlstra LKML-Reference: <4A7BE7B6.10904@cn.fujitsu.com> Signed-off-by: Ingo Molnar diff --git a/kernel/lockdep_proc.c b/kernel/lockdep_proc.c index d7135aa..e94caa6 100644 --- a/kernel/lockdep_proc.c +++ b/kernel/lockdep_proc.c @@ -758,7 +758,8 @@ static int __init lockdep_proc_init(void) &proc_lockdep_stats_operations); #ifdef CONFIG_LOCK_STAT - proc_create("lock_stat", S_IRUSR, NULL, &proc_lock_stat_operations); + proc_create("lock_stat", S_IRUSR | S_IWUSR, NULL, + &proc_lock_stat_operations); #endif return 0; -- cgit v0.10.2 From 0e692a94e378628b7d527260ad939894454bcca8 Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Fri, 7 Aug 2009 15:10:54 +0800 Subject: lockdep: Fix typos in documentation s/head/held Signed-off-by: Li Zefan Cc: Peter Zijlstra LKML-Reference: <4A7BD37E.9060806@cn.fujitsu.com> Signed-off-by: Ingo Molnar diff --git a/Documentation/lockdep-design.txt b/Documentation/lockdep-design.txt index e20d913..abf768c 100644 --- a/Documentation/lockdep-design.txt +++ b/Documentation/lockdep-design.txt @@ -30,9 +30,9 @@ State The validator tracks lock-class usage history into 4n + 1 separate state bits: - 'ever held in STATE context' -- 'ever head as readlock in STATE context' -- 'ever head with STATE enabled' -- 'ever head as readlock with STATE enabled' +- 'ever held as readlock in STATE context' +- 'ever held with STATE enabled' +- 'ever held as readlock with STATE enabled' Where STATE can be either one of (kernel/lockdep_states.h) - hardirq -- cgit v0.10.2 From 17332925d7b11bb6c2d0c49450ae58dd836005da Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 7 Aug 2009 11:03:26 +1000 Subject: drm/radeon/kms: setup MC/VRAM the same way for suspend/resume we should align the GTT after VRAM no matter what, as we can come back from resume and put in a different place and bad things happen. Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index a162ade..9ff6dcb 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -152,7 +152,9 @@ int radeon_mc_setup(struct radeon_device *rdev) } } else { rdev->mc.vram_location = 0; - rdev->mc.gtt_location = rdev->mc.mc_vram_size; + tmp = rdev->mc.mc_vram_size; + tmp = (tmp + rdev->mc.gtt_size - 1) & ~(rdev->mc.gtt_size - 1); + rdev->mc.gtt_location = tmp; } DRM_INFO("radeon: VRAM %uM\n", rdev->mc.real_vram_size >> 20); DRM_INFO("radeon: VRAM from 0x%08X to 0x%08X\n", -- cgit v0.10.2 From bd3f02212d6a457267e0c9c02c426151c436d9d4 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 7 Aug 2009 12:49:29 +0200 Subject: ring-buffer: Fix memleak in ring_buffer_free() I noticed oprofile memleaked in linux-2.6 current tree, and tracked this ring-buffer leak. Signed-off-by: Eric Dumazet LKML-Reference: <4A7C06B9.2090302@gmail.com> Cc: stable@kernel.org Signed-off-by: Steven Rostedt diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index d4d3580..a330513 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -735,6 +735,7 @@ ring_buffer_free(struct ring_buffer *buffer) put_online_cpus(); + kfree(buffer->buffers); free_cpumask_var(buffer->cpumask); kfree(buffer); -- cgit v0.10.2 From d25f14389a65c7f95512b01415d8d4a8d62855ab Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Mon, 27 Jul 2009 12:05:38 +0900 Subject: PCI hotplug: SGI hotplug: fix build failure The commit bd3d99c17039fd05a29587db3f4a180c48da115a ("PCI: Remove untested Electromechanical Interlock (EMI) support in pciehp."), which removes the definition of "struct hotplug_slot_attr", broke SGI hotplug driver. By this commit, we get the following compile error. drivers/pci/hotplug/sgi_hotplug.c:106: error: variable 'sn_slot_path_attr' has initializer but incomplete type drivers/pci/hotplug/sgi_hotplug.c:106: error: unknown field 'attr' specified in initializer drivers/pci/hotplug/sgi_hotplug.c:106: error: extra brace group at end of initializer drivers/pci/hotplug/sgi_hotplug.c:106: error: (near initialization for 'sn_slot_path_attr') drivers/pci/hotplug/sgi_hotplug.c:106: warning: excess elements in struct initializer drivers/pci/hotplug/sgi_hotplug.c:106: warning: (near initialization for 'sn_slot_path_attr') drivers/pci/hotplug/sgi_hotplug.c:106: error: unknown field 'show' specified in initializer drivers/pci/hotplug/sgi_hotplug.c:106: warning: excess elements in struct initializer drivers/pci/hotplug/sgi_hotplug.c:106: warning: (near initialization for 'sn_slot_path_attr') drivers/pci/hotplug/sgi_hotplug.c: In function 'sn_hp_destroy': drivers/pci/hotplug/sgi_hotplug.c:203: error: invalid use of undefined type 'struct hotplug_slot_attribute' drivers/pci/hotplug/sgi_hotplug.c: In function 'sn_hotplug_slot_register': drivers/pci/hotplug/sgi_hotplug.c:655: error: invalid use of undefined type 'struct hotplug_slot_attribute' This patch fixes this regression by adding the definition of struct hotplug_slot_attr into sgi_hotplug.c. Tested-by: Mike Habeck Signed-off-by: Kenji Kaneshige Signed-off-by: Jesse Barnes diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c index a4494d7..0a724bb 100644 --- a/drivers/pci/hotplug/sgi_hotplug.c +++ b/drivers/pci/hotplug/sgi_hotplug.c @@ -103,6 +103,12 @@ static ssize_t path_show (struct hotplug_slot *bss_hotplug_slot, return retval; } +struct hotplug_slot_attribute { + struct attribute attr; + ssize_t (*show)(struct hotplug_slot *, char *); + ssize_t (*store)(struct hotplug_slot *, const char *, size_t); +}; + static struct hotplug_slot_attribute sn_slot_path_attr = __ATTR_RO(path); static int sn_pci_slot_valid(struct pci_bus *pci_bus, int device) -- cgit v0.10.2 From 94f81a47c4a7a2d7a16fcfdd6d81da381732c101 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Mon, 27 Jul 2009 12:06:46 +0900 Subject: PCI hotplug: SGI hotplug: do not use hotplug_slot_attr By the pci slot changes, callbacks of attributes under slot directory (/sys/bus/pci/slots) had been changed to get the pointer to struct pci_slot instead of struct hotplug_slot. So the path_show() that assumes the parameter is a pointer to struct hotplug_slot seems broken. Tested-by: Mike Habeck Signed-off-by: Kenji Kaneshige Signed-off-by: Jesse Barnes diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c index 0a724bb..8aebe1e9 100644 --- a/drivers/pci/hotplug/sgi_hotplug.c +++ b/drivers/pci/hotplug/sgi_hotplug.c @@ -90,11 +90,10 @@ static struct hotplug_slot_ops sn_hotplug_slot_ops = { static DEFINE_MUTEX(sn_hotplug_mutex); -static ssize_t path_show (struct hotplug_slot *bss_hotplug_slot, - char *buf) +static ssize_t path_show(struct pci_slot *pci_slot, char *buf) { int retval = -ENOENT; - struct slot *slot = bss_hotplug_slot->private; + struct slot *slot = pci_slot->hotplug->private; if (!slot) return retval; @@ -103,13 +102,7 @@ static ssize_t path_show (struct hotplug_slot *bss_hotplug_slot, return retval; } -struct hotplug_slot_attribute { - struct attribute attr; - ssize_t (*show)(struct hotplug_slot *, char *); - ssize_t (*store)(struct hotplug_slot *, const char *, size_t); -}; - -static struct hotplug_slot_attribute sn_slot_path_attr = __ATTR_RO(path); +static struct pci_slot_attribute sn_slot_path_attr = __ATTR_RO(path); static int sn_pci_slot_valid(struct pci_bus *pci_bus, int device) { -- cgit v0.10.2 From 54e346215e4fe2ca8c94c54e546cc61902060510 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 7 Aug 2009 14:38:25 -0300 Subject: vfs: fix inode_init_always calling convention Currently inode_init_always calls into ->destroy_inode if the additional initialization fails. That's not only counter-intuitive because inode_init_always did not allocate the inode structure, but in case of XFS it's actively harmful as ->destroy_inode might delete the inode from a radix-tree that has never been added. This in turn might end up deleting the inode for the same inum that has been instanciated by another process and cause lots of cause subtile problems. Also in the case of re-initializing a reclaimable inode in XFS it would free an inode we still want to keep alive. Signed-off-by: Christoph Hellwig Reviewed-by: Eric Sandeen diff --git a/fs/inode.c b/fs/inode.c index 901bad1..af2c052 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -120,12 +120,11 @@ static void wake_up_inode(struct inode *inode) * These are initializations that need to be done on every inode * allocation as the fields are not initialised by slab allocation. */ -struct inode *inode_init_always(struct super_block *sb, struct inode *inode) +int inode_init_always(struct super_block *sb, struct inode *inode) { static const struct address_space_operations empty_aops; static struct inode_operations empty_iops; static const struct file_operations empty_fops; - struct address_space *const mapping = &inode->i_data; inode->i_sb = sb; @@ -152,7 +151,7 @@ struct inode *inode_init_always(struct super_block *sb, struct inode *inode) inode->dirtied_when = 0; if (security_inode_alloc(inode)) - goto out_free_inode; + goto out; /* allocate and initialize an i_integrity */ if (ima_inode_alloc(inode)) @@ -198,16 +197,12 @@ struct inode *inode_init_always(struct super_block *sb, struct inode *inode) inode->i_fsnotify_mask = 0; #endif - return inode; + return 0; out_free_security: security_inode_free(inode); -out_free_inode: - if (inode->i_sb->s_op->destroy_inode) - inode->i_sb->s_op->destroy_inode(inode); - else - kmem_cache_free(inode_cachep, (inode)); - return NULL; +out: + return -ENOMEM; } EXPORT_SYMBOL(inode_init_always); @@ -220,9 +215,18 @@ static struct inode *alloc_inode(struct super_block *sb) else inode = kmem_cache_alloc(inode_cachep, GFP_KERNEL); - if (inode) - return inode_init_always(sb, inode); - return NULL; + if (!inode) + return NULL; + + if (unlikely(inode_init_always(sb, inode))) { + if (inode->i_sb->s_op->destroy_inode) + inode->i_sb->s_op->destroy_inode(inode); + else + kmem_cache_free(inode_cachep, inode); + return NULL; + } + + return inode; } void destroy_inode(struct inode *inode) diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c index 5fcec6f..719c85b 100644 --- a/fs/xfs/xfs_iget.c +++ b/fs/xfs/xfs_iget.c @@ -64,6 +64,10 @@ xfs_inode_alloc( ip = kmem_zone_alloc(xfs_inode_zone, KM_SLEEP); if (!ip) return NULL; + if (inode_init_always(mp->m_super, VFS_I(ip))) { + kmem_zone_free(xfs_inode_zone, ip); + return NULL; + } ASSERT(atomic_read(&ip->i_iocount) == 0); ASSERT(atomic_read(&ip->i_pincount) == 0); @@ -105,17 +109,6 @@ xfs_inode_alloc( #ifdef XFS_DIR2_TRACE ip->i_dir_trace = ktrace_alloc(XFS_DIR2_KTRACE_SIZE, KM_NOFS); #endif - /* - * Now initialise the VFS inode. We do this after the xfs_inode - * initialisation as internal failures will result in ->destroy_inode - * being called and that will pass down through the reclaim path and - * free the XFS inode. This path requires the XFS inode to already be - * initialised. Hence if this call fails, the xfs_inode has already - * been freed and we should not reference it at all in the error - * handling. - */ - if (!inode_init_always(mp->m_super, VFS_I(ip))) - return NULL; /* prevent anyone from using this yet */ VFS_I(ip)->i_state = I_NEW|I_LOCK; @@ -167,7 +160,7 @@ xfs_iget_cache_hit( * errors cleanly, then tag it so it can be set up correctly * later. */ - if (!inode_init_always(mp->m_super, VFS_I(ip))) { + if (inode_init_always(mp->m_super, VFS_I(ip))) { error = ENOMEM; goto out_error; } diff --git a/include/linux/fs.h b/include/linux/fs.h index a36ffa5..0c3b5e5 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2137,7 +2137,7 @@ extern loff_t default_llseek(struct file *file, loff_t offset, int origin); extern loff_t vfs_llseek(struct file *file, loff_t offset, int origin); -extern struct inode * inode_init_always(struct super_block *, struct inode *); +extern int inode_init_always(struct super_block *, struct inode *); extern void inode_init_once(struct inode *); extern void inode_add_to_lists(struct super_block *, struct inode *); extern void iput(struct inode *); -- cgit v0.10.2 From 2e00c97e2c1d2ffc9e26252ca26b237678b0b772 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 7 Aug 2009 14:38:29 -0300 Subject: vfs: add __destroy_inode When we want to tear down an inode that lost the add to the cache race in XFS we must not call into ->destroy_inode because that would delete the inode that won the race from the inode cache radix tree. This patch provides the __destroy_inode helper needed to fix this, the actual fix will be in th next patch. As XFS was the only reason destroy_inode was exported we shift the export to the new __destroy_inode. Signed-off-by: Christoph Hellwig Reviewed-by: Eric Sandeen diff --git a/fs/inode.c b/fs/inode.c index af2c052..ae7b67e 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -229,7 +229,7 @@ static struct inode *alloc_inode(struct super_block *sb) return inode; } -void destroy_inode(struct inode *inode) +void __destroy_inode(struct inode *inode) { BUG_ON(inode_has_buffers(inode)); ima_inode_free(inode); @@ -241,13 +241,17 @@ void destroy_inode(struct inode *inode) if (inode->i_default_acl && inode->i_default_acl != ACL_NOT_CACHED) posix_acl_release(inode->i_default_acl); #endif +} +EXPORT_SYMBOL(__destroy_inode); + +void destroy_inode(struct inode *inode) +{ + __destroy_inode(inode); if (inode->i_sb->s_op->destroy_inode) inode->i_sb->s_op->destroy_inode(inode); else kmem_cache_free(inode_cachep, (inode)); } -EXPORT_SYMBOL(destroy_inode); - /* * These are initializations that only need to be done diff --git a/include/linux/fs.h b/include/linux/fs.h index 0c3b5e5..67888a9 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2164,6 +2164,7 @@ extern void __iget(struct inode * inode); extern void iget_failed(struct inode *); extern void clear_inode(struct inode *); extern void destroy_inode(struct inode *); +extern void __destroy_inode(struct inode *); extern struct inode *new_inode(struct super_block *); extern int should_remove_suid(struct dentry *); extern int file_remove_suid(struct file *); -- cgit v0.10.2 From b36ec0428a06fcbdb67d61e9e664154e5dd9a8c7 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 7 Aug 2009 14:38:34 -0300 Subject: xfs: fix freeing of inodes not yet added to the inode cache When freeing an inode that lost race getting added to the inode cache we must not call into ->destroy_inode, because that would delete the inode that won the race from the inode cache radix tree. This patch uses splits a new xfs_inode_free helper out of xfs_ireclaim and uses that plus __destroy_inode to make sure we really only free the memory allocted for the inode that lost the race, and not mess with the inode cache state. Signed-off-by: Christoph Hellwig Reviewed-by: Eric Sandeen Reported-by: Alex Samad Reported-by: Andrew Randrianasulu Reported-by: Stephane Reported-by: Tommy Reported-by: Miah Gregory Reported-by: Gabriel Barazer Reported-by: Leandro Lucarella Reported-by: Daniel Burr Reported-by: Nickolay Reported-by: Michael Guntsche Reported-by: Dan Carley Reported-by: Michael Ole Olsen Reported-by: Michael Weissenbacher Reported-by: Martin Spott Reported-by: Christian Kujau Tested-by: Michael Guntsche Tested-by: Dan Carley Tested-by: Christian Kujau diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c index 719c85b..34ec869 100644 --- a/fs/xfs/xfs_iget.c +++ b/fs/xfs/xfs_iget.c @@ -116,6 +116,71 @@ xfs_inode_alloc( return ip; } +STATIC void +xfs_inode_free( + struct xfs_inode *ip) +{ + switch (ip->i_d.di_mode & S_IFMT) { + case S_IFREG: + case S_IFDIR: + case S_IFLNK: + xfs_idestroy_fork(ip, XFS_DATA_FORK); + break; + } + + if (ip->i_afp) + xfs_idestroy_fork(ip, XFS_ATTR_FORK); + +#ifdef XFS_INODE_TRACE + ktrace_free(ip->i_trace); +#endif +#ifdef XFS_BMAP_TRACE + ktrace_free(ip->i_xtrace); +#endif +#ifdef XFS_BTREE_TRACE + ktrace_free(ip->i_btrace); +#endif +#ifdef XFS_RW_TRACE + ktrace_free(ip->i_rwtrace); +#endif +#ifdef XFS_ILOCK_TRACE + ktrace_free(ip->i_lock_trace); +#endif +#ifdef XFS_DIR2_TRACE + ktrace_free(ip->i_dir_trace); +#endif + + if (ip->i_itemp) { + /* + * Only if we are shutting down the fs will we see an + * inode still in the AIL. If it is there, we should remove + * it to prevent a use-after-free from occurring. + */ + xfs_log_item_t *lip = &ip->i_itemp->ili_item; + struct xfs_ail *ailp = lip->li_ailp; + + ASSERT(((lip->li_flags & XFS_LI_IN_AIL) == 0) || + XFS_FORCED_SHUTDOWN(ip->i_mount)); + if (lip->li_flags & XFS_LI_IN_AIL) { + spin_lock(&ailp->xa_lock); + if (lip->li_flags & XFS_LI_IN_AIL) + xfs_trans_ail_delete(ailp, lip); + else + spin_unlock(&ailp->xa_lock); + } + xfs_inode_item_destroy(ip); + ip->i_itemp = NULL; + } + + /* asserts to verify all state is correct here */ + ASSERT(atomic_read(&ip->i_iocount) == 0); + ASSERT(atomic_read(&ip->i_pincount) == 0); + ASSERT(!spin_is_locked(&ip->i_flags_lock)); + ASSERT(completion_done(&ip->i_flush)); + + kmem_zone_free(xfs_inode_zone, ip); +} + /* * Check the validity of the inode we just found it the cache */ @@ -292,7 +357,8 @@ out_preload_end: if (lock_flags) xfs_iunlock(ip, lock_flags); out_destroy: - xfs_destroy_inode(ip); + __destroy_inode(VFS_I(ip)); + xfs_inode_free(ip); return error; } @@ -497,62 +563,7 @@ xfs_ireclaim( xfs_qm_dqdetach(ip); xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); - switch (ip->i_d.di_mode & S_IFMT) { - case S_IFREG: - case S_IFDIR: - case S_IFLNK: - xfs_idestroy_fork(ip, XFS_DATA_FORK); - break; - } - - if (ip->i_afp) - xfs_idestroy_fork(ip, XFS_ATTR_FORK); - -#ifdef XFS_INODE_TRACE - ktrace_free(ip->i_trace); -#endif -#ifdef XFS_BMAP_TRACE - ktrace_free(ip->i_xtrace); -#endif -#ifdef XFS_BTREE_TRACE - ktrace_free(ip->i_btrace); -#endif -#ifdef XFS_RW_TRACE - ktrace_free(ip->i_rwtrace); -#endif -#ifdef XFS_ILOCK_TRACE - ktrace_free(ip->i_lock_trace); -#endif -#ifdef XFS_DIR2_TRACE - ktrace_free(ip->i_dir_trace); -#endif - if (ip->i_itemp) { - /* - * Only if we are shutting down the fs will we see an - * inode still in the AIL. If it is there, we should remove - * it to prevent a use-after-free from occurring. - */ - xfs_log_item_t *lip = &ip->i_itemp->ili_item; - struct xfs_ail *ailp = lip->li_ailp; - - ASSERT(((lip->li_flags & XFS_LI_IN_AIL) == 0) || - XFS_FORCED_SHUTDOWN(ip->i_mount)); - if (lip->li_flags & XFS_LI_IN_AIL) { - spin_lock(&ailp->xa_lock); - if (lip->li_flags & XFS_LI_IN_AIL) - xfs_trans_ail_delete(ailp, lip); - else - spin_unlock(&ailp->xa_lock); - } - xfs_inode_item_destroy(ip); - ip->i_itemp = NULL; - } - /* asserts to verify all state is correct here */ - ASSERT(atomic_read(&ip->i_iocount) == 0); - ASSERT(atomic_read(&ip->i_pincount) == 0); - ASSERT(!spin_is_locked(&ip->i_flags_lock)); - ASSERT(completion_done(&ip->i_flush)); - kmem_zone_free(xfs_inode_zone, ip); + xfs_inode_free(ip); } /* diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index 1804f86..65f24a3 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h @@ -310,23 +310,6 @@ static inline struct inode *VFS_I(struct xfs_inode *ip) } /* - * Get rid of a partially initialized inode. - * - * We have to go through destroy_inode to make sure allocations - * from init_inode_always like the security data are undone. - * - * We mark the inode bad so that it takes the short cut in - * the reclaim path instead of going through the flush path - * which doesn't make sense for an inode that has never seen the - * light of day. - */ -static inline void xfs_destroy_inode(struct xfs_inode *ip) -{ - make_bad_inode(VFS_I(ip)); - return destroy_inode(VFS_I(ip)); -} - -/* * i_flags helper functions */ static inline void -- cgit v0.10.2 From 2020002a878403a6858868d85a43623f74859dba Mon Sep 17 00:00:00 2001 From: Stoyan Gaydarov Date: Thu, 6 Aug 2009 15:07:28 -0700 Subject: drivers/w1/masters/omap_hdq.c: fix missing mutex unlock This was found using a semantic patch, more info can be found at: http://www.emn.fr/x-info/coccinelle/ Signed-off-by: Stoyan Gaydarov Acked-by: Evgeniy Polyakov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/w1/masters/omap_hdq.c b/drivers/w1/masters/omap_hdq.c index a7e3b70..0d92969 100644 --- a/drivers/w1/masters/omap_hdq.c +++ b/drivers/w1/masters/omap_hdq.c @@ -687,6 +687,7 @@ static int omap_hdq_remove(struct platform_device *pdev) if (hdq_data->hdq_usecount) { dev_dbg(&pdev->dev, "removed when use count is not zero\n"); + mutex_unlock(&hdq_data->hdq_mutex); return -EBUSY; } -- cgit v0.10.2 From 69dd647f969c28d18de77e2153f30d05a1874571 Mon Sep 17 00:00:00 2001 From: Xiao Guangrong Date: Thu, 6 Aug 2009 15:07:29 -0700 Subject: generic-ipi: fix hotplug_cfd() Use CONFIG_HOTPLUG_CPU, not CONFIG_CPU_HOTPLUG When hot-unpluging a cpu, it will leak memory allocated at cpu hotplug, but only if CPUMASK_OFFSTACK=y, which is default to n. The bug was introduced by 8969a5ede0f9e17da4b943712429aef2c9bcd82b ("generic-ipi: remove kmalloc()"). Signed-off-by: Xiao Guangrong Cc: Ingo Molnar Cc: Jens Axboe Cc: Nick Piggin Cc: Peter Zijlstra Cc: Rusty Russell Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/kernel/smp.c b/kernel/smp.c index ad63d85..94188b8 100644 --- a/kernel/smp.c +++ b/kernel/smp.c @@ -57,7 +57,7 @@ hotplug_cfd(struct notifier_block *nfb, unsigned long action, void *hcpu) return NOTIFY_BAD; break; -#ifdef CONFIG_CPU_HOTPLUG +#ifdef CONFIG_HOTPLUG_CPU case CPU_UP_CANCELED: case CPU_UP_CANCELED_FROZEN: -- cgit v0.10.2 From 93274e4d4e9416ad1fa47e2f26011e2c483fe5fe Mon Sep 17 00:00:00 2001 From: Stefani Seibold Date: Thu, 6 Aug 2009 15:07:30 -0700 Subject: fbcon: fix rotate upside down crash Fix the rotate_ud() function not to crash in case of a font which has not a width of multiple by 8: The inner loop of the font pixel copy should not access a bit outside the font memory area. Subtract the shift offset from the font width will prevent this. Signed-off-by: Stefani Seibold Cc: Krzysztof Helt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/console/fbcon_rotate.h b/drivers/video/console/fbcon_rotate.h index 75be5ce..e233444 100644 --- a/drivers/video/console/fbcon_rotate.h +++ b/drivers/video/console/fbcon_rotate.h @@ -45,7 +45,7 @@ static inline void rotate_ud(const char *in, char *out, u32 width, u32 height) width = (width + 7) & ~7; for (i = 0; i < height; i++) { - for (j = 0; j < width; j++) { + for (j = 0; j < width - shift; j++) { if (pattern_test_bit(j, i, width, in)) pattern_set_bit(width - (1 + j + shift), height - (1 + i), -- cgit v0.10.2 From 4bfc44958e499af9a73f62201543b3a1f617cfeb Mon Sep 17 00:00:00 2001 From: KAMEZAWA Hiroyuki Date: Thu, 6 Aug 2009 15:07:33 -0700 Subject: mm: make set_mempolicy(MPOL_INTERLEAV) N_HIGH_MEMORY aware At first, init_task's mems_allowed is initialized as this. init_task->mems_allowed == node_state[N_POSSIBLE] And cpuset's top_cpuset mask is initialized as this top_cpuset->mems_allowed = node_state[N_HIGH_MEMORY] Before 2.6.29: policy's mems_allowed is initialized as this. 1. update tasks->mems_allowed by its cpuset->mems_allowed. 2. policy->mems_allowed = nodes_and(tasks->mems_allowed, user's mask) Updating task's mems_allowed in reference to top_cpuset's one. cpuset's mems_allowed is aware of N_HIGH_MEMORY, always. In 2.6.30: After commit 58568d2a8215cb6f55caf2332017d7bdff954e1c ("cpuset,mm: update tasks' mems_allowed in time"), policy's mems_allowed is initialized as this. 1. policy->mems_allowd = nodes_and(task->mems_allowed, user's mask) Here, if task is in top_cpuset, task->mems_allowed is not updated from init's one. Assume user excutes command as #numactrl --interleave=all ,.... policy->mems_allowd = nodes_and(N_POSSIBLE, ALL_SET_MASK) Then, policy's mems_allowd can includes a possible node, which has no pgdat. MPOL's INTERLEAVE just scans nodemask of task->mems_allowd and access this directly. NODE_DATA(nid)->zonelist even if NODE_DATA(nid)==NULL Then, what's we need is making policy->mems_allowed be aware of N_HIGH_MEMORY. This patch does that. But to do so, extra nodemask will be on statck. Because I know cpumask has a new interface of CPUMASK_ALLOC(), I added it to node. This patch stands on old behavior. But I feel this fix itself is just a Band-Aid. But to do fundametal fix, we have to take care of memory hotplug and it takes time. (task->mems_allowd should be N_HIGH_MEMORY, I think.) mpol_set_nodemask() should be aware of N_HIGH_MEMORY and policy's nodemask should be includes only online nodes. In old behavior, this is guaranteed by frequent reference to cpuset's code. Now, most of them are removed and mempolicy has to check it by itself. To do check, a few nodemask_t will be used for calculating nodemask. But, size of nodemask_t can be big and it's not good to allocate them on stack. Now, cpumask_t has CPUMASK_ALLOC/FREE an easy code for get scratch area. NODEMASK_ALLOC/FREE shoudl be there. [akpm@linux-foundation.org: cleanups & tweaks] Tested-by: KOSAKI Motohiro Signed-off-by: KAMEZAWA Hiroyuki Cc: Miao Xie Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Christoph Lameter Cc: Paul Menage Cc: Nick Piggin Cc: Yasunori Goto Cc: Pekka Enberg Cc: David Rientjes Cc: Lee Schermerhorn Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/nodemask.h b/include/linux/nodemask.h index 829b94b..b359c4a 100644 --- a/include/linux/nodemask.h +++ b/include/linux/nodemask.h @@ -82,6 +82,12 @@ * to generate slightly worse code. So use a simple one-line #define * for node_isset(), instead of wrapping an inline inside a macro, the * way we do the other calls. + * + * NODEMASK_SCRATCH + * When doing above logical AND, OR, XOR, Remap operations the callers tend to + * need temporary nodemask_t's on the stack. But if NODES_SHIFT is large, + * nodemask_t's consume too much stack space. NODEMASK_SCRATCH is a helper + * for such situations. See below and CPUMASK_ALLOC also. */ #include @@ -473,4 +479,26 @@ static inline int num_node_state(enum node_states state) #define for_each_node(node) for_each_node_state(node, N_POSSIBLE) #define for_each_online_node(node) for_each_node_state(node, N_ONLINE) +/* + * For nodemask scrach area.(See CPUMASK_ALLOC() in cpumask.h) + */ + +#if NODES_SHIFT > 8 /* nodemask_t > 64 bytes */ +#define NODEMASK_ALLOC(x, m) struct x *m = kmalloc(sizeof(*m), GFP_KERNEL) +#define NODEMASK_FREE(m) kfree(m) +#else +#define NODEMASK_ALLOC(x, m) struct x _m, *m = &_m +#define NODEMASK_FREE(m) +#endif + +/* A example struture for using NODEMASK_ALLOC, used in mempolicy. */ +struct nodemask_scratch { + nodemask_t mask1; + nodemask_t mask2; +}; + +#define NODEMASK_SCRATCH(x) NODEMASK_ALLOC(nodemask_scratch, x) +#define NODEMASK_SCRATCH_FREE(x) NODEMASK_FREE(x) + + #endif /* __LINUX_NODEMASK_H */ diff --git a/mm/mempolicy.c b/mm/mempolicy.c index e08e2c4..7dd9d9f 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -191,25 +191,27 @@ static int mpol_new_bind(struct mempolicy *pol, const nodemask_t *nodes) * Must be called holding task's alloc_lock to protect task's mems_allowed * and mempolicy. May also be called holding the mmap_semaphore for write. */ -static int mpol_set_nodemask(struct mempolicy *pol, const nodemask_t *nodes) +static int mpol_set_nodemask(struct mempolicy *pol, + const nodemask_t *nodes, struct nodemask_scratch *nsc) { - nodemask_t cpuset_context_nmask; int ret; /* if mode is MPOL_DEFAULT, pol is NULL. This is right. */ if (pol == NULL) return 0; + /* Check N_HIGH_MEMORY */ + nodes_and(nsc->mask1, + cpuset_current_mems_allowed, node_states[N_HIGH_MEMORY]); VM_BUG_ON(!nodes); if (pol->mode == MPOL_PREFERRED && nodes_empty(*nodes)) nodes = NULL; /* explicit local allocation */ else { if (pol->flags & MPOL_F_RELATIVE_NODES) - mpol_relative_nodemask(&cpuset_context_nmask, nodes, - &cpuset_current_mems_allowed); + mpol_relative_nodemask(&nsc->mask2, nodes,&nsc->mask1); else - nodes_and(cpuset_context_nmask, *nodes, - cpuset_current_mems_allowed); + nodes_and(nsc->mask2, *nodes, nsc->mask1); + if (mpol_store_user_nodemask(pol)) pol->w.user_nodemask = *nodes; else @@ -217,8 +219,10 @@ static int mpol_set_nodemask(struct mempolicy *pol, const nodemask_t *nodes) cpuset_current_mems_allowed; } - ret = mpol_ops[pol->mode].create(pol, - nodes ? &cpuset_context_nmask : NULL); + if (nodes) + ret = mpol_ops[pol->mode].create(pol, &nsc->mask2); + else + ret = mpol_ops[pol->mode].create(pol, NULL); return ret; } @@ -620,12 +624,17 @@ static long do_set_mempolicy(unsigned short mode, unsigned short flags, { struct mempolicy *new, *old; struct mm_struct *mm = current->mm; + NODEMASK_SCRATCH(scratch); int ret; - new = mpol_new(mode, flags, nodes); - if (IS_ERR(new)) - return PTR_ERR(new); + if (!scratch) + return -ENOMEM; + new = mpol_new(mode, flags, nodes); + if (IS_ERR(new)) { + ret = PTR_ERR(new); + goto out; + } /* * prevent changing our mempolicy while show_numa_maps() * is using it. @@ -635,13 +644,13 @@ static long do_set_mempolicy(unsigned short mode, unsigned short flags, if (mm) down_write(&mm->mmap_sem); task_lock(current); - ret = mpol_set_nodemask(new, nodes); + ret = mpol_set_nodemask(new, nodes, scratch); if (ret) { task_unlock(current); if (mm) up_write(&mm->mmap_sem); mpol_put(new); - return ret; + goto out; } old = current->mempolicy; current->mempolicy = new; @@ -654,7 +663,10 @@ static long do_set_mempolicy(unsigned short mode, unsigned short flags, up_write(&mm->mmap_sem); mpol_put(old); - return 0; + ret = 0; +out: + NODEMASK_SCRATCH_FREE(scratch); + return ret; } /* @@ -1014,12 +1026,20 @@ static long do_mbind(unsigned long start, unsigned long len, if (err) return err; } - down_write(&mm->mmap_sem); - task_lock(current); - err = mpol_set_nodemask(new, nmask); - task_unlock(current); + { + NODEMASK_SCRATCH(scratch); + if (scratch) { + down_write(&mm->mmap_sem); + task_lock(current); + err = mpol_set_nodemask(new, nmask, scratch); + task_unlock(current); + if (err) + up_write(&mm->mmap_sem); + } else + err = -ENOMEM; + NODEMASK_SCRATCH_FREE(scratch); + } if (err) { - up_write(&mm->mmap_sem); mpol_put(new); return err; } @@ -1891,6 +1911,7 @@ restart: * Install non-NULL @mpol in inode's shared policy rb-tree. * On entry, the current task has a reference on a non-NULL @mpol. * This must be released on exit. + * This is called at get_inode() calls and we can use GFP_KERNEL. */ void mpol_shared_policy_init(struct shared_policy *sp, struct mempolicy *mpol) { @@ -1902,19 +1923,24 @@ void mpol_shared_policy_init(struct shared_policy *sp, struct mempolicy *mpol) if (mpol) { struct vm_area_struct pvma; struct mempolicy *new; + NODEMASK_SCRATCH(scratch); + if (!scratch) + return; /* contextualize the tmpfs mount point mempolicy */ new = mpol_new(mpol->mode, mpol->flags, &mpol->w.user_nodemask); if (IS_ERR(new)) { mpol_put(mpol); /* drop our ref on sb mpol */ + NODEMASK_SCRATCH_FREE(scratch); return; /* no valid nodemask intersection */ } task_lock(current); - ret = mpol_set_nodemask(new, &mpol->w.user_nodemask); + ret = mpol_set_nodemask(new, &mpol->w.user_nodemask, scratch); task_unlock(current); mpol_put(mpol); /* drop our ref on sb mpol */ if (ret) { + NODEMASK_SCRATCH_FREE(scratch); mpol_put(new); return; } @@ -1924,6 +1950,7 @@ void mpol_shared_policy_init(struct shared_policy *sp, struct mempolicy *mpol) pvma.vm_end = TASK_SIZE; /* policy covers entire file */ mpol_set_shared_policy(sp, &pvma, new); /* adds ref */ mpol_put(new); /* drop initial ref */ + NODEMASK_SCRATCH_FREE(scratch); } } @@ -2140,13 +2167,18 @@ int mpol_parse_str(char *str, struct mempolicy **mpol, int no_context) err = 1; else { int ret; - - task_lock(current); - ret = mpol_set_nodemask(new, &nodes); - task_unlock(current); - if (ret) + NODEMASK_SCRATCH(scratch); + if (scratch) { + task_lock(current); + ret = mpol_set_nodemask(new, &nodes, scratch); + task_unlock(current); + } else + ret = -ENOMEM; + NODEMASK_SCRATCH_FREE(scratch); + if (ret) { err = 1; - else if (no_context) { + mpol_put(new); + } else if (no_context) { /* save for contextualization */ new->w.user_nodemask = nodes; } -- cgit v0.10.2 From 521594442cc62d1c2af8436a05ab5918b7730b19 Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Thu, 6 Aug 2009 15:07:34 -0700 Subject: viafb: fix rmmod bug This fixes a bug caused by changing pointers (viafb_mode, viafb_mode1) assigned by module_param. It reduces driver complexity by not needlessly changing these vars as they are only read once and removing now superfluous code. On unpatched kernels loading viafb with viafb_mode or viafb_mode1 option used and afterwards unloading it results in: kernel BUG at mm/slub.c:2926! invalid opcode: 0000 [#1] PREEMPT last sysfs file: /sys/devices/virtual/block/loop0/removable Modules linked in: snd_hda_codec_realtek snd_hda_intel snd_hda_codec snd_hwdep snd_pcm rtl8187 snd_timer eeprom_93cx6 mmc_block snd soundcore via_sdmmc fb snd_page_alloc i2c_algo_bit i2c_viapro ehci_hcd uhci_hcd cfbcopyarea mmc_core cfbimgblt cfbfillrect video output [last unloaded: viafb] Pid: 3355, comm: rmmod Not tainted (2.6.31-rc1 #0) EIP: 0060:[] EFLAGS: 00010246 CPU: 0 EIP is at kfree+0x80/0xda EAX: c17c2da0 EBX: dc7edbdc ECX: 0000010f EDX: 00000000 ESI: c102c700 EDI: dc7ed8fa EBP: d703ff2c ESP: d703ff20 DS: 007b ES: 007b FS: 0000 GS: 0033 SS: 0068 Process rmmod (pid: 3355, ti=d703e000 task=db1412c0 task.ti=d703e000) Stack: dc7edbdc 00000014 00000016 d703ff40 c102c700 dc7f45d4 dc7f45d4 00000880 d703ff4c c103e571 00000000 d703ffac c103e751 66616976 da140062 db89ba80 00000328 d702edf8 db89ba80 d703ff9c c105d0f0 00000200 da14f898 00000014 Call Trace: [] ? destroy_params+0x1e/0x2b [] ? free_module+0xa2/0xd7 [] ? sys_delete_module+0x1ab/0x1da [] ? do_munmap+0x20a/0x225 [] ? sysenter_do_call+0x12/0x26 Code: 10 76 7a 8d 87 00 00 00 40 c1 e8 0c c1 e0 05 03 05 1c 87 41 c1 66 83 38 00 79 03 8b 40 0c 8b 10 84 d2 78 12 66 f7 c2 00 c0 75 04 <0f> 0b eb fe e8 6f 5a fe ff eb 47 8b 55 04 8b 58 0c 9c 5e fa 3b EIP: [] kfree+0x80/0xda SS:ESP 0068:d703ff20 This is caused by the current code changing the pointers assigned by module_param. During unload it tries to free the memory the pointers point at which is now part of an internal structure. The patch simply avoids changing the pointers. This is okay as they are read only once during the initialization process. Signed-off-by: Florian Tobias Schandinat Cc: Scott Fang Cc: Joseph Chan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c index fcd53ce..c896000 100644 --- a/drivers/video/via/hw.c +++ b/drivers/video/via/hw.c @@ -2407,14 +2407,14 @@ int viafb_setmode(int vmode_index, int hor_res, int ver_res, int video_bpp, viafb_dvi_set_mode(viafb_get_mode_index (viaparinfo->tmds_setting_info->h_active, viaparinfo->tmds_setting_info-> - v_active, 1), + v_active), video_bpp1, viaparinfo-> tmds_setting_info->iga_path); } else { viafb_dvi_set_mode(viafb_get_mode_index (viaparinfo->tmds_setting_info->h_active, viaparinfo-> - tmds_setting_info->v_active, 0), + tmds_setting_info->v_active), video_bpp, viaparinfo-> tmds_setting_info->iga_path); } diff --git a/drivers/video/via/lcd.c b/drivers/video/via/lcd.c index 6c7290a..78c6b33 100644 --- a/drivers/video/via/lcd.c +++ b/drivers/video/via/lcd.c @@ -580,10 +580,7 @@ static void load_lcd_k400_patch_tbl(int set_hres, int set_vres, int reg_num = 0; struct io_reg *lcd_patch_reg = NULL; - if (viaparinfo->lvds_setting_info->iga_path == IGA2) - vmode_index = viafb_get_mode_index(set_hres, set_vres, 1); - else - vmode_index = viafb_get_mode_index(set_hres, set_vres, 0); + vmode_index = viafb_get_mode_index(set_hres, set_vres); switch (panel_id) { /* LCD 800x600 */ case LCD_PANEL_ID1_800X600: @@ -761,10 +758,7 @@ static void load_lcd_p880_patch_tbl(int set_hres, int set_vres, int reg_num = 0; struct io_reg *lcd_patch_reg = NULL; - if (viaparinfo->lvds_setting_info->iga_path == IGA2) - vmode_index = viafb_get_mode_index(set_hres, set_vres, 1); - else - vmode_index = viafb_get_mode_index(set_hres, set_vres, 0); + vmode_index = viafb_get_mode_index(set_hres, set_vres); switch (panel_id) { case LCD_PANEL_ID5_1400X1050: @@ -832,10 +826,7 @@ static void load_lcd_patch_regs(int set_hres, int set_vres, { int vmode_index; - if (viaparinfo->lvds_setting_info->iga_path == IGA2) - vmode_index = viafb_get_mode_index(set_hres, set_vres, 1); - else - vmode_index = viafb_get_mode_index(set_hres, set_vres, 0); + vmode_index = viafb_get_mode_index(set_hres, set_vres); viafb_unlock_crt(); diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c index a0fec29..72833f3 100644 --- a/drivers/video/via/viafbdev.c +++ b/drivers/video/via/viafbdev.c @@ -32,7 +32,6 @@ static u32 pseudo_pal[17]; /* video mode */ static char *viafb_mode = "640x480"; static char *viafb_mode1 = "640x480"; -static int viafb_resMode = VIA_RES_640X480; /* Added for specifying active devices.*/ char *viafb_active_dev = ""; @@ -56,47 +55,47 @@ static void viafb_get_video_device(u32 *video_dev_info); /* Mode information */ static const struct viafb_modeinfo viafb_modentry[] = { - {480, 640, VIA_RES_480X640, "480x640"}, - {640, 480, VIA_RES_640X480, "640x480"}, - {800, 480, VIA_RES_800X480, "800x480"}, - {800, 600, VIA_RES_800X600, "800x600"}, - {1024, 768, VIA_RES_1024X768, "1024x768"}, - {1152, 864, VIA_RES_1152X864, "1152x864"}, - {1280, 1024, VIA_RES_1280X1024, "1280x1024"}, - {1600, 1200, VIA_RES_1600X1200, "1600x1200"}, - {1440, 1050, VIA_RES_1440X1050, "1440x1050"}, - {1280, 768, VIA_RES_1280X768, "1280x768"}, - {1280, 800, VIA_RES_1280X800, "1280x800"}, - {1280, 960, VIA_RES_1280X960, "1280x960"}, - {1920, 1440, VIA_RES_1920X1440, "1920x1440"}, - {848, 480, VIA_RES_848X480, "848x480"}, - {1400, 1050, VIA_RES_1400X1050, "1400x1050"}, - {720, 480, VIA_RES_720X480, "720x480"}, - {720, 576, VIA_RES_720X576, "720x576"}, - {1024, 512, VIA_RES_1024X512, "1024x512"}, - {1024, 576, VIA_RES_1024X576, "1024x576"}, - {1024, 600, VIA_RES_1024X600, "1024x600"}, - {1280, 720, VIA_RES_1280X720, "1280x720"}, - {1920, 1080, VIA_RES_1920X1080, "1920x1080"}, - {1366, 768, VIA_RES_1368X768, "1368x768"}, - {1680, 1050, VIA_RES_1680X1050, "1680x1050"}, - {960, 600, VIA_RES_960X600, "960x600"}, - {1000, 600, VIA_RES_1000X600, "1000x600"}, - {1024, 576, VIA_RES_1024X576, "1024x576"}, - {1024, 600, VIA_RES_1024X600, "1024x600"}, - {1088, 612, VIA_RES_1088X612, "1088x612"}, - {1152, 720, VIA_RES_1152X720, "1152x720"}, - {1200, 720, VIA_RES_1200X720, "1200x720"}, - {1280, 600, VIA_RES_1280X600, "1280x600"}, - {1360, 768, VIA_RES_1360X768, "1360x768"}, - {1440, 900, VIA_RES_1440X900, "1440x900"}, - {1600, 900, VIA_RES_1600X900, "1600x900"}, - {1600, 1024, VIA_RES_1600X1024, "1600x1024"}, - {1792, 1344, VIA_RES_1792X1344, "1792x1344"}, - {1856, 1392, VIA_RES_1856X1392, "1856x1392"}, - {1920, 1200, VIA_RES_1920X1200, "1920x1200"}, - {2048, 1536, VIA_RES_2048X1536, "2048x1536"}, - {0, 0, VIA_RES_INVALID, "640x480"} + {480, 640, VIA_RES_480X640}, + {640, 480, VIA_RES_640X480}, + {800, 480, VIA_RES_800X480}, + {800, 600, VIA_RES_800X600}, + {1024, 768, VIA_RES_1024X768}, + {1152, 864, VIA_RES_1152X864}, + {1280, 1024, VIA_RES_1280X1024}, + {1600, 1200, VIA_RES_1600X1200}, + {1440, 1050, VIA_RES_1440X1050}, + {1280, 768, VIA_RES_1280X768,}, + {1280, 800, VIA_RES_1280X800}, + {1280, 960, VIA_RES_1280X960}, + {1920, 1440, VIA_RES_1920X1440}, + {848, 480, VIA_RES_848X480}, + {1400, 1050, VIA_RES_1400X1050}, + {720, 480, VIA_RES_720X480}, + {720, 576, VIA_RES_720X576}, + {1024, 512, VIA_RES_1024X512}, + {1024, 576, VIA_RES_1024X576}, + {1024, 600, VIA_RES_1024X600}, + {1280, 720, VIA_RES_1280X720}, + {1920, 1080, VIA_RES_1920X1080}, + {1366, 768, VIA_RES_1368X768}, + {1680, 1050, VIA_RES_1680X1050}, + {960, 600, VIA_RES_960X600}, + {1000, 600, VIA_RES_1000X600}, + {1024, 576, VIA_RES_1024X576}, + {1024, 600, VIA_RES_1024X600}, + {1088, 612, VIA_RES_1088X612}, + {1152, 720, VIA_RES_1152X720}, + {1200, 720, VIA_RES_1200X720}, + {1280, 600, VIA_RES_1280X600}, + {1360, 768, VIA_RES_1360X768}, + {1440, 900, VIA_RES_1440X900}, + {1600, 900, VIA_RES_1600X900}, + {1600, 1024, VIA_RES_1600X1024}, + {1792, 1344, VIA_RES_1792X1344}, + {1856, 1392, VIA_RES_1856X1392}, + {1920, 1200, VIA_RES_1920X1200}, + {2048, 1536, VIA_RES_2048X1536}, + {0, 0, VIA_RES_INVALID} }; static struct fb_ops viafb_ops; @@ -177,7 +176,7 @@ static int viafb_check_var(struct fb_var_screeninfo *var, if (var->vmode & FB_VMODE_INTERLACED || var->vmode & FB_VMODE_DOUBLE) return -EINVAL; - vmode_index = viafb_get_mode_index(var->xres, var->yres, 0); + vmode_index = viafb_get_mode_index(var->xres, var->yres); if (vmode_index == VIA_RES_INVALID) { DEBUG_MSG(KERN_INFO "viafb: Mode %dx%dx%d not supported!!\n", @@ -233,14 +232,14 @@ static int viafb_set_par(struct fb_info *info) viafb_update_device_setting(info->var.xres, info->var.yres, info->var.bits_per_pixel, viafb_refresh, 0); - vmode_index = viafb_get_mode_index(info->var.xres, info->var.yres, 0); + vmode_index = viafb_get_mode_index(info->var.xres, info->var.yres); if (viafb_SAMM_ON == 1) { DEBUG_MSG(KERN_INFO "viafb_second_xres = %d, viafb_second_yres = %d, bpp = %d\n", viafb_second_xres, viafb_second_yres, viafb_bpp1); vmode_index1 = viafb_get_mode_index(viafb_second_xres, - viafb_second_yres, 1); + viafb_second_yres); DEBUG_MSG(KERN_INFO "->viafb_SAMM_ON: index=%d\n", vmode_index1); @@ -1262,7 +1261,7 @@ static int viafb_sync(struct fb_info *info) return 0; } -int viafb_get_mode_index(int hres, int vres, int flag) +int viafb_get_mode_index(int hres, int vres) { u32 i; DEBUG_MSG(KERN_INFO "viafb_get_mode_index!\n"); @@ -1272,13 +1271,7 @@ int viafb_get_mode_index(int hres, int vres, int flag) viafb_modentry[i].yres == vres) break; - viafb_resMode = viafb_modentry[i].mode_index; - if (flag) - viafb_mode1 = viafb_modentry[i].mode_res; - else - viafb_mode = viafb_modentry[i].mode_res; - - return viafb_resMode; + return viafb_modentry[i].mode_index; } static void check_available_device_to_enable(int device_id) @@ -2199,7 +2192,7 @@ static int __devinit via_pci_probe(void) strict_strtoul(tmpc, 0, &default_xres); strict_strtoul(tmpm, 0, &default_yres); - vmode_index = viafb_get_mode_index(default_xres, default_yres, 0); + vmode_index = viafb_get_mode_index(default_xres, default_yres); DEBUG_MSG(KERN_INFO "0->index=%d\n", vmode_index); if (viafb_SAMM_ON == 1) { diff --git a/drivers/video/via/viafbdev.h b/drivers/video/via/viafbdev.h index a4158e8..227b000 100644 --- a/drivers/video/via/viafbdev.h +++ b/drivers/video/via/viafbdev.h @@ -81,7 +81,6 @@ struct viafb_modeinfo { u32 xres; u32 yres; int mode_index; - char *mode_res; }; extern unsigned int viafb_second_virtual_yres; extern unsigned int viafb_second_virtual_xres; @@ -102,7 +101,7 @@ extern int strict_strtoul(const char *cp, unsigned int base, void viafb_memory_pitch_patch(struct fb_info *info); void viafb_fill_var_timing_info(struct fb_var_screeninfo *var, int refresh, int mode_index); -int viafb_get_mode_index(int hres, int vres, int flag); +int viafb_get_mode_index(int hres, int vres); u8 viafb_gpio_i2c_read_lvds(struct lvds_setting_information *plvds_setting_info, struct lvds_chip_information *plvds_chip_info, u8 index); -- cgit v0.10.2 From 0035fe00f77d2b0a1a2d001f7442136d1ec5aefa Mon Sep 17 00:00:00 2001 From: Johannes Weiner Date: Thu, 6 Aug 2009 15:07:36 -0700 Subject: fbcon: don't use vc_resize() on initialization Catalin and kmemleak spotted a leak of a VC screen buffer in vc_allocate() due to the following chain of events: vc_allocate() visual_init(init=1) vc->vc_sw->con_init(init=1) fbcon_init() vc_resize() vc->screen_buf = kmalloc() vc->screen_buf = kmalloc() The common way for the VC drivers is to set the screen dimension parameters manually in the init case and only call vc_resize() for !init - which allocates a screen buffer according to the new dimensions. fbcon instead would do vc_resize() unconditionally and afterwards set the dimensions manually (again) for !init - i.e. completely upside down. The vc_resize() allocated buffer would then get lost by vc_allocate() allocating a fresh one. Use vc_resize() only for actual resizing to close the leak. Set the dimensions manually only in initialization mode to remove the redundant setting in resize mode. The kmemleak trace from Catalin: unreferenced object 0xde158000 (size 12288): comm "Xorg", pid 1439, jiffies 4294961016 hex dump (first 32 bytes): 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00 . . . . . . . . 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00 . . . . . . . . backtrace: [] __save_stack_trace+0x17/0x1c [] create_object+0xcd/0x188 [] kmemleak_alloc+0x1b/0x3c [] __kmalloc+0xdb/0xe8 [] vc_do_resize+0x73/0x1e0 [] vc_resize+0x15/0x18 [] fbcon_init+0x1f9/0x2b8 [] visual_init+0x9f/0xdc [] vc_allocate+0x7f/0xfc [] con_open+0x17/0x80 [] tty_open+0x1f7/0x2e4 [] chrdev_open+0x101/0x118 [] __dentry_open+0x105/0x1cc [] nameidata_to_filp+0x2d/0x38 [] do_filp_open+0x2c1/0x54c [] do_sys_open+0x3b/0xb4 Reported-by: Catalin Marinas Signed-off-by: Johannes Weiner Tested-by: Catalin Marinas Cc: Pekka Enberg Cc: Krzysztof Helt Tested-by: Dave Young Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 471a9a6..3a44695 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -1082,7 +1082,6 @@ static void fbcon_init(struct vc_data *vc, int init) new_rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); new_cols /= vc->vc_font.width; new_rows /= vc->vc_font.height; - vc_resize(vc, new_cols, new_rows); /* * We must always set the mode. The mode of the previous console @@ -1111,10 +1110,11 @@ static void fbcon_init(struct vc_data *vc, int init) * vc_{cols,rows}, but we must not set those if we are only * resizing the console. */ - if (!init) { + if (init) { vc->vc_cols = new_cols; vc->vc_rows = new_rows; - } + } else + vc_resize(vc, new_cols, new_rows); if (logo) fbcon_prepare_logo(vc, info, cols, rows, new_cols, new_rows); -- cgit v0.10.2 From 69130c7cf96ea853dc5be599dd6a4b98907d39cc Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Thu, 6 Aug 2009 15:07:37 -0700 Subject: compat_ioctl: hook up compat handler for FIEMAP ioctl The FIEMAP_IOC_FIEMAP mapping ioctl was missing a 32-bit compat handler, which means that 32-bit suerspace on 64-bit kernels cannot use this ioctl command. The structure is nicely aligned, padded, and sized, so it is just this simple. Tested w/ 32-bit ioctl tester (from Josef) on a 64-bit kernel on ext4. Signed-off-by: Eric Sandeen Cc: Cc: Mark Lord Cc: Arnd Bergmann Cc: Josef Bacik Cc: Jan Kara Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index f28f070..f91fd51b 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -1905,6 +1905,7 @@ COMPATIBLE_IOCTL(FIONCLEX) COMPATIBLE_IOCTL(FIOASYNC) COMPATIBLE_IOCTL(FIONBIO) COMPATIBLE_IOCTL(FIONREAD) /* This is also TIOCINQ */ +COMPATIBLE_IOCTL(FS_IOC_FIEMAP) /* 0x00 */ COMPATIBLE_IOCTL(FIBMAP) COMPATIBLE_IOCTL(FIGETBSZ) -- cgit v0.10.2 From 2d8dd38a5aa0cc2490bbad9b75e77fa154e1d145 Mon Sep 17 00:00:00 2001 From: OGAWA Hirofumi Date: Thu, 6 Aug 2009 15:07:39 -0700 Subject: vfs: mnt_want_write_file(): fix special file handling I suspect that mnt_want_write_file() may have wrong assumption. I think mnt_want_write_file() is assuming it increments ->mnt_writers if (file->f_mode & FMODE_WRITE). But, if it's special_file(), it is false? Signed-off-by: OGAWA Hirofumi Acked-by: Dave Hansen Cc: Al Viro Cc: Nick Piggin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/namespace.c b/fs/namespace.c index 277c28a..7230787 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -316,7 +316,8 @@ EXPORT_SYMBOL_GPL(mnt_clone_write); */ int mnt_want_write_file(struct file *file) { - if (!(file->f_mode & FMODE_WRITE)) + struct inode *inode = file->f_dentry->d_inode; + if (!(file->f_mode & FMODE_WRITE) || special_file(inode->i_mode)) return mnt_want_write(file->f_path.mnt); else return mnt_clone_write(file->f_path.mnt); -- cgit v0.10.2 From 20de03dae54e10271ffd308654dfb4a117f4789d Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 6 Aug 2009 15:07:40 -0700 Subject: i.MX31: fix framebuffer locking regressions Recent framebuffer locking patches first made affected systems unbootable, then the dead-lock has been fixed but as of 2.6.31-rc4 the framebuffer on mx3 machines doesn't work. Fix this. Signed-off-by: Guennadi Liakhovetski Cc: Sascha Hauer Cc: Krzysztof Helt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/mx3fb.c b/drivers/video/mx3fb.c index f8778cd..054ef29 100644 --- a/drivers/video/mx3fb.c +++ b/drivers/video/mx3fb.c @@ -669,7 +669,8 @@ static uint32_t bpp_to_pixfmt(int bpp) } static int mx3fb_blank(int blank, struct fb_info *fbi); -static int mx3fb_map_video_memory(struct fb_info *fbi, unsigned int mem_len); +static int mx3fb_map_video_memory(struct fb_info *fbi, unsigned int mem_len, + bool lock); static int mx3fb_unmap_video_memory(struct fb_info *fbi); /** @@ -711,12 +712,7 @@ static void mx3fb_dma_done(void *arg) complete(&mx3_fbi->flip_cmpl); } -/** - * mx3fb_set_par() - set framebuffer parameters and change the operating mode. - * @fbi: framebuffer information pointer. - * @return: 0 on success or negative error code on failure. - */ -static int mx3fb_set_par(struct fb_info *fbi) +static int __set_par(struct fb_info *fbi, bool lock) { u32 mem_len; struct ipu_di_signal_cfg sig_cfg; @@ -727,10 +723,6 @@ static int mx3fb_set_par(struct fb_info *fbi) struct idmac_video_param *video = &ichan->params.video; struct scatterlist *sg = mx3_fbi->sg; - dev_dbg(mx3fb->dev, "%s [%c]\n", __func__, list_empty(&ichan->queue) ? '-' : '+'); - - mutex_lock(&mx3_fbi->mutex); - /* Total cleanup */ if (mx3_fbi->txd) sdc_disable_channel(mx3_fbi); @@ -742,10 +734,8 @@ static int mx3fb_set_par(struct fb_info *fbi) if (fbi->fix.smem_start) mx3fb_unmap_video_memory(fbi); - if (mx3fb_map_video_memory(fbi, mem_len) < 0) { - mutex_unlock(&mx3_fbi->mutex); + if (mx3fb_map_video_memory(fbi, mem_len, lock) < 0) return -ENOMEM; - } } sg_init_table(&sg[0], 1); @@ -791,7 +781,6 @@ static int mx3fb_set_par(struct fb_info *fbi) fbi->var.vsync_len, fbi->var.lower_margin + fbi->var.vsync_len, sig_cfg) != 0) { - mutex_unlock(&mx3_fbi->mutex); dev_err(fbi->device, "mx3fb: Error initializing panel.\n"); return -EINVAL; @@ -810,9 +799,30 @@ static int mx3fb_set_par(struct fb_info *fbi) if (mx3_fbi->blank == FB_BLANK_UNBLANK) sdc_enable_channel(mx3_fbi); + return 0; +} + +/** + * mx3fb_set_par() - set framebuffer parameters and change the operating mode. + * @fbi: framebuffer information pointer. + * @return: 0 on success or negative error code on failure. + */ +static int mx3fb_set_par(struct fb_info *fbi) +{ + struct mx3fb_info *mx3_fbi = fbi->par; + struct mx3fb_data *mx3fb = mx3_fbi->mx3fb; + struct idmac_channel *ichan = mx3_fbi->idmac_channel; + int ret; + + dev_dbg(mx3fb->dev, "%s [%c]\n", __func__, list_empty(&ichan->queue) ? '-' : '+'); + + mutex_lock(&mx3_fbi->mutex); + + ret = __set_par(fbi, true); + mutex_unlock(&mx3_fbi->mutex); - return 0; + return ret; } /** @@ -966,21 +976,11 @@ static int mx3fb_setcolreg(unsigned int regno, unsigned int red, return ret; } -/** - * mx3fb_blank() - blank the display. - */ -static int mx3fb_blank(int blank, struct fb_info *fbi) +static void __blank(int blank, struct fb_info *fbi) { struct mx3fb_info *mx3_fbi = fbi->par; struct mx3fb_data *mx3fb = mx3_fbi->mx3fb; - dev_dbg(fbi->device, "%s, blank = %d, base %p, len %u\n", __func__, - blank, fbi->screen_base, fbi->fix.smem_len); - - if (mx3_fbi->blank == blank) - return 0; - - mutex_lock(&mx3_fbi->mutex); mx3_fbi->blank = blank; switch (blank) { @@ -999,6 +999,23 @@ static int mx3fb_blank(int blank, struct fb_info *fbi) sdc_set_brightness(mx3fb, mx3fb->backlight_level); break; } +} + +/** + * mx3fb_blank() - blank the display. + */ +static int mx3fb_blank(int blank, struct fb_info *fbi) +{ + struct mx3fb_info *mx3_fbi = fbi->par; + + dev_dbg(fbi->device, "%s, blank = %d, base %p, len %u\n", __func__, + blank, fbi->screen_base, fbi->fix.smem_len); + + if (mx3_fbi->blank == blank) + return 0; + + mutex_lock(&mx3_fbi->mutex); + __blank(blank, fbi); mutex_unlock(&mx3_fbi->mutex); return 0; @@ -1198,6 +1215,7 @@ static int mx3fb_resume(struct platform_device *pdev) * mx3fb_map_video_memory() - allocates the DRAM memory for the frame buffer. * @fbi: framebuffer information pointer * @mem_len: length of mapped memory + * @lock: do not lock during initialisation * @return: Error code indicating success or failure * * This buffer is remapped into a non-cached, non-buffered, memory region to @@ -1205,7 +1223,8 @@ static int mx3fb_resume(struct platform_device *pdev) * area is remapped, all virtual memory access to the video memory should occur * at the new region. */ -static int mx3fb_map_video_memory(struct fb_info *fbi, unsigned int mem_len) +static int mx3fb_map_video_memory(struct fb_info *fbi, unsigned int mem_len, + bool lock) { int retval = 0; dma_addr_t addr; @@ -1221,10 +1240,12 @@ static int mx3fb_map_video_memory(struct fb_info *fbi, unsigned int mem_len) goto err0; } - mutex_lock(&fbi->mm_lock); + if (lock) + mutex_lock(&fbi->mm_lock); fbi->fix.smem_start = addr; fbi->fix.smem_len = mem_len; - mutex_unlock(&fbi->mm_lock); + if (lock) + mutex_unlock(&fbi->mm_lock); dev_dbg(fbi->device, "allocated fb @ p=0x%08x, v=0x%p, size=%d.\n", (uint32_t) fbi->fix.smem_start, fbi->screen_base, fbi->fix.smem_len); @@ -1365,6 +1386,11 @@ static int init_fb_chan(struct mx3fb_data *mx3fb, struct idmac_channel *ichan) init_completion(&mx3fbi->flip_cmpl); disable_irq(ichan->eof_irq); dev_dbg(mx3fb->dev, "disabling irq %d\n", ichan->eof_irq); + ret = __set_par(fbi, false); + if (ret < 0) + goto esetpar; + + __blank(FB_BLANK_UNBLANK, fbi); dev_info(dev, "registered, using mode %s\n", fb_mode); -- cgit v0.10.2 From 2198a64a7487aba036f71998ade8a6528070d32c Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Thu, 6 Aug 2009 15:07:41 -0700 Subject: drivers/mmc: correct error-handling code sdhci_alloc_host returns an ERR_PTR value in an error case instead of NULL. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @match exists@ expression x, E; statement S1, S2; @@ x = sdhci_alloc_host(...) ... when != x = E ( * if (x == NULL || ...) S1 else S2 | * if (x == NULL && ...) S1 else S2 ) // Signed-off-by: Julia Lawall Acked-by: Anton Vorontsov Cc: Matt Fleming Cc: Ian Molton Cc: "Roberto A. Foglietta" Cc: Philip Langdale Cc: Pierre Ossman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/mmc/host/sdhci-of.c b/drivers/mmc/host/sdhci-of.c index 9088443..1e8aa590 100644 --- a/drivers/mmc/host/sdhci-of.c +++ b/drivers/mmc/host/sdhci-of.c @@ -234,7 +234,7 @@ static int __devinit sdhci_of_probe(struct of_device *ofdev, return -ENODEV; host = sdhci_alloc_host(&ofdev->dev, sizeof(*of_host)); - if (!host) + if (IS_ERR(host)) return -ENOMEM; of_host = sdhci_priv(host); -- cgit v0.10.2 From 9c8a8228d0827e0d91d28527209988f672f97d28 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 6 Aug 2009 15:09:28 -0700 Subject: execve: must clear current->clear_child_tid While looking at Jens Rosenboom bug report (http://lkml.org/lkml/2009/7/27/35) about strange sys_futex call done from a dying "ps" program, we found following problem. clone() syscall has special support for TID of created threads. This support includes two features. One (CLONE_CHILD_SETTID) is to set an integer into user memory with the TID value. One (CLONE_CHILD_CLEARTID) is to clear this same integer once the created thread dies. The integer location is a user provided pointer, provided at clone() time. kernel keeps this pointer value into current->clear_child_tid. At execve() time, we should make sure kernel doesnt keep this user provided pointer, as full user memory is replaced by a new one. As glibc fork() actually uses clone() syscall with CLONE_CHILD_SETTID and CLONE_CHILD_CLEARTID set, chances are high that we might corrupt user memory in forked processes. Following sequence could happen: 1) bash (or any program) starts a new process, by a fork() call that glibc maps to a clone( ... CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID ...) syscall 2) When new process starts, its current->clear_child_tid is set to a location that has a meaning only in bash (or initial program) context (&THREAD_SELF->tid) 3) This new process does the execve() syscall to start a new program. current->clear_child_tid is left unchanged (a non NULL value) 4) If this new program creates some threads, and initial thread exits, kernel will attempt to clear the integer pointed by current->clear_child_tid from mm_release() : if (tsk->clear_child_tid && !(tsk->flags & PF_SIGNALED) && atomic_read(&mm->mm_users) > 1) { u32 __user * tidptr = tsk->clear_child_tid; tsk->clear_child_tid = NULL; /* * We don't check the error code - if userspace has * not set up a proper pointer then tough luck. */ << here >> put_user(0, tidptr); sys_futex(tidptr, FUTEX_WAKE, 1, NULL, NULL, 0); } 5) OR : if new program is not multi-threaded, but spied by /proc/pid users (ps command for example), mm_users > 1, and the exiting program could corrupt 4 bytes in a persistent memory area (shm or memory mapped file) If current->clear_child_tid points to a writeable portion of memory of the new program, kernel happily and silently corrupts 4 bytes of memory, with unexpected effects. Fix is straightforward and should not break any sane program. Reported-by: Jens Rosenboom Acked-by: Linus Torvalds Signed-off-by: Eric Dumazet Signed-off-by: Oleg Nesterov Cc: Peter Zijlstra Cc: Sonny Rao Cc: Ingo Molnar Cc: Thomas Gleixner Cc: Ulrich Drepper Cc: Oleg Nesterov Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/kernel/fork.c b/kernel/fork.c index 466531e..021e113 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -568,18 +568,18 @@ void mm_release(struct task_struct *tsk, struct mm_struct *mm) * the value intact in a core dump, and to save the unnecessary * trouble otherwise. Userland only wants this done for a sys_exit. */ - if (tsk->clear_child_tid - && !(tsk->flags & PF_SIGNALED) - && atomic_read(&mm->mm_users) > 1) { - u32 __user * tidptr = tsk->clear_child_tid; + if (tsk->clear_child_tid) { + if (!(tsk->flags & PF_SIGNALED) && + atomic_read(&mm->mm_users) > 1) { + /* + * We don't check the error code - if userspace has + * not set up a proper pointer then tough luck. + */ + put_user(0, tsk->clear_child_tid); + sys_futex(tsk->clear_child_tid, FUTEX_WAKE, + 1, NULL, NULL, 0); + } tsk->clear_child_tid = NULL; - - /* - * We don't check the error code - if userspace has - * not set up a proper pointer then tough luck. - */ - put_user(0, tidptr); - sys_futex(tidptr, FUTEX_WAKE, 1, NULL, NULL, 0); } } -- cgit v0.10.2 From daeb6b6fbe27049f465c48a7d0ee5555c3b84064 Mon Sep 17 00:00:00 2001 From: Phillip Lougher Date: Thu, 6 Aug 2009 15:09:30 -0700 Subject: bzip2/lzma/gzip: fix comments describing decompressor API Fix and improve comments in decompress/generic.h that describe the decompressor API. Also remove an unused definition, and rename INBUF_LEN in lib/decompress_inflate.c to conform to bzip2/lzma naming. Signed-off-by: Phillip Lougher Cc: "H. Peter Anvin" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/decompress/generic.h b/include/linux/decompress/generic.h index 6dfb856..0c7111a 100644 --- a/include/linux/decompress/generic.h +++ b/include/linux/decompress/generic.h @@ -1,31 +1,37 @@ #ifndef DECOMPRESS_GENERIC_H #define DECOMPRESS_GENERIC_H -/* Minimal chunksize to be read. - *Bzip2 prefers at least 4096 - *Lzma prefers 0x10000 */ -#define COMPR_IOBUF_SIZE 4096 - typedef int (*decompress_fn) (unsigned char *inbuf, int len, int(*fill)(void*, unsigned int), - int(*writebb)(void*, unsigned int), - unsigned char *output, + int(*flush)(void*, unsigned int), + unsigned char *outbuf, int *posp, void(*error)(char *x)); /* inbuf - input buffer *len - len of pre-read data in inbuf - *fill - function to fill inbuf if empty - *writebb - function to write out outbug + *fill - function to fill inbuf when empty + *flush - function to write out outbuf + *outbuf - output buffer *posp - if non-null, input position (number of bytes read) will be * returned here * - *If len != 0, the inbuf is initialized (with as much data), and fill - *should not be called - *If len = 0, the inbuf is allocated, but empty. Its size is IOBUF_SIZE - *fill should be called (repeatedly...) to read data, at most IOBUF_SIZE + *If len != 0, inbuf should contain all the necessary input data, and fill + *should be NULL + *If len = 0, inbuf can be NULL, in which case the decompressor will allocate + *the input buffer. If inbuf != NULL it must be at least XXX_IOBUF_SIZE bytes. + *fill will be called (repeatedly...) to read data, at most XXX_IOBUF_SIZE + *bytes should be read per call. Replace XXX with the appropriate decompressor + *name, i.e. LZMA_IOBUF_SIZE. + * + *If flush = NULL, outbuf must be large enough to buffer all the expected + *output. If flush != NULL, the output buffer will be allocated by the + *decompressor (outbuf = NULL), and the flush function will be called to + *flush the output buffer at the appropriate time (decompressor and stream + *dependent). */ + /* Utility routine to detect the decompression method */ decompress_fn decompress_method(const unsigned char *inbuf, int len, const char **name); diff --git a/lib/decompress_inflate.c b/lib/decompress_inflate.c index e36b296..bfe605a 100644 --- a/lib/decompress_inflate.c +++ b/lib/decompress_inflate.c @@ -25,7 +25,7 @@ #include #include -#define INBUF_LEN (16*1024) +#define GZIP_IOBUF_SIZE (16*1024) /* Included from initramfs et al code */ STATIC int INIT gunzip(unsigned char *buf, int len, @@ -55,7 +55,7 @@ STATIC int INIT gunzip(unsigned char *buf, int len, if (buf) zbuf = buf; else { - zbuf = malloc(INBUF_LEN); + zbuf = malloc(GZIP_IOBUF_SIZE); len = 0; } if (!zbuf) { @@ -77,7 +77,7 @@ STATIC int INIT gunzip(unsigned char *buf, int len, } if (len == 0) - len = fill(zbuf, INBUF_LEN); + len = fill(zbuf, GZIP_IOBUF_SIZE); /* verify the gzip header */ if (len < 10 || @@ -113,7 +113,7 @@ STATIC int INIT gunzip(unsigned char *buf, int len, while (rc == Z_OK) { if (strm->avail_in == 0) { /* TODO: handle case where both pos and fill are set */ - len = fill(zbuf, INBUF_LEN); + len = fill(zbuf, GZIP_IOBUF_SIZE); if (len < 0) { rc = -1; error("read error"); -- cgit v0.10.2 From b1af4315d823a2b6659c5b14bc17f7bc61878ef4 Mon Sep 17 00:00:00 2001 From: Phillip Lougher Date: Thu, 6 Aug 2009 15:09:31 -0700 Subject: bzip2/lzma: remove nasty uncompressed size hack in pre-boot environment decompress_bunzip2 and decompress_unlzma have a nasty hack that subtracts 4 from the input length if being called in the pre-boot environment. This is a nasty hack because it relies on the fact that flush = NULL only when called from the pre-boot environment (i.e. arch/x86/boot/compressed/misc.c). initramfs.c/do_mounts_rd.c pass in a flush buffer (flush != NULL). This hack prevents the decompressors from being used with flush = NULL by other callers unless knowledge of the hack is propagated to them. This patch removes the hack by making decompress (called only from the pre-boot environment) a wrapper function that subtracts 4 from the input length before calling the decompressor. Signed-off-by: Phillip Lougher Cc: "H. Peter Anvin" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/lib/decompress_bunzip2.c b/lib/decompress_bunzip2.c index 708e2a8..d3dc9f2 100644 --- a/lib/decompress_bunzip2.c +++ b/lib/decompress_bunzip2.c @@ -45,9 +45,11 @@ */ -#ifndef STATIC +#ifdef STATIC +#define PREBOOT +#else #include -#endif /* !STATIC */ +#endif /* STATIC */ #include #include @@ -681,9 +683,7 @@ STATIC int INIT bunzip2(unsigned char *buf, int len, set_error_fn(error_fn); if (flush) outbuf = malloc(BZIP2_IOBUF_SIZE); - else - len -= 4; /* Uncompressed size hack active in pre-boot - environment */ + if (!outbuf) { error("Could not allocate output bufer"); return -1; @@ -733,4 +733,14 @@ exit_0: return i; } -#define decompress bunzip2 +#ifdef PREBOOT +STATIC int INIT decompress(unsigned char *buf, int len, + int(*fill)(void*, unsigned int), + int(*flush)(void*, unsigned int), + unsigned char *outbuf, + int *pos, + void(*error_fn)(char *x)) +{ + return bunzip2(buf, len - 4, fill, flush, outbuf, pos, error_fn); +} +#endif diff --git a/lib/decompress_unlzma.c b/lib/decompress_unlzma.c index 32123a1..d3f9468 100644 --- a/lib/decompress_unlzma.c +++ b/lib/decompress_unlzma.c @@ -29,7 +29,9 @@ *Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef STATIC +#ifdef STATIC +#define PREBOOT +#else #include #endif /* STATIC */ @@ -543,9 +545,7 @@ STATIC inline int INIT unlzma(unsigned char *buf, int in_len, int ret = -1; set_error_fn(error_fn); - if (!flush) - in_len -= 4; /* Uncompressed size hack active in pre-boot - environment */ + if (buf) inbuf = buf; else @@ -645,4 +645,15 @@ exit_0: return ret; } -#define decompress unlzma +#ifdef PREBOOT +STATIC int INIT decompress(unsigned char *buf, int in_len, + int(*fill)(void*, unsigned int), + int(*flush)(void*, unsigned int), + unsigned char *output, + int *posp, + void(*error_fn)(char *x) + ) +{ + return unlzma(buf, in_len - 4, fill, flush, output, posp, error_fn); +} +#endif -- cgit v0.10.2 From 9e5cf0ca2e9b65110ae5f094d7f0f7165cd1bbbb Mon Sep 17 00:00:00 2001 From: Albin Tonnerre Date: Thu, 6 Aug 2009 15:09:32 -0700 Subject: lib/decompress_*: only include if STATIC is not defined These includes were added by 079effb6933f34b9b1b67b08bd4fd7fb672d16ef ("kmemtrace, kbuild: fix slab.h dependency problem in lib/decompress_inflate.c") to fix the build when using kmemtrace. However this is not necessary when used to create a compressed kernel, and actually creates issues (brings a lot of things unavailable in the decompression environment), so don't include it if STATIC is defined. Signed-off-by: Albin Tonnerre Cc: Sam Ravnborg Cc: Russell King Cc: Ingo Molnar Cc: Thomas Gleixner Cc: "H. Peter Anvin" Cc: Pekka Enberg Cc: Eduard - Gabriel Munteanu Cc: Phillip Lougher Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/lib/decompress_bunzip2.c b/lib/decompress_bunzip2.c index d3dc9f2..600f473 100644 --- a/lib/decompress_bunzip2.c +++ b/lib/decompress_bunzip2.c @@ -49,10 +49,10 @@ #define PREBOOT #else #include +#include #endif /* STATIC */ #include -#include #ifndef INT_MAX #define INT_MAX 0x7fffffff diff --git a/lib/decompress_inflate.c b/lib/decompress_inflate.c index bfe605a..68dfce5 100644 --- a/lib/decompress_inflate.c +++ b/lib/decompress_inflate.c @@ -19,11 +19,11 @@ #include "zlib_inflate/inflate.h" #include "zlib_inflate/infutil.h" +#include #endif /* STATIC */ #include -#include #define GZIP_IOBUF_SIZE (16*1024) diff --git a/lib/decompress_unlzma.c b/lib/decompress_unlzma.c index d3f9468..0b954e0 100644 --- a/lib/decompress_unlzma.c +++ b/lib/decompress_unlzma.c @@ -33,10 +33,10 @@ #define PREBOOT #else #include +#include #endif /* STATIC */ #include -#include #define MIN(a, b) (((a) < (b)) ? (a) : (b)) -- cgit v0.10.2 From 3440625d78711bee41a84cf29c3d8c579b522666 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 6 Aug 2009 15:09:34 -0700 Subject: flat: fix uninitialized ptr with shared libs The new credentials code broke load_flat_shared_library() as it now uses an uninitialized cred pointer. Reported-by: Bernd Schmidt Tested-by: Bernd Schmidt Cc: Mike Frysinger Cc: David Howells Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c index 697f6b5..e92f229 100644 --- a/fs/binfmt_flat.c +++ b/fs/binfmt_flat.c @@ -828,15 +828,22 @@ static int load_flat_shared_library(int id, struct lib_info *libs) if (IS_ERR(bprm.file)) return res; + bprm.cred = prepare_exec_creds(); + res = -ENOMEM; + if (!bprm.cred) + goto out; + res = prepare_binprm(&bprm); if (res <= (unsigned long)-4096) res = load_flat_file(&bprm, libs, id, NULL); - if (bprm.file) { - allow_write_access(bprm.file); - fput(bprm.file); - bprm.file = NULL; - } + + abort_creds(bprm.cred); + +out: + allow_write_access(bprm.file); + fput(bprm.file); + return(res); } -- cgit v0.10.2 From 4baf8c9201e88546918cbfa61ea8062c38bc1644 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Fri, 7 Aug 2009 13:47:08 -0400 Subject: Btrfs: remove superfluous NULL pointer check in btrfs_rename() This takes care of the following entry from Dan's list: fs/btrfs/inode.c +4788 btrfs_rename(36) warning: variable derefenced before check 'old_inode' Reported-by: Dan Carpenter Cc: Jonathan Corbet Cc: Eugene Teo Cc: Julia Lawall Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Chris Mason diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 3ea827d..04b53b5 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -4806,8 +4806,7 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry, * and the replacement file is large. Start IO on it now so * we don't add too much work to the end of the transaction */ - if (new_inode && old_inode && S_ISREG(old_inode->i_mode) && - new_inode->i_size && + if (new_inode && S_ISREG(old_inode->i_mode) && new_inode->i_size && old_inode->i_size > BTRFS_ORDERED_OPERATIONS_FLUSH_LIMIT) filemap_flush(old_inode->i_mapping); -- cgit v0.10.2 From 60f2e8f8a07331097a57ec4abcdc680405579377 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 7 Aug 2009 13:51:33 -0400 Subject: Btrfs: correct error-handling zlib error handling find_zlib_workspace returns an ERR_PTR value in an error case instead of NULL. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @match exists@ expression x, E; statement S1, S2; @@ x = find_zlib_workspace(...) ... when != x = E ( * if (x == NULL || ...) S1 else S2 | * if (x == NULL && ...) S1 else S2 ) // Signed-off-by: Julia Lawall Signed-off-by: Chris Mason diff --git a/fs/btrfs/zlib.c b/fs/btrfs/zlib.c index ecfbce8..3e2b90e 100644 --- a/fs/btrfs/zlib.c +++ b/fs/btrfs/zlib.c @@ -208,7 +208,7 @@ int btrfs_zlib_compress_pages(struct address_space *mapping, *total_in = 0; workspace = find_zlib_workspace(); - if (!workspace) + if (IS_ERR(workspace)) return -1; if (Z_OK != zlib_deflateInit(&workspace->def_strm, 3)) { @@ -366,7 +366,7 @@ int btrfs_zlib_decompress_biovec(struct page **pages_in, char *kaddr; workspace = find_zlib_workspace(); - if (!workspace) + if (IS_ERR(workspace)) return -ENOMEM; data_in = kmap(pages_in[page_in_index]); @@ -547,7 +547,7 @@ int btrfs_zlib_decompress(unsigned char *data_in, return -ENOMEM; workspace = find_zlib_workspace(); - if (!workspace) + if (IS_ERR(workspace)) return -ENOMEM; workspace->inf_strm.next_in = data_in; -- cgit v0.10.2 From ceab36edd3d3ad3ffd01d41d6d1e05ac1ff8357e Mon Sep 17 00:00:00 2001 From: Yan Zheng Date: Fri, 7 Aug 2009 13:51:33 -0400 Subject: Btrfs: fix balancing oops when invalidate_inode_pages2 returns EBUSY invalidate_inode_pages2_range may return -EBUSY occasionally which results Oops. This patch fixes the issue by moving invalidate_inode_pages2_range into a loop and keeping calling it until the return value is not -EBUSY. The EBUSY return is temporary, and can happen when the btrfs release page function is unable to release a page because the EXTENT_LOCK bit is set. Signed-off-by: Yan Zheng Signed-off-by: Chris Mason diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index e71264d..c04f7f2 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c @@ -2553,8 +2553,13 @@ int relocate_inode_pages(struct inode *inode, u64 start, u64 len) last_index = (start + len - 1) >> PAGE_CACHE_SHIFT; /* make sure the dirty trick played by the caller work */ - ret = invalidate_inode_pages2_range(inode->i_mapping, - first_index, last_index); + while (1) { + ret = invalidate_inode_pages2_range(inode->i_mapping, + first_index, last_index); + if (ret != -EBUSY) + break; + schedule_timeout(HZ/10); + } if (ret) goto out_unlock; -- cgit v0.10.2 From 49276560c9004fce24c42e3c0ad75f34d956fc63 Mon Sep 17 00:00:00 2001 From: Khanh-Dang Nguyen Thu Lam Date: Tue, 28 Jul 2009 19:41:17 +0200 Subject: USB: pl2303: New vendor and product id I am submitting a patch for the pl2303 driver. This patch adds support for the "Sony QN-3USB" cable (vendor=0x054c, product=0x0437). This USB cable is a so-called data cable used to connect a Sony mobile phone to a computer. Supported models are Sony CMD-J5, J6, J7, J16, J26, J70 and Z7. I have used this patch with my Sony CMD-J70 for several days and I haven't encountered any kernel/hardware issue. From: Khanh-Dang Nguyen Thu Lam Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 7d15bfa..3e86815 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -95,6 +95,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) }, { USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) }, { USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) }, + { USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) }, { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index 12aac7d..ee9505e 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -126,3 +126,7 @@ /* Cressi Edy (diving computer) PC interface */ #define CRESSI_VENDOR_ID 0x04b8 #define CRESSI_EDY_PRODUCT_ID 0x0521 + +/* Sony, USB data cable for CMD-Jxx mobile phones */ +#define SONY_VENDOR_ID 0x054c +#define SONY_QN3USB_PRODUCT_ID 0x0437 -- cgit v0.10.2 From 18753ebc8a98efe0e8ff6167afb31cef220c8e50 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 29 Jul 2009 11:39:03 +0200 Subject: USB: devio: Properly do access_ok() checks access_ok() checks must be done on every part of the userspace structure that is accessed. If access_ok() on one part of the struct succeeded, it does not imply it will succeed on other parts of the struct. (Does depend on the architecture implementation of access_ok()). This changes the __get_user() users to first check access_ok() on the data structure. Signed-off-by: Michael Buesch Cc: stable Cc: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 38b8bce..e192fa0 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -1321,7 +1321,8 @@ static int get_urb32(struct usbdevfs_urb *kurb, struct usbdevfs_urb32 __user *uurb) { __u32 uptr; - if (get_user(kurb->type, &uurb->type) || + if (!access_ok(VERIFY_READ, uurb, sizeof(*uurb)) || + __get_user(kurb->type, &uurb->type) || __get_user(kurb->endpoint, &uurb->endpoint) || __get_user(kurb->status, &uurb->status) || __get_user(kurb->flags, &uurb->flags) || @@ -1536,8 +1537,9 @@ static int proc_ioctl_compat(struct dev_state *ps, compat_uptr_t arg) u32 udata; uioc = compat_ptr((long)arg); - if (get_user(ctrl.ifno, &uioc->ifno) || - get_user(ctrl.ioctl_code, &uioc->ioctl_code) || + if (!access_ok(VERIFY_READ, uioc, sizeof(*uioc)) || + __get_user(ctrl.ifno, &uioc->ifno) || + __get_user(ctrl.ioctl_code, &uioc->ioctl_code) || __get_user(udata, &uioc->data)) return -EFAULT; ctrl.data = compat_ptr(udata); -- cgit v0.10.2 From e8e2ff462dd92693f29eb848f42d3eb720390d59 Mon Sep 17 00:00:00 2001 From: "Gupta, Ajay Kumar" Date: Wed, 29 Jul 2009 11:58:57 +0530 Subject: USB: musb: fix the nop registration for OMAP3EVM OMAP3EVM uses ISP1504 phy which doesn't require any programming and thus has to use NOP otg transceiver. Cleanups being done: - Remove unwanted code in usb-musb.c file - Register NOP in OMAP3EVM board file using usb_nop_xceiv_register(). - Select NOP_USB_XCEIV for OMAP3EVM boards. - Don't enable TWL4030_USB in omap3_evm_defconfig Signed-off-by: Ajay Kumar Gupta Signed-off-by: Eino-Ville Talvala Acked-by: David Brownell Signed-off-by: Greg Kroah-Hartman diff --git a/arch/arm/configs/omap3_evm_defconfig b/arch/arm/configs/omap3_evm_defconfig index 28be17f..d5ff477 100644 --- a/arch/arm/configs/omap3_evm_defconfig +++ b/arch/arm/configs/omap3_evm_defconfig @@ -1107,7 +1107,7 @@ CONFIG_USB_ZERO=m CONFIG_USB_OTG_UTILS=y # CONFIG_USB_GPIO_VBUS is not set # CONFIG_ISP1301_OMAP is not set -CONFIG_TWL4030_USB=y +# CONFIG_TWL4030_USB is not set # CONFIG_NOP_USB_XCEIV is not set CONFIG_MMC=y # CONFIG_MMC_DEBUG is not set diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c index d3cc145..cf3dd77 100644 --- a/arch/arm/mach-omap2/board-omap3evm.c +++ b/arch/arm/mach-omap2/board-omap3evm.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -307,6 +308,10 @@ static void __init omap3_evm_init(void) ARRAY_SIZE(omap3evm_spi_board_info)); omap_serial_init(); +#ifdef CONFIG_NOP_USB_XCEIV + /* OMAP3EVM uses ISP1504 phy and so register nop transceiver */ + usb_nop_xceiv_register(); +#endif usb_musb_init(); ads7846_dev_init(); } diff --git a/arch/arm/mach-omap2/usb-musb.c b/arch/arm/mach-omap2/usb-musb.c index d85296d..739e59e 100644 --- a/arch/arm/mach-omap2/usb-musb.c +++ b/arch/arm/mach-omap2/usb-musb.c @@ -155,20 +155,6 @@ static struct platform_device musb_device = { .resource = musb_resources, }; -#ifdef CONFIG_NOP_USB_XCEIV -static u64 nop_xceiv_dmamask = DMA_BIT_MASK(32); - -static struct platform_device nop_xceiv_device = { - .name = "nop_usb_xceiv", - .id = -1, - .dev = { - .dma_mask = &nop_xceiv_dmamask, - .coherent_dma_mask = DMA_BIT_MASK(32), - .platform_data = NULL, - }, -}; -#endif - void __init usb_musb_init(void) { if (cpu_is_omap243x()) @@ -183,13 +169,6 @@ void __init usb_musb_init(void) */ musb_plat.clock = "ick"; -#ifdef CONFIG_NOP_USB_XCEIV - if (platform_device_register(&nop_xceiv_device) < 0) { - printk(KERN_ERR "Unable to register NOP-XCEIV device\n"); - return; - } -#endif - if (platform_device_register(&musb_device) < 0) { printk(KERN_ERR "Unable to register HS-USB (MUSB) device\n"); return; diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index 70073b1..803adcb 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -12,6 +12,7 @@ config USB_MUSB_HDRC depends on !SUPERH select NOP_USB_XCEIV if ARCH_DAVINCI select TWL4030_USB if MACH_OMAP_3430SDP + select NOP_USB_XCEIV if MACH_OMAP3EVM select USB_OTG_UTILS tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)' help -- cgit v0.10.2 From 01105a246345f011fde64d24a601090b646e9e4c Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 30 Jul 2009 15:28:14 -0400 Subject: USB: usbfs: fix -ENOENT error code to be -ENODEV This patch (as1272) changes the error code returned when an open call for a USB device node fails to locate the corresponding device. The appropriate error code is -ENODEV, not -ENOENT. Signed-off-by: Alan Stern CC: Kay Sievers Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index e192fa0..4247ecc 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -595,7 +595,7 @@ static int usbdev_open(struct inode *inode, struct file *file) if (!ps) goto out; - ret = -ENOENT; + ret = -ENODEV; /* usbdev device-node */ if (imajor(inode) == USB_DEVICE_MAJOR) -- cgit v0.10.2 From 7a0f0d951273eee889c2441846842348ebc00a2a Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 31 Jul 2009 10:40:22 -0400 Subject: USB: EHCI: fix two new bugs related to Clear-TT-Buffer This patch (as1273) fixes two(!) bugs introduced by the new Clear-TT-Buffer implementation in ehci-hcd. It is now possible for an idle QH to have some URBs on its queue -- this will happen if a Clear-TT-Buffer is pending for the QH's endpoint. Consequently we should not issue a warning when someone tries to unlink an URB from an idle QH; instead we should process the request immediately. The refcounts for QHs could get messed up, because submit_async() would increment the refcount when calling qh_link_async() and qh_link_async() would then refuse to link the QH into the schedule if a Clear-TT-Buffer was pending. Instead we should increment the refcount only when the QH actually is added to the schedule. The current code tries to be clever by leaving the refcount alone if an unlink is immediately followed by a relink; the patch changes this to an unconditional decrement and increment (although they occur in the opposite order). Signed-off-by: Alan Stern CC: David Brownell Tested-by: Manuel Lauss Tested-by: Matthijs Kooijman Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 7d03549..11c627c 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -903,7 +903,8 @@ static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) /* already started */ break; case QH_STATE_IDLE: - WARN_ON(1); + /* QH might be waiting for a Clear-TT-Buffer */ + qh_completions(ehci, qh); break; } break; diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 9a13847..b273805 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -940,6 +940,7 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh) head->qh_next.qh = qh; head->hw_next = dma; + qh_get(qh); qh->xacterrs = QH_XACTERR_MAX; qh->qh_state = QH_STATE_LINKED; /* qtd completions reported later by interrupt */ @@ -1080,7 +1081,7 @@ submit_async ( * the HC and TT handle it when the TT has a buffer ready. */ if (likely (qh->qh_state == QH_STATE_IDLE)) - qh_link_async (ehci, qh_get (qh)); + qh_link_async(ehci, qh); done: spin_unlock_irqrestore (&ehci->lock, flags); if (unlikely (qh == NULL)) @@ -1115,8 +1116,6 @@ static void end_unlink_async (struct ehci_hcd *ehci) && HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) qh_link_async (ehci, qh); else { - qh_put (qh); // refcount from async list - /* it's not free to turn the async schedule on/off; leave it * active but idle for a while once it empties. */ @@ -1124,6 +1123,7 @@ static void end_unlink_async (struct ehci_hcd *ehci) && ehci->async->qh_next.qh == NULL) timer_action (ehci, TIMER_ASYNC_OFF); } + qh_put(qh); /* refcount from async list */ if (next) { ehci->reclaim = NULL; -- cgit v0.10.2 From ef4638f955f2c4a667c8af20769d03f5ed3781ca Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 31 Jul 2009 10:41:40 -0400 Subject: USB: EHCI: fix counting of transaction error retries This patch (as1274) simplifies the counting of transaction-error retries. Now we will count up from 0 to QH_XACTERR_MAX instead of down from QH_XACTERR_MAX to 0. The patch also fixes a small bug: qh->xacterr was not getting initialized for interrupt endpoints. Signed-off-by: Alan Stern Tested-by: Matthijs Kooijman Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index b273805..7673554 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -375,12 +375,11 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) */ if ((token & QTD_STS_XACT) && QTD_CERR(token) == 0 && - --qh->xacterrs > 0 && + ++qh->xacterrs < QH_XACTERR_MAX && !urb->unlinked) { ehci_dbg(ehci, "detected XactErr len %zu/%zu retry %d\n", - qtd->length - QTD_LENGTH(token), qtd->length, - QH_XACTERR_MAX - qh->xacterrs); + qtd->length - QTD_LENGTH(token), qtd->length, qh->xacterrs); /* reset the token in the qtd and the * qh overlay (which still contains @@ -494,7 +493,7 @@ halt: last = qtd; /* reinit the xacterr counter for the next qtd */ - qh->xacterrs = QH_XACTERR_MAX; + qh->xacterrs = 0; } /* last urb's completion might still need calling */ @@ -941,7 +940,7 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh) head->hw_next = dma; qh_get(qh); - qh->xacterrs = QH_XACTERR_MAX; + qh->xacterrs = 0; qh->qh_state = QH_STATE_LINKED; /* qtd completions reported later by interrupt */ } diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 74f7f83..edd61ee 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -542,6 +542,7 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh) } } qh->qh_state = QH_STATE_LINKED; + qh->xacterrs = 0; qh_get (qh); /* update per-qh bandwidth for usbfs */ -- cgit v0.10.2 From c47aacc67a3d26dfab9c9b8965975ed2b2010b30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20H=C3=A4nninen?= Date: Fri, 31 Jul 2009 22:32:39 +0300 Subject: USB: ftdi_sio: add vendor and product id for Bayer glucose meter serial converter cable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Attached patch adds USB vendor and product IDs for Bayer's USB to serial converter cable used by Bayer blood glucose meters. It seems to be a FT232RL based device and works without any problem with ftdi_sio driver when this patch is applied. See: http://winglucofacts.com/cables/ Signed-off-by: Marko Hänninen Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index b574878..500087e 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -699,6 +699,7 @@ static struct usb_device_id id_table_combined [] = { .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(LARSENBRUSGAARD_VID, LB_ALTITRACK_PID) }, { USB_DEVICE(GN_OTOMETRICS_VID, AURICAL_USB_PID) }, + { USB_DEVICE(BAYER_VID, BAYER_CONTOUR_CABLE_PID) }, { }, /* Optional parameter entry */ { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index 24dbd99..f203b2a 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -954,6 +954,13 @@ #define AURICAL_USB_PID 0x0010 /* Aurical USB Audiometer */ /* + * Bayer Ascensia Contour blood glucose meter USB-converter cable. + * http://winglucofacts.com/cables/ + */ +#define BAYER_VID 0x1A79 +#define BAYER_CONTOUR_CABLE_PID 0x6001 + +/* * BmRequestType: 1100 0000b * bRequest: FTDI_E2_READ * wValue: 0 -- cgit v0.10.2 From 50d0678e2026c18e4147f0b16b5853113659b82d Mon Sep 17 00:00:00 2001 From: Dhaval Vasa Date: Fri, 7 Aug 2009 17:26:49 +0530 Subject: USB: ftdi_sio: add product_id for Marvell OpenRD Base, Client reference: http://www.open-rd.org Signed-off-by: Dhaval Vasa Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 500087e..8fec5d4 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -700,6 +700,8 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(LARSENBRUSGAARD_VID, LB_ALTITRACK_PID) }, { USB_DEVICE(GN_OTOMETRICS_VID, AURICAL_USB_PID) }, { USB_DEVICE(BAYER_VID, BAYER_CONTOUR_CABLE_PID) }, + { USB_DEVICE(FTDI_VID, MARVELL_OPENRD_PID), + .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { }, /* Optional parameter entry */ { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index f203b2a..8c92b88 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -961,6 +961,13 @@ #define BAYER_CONTOUR_CABLE_PID 0x6001 /* + * Marvell OpenRD Base, Client + * http://www.open-rd.org + * OpenRD Base, Client use VID 0x0403 + */ +#define MARVELL_OPENRD_PID 0x9e90 + +/* * BmRequestType: 1100 0000b * bRequest: FTDI_E2_READ * wValue: 0 -- cgit v0.10.2 From c15e3ca1d822abba78c00b1ffc3e7b382a50396e Mon Sep 17 00:00:00 2001 From: Rogerio Brito Date: Thu, 6 Aug 2009 15:20:19 -0700 Subject: USB: storage: include Prolific Technology USB drive in unusual_devs list Add a quirk entry for the Leading Driver UD-11 usb flash drive. As Alan Stern told me, the device doesn't deal correctly with the locking media feature of the device, and this patch incorporates it. Compiled, tested, working. Signed-off-by: Rogerio Brito Cc: Phil Dibowitz Cc: Alan Stern Cc: Robert Hancock Cc: stable Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 1b9c5dd..7477d41 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -838,6 +838,13 @@ UNUSUAL_DEV( 0x066f, 0x8000, 0x0001, 0x0001, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY ), +/* Reported by Rogerio Brito */ +UNUSUAL_DEV( 0x067b, 0x2317, 0x0001, 0x001, + "Prolific Technology, Inc.", + "Mass Storage Device", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_NOT_LOCKABLE ), + /* Reported by Richard -=[]=- */ /* Change to bcdDeviceMin (0x0100 to 0x0001) reported by * Thomas Bartosik */ -- cgit v0.10.2 From cf7fdd57f978d40ceb9a0f58a25f5cf9c84d6f33 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Tue, 4 Aug 2009 23:52:09 +0200 Subject: USB: fix oops on disconnect in cdc-acm This patch fixes an oops caused when during an unplug a device's table of endpoints is zeroed before the driver is notified. A pointer to the endpoint must be cached. this fixes a regression caused by commit 5186ffee2320942c3dc9745f7930e0eb15329ca6 Therefore it should go into 2.6.31 Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index e1f8941..2bfc41e 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -387,7 +387,6 @@ static void acm_rx_tasklet(unsigned long _acm) struct acm_ru *rcv; unsigned long flags; unsigned char throttled; - struct usb_host_endpoint *ep; dbg("Entering acm_rx_tasklet"); @@ -463,14 +462,12 @@ urbs: rcv->buffer = buf; - ep = (usb_pipein(acm->rx_endpoint) ? acm->dev->ep_in : acm->dev->ep_out) - [usb_pipeendpoint(acm->rx_endpoint)]; - if (usb_endpoint_xfer_int(&ep->desc)) + if (acm->is_int_ep) usb_fill_int_urb(rcv->urb, acm->dev, acm->rx_endpoint, buf->base, acm->readsize, - acm_read_bulk, rcv, ep->desc.bInterval); + acm_read_bulk, rcv, acm->bInterval); else usb_fill_bulk_urb(rcv->urb, acm->dev, acm->rx_endpoint, @@ -1183,6 +1180,9 @@ made_compressed_probe: spin_lock_init(&acm->read_lock); mutex_init(&acm->mutex); acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress); + acm->is_int_ep = usb_endpoint_xfer_int(epread); + if (acm->is_int_ep) + acm->bInterval = epread->bInterval; tty_port_init(&acm->port); acm->port.ops = &acm_port_ops; diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h index 1602324..c4a0ee8 100644 --- a/drivers/usb/class/cdc-acm.h +++ b/drivers/usb/class/cdc-acm.h @@ -126,6 +126,8 @@ struct acm { unsigned int ctrl_caps; /* control capabilities from the class specific header */ unsigned int susp_count; /* number of suspended interfaces */ int combined_interfaces:1; /* control and data collapsed */ + int is_int_ep:1; /* interrupt endpoints contrary to spec used */ + u8 bInterval; struct acm_wb *delayed_wb; /* write queued for a device about to be woken */ }; -- cgit v0.10.2 From 4d2da07bc876fc5bc455e0721df388a3db7e4ba5 Mon Sep 17 00:00:00 2001 From: Jakob Gruber Date: Thu, 30 Jul 2009 20:37:36 +0200 Subject: Staging: rt2870: Add USB ID for Linksys, Planex Communications, Belkin Linksys WUSB100, Belkin F5D8053 N, Planex Communications unknown model. Signed-off-by: Jakob Gruber Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/rt2870/rt2870.h b/drivers/staging/rt2870/rt2870.h index 29e3b53..10e1640 100644 --- a/drivers/staging/rt2870/rt2870.h +++ b/drivers/staging/rt2870/rt2870.h @@ -79,6 +79,7 @@ { \ {USB_DEVICE(0x148F,0x2770)}, /* Ralink */ \ {USB_DEVICE(0x1737,0x0071)}, /* Linksys WUSB600N */ \ + {USB_DEVICE(0x1737,0x0070)}, /* Linksys */ \ {USB_DEVICE(0x148F,0x2870)}, /* Ralink */ \ {USB_DEVICE(0x148F,0x3070)}, /* Ralink */ \ {USB_DEVICE(0x0B05,0x1731)}, /* Asus */ \ @@ -93,12 +94,14 @@ {USB_DEVICE(0x14B2,0x3C06)}, /* Conceptronic */ \ {USB_DEVICE(0x14B2,0x3C28)}, /* Conceptronic */ \ {USB_DEVICE(0x2019,0xED06)}, /* Planex Communications, Inc. */ \ + {USB_DEVICE(0x2019,0xED14)}, /* Planex Communications, Inc. */ \ {USB_DEVICE(0x2019,0xAB25)}, /* Planex Communications, Inc. RT3070 */ \ {USB_DEVICE(0x07D1,0x3C09)}, /* D-Link */ \ {USB_DEVICE(0x07D1,0x3C11)}, /* D-Link */ \ {USB_DEVICE(0x14B2,0x3C07)}, /* AL */ \ {USB_DEVICE(0x14B2,0x3C12)}, /* AL */ \ {USB_DEVICE(0x050D,0x8053)}, /* Belkin */ \ + {USB_DEVICE(0x050D,0x815C)}, /* Belkin */ \ {USB_DEVICE(0x14B2,0x3C23)}, /* Airlink */ \ {USB_DEVICE(0x14B2,0x3C27)}, /* Airlink */ \ {USB_DEVICE(0x07AA,0x002F)}, /* Corega */ \ -- cgit v0.10.2 From 2c63abf9e8a51dec886da482dfd8ae752581a61c Mon Sep 17 00:00:00 2001 From: Mike Galbraith Date: Fri, 31 Jul 2009 07:14:04 +0200 Subject: Staging: rt2870: Revert d44ca7 Removal of kernel_thread() API Staging: rt2870: Revert d44ca7 Removal of kernel_thread() API The sanity check this patch introduced triggers on shutdown, apparently due to threads having already exited by the time BUG_ON() is reached. Signed-off-by: Mike Galbraith Cc: Peter Teoh Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/rt2860/rt_linux.h b/drivers/staging/rt2860/rt_linux.h index 85175c1..25b53ac 100644 --- a/drivers/staging/rt2860/rt_linux.h +++ b/drivers/staging/rt2860/rt_linux.h @@ -43,9 +43,6 @@ #include "rtmp_type.h" #include #include -#if !defined(RT2860) && !defined(RT30xx) -#include -#endif #include #include @@ -166,9 +163,7 @@ typedef int (*HARD_START_XMIT_FUNC)(struct sk_buff *skb, struct net_device *net_ #ifndef RT30xx typedef struct pid * THREAD_PID; -#ifdef RT2860 #define THREAD_PID_INIT_VALUE NULL -#endif #define GET_PID(_v) find_get_pid(_v) #define GET_PID_NUMBER(_v) pid_nr(_v) #define CHECK_PID_LEGALITY(_pid) if (pid_nr(_pid) >= 0) @@ -188,12 +183,12 @@ struct os_cookie { dma_addr_t pAd_pa; #endif #ifdef RT2870 - struct usb_device *pUsb_Dev; + struct usb_device *pUsb_Dev; #ifndef RT30xx - struct task_struct *MLMEThr_task; - struct task_struct *RTUSBCmdThr_task; - struct task_struct *TimerQThr_task; + THREAD_PID MLMEThr_pid; + THREAD_PID RTUSBCmdThr_pid; + THREAD_PID TimerQThr_pid; #endif #ifdef RT30xx struct pid *MLMEThr_pid; diff --git a/drivers/staging/rt2870/2870_main_dev.c b/drivers/staging/rt2870/2870_main_dev.c index dd01c64..a4e8696 100644 --- a/drivers/staging/rt2870/2870_main_dev.c +++ b/drivers/staging/rt2870/2870_main_dev.c @@ -235,7 +235,7 @@ INT MlmeThread( DBGPRINT(RT_DEBUG_TRACE,( "<---%s\n",__func__)); #ifndef RT30xx - pObj->MLMEThr_task = NULL; + pObj->MLMEThr_pid = THREAD_PID_INIT_VALUE; #endif #ifdef RT30xx pObj->MLMEThr_pid = NULL; @@ -348,7 +348,7 @@ INT RTUSBCmdThread( DBGPRINT(RT_DEBUG_TRACE,( "<---RTUSBCmdThread\n")); #ifndef RT30xx - pObj->RTUSBCmdThr_task = NULL; + pObj->RTUSBCmdThr_pid = THREAD_PID_INIT_VALUE; #endif #ifdef RT30xx pObj->RTUSBCmdThr_pid = NULL; @@ -447,7 +447,7 @@ INT TimerQThread( DBGPRINT(RT_DEBUG_TRACE,( "<---%s\n",__func__)); #ifndef RT30xx - pObj->TimerQThr_task = NULL; + pObj->TimerQThr_pid = THREAD_PID_INIT_VALUE; #endif #ifdef RT30xx pObj->TimerQThr_pid = NULL; @@ -883,46 +883,69 @@ VOID RT28xxThreadTerminate( // Terminate Threads #ifndef RT30xx - BUG_ON(pObj->TimerQThr_task == NULL); - CHECK_PID_LEGALITY(task_pid(pObj->TimerQThr_task)) + CHECK_PID_LEGALITY(pObj->TimerQThr_pid) { POS_COOKIE pObj = (POS_COOKIE)pAd->OS_Cookie; - printk(KERN_DEBUG "Terminate the TimerQThr pid=%d!\n", - pid_nr(task_pid(pObj->TimerQThr_task))); + printk("Terminate the TimerQThr_pid=%d!\n", GET_PID_NUMBER(pObj->TimerQThr_pid)); mb(); pAd->TimerFunc_kill = 1; mb(); - kthread_stop(pObj->TimerQThr_task); - pObj->TimerQThr_task = NULL; + ret = KILL_THREAD_PID(pObj->TimerQThr_pid, SIGTERM, 1); + if (ret) + { + printk(KERN_WARNING "%s: unable to stop TimerQThread, pid=%d, ret=%d!\n", + pAd->net_dev->name, GET_PID_NUMBER(pObj->TimerQThr_pid), ret); + } + else + { + wait_for_completion(&pAd->TimerQComplete); + pObj->TimerQThr_pid = THREAD_PID_INIT_VALUE; + } } - BUG_ON(pObj->MLMEThr_task == NULL); - CHECK_PID_LEGALITY(task_pid(pObj->MLMEThr_task)) + CHECK_PID_LEGALITY(pObj->MLMEThr_pid) { - printk(KERN_DEBUG "Terminate the MLMEThr pid=%d!\n", - pid_nr(task_pid(pObj->MLMEThr_task))); + printk("Terminate the MLMEThr_pid=%d!\n", GET_PID_NUMBER(pObj->MLMEThr_pid)); mb(); pAd->mlme_kill = 1; //RT28XX_MLME_HANDLER(pAd); mb(); - kthread_stop(pObj->MLMEThr_task); - pObj->MLMEThr_task = NULL; + ret = KILL_THREAD_PID(pObj->MLMEThr_pid, SIGTERM, 1); + if (ret) + { + printk (KERN_WARNING "%s: unable to Mlme thread, pid=%d, ret=%d!\n", + pAd->net_dev->name, GET_PID_NUMBER(pObj->MLMEThr_pid), ret); + } + else + { + //wait_for_completion (&pAd->notify); + wait_for_completion (&pAd->mlmeComplete); + pObj->MLMEThr_pid = THREAD_PID_INIT_VALUE; + } } - BUG_ON(pObj->RTUSBCmdThr_task == NULL); - CHECK_PID_LEGALITY(task_pid(pObj->RTUSBCmdThr_task)) + CHECK_PID_LEGALITY(pObj->RTUSBCmdThr_pid) { - printk(KERN_DEBUG "Terminate the RTUSBCmdThr pid=%d!\n", - pid_nr(task_pid(pObj->RTUSBCmdThr_task))); + printk("Terminate the RTUSBCmdThr_pid=%d!\n", GET_PID_NUMBER(pObj->RTUSBCmdThr_pid)); mb(); NdisAcquireSpinLock(&pAd->CmdQLock); pAd->CmdQ.CmdQState = RT2870_THREAD_STOPED; NdisReleaseSpinLock(&pAd->CmdQLock); mb(); //RTUSBCMDUp(pAd); - kthread_stop(pObj->RTUSBCmdThr_task); - pObj->RTUSBCmdThr_task = NULL; + ret = KILL_THREAD_PID(pObj->RTUSBCmdThr_pid, SIGTERM, 1); + if (ret) + { + printk(KERN_WARNING "%s: unable to RTUSBCmd thread, pid=%d, ret=%d!\n", + pAd->net_dev->name, GET_PID_NUMBER(pObj->RTUSBCmdThr_pid), ret); + } + else + { + //wait_for_completion (&pAd->notify); + wait_for_completion (&pAd->CmdQComplete); + pObj->RTUSBCmdThr_pid = THREAD_PID_INIT_VALUE; + } } #endif #ifdef RT30xx @@ -1045,7 +1068,7 @@ BOOLEAN RT28XXChipsetCheck( dev_p->descriptor.idProduct == rtusb_usb_id[i].idProduct) { #ifndef RT30xx - printk(KERN_DEBUG "rt2870: idVendor = 0x%x, idProduct = 0x%x\n", + printk("rt2870: idVendor = 0x%x, idProduct = 0x%x\n", #endif #ifdef RT30xx printk("rt2870: idVendor = 0x%x, idProduct = 0x%x\n", diff --git a/drivers/staging/rt2870/common/2870_rtmp_init.c b/drivers/staging/rt2870/common/2870_rtmp_init.c index 0f4c8af..80909e9 100644 --- a/drivers/staging/rt2870/common/2870_rtmp_init.c +++ b/drivers/staging/rt2870/common/2870_rtmp_init.c @@ -700,8 +700,8 @@ NDIS_STATUS AdapterBlockAllocateMemory( usb_dev = pObj->pUsb_Dev; #ifndef RT30xx - pObj->MLMEThr_task = NULL; - pObj->RTUSBCmdThr_task = NULL; + pObj->MLMEThr_pid = THREAD_PID_INIT_VALUE; + pObj->RTUSBCmdThr_pid = THREAD_PID_INIT_VALUE; #endif #ifdef RT30xx pObj->MLMEThr_pid = NULL; @@ -743,7 +743,7 @@ NDIS_STATUS CreateThreads( PRTMP_ADAPTER pAd = net_dev->ml_priv; POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; #ifndef RT30xx - struct task_struct *tsk; + pid_t pid_number = -1; #endif #ifdef RT30xx pid_t pid_number; @@ -762,10 +762,10 @@ NDIS_STATUS CreateThreads( // Creat MLME Thread #ifndef RT30xx - pObj->MLMEThr_task = NULL; - tsk = kthread_run(MlmeThread, pAd, "%s", pAd->net_dev->name); - - if (IS_ERR(tsk)) { + pObj->MLMEThr_pid= THREAD_PID_INIT_VALUE; + pid_number = kernel_thread(MlmeThread, pAd, CLONE_VM); + if (pid_number < 0) + { #endif #ifdef RT30xx pObj->MLMEThr_pid = NULL; @@ -778,7 +778,7 @@ NDIS_STATUS CreateThreads( } #ifndef RT30xx - pObj->MLMEThr_task = tsk; + pObj->MLMEThr_pid = GET_PID(pid_number); #endif #ifdef RT30xx pObj->MLMEThr_pid = find_get_pid(pid_number); @@ -788,10 +788,9 @@ NDIS_STATUS CreateThreads( // Creat Command Thread #ifndef RT30xx - pObj->RTUSBCmdThr_task = NULL; - tsk = kthread_run(RTUSBCmdThread, pAd, "%s", pAd->net_dev->name); - - if (IS_ERR(tsk) < 0) + pObj->RTUSBCmdThr_pid= THREAD_PID_INIT_VALUE; + pid_number = kernel_thread(RTUSBCmdThread, pAd, CLONE_VM); + if (pid_number < 0) #endif #ifdef RT30xx pObj->RTUSBCmdThr_pid = NULL; @@ -804,7 +803,7 @@ NDIS_STATUS CreateThreads( } #ifndef RT30xx - pObj->RTUSBCmdThr_task = tsk; + pObj->RTUSBCmdThr_pid = GET_PID(pid_number); #endif #ifdef RT30xx pObj->RTUSBCmdThr_pid = find_get_pid(pid_number); @@ -812,9 +811,9 @@ NDIS_STATUS CreateThreads( wait_for_completion(&(pAd->CmdQComplete)); #ifndef RT30xx - pObj->TimerQThr_task = NULL; - tsk = kthread_run(TimerQThread, pAd, "%s", pAd->net_dev->name); - if (IS_ERR(tsk) < 0) + pObj->TimerQThr_pid= THREAD_PID_INIT_VALUE; + pid_number = kernel_thread(TimerQThread, pAd, CLONE_VM); + if (pid_number < 0) #endif #ifdef RT30xx pObj->TimerQThr_pid = NULL; @@ -826,7 +825,7 @@ NDIS_STATUS CreateThreads( return NDIS_STATUS_FAILURE; } #ifndef RT30xx - pObj->TimerQThr_task = tsk; + pObj->TimerQThr_pid = GET_PID(pid_number); #endif #ifdef RT30xx pObj->TimerQThr_pid = find_get_pid(pid_number); diff --git a/drivers/staging/rt2870/common/rtusb_io.c b/drivers/staging/rt2870/common/rtusb_io.c index fd1b0c1..704b5c2 100644 --- a/drivers/staging/rt2870/common/rtusb_io.c +++ b/drivers/staging/rt2870/common/rtusb_io.c @@ -984,8 +984,7 @@ NDIS_STATUS RTUSBEnqueueCmdFromNdis( POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; #ifndef RT30xx - BUG_ON(pObj->RTUSBCmdThr_task == NULL); - CHECK_PID_LEGALITY(task_pid(pObj->RTUSBCmdThr_task)) + CHECK_PID_LEGALITY(pObj->RTUSBCmdThr_pid) #endif #ifdef RT30xx if (pObj->RTUSBCmdThr_pid < 0) diff --git a/drivers/staging/rt2870/rt2870.h b/drivers/staging/rt2870/rt2870.h index 10e1640..2b8872b 100644 --- a/drivers/staging/rt2870/rt2870.h +++ b/drivers/staging/rt2870/rt2870.h @@ -590,16 +590,14 @@ VOID RTUSBBulkRxComplete(purbb_t pUrb, struct pt_regs *pt_regs); #define RTUSBMlmeUp(pAd) \ { \ POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; \ - BUG_ON(pObj->MLMEThr_task == NULL); \ - CHECK_PID_LEGALITY(task_pid(pObj->MLMEThr_task)) \ + CHECK_PID_LEGALITY(pObj->MLMEThr_pid) \ up(&(pAd->mlme_semaphore)); \ } #define RTUSBCMDUp(pAd) \ { \ POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; \ - BUG_ON(pObj->RTUSBCmdThr_task == NULL); \ - CHECK_PID_LEGALITY(task_pid(pObj->RTUSBCmdThr_task)) \ + CHECK_PID_LEGALITY(pObj->RTUSBCmdThr_pid) \ up(&(pAd->RTUSBCmd_semaphore)); \ } #endif -- cgit v0.10.2 From ce9c010c5c39df05ed81a06aba492c45ee0c6f19 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 4 Aug 2009 16:53:36 -0700 Subject: Staging: rtl8192su: fix build error This fixes a build error when selecting the rtl8192su driver as a module. This has been reported by me, and the opensuse kernel developer team, and I finally tracked it down. Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/rtl8192su/ieee80211.h b/drivers/staging/rtl8192su/ieee80211.h index 0edb09a..ea97393 100644 --- a/drivers/staging/rtl8192su/ieee80211.h +++ b/drivers/staging/rtl8192su/ieee80211.h @@ -2645,7 +2645,7 @@ extern int ieee80211_encrypt_fragment( struct sk_buff *frag, int hdr_len); -extern int ieee80211_xmit(struct sk_buff *skb, +extern int rtl8192_ieee80211_xmit(struct sk_buff *skb, struct net_device *dev); extern void ieee80211_txb_free(struct ieee80211_txb *); diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211.h b/drivers/staging/rtl8192su/ieee80211/ieee80211.h index 720bfcb..5e3a2cb 100644 --- a/drivers/staging/rtl8192su/ieee80211/ieee80211.h +++ b/drivers/staging/rtl8192su/ieee80211/ieee80211.h @@ -2645,7 +2645,7 @@ extern int ieee80211_encrypt_fragment( struct sk_buff *frag, int hdr_len); -extern int ieee80211_xmit(struct sk_buff *skb, +extern int rtl8192_ieee80211_xmit(struct sk_buff *skb, struct net_device *dev); extern void ieee80211_txb_free(struct ieee80211_txb *); diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8192su/ieee80211/ieee80211_tx.c index 7294572..cba12b8 100644 --- a/drivers/staging/rtl8192su/ieee80211/ieee80211_tx.c +++ b/drivers/staging/rtl8192su/ieee80211/ieee80211_tx.c @@ -618,7 +618,7 @@ void ieee80211_query_seqnum(struct ieee80211_device*ieee, struct sk_buff* skb, u } } -int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) +int rtl8192_ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) { #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) struct ieee80211_device *ieee = netdev_priv(dev); @@ -943,5 +943,6 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) return 1; } +EXPORT_SYMBOL(rtl8192_ieee80211_xmit); EXPORT_SYMBOL(ieee80211_txb_free); diff --git a/drivers/staging/rtl8192su/r8192U_core.c b/drivers/staging/rtl8192su/r8192U_core.c index 4ab2507..70f81a8 100644 --- a/drivers/staging/rtl8192su/r8192U_core.c +++ b/drivers/staging/rtl8192su/r8192U_core.c @@ -12142,7 +12142,7 @@ static const struct net_device_ops rtl8192_netdev_ops = { .ndo_set_mac_address = r8192_set_mac_adr, .ndo_validate_addr = eth_validate_addr, .ndo_change_mtu = eth_change_mtu, - .ndo_start_xmit = ieee80211_xmit, + .ndo_start_xmit = rtl8192_ieee80211_xmit, }; #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) -- cgit v0.10.2 From 5fb4d2525b6dcffbb8bc26a7dfc7ed17ad323a06 Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Fri, 7 Aug 2009 16:12:03 -0700 Subject: staging: add dependencies on PCI for drivers that require it This patch adds PCI dependencies to staging drivers that require it. Signed-off-by: Jeff Mahoney Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/b3dfg/Kconfig b/drivers/staging/b3dfg/Kconfig index 5242310..9e6573c 100644 --- a/drivers/staging/b3dfg/Kconfig +++ b/drivers/staging/b3dfg/Kconfig @@ -1,5 +1,6 @@ config B3DFG tristate "Brontes 3d Frame Framegrabber" + depends on PCI default n ---help--- This driver provides support for the Brontes 3d Framegrabber diff --git a/drivers/staging/heci/Kconfig b/drivers/staging/heci/Kconfig index ae8d588..c7206f8 100644 --- a/drivers/staging/heci/Kconfig +++ b/drivers/staging/heci/Kconfig @@ -1,5 +1,6 @@ config HECI tristate "Intel Management Engine Interface (MEI) Support" + depends on PCI ---help--- The Intel Management Engine Interface (Intel MEI) driver allows applications to access the Active Management Technology -- cgit v0.10.2 From 749d00dbf154fc2f9ac59df669205039de0d5b45 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Fri, 7 Aug 2009 21:00:10 +0200 Subject: Staging: rspiusb: Fix buffer overflow usb_buffer_map_sg() may return -1. This will result in a read from pdx->PixelUrb[frameInfo][-1] Signed-off-by: Roel Kluin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/rspiusb/rspiusb.c b/drivers/staging/rspiusb/rspiusb.c index 2f8155c..04e2f92 100644 --- a/drivers/staging/rspiusb/rspiusb.c +++ b/drivers/staging/rspiusb/rspiusb.c @@ -716,6 +716,8 @@ static int MapUserBuffer(struct ioctl_struct *io, struct device_extension *pdx) pdx->PixelUrb[frameInfo][i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT; } + if (i == 0) + return -EINVAL; /* only interrupt when last URB completes */ pdx->PixelUrb[frameInfo][--i]->transfer_flags &= ~URB_NO_INTERRUPT; pdx->pendedPixelUrbs[frameInfo] = -- cgit v0.10.2 From 087d7e56deffb611a098e7e257388a41edbeef1f Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Tue, 4 Aug 2009 08:59:59 -0700 Subject: x86: Fix MSI-X initialization by using online_mask for x2apic target_cpus found a system where x2apic reports an MSI-X irq initialization failure: [ 302.859446] igbvf 0000:81:10.4: enabling device (0000 -> 0002) [ 302.874369] igbvf 0000:81:10.4: using 64bit DMA mask [ 302.879023] igbvf 0000:81:10.4: using 64bit consistent DMA mask [ 302.894386] igbvf 0000:81:10.4: enabling bus mastering [ 302.898171] igbvf 0000:81:10.4: setting latency timer to 64 [ 302.914050] reserve_memtype added 0xefb08000-0xefb0c000, track uncached-minus, req uncached-minus, ret uncached-minus [ 302.933839] reserve_memtype added 0xefb28000-0xefb29000, track uncached-minus, req uncached-minus, ret uncached-minus [ 302.940367] alloc irq_desc for 265 on node 4 [ 302.956874] alloc kstat_irqs on node 4 [ 302.959452] alloc irq_2_iommu on node 0 [ 302.974328] igbvf 0000:81:10.4: irq 265 for MSI/MSI-X [ 302.977778] alloc irq_desc for 266 on node 4 [ 302.980347] alloc kstat_irqs on node 4 [ 302.995312] free_memtype request 0xefb28000-0xefb29000 [ 302.998816] igbvf 0000:81:10.4: Failed to initialize MSI-X interrupts. ... it turns out that when trying to enable MSI-X, __assign_irq_vector(new, cfg_new, apic->target_cpus()) can not get vector because for x2apic target-cpus returns cpumask_of(0) Update that to online_mask like xapic. Signed-off-by: Yinghai Lu Acked-by: Suresh Siddha LKML-Reference: <4A785AFF.3050902@kernel.org> Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/apic/x2apic_cluster.c b/arch/x86/kernel/apic/x2apic_cluster.c index 2ed4e2b..a5371ec 100644 --- a/arch/x86/kernel/apic/x2apic_cluster.c +++ b/arch/x86/kernel/apic/x2apic_cluster.c @@ -17,11 +17,13 @@ static int x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id) return x2apic_enabled(); } -/* Start with all IRQs pointing to boot CPU. IRQ balancing will shift them. */ - +/* + * need to use more than cpu 0, because we need more vectors when + * MSI-X are used. + */ static const struct cpumask *x2apic_target_cpus(void) { - return cpumask_of(0); + return cpu_online_mask; } /* diff --git a/arch/x86/kernel/apic/x2apic_phys.c b/arch/x86/kernel/apic/x2apic_phys.c index 0b631c6..a8989aa 100644 --- a/arch/x86/kernel/apic/x2apic_phys.c +++ b/arch/x86/kernel/apic/x2apic_phys.c @@ -27,11 +27,13 @@ static int x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id) return 0; } -/* Start with all IRQs pointing to boot CPU. IRQ balancing will shift them. */ - +/* + * need to use more than cpu 0, because we need more vectors when + * MSI-X are used. + */ static const struct cpumask *x2apic_target_cpus(void) { - return cpumask_of(0); + return cpu_online_mask; } static void x2apic_vector_allocation_domain(int cpu, struct cpumask *retmask) -- cgit v0.10.2 From ad7d6c7a0654a4bbda3e109f56af713267e96274 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Tue, 4 Aug 2009 09:01:33 -0700 Subject: x86/irq: Fix move_irq_desc() for nodes without ram Don't move it if target node is -1. Signed-off-by: Yinghai Lu LKML-Reference: <4A785B5D.4070702@kernel.org> Signed-off-by: Ingo Molnar diff --git a/kernel/irq/numa_migrate.c b/kernel/irq/numa_migrate.c index 2f69bee..3fd3019 100644 --- a/kernel/irq/numa_migrate.c +++ b/kernel/irq/numa_migrate.c @@ -107,8 +107,8 @@ out_unlock: struct irq_desc *move_irq_desc(struct irq_desc *desc, int node) { - /* those all static, do move them */ - if (desc->irq < NR_IRQS_LEGACY) + /* those static or target node is -1, do not move them */ + if (desc->irq < NR_IRQS_LEGACY || node == -1) return desc; if (desc->node != node) -- cgit v0.10.2 From 498cdbfbcf98e0d2c90a26e6a02a82f043876e48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ozan=20=C3=87a=C4=9Flayan?= Date: Tue, 4 Aug 2009 19:39:31 +0300 Subject: x86: Add quirk to make Apple MacBookPro5,1 use reboot=pci MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MacBookPro5,1 is not able to reboot unless reboot=pci is set. This patch forces it through a DMI quirk specific to this device. Signed-off-by: Ozan Çağlayan LKML-Reference: <1249403971-6543-1-git-send-email-ozan@pardus.org.tr> Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 834c9da..9eb8976 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -405,7 +405,7 @@ EXPORT_SYMBOL(machine_real_restart); #endif /* CONFIG_X86_32 */ /* - * Apple MacBook5,2 (2009 MacBook) needs reboot=p + * Some Apple MacBook and MacBookPro's needs reboot=p to be able to reboot */ static int __init set_pci_reboot(const struct dmi_system_id *d) { @@ -426,6 +426,14 @@ static struct dmi_system_id __initdata pci_reboot_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5,2"), }, }, + { /* Handle problems with rebooting on Apple MacBookPro5,1 */ + .callback = set_pci_reboot, + .ident = "Apple MacBookPro5,1", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,1"), + }, + }, { } }; -- cgit v0.10.2 From 96b2de313b1e0e02aea80ee47df6a2b5cbdf8e13 Mon Sep 17 00:00:00 2001 From: Tom Zanussi Date: Sat, 8 Aug 2009 10:49:09 -0500 Subject: tracing/filters: Don't use pred on alloc failure Dan Carpenter sent me a fix to prevent pred from being used if it couldn't be allocated. I noticed the same problem also existed for the create_pred() case and added a fix for that. Reported-by: Dan Carpenter Signed-off-by: Tom Zanussi Cc: Steven Rostedt Cc: Frederic Weisbecker Cc: Li Zefan LKML-Reference: <1249746549.6453.29.camel@tropicana> Signed-off-by: Ingo Molnar diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index 936c621..1557148 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c @@ -1029,6 +1029,8 @@ static int replace_preds(struct event_subsystem *system, if (elt->op == OP_AND || elt->op == OP_OR) { pred = create_logical_pred(elt->op); + if (!pred) + return -ENOMEM; if (call) { err = filter_add_pred(ps, call, pred); filter_free_pred(pred); @@ -1048,6 +1050,8 @@ static int replace_preds(struct event_subsystem *system, } pred = create_pred(elt->op, operand1, operand2); + if (!pred) + return -ENOMEM; if (call) { err = filter_add_pred(ps, call, pred); filter_free_pred(pred); -- cgit v0.10.2 From 26528e773ecc74fb1b61b7275f86f761cbb340ec Mon Sep 17 00:00:00 2001 From: Tom Zanussi Date: Sat, 8 Aug 2009 10:49:53 -0500 Subject: tracing/filters: Always free pred on filter_add_subsystem_pred() failure If filter_add_subsystem_pred() fails due to ENOSPC or ENOMEM, the pred doesn't get freed, while as a side effect it does for other errors. Make it so the caller always frees the pred for any error. Signed-off-by: Tom Zanussi Cc: Steven Rostedt Cc: Frederic Weisbecker Cc: Li Zefan LKML-Reference: <1249746593.6453.32.camel@tropicana> Signed-off-by: Ingo Molnar diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index 1557148..f32dc9d 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c @@ -624,9 +624,6 @@ static int filter_add_subsystem_pred(struct filter_parse_state *ps, return -ENOSPC; } - filter->preds[filter->n_preds] = pred; - filter->n_preds++; - list_for_each_entry(call, &ftrace_events, list) { if (!call->define_fields) @@ -643,6 +640,9 @@ static int filter_add_subsystem_pred(struct filter_parse_state *ps, } replace_filter_string(call->filter, filter_string); } + + filter->preds[filter->n_preds] = pred; + filter->n_preds++; out: return err; } @@ -1034,9 +1034,12 @@ static int replace_preds(struct event_subsystem *system, if (call) { err = filter_add_pred(ps, call, pred); filter_free_pred(pred); - } else + } else { err = filter_add_subsystem_pred(ps, system, pred, filter_string); + if (err) + filter_free_pred(pred); + } if (err) return err; @@ -1055,9 +1058,12 @@ static int replace_preds(struct event_subsystem *system, if (call) { err = filter_add_pred(ps, call, pred); filter_free_pred(pred); - } else + } else { err = filter_add_subsystem_pred(ps, system, pred, filter_string); + if (err) + filter_free_pred(pred); + } if (err) return err; -- cgit v0.10.2 From 17d42c1c497aa54952b9e58c1502a46f0df40315 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Thu, 6 Aug 2009 16:03:30 -0700 Subject: posix_cpu_timers_exit_group(): Do not use thread_group_cputimer() When the process exits we don't have to run new cputimer nor use running one (as it not accounts when tsk->exit_state != 0) to get process CPU times. As there is only one thread we can just use CPU times fields from task and signal structs. Signed-off-by: Stanislaw Gruszka Cc: Peter Zijlstra Cc: Roland McGrath Cc: Vitaly Mayatskikh Signed-off-by: Andrew Morton Signed-off-by: Ingo Molnar diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c index bece7c0..e33a21c 100644 --- a/kernel/posix-cpu-timers.c +++ b/kernel/posix-cpu-timers.c @@ -521,11 +521,12 @@ void posix_cpu_timers_exit(struct task_struct *tsk) } void posix_cpu_timers_exit_group(struct task_struct *tsk) { - struct task_cputime cputime; + struct signal_struct *const sig = tsk->signal; - thread_group_cputimer(tsk, &cputime); cleanup_timers(tsk->signal->cpu_timers, - cputime.utime, cputime.stime, cputime.sum_exec_runtime); + cputime_add(tsk->utime, sig->utime), + cputime_add(tsk->stime, sig->stime), + tsk->se.sum_exec_runtime + sig->sum_sched_runtime); } static void clear_dead_task(struct k_itimer *timer, union cpu_time_count now) -- cgit v0.10.2 From 38d5487db7f289be1d56ac7df704ee49ed3213b9 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 20 Jul 2009 14:49:17 -0700 Subject: drm: When adding probed modes, preserve duplicate mode types The code which takes probed modes and adds them to a connector eliminates duplicate modes by comparing them using drm_mode_equal. That function doesn't consider the type bits, which means that any modes which differ only in the type field will be lost. One of the bits in the mode->type field is the DRM_MODE_TYPE_PREFERRED bit. If the mode with that bit is lost, then higher level code will not know which mode to select, causing a random mode to be used instead. This patch simply merges the two mode type bits together; that seems reasonable to me, but perhaps only a subset of the bits should be used? None of these can be user defined as they all come from looking at just the hardware. Signed-off-by: Keith Packard Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index 54f492a..7914097 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -566,6 +566,8 @@ void drm_mode_connector_list_update(struct drm_connector *connector) found_it = 1; /* if equal delete the probed mode */ mode->status = pmode->status; + /* Merge type bits together */ + mode->type |= pmode->type; list_del(&pmode->head); drm_mode_destroy(connector->dev, pmode); break; -- cgit v0.10.2 From 8d3457ec3198a569dd14dc9e3ae8b6163bcaa0b5 Mon Sep 17 00:00:00 2001 From: Paul Rolland Date: Sun, 9 Aug 2009 12:24:01 +1000 Subject: drm: silence pointless vblank warning. Some applications/hardware combinations are triggering the message "failed to acquire vblank counter" to be issued up to 20 times a second, which makes it both useless and dangerous, as this may hide other important messages. This changes makes it only appear when people are debugging. Signed-off-by: Paul Rolland Reviewed-by: Jesse Barnes Lost-twice-by: Dave Airlie Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index b4a3dbc..f85aaf2 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -566,7 +566,7 @@ int drm_wait_vblank(struct drm_device *dev, void *data, ret = drm_vblank_get(dev, crtc); if (ret) { - DRM_ERROR("failed to acquire vblank counter, %d\n", ret); + DRM_DEBUG("failed to acquire vblank counter, %d\n", ret); return ret; } seq = drm_vblank_count(dev, crtc); -- cgit v0.10.2 From 6cb504c29b1338925c83e4430e42a51eaa43781e Mon Sep 17 00:00:00 2001 From: Frans Pop Date: Sun, 9 Aug 2009 12:25:29 +1000 Subject: drm/i915: silence vblank warnings these errors are pretty pointless Reviewed-by: Jesse Barnes Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 83aee80..7ebc84c 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -190,7 +190,7 @@ u32 i915_get_vblank_counter(struct drm_device *dev, int pipe) low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL; if (!i915_pipe_enabled(dev, pipe)) { - DRM_ERROR("trying to get vblank count for disabled pipe %d\n", pipe); + DRM_DEBUG("trying to get vblank count for disabled pipe %d\n", pipe); return 0; } @@ -219,7 +219,7 @@ u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe) int reg = pipe ? PIPEB_FRMCOUNT_GM45 : PIPEA_FRMCOUNT_GM45; if (!i915_pipe_enabled(dev, pipe)) { - DRM_ERROR("trying to get vblank count for disabled pipe %d\n", pipe); + DRM_DEBUG("trying to get vblank count for disabled pipe %d\n", pipe); return 0; } -- cgit v0.10.2 From fdb8a42742ac95606668f73481dfb2f760658fdd Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Thu, 6 Aug 2009 15:58:13 -0700 Subject: x86: fix buffer overflow in efi_init() If the vendor name (from c16) can be longer than 100 bytes (or missing a terminating null), then the null is written past the end of vendor[]. Found with Parfait, http://research.sun.com/projects/parfait/ Signed-off-by: Roel Kluin Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: H. Peter Anvin Cc: Huang Ying diff --git a/arch/x86/kernel/efi.c b/arch/x86/kernel/efi.c index 19ccf6d..fe26ba3 100644 --- a/arch/x86/kernel/efi.c +++ b/arch/x86/kernel/efi.c @@ -354,7 +354,7 @@ void __init efi_init(void) */ c16 = tmp = early_ioremap(efi.systab->fw_vendor, 2); if (c16) { - for (i = 0; i < sizeof(vendor) && *c16; ++i) + for (i = 0; i < sizeof(vendor) - 1 && *c16; ++i) vendor[i] = *c16++; vendor[i] = '\0'; } else -- cgit v0.10.2 From b4a2f5e723e4f7df46731106faf9e2405673c073 Mon Sep 17 00:00:00 2001 From: Gleb Natapov Date: Sun, 5 Jul 2009 18:48:11 +0300 Subject: KVM: Avoid redelivery of edge interrupt before next edge The check for an edge is broken in current ioapic code. ioapic->irr is cleared on each edge interrupt by ioapic_service() and this makes old_irr != ioapic->irr condition in kvm_ioapic_set_irq() to be always true. The patch fixes the code to properly recognise edge. Some HW emulation calls set_irq() without level change. If each such call is propagated to an OS it may confuse a device driver. This is the case with keyboard device emulation and Windows XP x64 installer on SMP VM. Each keystroke produce two interrupts (down/up) one interrupt is submitted to CPU0 and another to CPU1. This confuses Windows somehow and it ignores keystrokes. Signed-off-by: Gleb Natapov Signed-off-by: Avi Kivity diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c index 1eddae9..1150c6d5 100644 --- a/virt/kvm/ioapic.c +++ b/virt/kvm/ioapic.c @@ -95,8 +95,6 @@ static int ioapic_service(struct kvm_ioapic *ioapic, unsigned int idx) if (injected && pent->fields.trig_mode == IOAPIC_LEVEL_TRIG) pent->fields.remote_irr = 1; } - if (!pent->fields.trig_mode) - ioapic->irr &= ~(1 << idx); return injected; } @@ -136,7 +134,8 @@ static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val) mask_after = ioapic->redirtbl[index].fields.mask; if (mask_before != mask_after) kvm_fire_mask_notifiers(ioapic->kvm, index, mask_after); - if (ioapic->irr & (1 << index)) + if (ioapic->redirtbl[index].fields.trig_mode == IOAPIC_LEVEL_TRIG + && ioapic->irr & (1 << index)) ioapic_service(ioapic, index); break; } @@ -184,9 +183,10 @@ int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level) if (!level) ioapic->irr &= ~mask; else { + int edge = (entry.fields.trig_mode == IOAPIC_EDGE_TRIG); ioapic->irr |= mask; - if ((!entry.fields.trig_mode && old_irr != ioapic->irr) - || !entry.fields.remote_irr) + if ((edge && old_irr != ioapic->irr) || + (!edge && !entry.fields.remote_irr)) ret = ioapic_service(ioapic, irq); } } -- cgit v0.10.2 From 3a6593050fbd8bbcaed3a44d01c31d907315c86c Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 21 Jul 2009 17:34:57 +0200 Subject: perf_counter, ftrace: Fix perf_counter integration Adds possible second part to the assign argument of TP_EVENT(). TP_perf_assign( __perf_count(foo); __perf_addr(bar); ) Which, when specified make the swcounter increment with @foo instead of the usual 1, and report @bar for PERF_SAMPLE_ADDR (data address associated with the event) when this triggers a counter overflow. Signed-off-by: Peter Zijlstra Acked-by: Steven Rostedt Cc: Frederic Weisbecker Cc: Jason Baron Cc: Paul Mackerras Signed-off-by: Ingo Molnar diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index 1867553..fec71f8 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h @@ -144,6 +144,9 @@ #undef TP_fast_assign #define TP_fast_assign(args...) args +#undef TP_perf_assign +#define TP_perf_assign(args...) + #undef TRACE_EVENT #define TRACE_EVENT(call, proto, args, tstruct, func, print) \ static int \ @@ -345,6 +348,88 @@ static inline int ftrace_get_offsets_##call( \ #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) +#ifdef CONFIG_EVENT_PROFILE + +/* + * Generate the functions needed for tracepoint perf_counter support. + * + * static void ftrace_profile_(proto) + * { + * extern void perf_tpcounter_event(int, u64, u64); + * u64 __addr = 0, __count = 1; + * + * <-- here we expand the TP_perf_assign() macro + * + * perf_tpcounter_event(event_.id, __addr, __count); + * } + * + * static int ftrace_profile_enable_(struct ftrace_event_call *event_call) + * { + * int ret = 0; + * + * if (!atomic_inc_return(&event_call->profile_count)) + * ret = register_trace_(ftrace_profile_); + * + * return ret; + * } + * + * static void ftrace_profile_disable_(struct ftrace_event_call *event_call) + * { + * if (atomic_add_negative(-1, &event->call->profile_count)) + * unregister_trace_(ftrace_profile_); + * } + * + */ + +#undef TP_fast_assign +#define TP_fast_assign(args...) + +#undef TP_perf_assign +#define TP_perf_assign(args...) args + +#undef __perf_addr +#define __perf_addr(a) __addr = (a) + +#undef __perf_count +#define __perf_count(c) __count = (c) + +#undef TRACE_EVENT +#define TRACE_EVENT(call, proto, args, tstruct, assign, print) \ + \ +static void ftrace_profile_##call(proto) \ +{ \ + extern void perf_tpcounter_event(int, u64, u64); \ + u64 __addr = 0, __count = 1; \ + { assign; } \ + perf_tpcounter_event(event_##call.id, __addr, __count); \ +} \ + \ +static int ftrace_profile_enable_##call(struct ftrace_event_call *event_call) \ +{ \ + int ret = 0; \ + \ + if (!atomic_inc_return(&event_call->profile_count)) \ + ret = register_trace_##call(ftrace_profile_##call); \ + \ + return ret; \ +} \ + \ +static void ftrace_profile_disable_##call(struct ftrace_event_call *event_call)\ +{ \ + if (atomic_add_negative(-1, &event_call->profile_count)) \ + unregister_trace_##call(ftrace_profile_##call); \ +} + +#include TRACE_INCLUDE(TRACE_INCLUDE_FILE) + +#undef TP_fast_assign +#define TP_fast_assign(args...) args + +#undef TP_perf_assign +#define TP_perf_assign(args...) + +#endif + /* * Stage 4 of the trace events. * @@ -447,28 +532,6 @@ static inline int ftrace_get_offsets_##call( \ #define TP_FMT(fmt, args...) fmt "\n", ##args #ifdef CONFIG_EVENT_PROFILE -#define _TRACE_PROFILE(call, proto, args) \ -static void ftrace_profile_##call(proto) \ -{ \ - extern void perf_tpcounter_event(int); \ - perf_tpcounter_event(event_##call.id); \ -} \ - \ -static int ftrace_profile_enable_##call(struct ftrace_event_call *event_call) \ -{ \ - int ret = 0; \ - \ - if (!atomic_inc_return(&event_call->profile_count)) \ - ret = register_trace_##call(ftrace_profile_##call); \ - \ - return ret; \ -} \ - \ -static void ftrace_profile_disable_##call(struct ftrace_event_call *event_call)\ -{ \ - if (atomic_add_negative(-1, &event_call->profile_count)) \ - unregister_trace_##call(ftrace_profile_##call); \ -} #define _TRACE_PROFILE_INIT(call) \ .profile_count = ATOMIC_INIT(-1), \ @@ -476,7 +539,6 @@ static void ftrace_profile_disable_##call(struct ftrace_event_call *event_call)\ .profile_disable = ftrace_profile_disable_##call, #else -#define _TRACE_PROFILE(call, proto, args) #define _TRACE_PROFILE_INIT(call) #endif @@ -502,7 +564,6 @@ static void ftrace_profile_disable_##call(struct ftrace_event_call *event_call)\ #undef TRACE_EVENT #define TRACE_EVENT(call, proto, args, tstruct, assign, print) \ -_TRACE_PROFILE(call, PARAMS(proto), PARAMS(args)) \ \ static struct ftrace_event_call event_##call; \ \ @@ -586,6 +647,5 @@ __attribute__((section("_ftrace_events"))) event_##call = { \ #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) -#undef _TRACE_PROFILE #undef _TRACE_PROFILE_INIT diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c index 673c1aa..52eb4b6 100644 --- a/kernel/perf_counter.c +++ b/kernel/perf_counter.c @@ -3703,17 +3703,17 @@ static const struct pmu perf_ops_task_clock = { }; #ifdef CONFIG_EVENT_PROFILE -void perf_tpcounter_event(int event_id) +void perf_tpcounter_event(int event_id, u64 addr, u64 count) { struct perf_sample_data data = { .regs = get_irq_regs(), - .addr = 0, + .addr = addr, }; if (!data.regs) data.regs = task_pt_regs(current); - do_perf_swcounter_event(PERF_TYPE_TRACEPOINT, event_id, 1, 1, &data); + do_perf_swcounter_event(PERF_TYPE_TRACEPOINT, event_id, count, 1, &data); } EXPORT_SYMBOL_GPL(perf_tpcounter_event); -- cgit v0.10.2 From f413cdb80ce00ec1a4d0ab949b5d96c81cae7f75 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Fri, 7 Aug 2009 01:25:54 +0200 Subject: perf_counter: Fix/complete ftrace event records sampling This patch implements the kernel side support for ftrace event record sampling. A new counter sampling attribute is added: PERF_SAMPLE_TP_RECORD which requests ftrace events record sampling. In this case if a PERF_TYPE_TRACEPOINT counter is active and a tracepoint fires, we emit the tracepoint binary record to the perfcounter event buffer, as a sample. Result, after setting PERF_SAMPLE_TP_RECORD attribute from perf record: perf record -f -F 1 -a -e workqueue:workqueue_execution perf report -D 0x21e18 [0x48]: event: 9 . . ... raw event: size 72 bytes . 0000: 09 00 00 00 01 00 48 00 d0 c7 00 81 ff ff ff ff ......H........ . 0010: 0a 00 00 00 0a 00 00 00 21 00 00 00 00 00 00 00 ........!...... . 0020: 2b 00 01 02 0a 00 00 00 0a 00 00 00 65 76 65 6e +...........eve . 0030: 74 73 2f 31 00 00 00 00 00 00 00 00 0a 00 00 00 ts/1........... . 0040: e0 b1 31 81 ff ff ff ff ....... . 0x21e18 [0x48]: PERF_EVENT_SAMPLE (IP, 1): 10: 0xffffffff8100c7d0 period: 33 The raw ftrace binary record starts at offset 0020. Translation: struct trace_entry { type = 0x2b = 43; flags = 1; preempt_count = 2; pid = 0xa = 10; tgid = 0xa = 10; } thread_comm = "events/1" thread_pid = 0xa = 10; func = 0xffffffff8131b1e0 = flush_to_ldisc() What will come next? - Userspace support ('perf trace'), 'flight data recorder' mode for perf trace, etc. - The unconditional copy from the profiling callback brings some costs however if someone wants no such sampling to occur, and needs to be fixed in the future. For that we need to have an instant access to the perf counter attribute. This is a matter of a flag to add in the struct ftrace_event. - Take care of the events recursivity! Don't ever try to record a lock event for example, it seems some locking is used in the profiling fast path and lead to a tracing recursivity. That will be fixed using raw spinlock or recursivity protection. - [...] - Profit! :-) Signed-off-by: Frederic Weisbecker Cc: Li Zefan Cc: Tom Zanussi Cc: Arnaldo Carvalho de Melo Cc: Peter Zijlstra Cc: Mike Galbraith Cc: Steven Rostedt Cc: Paul Mackerras Cc: Pekka Enberg Cc: Gabriel Munteanu Cc: Lai Jiangshan Signed-off-by: Ingo Molnar diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h index d7cd193..a81170d 100644 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h @@ -89,7 +89,9 @@ enum print_line_t { TRACE_TYPE_NO_CONSUME = 3 /* Handled but ask to not consume */ }; - +void tracing_generic_entry_update(struct trace_entry *entry, + unsigned long flags, + int pc); struct ring_buffer_event * trace_current_buffer_lock_reserve(int type, unsigned long len, unsigned long flags, int pc); diff --git a/include/linux/perf_counter.h b/include/linux/perf_counter.h index e604e6e..a67dd5c 100644 --- a/include/linux/perf_counter.h +++ b/include/linux/perf_counter.h @@ -121,8 +121,9 @@ enum perf_counter_sample_format { PERF_SAMPLE_CPU = 1U << 7, PERF_SAMPLE_PERIOD = 1U << 8, PERF_SAMPLE_STREAM_ID = 1U << 9, + PERF_SAMPLE_TP_RECORD = 1U << 10, - PERF_SAMPLE_MAX = 1U << 10, /* non-ABI */ + PERF_SAMPLE_MAX = 1U << 11, /* non-ABI */ }; /* @@ -413,6 +414,11 @@ struct perf_callchain_entry { __u64 ip[PERF_MAX_STACK_DEPTH]; }; +struct perf_tracepoint_record { + int size; + char *record; +}; + struct task_struct; /** @@ -681,6 +687,7 @@ struct perf_sample_data { struct pt_regs *regs; u64 addr; u64 period; + void *private; }; extern int perf_counter_overflow(struct perf_counter *counter, int nmi, diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index fec71f8..7fb16d9 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h @@ -353,15 +353,7 @@ static inline int ftrace_get_offsets_##call( \ /* * Generate the functions needed for tracepoint perf_counter support. * - * static void ftrace_profile_(proto) - * { - * extern void perf_tpcounter_event(int, u64, u64); - * u64 __addr = 0, __count = 1; - * - * <-- here we expand the TP_perf_assign() macro - * - * perf_tpcounter_event(event_.id, __addr, __count); - * } + * NOTE: The insertion profile callback (ftrace_profile_) is defined later * * static int ftrace_profile_enable_(struct ftrace_event_call *event_call) * { @@ -381,28 +373,10 @@ static inline int ftrace_get_offsets_##call( \ * */ -#undef TP_fast_assign -#define TP_fast_assign(args...) - -#undef TP_perf_assign -#define TP_perf_assign(args...) args - -#undef __perf_addr -#define __perf_addr(a) __addr = (a) - -#undef __perf_count -#define __perf_count(c) __count = (c) - #undef TRACE_EVENT #define TRACE_EVENT(call, proto, args, tstruct, assign, print) \ \ -static void ftrace_profile_##call(proto) \ -{ \ - extern void perf_tpcounter_event(int, u64, u64); \ - u64 __addr = 0, __count = 1; \ - { assign; } \ - perf_tpcounter_event(event_##call.id, __addr, __count); \ -} \ +static void ftrace_profile_##call(proto); \ \ static int ftrace_profile_enable_##call(struct ftrace_event_call *event_call) \ { \ @@ -422,12 +396,6 @@ static void ftrace_profile_disable_##call(struct ftrace_event_call *event_call)\ #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) -#undef TP_fast_assign -#define TP_fast_assign(args...) args - -#undef TP_perf_assign -#define TP_perf_assign(args...) - #endif /* @@ -647,5 +615,99 @@ __attribute__((section("_ftrace_events"))) event_##call = { \ #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) +/* + * Define the insertion callback to profile events + * + * The job is very similar to ftrace_raw_event_ except that we don't + * insert in the ring buffer but in a perf counter. + * + * static void ftrace_profile_(proto) + * { + * struct ftrace_data_offsets_ __maybe_unused __data_offsets; + * struct ftrace_event_call *event_call = &event_; + * extern void perf_tpcounter_event(int, u64, u64, void *, int); + * struct ftrace_raw_##call *entry; + * u64 __addr = 0, __count = 1; + * unsigned long irq_flags; + * int __entry_size; + * int __data_size; + * int pc; + * + * local_save_flags(irq_flags); + * pc = preempt_count(); + * + * __data_size = ftrace_get_offsets_(&__data_offsets, args); + * __entry_size = __data_size + sizeof(*entry); + * + * do { + * char raw_data[__entry_size]; <- allocate our sample in the stack + * struct trace_entry *ent; + * + * entry = (struct ftrace_raw_ *)raw_data; + * ent = &entry->ent; + * tracing_generic_entry_update(ent, irq_flags, pc); + * ent->type = event_call->id; + * + * <- do some jobs with dynamic arrays + * + * <- affect our values + * + * perf_tpcounter_event(event_call->id, __addr, __count, entry, + * __entry_size); <- submit them to perf counter + * } while (0); + * + * } + */ + +#ifdef CONFIG_EVENT_PROFILE + +#undef __perf_addr +#define __perf_addr(a) __addr = (a) + +#undef __perf_count +#define __perf_count(c) __count = (c) + +#undef TRACE_EVENT +#define TRACE_EVENT(call, proto, args, tstruct, assign, print) \ +static void ftrace_profile_##call(proto) \ +{ \ + struct ftrace_data_offsets_##call __maybe_unused __data_offsets;\ + struct ftrace_event_call *event_call = &event_##call; \ + extern void perf_tpcounter_event(int, u64, u64, void *, int); \ + struct ftrace_raw_##call *entry; \ + u64 __addr = 0, __count = 1; \ + unsigned long irq_flags; \ + int __entry_size; \ + int __data_size; \ + int pc; \ + \ + local_save_flags(irq_flags); \ + pc = preempt_count(); \ + \ + __data_size = ftrace_get_offsets_##call(&__data_offsets, args); \ + __entry_size = ALIGN(__data_size + sizeof(*entry), sizeof(u64));\ + \ + do { \ + char raw_data[__entry_size]; \ + struct trace_entry *ent; \ + \ + entry = (struct ftrace_raw_##call *)raw_data; \ + ent = &entry->ent; \ + tracing_generic_entry_update(ent, irq_flags, pc); \ + ent->type = event_call->id; \ + \ + tstruct \ + \ + { assign; } \ + \ + perf_tpcounter_event(event_call->id, __addr, __count, entry,\ + __entry_size); \ + } while (0); \ + \ +} + +#include TRACE_INCLUDE(TRACE_INCLUDE_FILE) +#endif /* CONFIG_EVENT_PROFILE */ + #undef _TRACE_PROFILE_INIT diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c index 52eb4b6..8681021 100644 --- a/kernel/perf_counter.c +++ b/kernel/perf_counter.c @@ -2646,6 +2646,7 @@ static void perf_counter_output(struct perf_counter *counter, int nmi, u64 counter; } group_entry; struct perf_callchain_entry *callchain = NULL; + struct perf_tracepoint_record *tp; int callchain_size = 0; u64 time; struct { @@ -2714,6 +2715,11 @@ static void perf_counter_output(struct perf_counter *counter, int nmi, header.size += sizeof(u64); } + if (sample_type & PERF_SAMPLE_TP_RECORD) { + tp = data->private; + header.size += tp->size; + } + ret = perf_output_begin(&handle, counter, header.size, nmi, 1); if (ret) return; @@ -2777,6 +2783,9 @@ static void perf_counter_output(struct perf_counter *counter, int nmi, } } + if (sample_type & PERF_SAMPLE_TP_RECORD) + perf_output_copy(&handle, tp->record, tp->size); + perf_output_end(&handle); } @@ -3703,11 +3712,18 @@ static const struct pmu perf_ops_task_clock = { }; #ifdef CONFIG_EVENT_PROFILE -void perf_tpcounter_event(int event_id, u64 addr, u64 count) +void perf_tpcounter_event(int event_id, u64 addr, u64 count, void *record, + int entry_size) { + struct perf_tracepoint_record tp = { + .size = entry_size, + .record = record, + }; + struct perf_sample_data data = { .regs = get_irq_regs(), .addr = addr, + .private = &tp, }; if (!data.regs) diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 8930e39..c22b40f 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -848,6 +848,7 @@ tracing_generic_entry_update(struct trace_entry *entry, unsigned long flags, ((pc & SOFTIRQ_MASK) ? TRACE_FLAG_SOFTIRQ : 0) | (need_resched() ? TRACE_FLAG_NEED_RESCHED : 0); } +EXPORT_SYMBOL_GPL(tracing_generic_entry_update); struct ring_buffer_event *trace_buffer_lock_reserve(struct trace_array *tr, int type, diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 3548ae5..8b9f4f6 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -438,10 +438,6 @@ struct trace_entry *tracing_get_trace_entry(struct trace_array *tr, struct trace_entry *trace_find_next_entry(struct trace_iterator *iter, int *ent_cpu, u64 *ent_ts); -void tracing_generic_entry_update(struct trace_entry *entry, - unsigned long flags, - int pc); - void default_wait_pipe(struct trace_iterator *iter); void poll_wait_pipe(struct trace_iterator *iter); diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 6da0992..90c9808 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -412,6 +412,7 @@ static void create_counter(int counter, int cpu, pid_t pid) if (call_graph) attr->sample_type |= PERF_SAMPLE_CALLCHAIN; + attr->mmap = track; attr->comm = track; attr->inherit = (cpu < 0) && inherit; -- cgit v0.10.2 From 923c42c19944da214d697e312a040384a0e33e78 Mon Sep 17 00:00:00 2001 From: Mike Galbraith Date: Wed, 22 Jul 2009 20:36:03 +0200 Subject: perf_counter tools: Fix/resurrect perf top annotation in a simple interactive form perf top used to have annotation support, but it has bitrotted and removed. This patch restores that: it allows the user to select any symbol in kernel space for source level annotation on the fly, switch between event counters and alter display variables. When symbol details are being displayed, stopping annotation reverts to normal. known keys: [d] select display delay. [e] select display entries (lines). [E] select annotation event counter. [f] select normal display count filter. [F] select annotation display count filter (percentage). [qQ] quit. [s] select annotation symbol and start annotation. [S] stop annotation, revert to normal display. [z] toggle event count zeroing. Sample: ------------------------------------------------------------------------------ PerfTop: 16719 irqs/sec kernel:78.7% [cache-misses/cache-references/instructions/cycles], (all, 4 CPUs) ------------------------------------------------------------------------------ Showing cache-misses for e1000_clean_rx_irq Events Pcnt (>=3%) 0 0.0% /* adjust length to remove Ethernet CRC */ 0 0.0% if (!(adapter->flags2 & FLAG2_CRC_STRIPPING)) 0 0.0% length -= 4; 436 5.0% f039: 41 f6 84 24 5c 29 00 testb $0x1,0x295c(%r12) 0 0.0% f089: 8b 4d 84 mov -0x7c(%rbp),%ecx 0 0.0% f08c: 48 83 ef 02 sub $0x2,%rdi 0 0.0% f090: 48 83 ee 02 sub $0x2,%rsi 811 9.3% f094: f3 a4 rep movsb %ds:(%rsi),%es:(%rdi) 0 0.0% 0 0.0% while (rx_desc->status & E1000_RXD_STAT_DD) { 0 0.0% f114: 41 f6 47 0c 01 testb $0x1,0xc(%r15) 7226 82.6% f119: 0f 85 24 fe ff ff jne ef43 Available events: 0 cache-misses 1 cache-references 2 instructions 3 cycles Enter details event counter: 2 ------------------------------------------------------------------------------ PerfTop: 15035 irqs/sec kernel:79.0% [cache-misses/cache-references/instructions/cycles], (all, 4 CPUs) ------------------------------------------------------------------------------ Showing instructions for e1000_clean_rx_irq Events Pcnt (>=3%) 0 0.0% int *work_done, int work_to_do) 0 0.0% { 175 0.9% eebf: 55 push %rbp 1898 9.8% eec0: 48 89 e5 mov %rsp,%rbp 0 0.0% 0 0.0% i = rx_ring->next_to_clean; 140 0.7% ef0a: 0f b7 41 1a movzwl 0x1a(%rcx),%eax 670 3.4% ef0e: 89 45 ac mov %eax,-0x54(%rbp) 0 0.0% { 0 0.0% memcpy(skb->data + offset, from, len); 91 0.5% f07b: 49 8b b6 e8 00 00 00 mov 0xe8(%r14),%rsi 1153 5.9% f082: 48 8b b8 e8 00 00 00 mov 0xe8(%rax),%rdi 42 0.2% f089: 8b 4d 84 mov -0x7c(%rbp),%ecx 14 0.1% f08c: 48 83 ef 02 sub $0x2,%rdi 0 0.0% f090: 48 83 ee 02 sub $0x2,%rsi 1618 8.3% f094: f3 a4 rep movsb %ds:(%rsi),%es:(%rdi) 0 0.0% 0 0.0% /* return some buffers to hardware, one at a time is too slow */ 0 0.0% if (cleaned_count >= E1000_RX_BUFFER_WRITE) { 867 4.5% f0e7: 83 7d b0 0f cmpl $0xf,-0x50(%rbp) 0 0.0% 0 0.0% while (rx_desc->status & E1000_RXD_STAT_DD) { 37 0.2% f114: 41 f6 47 0c 01 testb $0x1,0xc(%r15) 4047 20.8% f119: 0f 85 24 fe ff ff jne ef43 Signed-off-by: Mike Galbraith Signed-off-by: Peter Zijlstra Cc: Paul Mackerras Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index f139f1a..d587013 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -31,6 +31,8 @@ #include #include +#include +#include #include #include @@ -54,7 +56,7 @@ static int system_wide = 0; static int default_interval = 100000; -static u64 count_filter = 5; +static int count_filter = 5; static int print_entries = 15; static int target_pid = -1; @@ -69,15 +71,27 @@ static int freq = 0; static int verbose = 0; static char *vmlinux = NULL; -static char *sym_filter; -static unsigned long filter_start; -static unsigned long filter_end; - static int delay_secs = 2; static int zero; static int dump_symtab; /* + * Source + */ + +struct source_line { + u64 eip; + unsigned long count[MAX_COUNTERS]; + char *line; + struct source_line *next; +}; + +static char *sym_filter = NULL; +struct sym_entry *sym_filter_entry = NULL; +static int sym_pcnt_filter = 5; +static int sym_counter = 0; + +/* * Symbols */ @@ -91,9 +105,237 @@ struct sym_entry { unsigned long snap_count; double weight; int skip; + struct source_line *source; + struct source_line *lines; + struct source_line **lines_tail; + pthread_mutex_t source_lock; }; -struct sym_entry *sym_filter_entry; +/* + * Source functions + */ + +static void parse_source(struct sym_entry *syme) +{ + struct symbol *sym; + struct module *module; + struct section *section = NULL; + FILE *file; + char command[PATH_MAX*2], *path = vmlinux; + u64 start, end, len; + + if (!syme) + return; + + if (syme->lines) { + pthread_mutex_lock(&syme->source_lock); + goto out_assign; + } + + sym = (struct symbol *)(syme + 1); + module = sym->module; + + if (module) + path = module->path; + if (!path) + return; + + start = sym->obj_start; + if (!start) + start = sym->start; + + if (module) { + section = module->sections->find_section(module->sections, ".text"); + if (section) + start -= section->vma; + } + + end = start + sym->end - sym->start + 1; + len = sym->end - sym->start; + + sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s", start, end, path); + + file = popen(command, "r"); + if (!file) + return; + + pthread_mutex_lock(&syme->source_lock); + syme->lines_tail = &syme->lines; + while (!feof(file)) { + struct source_line *src; + size_t dummy = 0; + char *c; + + src = malloc(sizeof(struct source_line)); + assert(src != NULL); + memset(src, 0, sizeof(struct source_line)); + + if (getline(&src->line, &dummy, file) < 0) + break; + if (!src->line) + break; + + c = strchr(src->line, '\n'); + if (c) + *c = 0; + + src->next = NULL; + *syme->lines_tail = src; + syme->lines_tail = &src->next; + + if (strlen(src->line)>8 && src->line[8] == ':') { + src->eip = strtoull(src->line, NULL, 16); + if (section) + src->eip += section->vma; + } + if (strlen(src->line)>8 && src->line[16] == ':') { + src->eip = strtoull(src->line, NULL, 16); + if (section) + src->eip += section->vma; + } + } + pclose(file); +out_assign: + sym_filter_entry = syme; + pthread_mutex_unlock(&syme->source_lock); +} + +static void __zero_source_counters(struct sym_entry *syme) +{ + int i; + struct source_line *line; + + line = syme->lines; + while (line) { + for (i = 0; i < nr_counters; i++) + line->count[i] = 0; + line = line->next; + } +} + +static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip) +{ + struct source_line *line; + + if (syme != sym_filter_entry) + return; + + if (pthread_mutex_trylock(&syme->source_lock)) + return; + + if (!syme->source) + goto out_unlock; + + for (line = syme->lines; line; line = line->next) { + if (line->eip == ip) { + line->count[counter]++; + break; + } + if (line->eip > ip) + break; + } +out_unlock: + pthread_mutex_unlock(&syme->source_lock); +} + +static void lookup_sym_source(struct sym_entry *syme) +{ + struct symbol *symbol = (struct symbol *)(syme + 1); + struct source_line *line; + char pattern[PATH_MAX]; + char *idx; + + sprintf(pattern, "<%s>:", symbol->name); + + if (symbol->module) { + idx = strstr(pattern, "\t"); + if (idx) + *idx = 0; + } + + pthread_mutex_lock(&syme->source_lock); + for (line = syme->lines; line; line = line->next) { + if (strstr(line->line, pattern)) { + syme->source = line; + break; + } + } + pthread_mutex_unlock(&syme->source_lock); +} + +static void show_lines(struct source_line *queue, int count, int total) +{ + int i; + struct source_line *line; + + line = queue; + for (i = 0; i < count; i++) { + float pcnt = 100.0*(float)line->count[sym_counter]/(float)total; + + printf("%8li %4.1f%%\t%s\n", line->count[sym_counter], pcnt, line->line); + line = line->next; + } +} + +#define TRACE_COUNT 3 + +static void show_details(struct sym_entry *syme) +{ + struct symbol *symbol; + struct source_line *line; + struct source_line *line_queue = NULL; + int displayed = 0; + int line_queue_count = 0, total = 0, more = 0; + + if (!syme) + return; + + if (!syme->source) + lookup_sym_source(syme); + + if (!syme->source) + return; + + symbol = (struct symbol *)(syme + 1); + printf("Showing %s for %s\n", event_name(sym_counter), symbol->name); + printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter); + + pthread_mutex_lock(&syme->source_lock); + line = syme->source; + while (line) { + total += line->count[sym_counter]; + line = line->next; + } + + line = syme->source; + while (line) { + float pcnt = 0.0; + + if (!line_queue_count) + line_queue = line; + line_queue_count++; + + if (line->count[sym_counter]) + pcnt = 100.0 * line->count[sym_counter] / (float)total; + if (pcnt >= (float)sym_pcnt_filter) { + if (displayed <= print_entries) + show_lines(line_queue, line_queue_count, total); + else more++; + displayed += line_queue_count; + line_queue_count = 0; + line_queue = NULL; + } else if (line_queue_count > TRACE_COUNT) { + line_queue = line_queue->next; + line_queue_count--; + } + + line->count[sym_counter] = zero ? 0 : line->count[sym_counter] * 7 / 8; + line = line->next; + } + pthread_mutex_unlock(&syme->source_lock); + if (more) + printf("%d lines not displayed, maybe increase display entries [e]\n", more); +} struct dso *kernel_dso; @@ -228,6 +470,11 @@ static void print_sym_table(void) printf("------------------------------------------------------------------------------\n\n"); + if (sym_filter_entry) { + show_details(sym_filter_entry); + return; + } + if (nr_counters == 1) printf(" samples pcnt"); else @@ -242,7 +489,7 @@ static void print_sym_table(void) struct symbol *sym = (struct symbol *)(syme + 1); double pcnt; - if (++printed > print_entries || syme->snap_count < count_filter) + if (++printed > print_entries || (int)syme->snap_count < count_filter) continue; pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) / @@ -261,19 +508,208 @@ static void print_sym_table(void) } } +static void prompt_integer(int *target, const char *msg) +{ + char *buf = malloc(0), *p; + size_t dummy = 0; + int tmp; + + fprintf(stdout, "\n%s: ", msg); + if (getline(&buf, &dummy, stdin) < 0) + return; + + p = strchr(buf, '\n'); + if (p) + *p = 0; + + p = buf; + while(*p) { + if (!isdigit(*p)) + goto out_free; + p++; + } + tmp = strtoul(buf, NULL, 10); + *target = tmp; +out_free: + free(buf); +} + +static void prompt_percent(int *target, const char *msg) +{ + int tmp = 0; + + prompt_integer(&tmp, msg); + if (tmp >= 0 && tmp <= 100) + *target = tmp; +} + +static void prompt_symbol(struct sym_entry **target, const char *msg) +{ + char *buf = malloc(0), *p; + struct sym_entry *syme = *target, *n, *found = NULL; + size_t dummy = 0; + + /* zero counters of active symbol */ + if (syme) { + pthread_mutex_lock(&syme->source_lock); + __zero_source_counters(syme); + *target = NULL; + pthread_mutex_unlock(&syme->source_lock); + } + + fprintf(stdout, "\n%s: ", msg); + if (getline(&buf, &dummy, stdin) < 0) + goto out_free; + + p = strchr(buf, '\n'); + if (p) + *p = 0; + + pthread_mutex_lock(&active_symbols_lock); + syme = list_entry(active_symbols.next, struct sym_entry, node); + pthread_mutex_unlock(&active_symbols_lock); + + list_for_each_entry_safe_from(syme, n, &active_symbols, node) { + struct symbol *sym = (struct symbol *)(syme + 1); + + if (!strcmp(buf, sym->name)) { + found = syme; + break; + } + } + + if (!found) { + fprintf(stderr, "Sorry, %s is not active.\n", sym_filter); + sleep(1); + return; + } else + parse_source(found); + +out_free: + free(buf); +} + +static void print_known_keys(void) +{ + fprintf(stdout, "\nknown keys:\n"); + fprintf(stdout, "\t[d] select display delay.\n"); + fprintf(stdout, "\t[e] select display entries (lines).\n"); + fprintf(stdout, "\t[E] select annotation event counter.\n"); + fprintf(stdout, "\t[f] select normal display count filter.\n"); + fprintf(stdout, "\t[F] select annotation display count filter (percentage).\n"); + fprintf(stdout, "\t[qQ] quit.\n"); + fprintf(stdout, "\t[s] select annotation symbol and start annotation.\n"); + fprintf(stdout, "\t[S] stop annotation, revert to normal display.\n"); + fprintf(stdout, "\t[z] toggle event count zeroing.\n"); +} + +static void handle_keypress(int c) +{ + int once = 0; +repeat: + switch (c) { + case 'd': + prompt_integer(&delay_secs, "Enter display delay"); + break; + case 'e': + prompt_integer(&print_entries, "Enter display entries (lines)"); + break; + case 'E': + if (nr_counters > 1) { + int i; + + fprintf(stderr, "\nAvailable events:"); + for (i = 0; i < nr_counters; i++) + fprintf(stderr, "\n\t%d %s", i, event_name(i)); + + prompt_integer(&sym_counter, "Enter details event counter"); + + if (sym_counter >= nr_counters) { + fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(0)); + sym_counter = 0; + sleep(1); + } + } else sym_counter = 0; + break; + case 'f': + prompt_integer(&count_filter, "Enter display event count filter"); + break; + case 'F': + prompt_percent(&sym_pcnt_filter, "Enter details display event filter (percent)"); + break; + case 'q': + case 'Q': + printf("exiting.\n"); + exit(0); + case 's': + prompt_symbol(&sym_filter_entry, "Enter details symbol"); + break; + case 'S': + if (!sym_filter_entry) + break; + else { + struct sym_entry *syme = sym_filter_entry; + + pthread_mutex_lock(&syme->source_lock); + sym_filter_entry = NULL; + __zero_source_counters(syme); + pthread_mutex_unlock(&syme->source_lock); + } + break; + case 'z': + zero = ~zero; + break; + default: { + struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; + struct termios tc, save; + + if (!once) { + print_known_keys(); + once++; + } + + tcgetattr(0, &save); + tc = save; + tc.c_lflag &= ~(ICANON | ECHO); + tc.c_cc[VMIN] = 0; + tc.c_cc[VTIME] = 0; + tcsetattr(0, TCSANOW, &tc); + + poll(&stdin_poll, 1, -1); + c = getc(stdin); + + tcsetattr(0, TCSAFLUSH, &save); + goto repeat; + } + } +} + static void *display_thread(void *arg __used) { struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; - int delay_msecs = delay_secs * 1000; - - printf("PerfTop refresh period: %d seconds\n", delay_secs); + struct termios tc, save; + int delay_msecs, c; + + tcgetattr(0, &save); + tc = save; + tc.c_lflag &= ~(ICANON | ECHO); + tc.c_cc[VMIN] = 0; + tc.c_cc[VTIME] = 0; +repeat: + delay_msecs = delay_secs * 1000; + tcsetattr(0, TCSANOW, &tc); + /* trash return*/ + getc(stdin); do { print_sym_table(); } while (!poll(&stdin_poll, 1, delay_msecs) == 1); - printf("key pressed - exiting.\n"); - exit(0); + c = getc(stdin); + tcsetattr(0, TCSAFLUSH, &save); + + handle_keypress(c); + goto repeat; return NULL; } @@ -293,7 +729,6 @@ static const char *skip_symbols[] = { static int symbol_filter(struct dso *self, struct symbol *sym) { - static int filter_match; struct sym_entry *syme; const char *name = sym->name; int i; @@ -315,6 +750,10 @@ static int symbol_filter(struct dso *self, struct symbol *sym) return 1; syme = dso__sym_priv(self, sym); + pthread_mutex_init(&syme->source_lock, NULL); + if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) + sym_filter_entry = syme; + for (i = 0; skip_symbols[i]; i++) { if (!strcmp(skip_symbols[i], name)) { syme->skip = 1; @@ -322,29 +761,6 @@ static int symbol_filter(struct dso *self, struct symbol *sym) } } - if (filter_match == 1) { - filter_end = sym->start; - filter_match = -1; - if (filter_end - filter_start > 10000) { - fprintf(stderr, - "hm, too large filter symbol <%s> - skipping.\n", - sym_filter); - fprintf(stderr, "symbol filter start: %016lx\n", - filter_start); - fprintf(stderr, " end: %016lx\n", - filter_end); - filter_end = filter_start = 0; - sym_filter = NULL; - sleep(1); - } - } - - if (filter_match == 0 && sym_filter && !strcmp(name, sym_filter)) { - filter_match = 1; - filter_start = sym->start; - } - - return 0; } @@ -380,8 +796,6 @@ out_delete_dso: return -1; } -#define TRACE_COUNT 3 - /* * Binary search in the histogram table and record the hit: */ @@ -394,6 +808,7 @@ static void record_ip(u64 ip, int counter) if (!syme->skip) { syme->count[counter]++; + record_precise_ip(syme, counter, ip); pthread_mutex_lock(&active_symbols_lock); if (list_empty(&syme->node) || !syme->node.next) __list_insert_active_sym(syme); @@ -690,8 +1105,8 @@ static const struct option options[] = { "put the counters into a counter group"), OPT_BOOLEAN('i', "inherit", &inherit, "child tasks inherit counters"), - OPT_STRING('s', "sym-filter", &sym_filter, "pattern", - "only display symbols matchig this pattern"), + OPT_STRING('s', "sym-annotate", &sym_filter, "symbol name", + "symbol to annotate - requires -k option"), OPT_BOOLEAN('z', "zero", &zero, "zero history across updates"), OPT_INTEGER('F', "freq", &freq, @@ -734,6 +1149,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) delay_secs = 1; parse_symbols(); + parse_source(sym_filter_entry); /* * Fill in the ones not specifically initialized via -c: -- cgit v0.10.2 From 46ab976443c6c566c8fe6fc72a6733a55ba9fbea Mon Sep 17 00:00:00 2001 From: Mike Galbraith Date: Fri, 24 Jul 2009 10:09:50 +0200 Subject: perf_counter tools: Allow perf top top users to switch between weighted and individual counter display Add [w]eighted hotkey. Pressing [w] toggles between displaying weighted total of all counters, and the counter selected via [E]vent select key. ------------------------------------------------------------------------------ PerfTop: 90395 irqs/sec kernel:16.1% [cache-misses/cache-references/instructions], (all, 4 CPUs) ------------------------------------------------------------------------------ weight samples pcnt RIP kernel function ______ _______ _____ ________________ _______________ 1275408.6 10881 - 5.3% - ffffffff81146f70 : copy_page_c 553683.4 43569 - 21.3% - ffffffff81146f20 : clear_page_c 74075.0 6768 - 3.3% - ffffffff81147190 : copy_user_generic_string 40602.9 7538 - 3.7% - ffffffff81284ba2 : _spin_lock 26882.1 965 - 0.5% - ffffffff8109d280 : file_ra_state_init [w] ------------------------------------------------------------------------------ PerfTop: 91221 irqs/sec kernel:14.5% [10000Hz cache-misses], (all, 4 CPUs) ------------------------------------------------------------------------------ weight samples pcnt RIP kernel function ______ _______ _____ ________________ _______________ 47320.00 - 22.3% - ffffffff81146f20 : clear_page_c 14261.00 - 6.7% - ffffffff810992f5 : __rmqueue 11046.00 - 5.2% - ffffffff81146f70 : copy_page_c 7842.00 - 3.7% - ffffffff81284ba2 : _spin_lock 7234.00 - 3.4% - ffffffff810aa1d6 : unmap_vmas Signed-off-by: Mike Galbraith Signed-off-by: Peter Zijlstra Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index d587013..4eef346 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -90,6 +90,7 @@ static char *sym_filter = NULL; struct sym_entry *sym_filter_entry = NULL; static int sym_pcnt_filter = 5; static int sym_counter = 0; +static int display_weighted = -1; /* * Symbols @@ -354,6 +355,9 @@ static double sym_weight(const struct sym_entry *sym) double weight = sym->snap_count; int counter; + if (!display_weighted) + return weight; + for (counter = 1; counter < nr_counters-1; counter++) weight *= sym->count[counter]; @@ -401,7 +405,7 @@ static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se) static void print_sym_table(void) { int printed = 0, j; - int counter; + int counter, snap = !display_weighted ? sym_counter : 0; float samples_per_sec = samples/delay_secs; float ksamples_per_sec = (samples-userspace_samples)/delay_secs; float sum_ksamples = 0.0; @@ -417,7 +421,7 @@ static void print_sym_table(void) pthread_mutex_unlock(&active_symbols_lock); list_for_each_entry_safe_from(syme, n, &active_symbols, node) { - syme->snap_count = syme->count[0]; + syme->snap_count = syme->count[snap]; if (syme->snap_count != 0) { syme->weight = sym_weight(syme); rb_insert_active_sym(&tmp, syme); @@ -437,7 +441,7 @@ static void print_sym_table(void) samples_per_sec, 100.0 - (100.0*((samples_per_sec-ksamples_per_sec)/samples_per_sec))); - if (nr_counters == 1) { + if (nr_counters == 1 || !display_weighted) { printf("%Ld", (u64)attrs[0].sample_period); if (freq) printf("Hz "); @@ -445,7 +449,9 @@ static void print_sym_table(void) printf(" "); } - for (counter = 0; counter < nr_counters; counter++) { + if (!display_weighted) + printf("%s", event_name(sym_counter)); + else for (counter = 0; counter < nr_counters; counter++) { if (counter) printf("/"); @@ -495,7 +501,7 @@ static void print_sym_table(void) pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) / sum_ksamples)); - if (nr_counters == 1) + if (nr_counters == 1 || !display_weighted) printf("%20.2f - ", syme->weight); else printf("%9.1f %10ld - ", syme->weight, syme->snap_count); @@ -594,13 +600,14 @@ static void print_known_keys(void) fprintf(stdout, "\nknown keys:\n"); fprintf(stdout, "\t[d] select display delay.\n"); fprintf(stdout, "\t[e] select display entries (lines).\n"); - fprintf(stdout, "\t[E] select annotation event counter.\n"); + fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(sym_counter)); fprintf(stdout, "\t[f] select normal display count filter.\n"); fprintf(stdout, "\t[F] select annotation display count filter (percentage).\n"); fprintf(stdout, "\t[qQ] quit.\n"); fprintf(stdout, "\t[s] select annotation symbol and start annotation.\n"); fprintf(stdout, "\t[S] stop annotation, revert to normal display.\n"); - fprintf(stdout, "\t[z] toggle event count zeroing.\n"); + fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", display_weighted ? 1 : 0); + fprintf(stdout, "\t[z] toggle sample zeroing. \t(%d)\n", zero ? 1 : 0); } static void handle_keypress(int c) @@ -656,6 +663,9 @@ repeat: pthread_mutex_unlock(&syme->source_lock); } break; + case 'w': + display_weighted = ~display_weighted; + break; case 'z': zero = ~zero; break; -- cgit v0.10.2 From 7b4b6658e152ed4568cfff48175d93645df081d1 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 22 Jul 2009 09:29:32 +0200 Subject: perf_counter: Fix software counters for fast moving event sources Reimplement the software counters to deal with fast moving event sources (such as tracepoints). This means being able to generate multiple overflows from a single 'event' as well as support throttling. Signed-off-by: Peter Zijlstra Cc: Paul Mackerras Signed-off-by: Ingo Molnar diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c index 8681021..615440a 100644 --- a/kernel/perf_counter.c +++ b/kernel/perf_counter.c @@ -3344,87 +3344,81 @@ int perf_counter_overflow(struct perf_counter *counter, int nmi, * Generic software counter infrastructure */ -static void perf_swcounter_update(struct perf_counter *counter) +/* + * We directly increment counter->count and keep a second value in + * counter->hw.period_left to count intervals. This period counter + * is kept in the range [-sample_period, 0] so that we can use the + * sign as trigger. + */ + +static u64 perf_swcounter_set_period(struct perf_counter *counter) { struct hw_perf_counter *hwc = &counter->hw; - u64 prev, now; - s64 delta; + u64 period = hwc->last_period; + u64 nr, offset; + s64 old, val; + + hwc->last_period = hwc->sample_period; again: - prev = atomic64_read(&hwc->prev_count); - now = atomic64_read(&hwc->count); - if (atomic64_cmpxchg(&hwc->prev_count, prev, now) != prev) - goto again; + old = val = atomic64_read(&hwc->period_left); + if (val < 0) + return 0; - delta = now - prev; + nr = div64_u64(period + val, period); + offset = nr * period; + val -= offset; + if (atomic64_cmpxchg(&hwc->period_left, old, val) != old) + goto again; - atomic64_add(delta, &counter->count); - atomic64_sub(delta, &hwc->period_left); + return nr; } -static void perf_swcounter_set_period(struct perf_counter *counter) +static void perf_swcounter_overflow(struct perf_counter *counter, + int nmi, struct perf_sample_data *data) { struct hw_perf_counter *hwc = &counter->hw; - s64 left = atomic64_read(&hwc->period_left); - s64 period = hwc->sample_period; + u64 overflow; - if (unlikely(left <= -period)) { - left = period; - atomic64_set(&hwc->period_left, left); - hwc->last_period = period; - } + data->period = counter->hw.last_period; + overflow = perf_swcounter_set_period(counter); - if (unlikely(left <= 0)) { - left += period; - atomic64_add(period, &hwc->period_left); - hwc->last_period = period; - } + if (hwc->interrupts == MAX_INTERRUPTS) + return; - atomic64_set(&hwc->prev_count, -left); - atomic64_set(&hwc->count, -left); + for (; overflow; overflow--) { + if (perf_counter_overflow(counter, nmi, data)) { + /* + * We inhibit the overflow from happening when + * hwc->interrupts == MAX_INTERRUPTS. + */ + break; + } + } } -static enum hrtimer_restart perf_swcounter_hrtimer(struct hrtimer *hrtimer) +static void perf_swcounter_unthrottle(struct perf_counter *counter) { - enum hrtimer_restart ret = HRTIMER_RESTART; - struct perf_sample_data data; - struct perf_counter *counter; - u64 period; - - counter = container_of(hrtimer, struct perf_counter, hw.hrtimer); - counter->pmu->read(counter); - - data.addr = 0; - data.regs = get_irq_regs(); /* - * In case we exclude kernel IPs or are somehow not in interrupt - * context, provide the next best thing, the user IP. + * Nothing to do, we already reset hwc->interrupts. */ - if ((counter->attr.exclude_kernel || !data.regs) && - !counter->attr.exclude_user) - data.regs = task_pt_regs(current); +} - if (data.regs) { - if (perf_counter_overflow(counter, 0, &data)) - ret = HRTIMER_NORESTART; - } +static void perf_swcounter_add(struct perf_counter *counter, u64 nr, + int nmi, struct perf_sample_data *data) +{ + struct hw_perf_counter *hwc = &counter->hw; - period = max_t(u64, 10000, counter->hw.sample_period); - hrtimer_forward_now(hrtimer, ns_to_ktime(period)); + atomic64_add(nr, &counter->count); - return ret; -} + if (!hwc->sample_period) + return; -static void perf_swcounter_overflow(struct perf_counter *counter, - int nmi, struct perf_sample_data *data) -{ - data->period = counter->hw.last_period; + if (!data->regs) + return; - perf_swcounter_update(counter); - perf_swcounter_set_period(counter); - if (perf_counter_overflow(counter, nmi, data)) - /* soft-disable the counter */ - ; + if (!atomic64_add_negative(nr, &hwc->period_left)) + perf_swcounter_overflow(counter, nmi, data); } static int perf_swcounter_is_counting(struct perf_counter *counter) @@ -3488,15 +3482,6 @@ static int perf_swcounter_match(struct perf_counter *counter, return 1; } -static void perf_swcounter_add(struct perf_counter *counter, u64 nr, - int nmi, struct perf_sample_data *data) -{ - int neg = atomic64_add_negative(nr, &counter->hw.count); - - if (counter->hw.sample_period && !neg && data->regs) - perf_swcounter_overflow(counter, nmi, data); -} - static void perf_swcounter_ctx_event(struct perf_counter_context *ctx, enum perf_type_id type, u32 event, u64 nr, int nmi, @@ -3575,27 +3560,66 @@ void __perf_swcounter_event(u32 event, u64 nr, int nmi, static void perf_swcounter_read(struct perf_counter *counter) { - perf_swcounter_update(counter); } static int perf_swcounter_enable(struct perf_counter *counter) { - perf_swcounter_set_period(counter); + struct hw_perf_counter *hwc = &counter->hw; + + if (hwc->sample_period) { + hwc->last_period = hwc->sample_period; + perf_swcounter_set_period(counter); + } return 0; } static void perf_swcounter_disable(struct perf_counter *counter) { - perf_swcounter_update(counter); } static const struct pmu perf_ops_generic = { .enable = perf_swcounter_enable, .disable = perf_swcounter_disable, .read = perf_swcounter_read, + .unthrottle = perf_swcounter_unthrottle, }; /* + * hrtimer based swcounter callback + */ + +static enum hrtimer_restart perf_swcounter_hrtimer(struct hrtimer *hrtimer) +{ + enum hrtimer_restart ret = HRTIMER_RESTART; + struct perf_sample_data data; + struct perf_counter *counter; + u64 period; + + counter = container_of(hrtimer, struct perf_counter, hw.hrtimer); + counter->pmu->read(counter); + + data.addr = 0; + data.regs = get_irq_regs(); + /* + * In case we exclude kernel IPs or are somehow not in interrupt + * context, provide the next best thing, the user IP. + */ + if ((counter->attr.exclude_kernel || !data.regs) && + !counter->attr.exclude_user) + data.regs = task_pt_regs(current); + + if (data.regs) { + if (perf_counter_overflow(counter, 0, &data)) + ret = HRTIMER_NORESTART; + } + + period = max_t(u64, 10000, counter->hw.sample_period); + hrtimer_forward_now(hrtimer, ns_to_ktime(period)); + + return ret; +} + +/* * Software counter: cpu wall time clock */ -- cgit v0.10.2 From 091bd2e993fcb1094a23e36157285b62bc87afdf Mon Sep 17 00:00:00 2001 From: Mike Galbraith Date: Tue, 4 Aug 2009 10:21:23 +0200 Subject: perf top: Improve interactive key handling Pressing any key which is not currently mapped to functionality, based on startup command line options, displays currently mapped keys, and prompts for input. Pressing any unmapped key at the prompt returns the user to display mode with variables unchanged. eg, pressing ? etc displays currently available keys, the value of the variable associated with that key, and prompts. Pressing same again aborts input. Signed-off-by: Mike Galbraith Cc: Peter Zijlstra Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 4eef346..7de28ce 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -595,25 +595,84 @@ out_free: free(buf); } -static void print_known_keys(void) +static void print_mapped_keys(void) { - fprintf(stdout, "\nknown keys:\n"); - fprintf(stdout, "\t[d] select display delay.\n"); - fprintf(stdout, "\t[e] select display entries (lines).\n"); - fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(sym_counter)); - fprintf(stdout, "\t[f] select normal display count filter.\n"); - fprintf(stdout, "\t[F] select annotation display count filter (percentage).\n"); - fprintf(stdout, "\t[qQ] quit.\n"); - fprintf(stdout, "\t[s] select annotation symbol and start annotation.\n"); - fprintf(stdout, "\t[S] stop annotation, revert to normal display.\n"); - fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", display_weighted ? 1 : 0); + char *name = NULL; + + if (sym_filter_entry) { + struct symbol *sym = (struct symbol *)(sym_filter_entry+1); + name = sym->name; + } + + fprintf(stdout, "\nMapped keys:\n"); + fprintf(stdout, "\t[d] display refresh delay. \t(%d)\n", delay_secs); + fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", print_entries); + + if (nr_counters > 1) + fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(sym_counter)); + + fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", count_filter); + + if (vmlinux) { + fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", sym_pcnt_filter); + fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); + fprintf(stdout, "\t[S] stop annotation.\n"); + } + + if (nr_counters > 1) + fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", display_weighted ? 1 : 0); + fprintf(stdout, "\t[z] toggle sample zeroing. \t(%d)\n", zero ? 1 : 0); + fprintf(stdout, "\t[qQ] quit.\n"); +} + +static int key_mapped(int c) +{ + switch (c) { + case 'd': + case 'e': + case 'f': + case 'z': + case 'q': + case 'Q': + return 1; + case 'E': + case 'w': + return nr_counters > 1 ? 1 : 0; + case 'F': + case 's': + case 'S': + return vmlinux ? 1 : 0; + } + + return 0; } static void handle_keypress(int c) { - int once = 0; -repeat: + if (!key_mapped(c)) { + struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; + struct termios tc, save; + + print_mapped_keys(); + fprintf(stdout, "\nEnter selection, or unmapped key to continue: "); + fflush(stdout); + + tcgetattr(0, &save); + tc = save; + tc.c_lflag &= ~(ICANON | ECHO); + tc.c_cc[VMIN] = 0; + tc.c_cc[VTIME] = 0; + tcsetattr(0, TCSANOW, &tc); + + poll(&stdin_poll, 1, -1); + c = getc(stdin); + + tcsetattr(0, TCSAFLUSH, &save); + if (!key_mapped(c)) + return; + } + switch (c) { case 'd': prompt_integer(&delay_secs, "Enter display delay"); @@ -669,28 +728,6 @@ repeat: case 'z': zero = ~zero; break; - default: { - struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; - struct termios tc, save; - - if (!once) { - print_known_keys(); - once++; - } - - tcgetattr(0, &save); - tc = save; - tc.c_lflag &= ~(ICANON | ECHO); - tc.c_cc[VMIN] = 0; - tc.c_cc[VTIME] = 0; - tcsetattr(0, TCSANOW, &tc); - - poll(&stdin_poll, 1, -1); - c = getc(stdin); - - tcsetattr(0, TCSAFLUSH, &save); - goto repeat; - } } } @@ -705,6 +742,7 @@ static void *display_thread(void *arg __used) tc.c_lflag &= ~(ICANON | ECHO); tc.c_cc[VMIN] = 0; tc.c_cc[VTIME] = 0; + repeat: delay_msecs = delay_secs * 1000; tcsetattr(0, TCSANOW, &tc); -- cgit v0.10.2 From 836179834833272f89098c6d1e1b89e8e69797c2 Mon Sep 17 00:00:00 2001 From: Mike Galbraith Date: Tue, 4 Aug 2009 10:24:41 +0200 Subject: perf top: Update man page perf_counter tools: update perf top manual page to reflect current implementation. Signed-off-by: Mike Galbraith Cc: Peter Zijlstra Signed-off-by: Ingo Molnar diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt index 539d012..4a7d558 100644 --- a/tools/perf/Documentation/perf-top.txt +++ b/tools/perf/Documentation/perf-top.txt @@ -3,36 +3,122 @@ perf-top(1) NAME ---- -perf-top - Run a command and profile it +perf-top - System profiling tool. SYNOPSIS -------- [verse] -'perf top' [-e | --event=EVENT] [-l] [-a] +'perf top' [-e | --event=EVENT] [] DESCRIPTION ----------- -This command runs a command and gathers a performance counter profile -from it. +This command generates and displays a performance counter profile in realtime. OPTIONS ------- -...:: - Any command you can specify in a shell. +-a:: +--all-cpus:: + System-wide collection. (default) + +-c :: +--count=:: + Event period to sample. + +-C :: +--CPU=:: + CPU to profile. + +-d :: +--delay=:: + Number of seconds to delay between refreshes. --e:: ---event=:: +-e :: +--event=:: Select the PMU event. Selection can be a symbolic event name (use 'perf list' to list all events) or a raw PMU event (eventsel+umask) in the form of rNNN where NNN is a - hexadecimal event descriptor. + hexadecimal event descriptor. --a:: - system-wide collection +-E :: +--entries=:: + Display this many functions. + +-f :: +--count-filter=:: + Only display functions with more events than this. + +-F :: +--freq=:: + Profile at this frequency. + +-i:: +--inherit:: + Child tasks inherit counters, only makes sens with -p option. + +-k :: +--vmlinux=:: + Path to vmlinux. Required for annotation functionality. + +-m :: +--mmap-pages=:: + Number of mmapped data pages. + +-p :: +--pid=:: + Profile events on existing pid. + +-r :: +--realtime=:: + Collect data with this RT SCHED_FIFO priority. + +-s :: +--sym-annotate=:: + Annotate this symbol. Requires -k option. + +-v:: +--verbose:: + Be more verbose (show counter open errors, etc). + +-z:: +--zero:: + Zero history across display updates. + +INTERACTIVE PROMPTING KEYS +-------------------------- + +[d]:: + Display refresh delay. + +[e]:: + Number of entries to display. + +[E]:: + Event to display when multiple counters are active. + +[f]:: + Profile display filter (>= hit count). + +[F]:: + Annotation display filter (>= % of total). + +[s]:: + Annotate symbol. + +[S]:: + Stop annotation, return to full profile display. + +[w]:: + Toggle between weighted sum and individual count[E]r profile. + +[z]:: + Toggle event count zeroing across display updates. + +[qQ]:: + Quit. + +Pressing any unmapped key displays a menu, and prompts for input. --l:: - scale counter values SEE ALSO -------- -- cgit v0.10.2 From 1953287bfe8afcbbd235bd6c42c9df06d52438dc Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Fri, 7 Aug 2009 07:11:05 +0200 Subject: perf tools: Fix call-chain cumul hit based sub-total (fractal mode) The callchain fractal mode builds each new total hits in a new branch of profiling by using the parent's hits of the current branch plus the hits of the children. This is wrong, the total hits of a branch should be made of the sum of every children hits, we must ignore the parent hits in this scope. This patch also fixes another mistake with the hit counting. Now the rates are correct. Signed-off-by: Frederic Weisbecker Cc: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Mike Galbraith Cc: Pekka Enberg Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 8cb58d6..da402e1 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -901,7 +901,7 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self, int i; if (callchain_param.mode == CHAIN_GRAPH_REL) - new_total = self->cumul_hit; + new_total = self->children_hit; else new_total = total_samples; @@ -930,7 +930,7 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self, ret += ipchain__fprintf_graph(fp, chain, depth, new_depth_mask, i++, new_total, - child->cumul_hit); + cumul_hits(child)); } ret += callchain__fprintf_graph(fp, child, new_total, depth + 1, diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index 9d3c814..98c5627 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c @@ -26,10 +26,14 @@ rb_insert_callchain(struct rb_root *root, struct callchain_node *chain, struct rb_node **p = &root->rb_node; struct rb_node *parent = NULL; struct callchain_node *rnode; + u64 chain_cumul = cumul_hits(chain); while (*p) { + u64 rnode_cumul; + parent = *p; rnode = rb_entry(parent, struct callchain_node, rb_node); + rnode_cumul = cumul_hits(rnode); switch (mode) { case CHAIN_FLAT: @@ -40,7 +44,7 @@ rb_insert_callchain(struct rb_root *root, struct callchain_node *chain, break; case CHAIN_GRAPH_ABS: /* Falldown */ case CHAIN_GRAPH_REL: - if (rnode->cumul_hit < chain->cumul_hit) + if (rnode_cumul < chain_cumul) p = &(*p)->rb_left; else p = &(*p)->rb_right; @@ -87,7 +91,7 @@ static void __sort_chain_graph_abs(struct callchain_node *node, chain_for_each_child(child, node) { __sort_chain_graph_abs(child, min_hit); - if (child->cumul_hit >= min_hit) + if (cumul_hits(child) >= min_hit) rb_insert_callchain(&node->rb_root, child, CHAIN_GRAPH_ABS); } @@ -108,11 +112,11 @@ static void __sort_chain_graph_rel(struct callchain_node *node, u64 min_hit; node->rb_root = RB_ROOT; - min_hit = node->cumul_hit * min_percent / 100.0; + min_hit = node->children_hit * min_percent / 100.0; chain_for_each_child(child, node) { __sort_chain_graph_rel(child, min_percent); - if (child->cumul_hit >= min_hit) + if (cumul_hits(child) >= min_hit) rb_insert_callchain(&node->rb_root, child, CHAIN_GRAPH_REL); } @@ -211,7 +215,8 @@ add_child(struct callchain_node *parent, struct ip_callchain *chain, new = create_child(parent, false); fill_node(new, chain, start, syms); - new->cumul_hit = new->hit = 1; + new->children_hit = 0; + new->hit = 1; } /* @@ -241,7 +246,8 @@ split_add_child(struct callchain_node *parent, struct ip_callchain *chain, /* split the hits */ new->hit = parent->hit; - new->cumul_hit = parent->cumul_hit; + new->children_hit = parent->children_hit; + parent->children_hit = cumul_hits(new); new->val_nr = parent->val_nr - idx_local; parent->val_nr = idx_local; @@ -249,6 +255,7 @@ split_add_child(struct callchain_node *parent, struct ip_callchain *chain, if (idx_total < chain->nr) { parent->hit = 0; add_child(parent, chain, idx_total, syms); + parent->children_hit++; } else { parent->hit = 1; } @@ -269,13 +276,13 @@ __append_chain_children(struct callchain_node *root, struct ip_callchain *chain, unsigned int ret = __append_chain(rnode, chain, start, syms); if (!ret) - goto cumul; + goto inc_children_hit; } /* nothing in children, add to the current node */ add_child(root, chain, start, syms); -cumul: - root->cumul_hit++; +inc_children_hit: + root->children_hit++; } static int @@ -317,8 +324,6 @@ __append_chain(struct callchain_node *root, struct ip_callchain *chain, /* we match 100% of the path, increment the hit */ if (i - start == root->val_nr && i == chain->nr) { root->hit++; - root->cumul_hit++; - return 0; } diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index 7812122..b2d128e 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h @@ -21,7 +21,7 @@ struct callchain_node { struct rb_root rb_root; /* sorted tree of children */ unsigned int val_nr; u64 hit; - u64 cumul_hit; /* hit + hits of children */ + u64 children_hit; }; struct callchain_param; @@ -48,6 +48,11 @@ static inline void callchain_init(struct callchain_node *node) INIT_LIST_HEAD(&node->val); } +static inline u64 cumul_hits(struct callchain_node *node) +{ + return node->hit + node->children_hit; +} + int register_callchain_param(struct callchain_param *param); void append_chain(struct callchain_node *root, struct ip_callchain *chain, struct symbol **syms); -- cgit v0.10.2 From 1c222bce7dd0cb9578b4c5cd3874a74f1db497c3 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 6 Aug 2009 20:57:41 +0200 Subject: perf tools: Fix multi-counter stat bug caused by incorrect reading of perf.data file header Brice Goglin reported that only the first result from a multi-counter perf record --stat run is accurate, the rest looks bogus. A silly mistake made us re-read the first attribute for every recorded attribute. Reported-by: Brice Goglin Signed-off-by: Peter Zijlstra Tested-by: Brice Goglin Cc: paulus@samba.org Signed-off-by: Ingo Molnar diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 450384b..95a44bc 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -213,9 +213,10 @@ struct perf_header *perf_header__read(int fd) for (i = 0; i < nr_attrs; i++) { struct perf_header_attr *attr; - off_t tmp = lseek(fd, 0, SEEK_CUR); + off_t tmp; do_read(fd, &f_attr, sizeof(f_attr)); + tmp = lseek(fd, 0, SEEK_CUR); attr = perf_header_attr__new(&f_attr.attr); -- cgit v0.10.2 From 8f18aec535b5ca513dd13b531730177d35175ffa Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 6 Aug 2009 19:40:28 +0200 Subject: perf report: Fix per task mult-counter stat reporting Brice Goglin reported: > I can easily sort them by thread id, but I don't know how to match > my 4 events with each group of 4 lines. Also report the counter id and the time running/enabled stats (in case the counter got time-shared). Reported-by: Brice Goglin Signed-off-by: Peter Zijlstra Tested-by: Brice Goglin Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index da402e1..8420546 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -112,7 +112,9 @@ struct read_event { struct perf_event_header header; u32 pid,tid; u64 value; - u64 format[3]; + u64 time_enabled; + u64 time_running; + u64 id; }; typedef union event_union { @@ -1690,14 +1692,37 @@ static void trace_event(event_t *event) dprintf(".\n"); } +static struct perf_header *header; + +static struct perf_counter_attr *perf_header__find_attr(u64 id) +{ + int i; + + for (i = 0; i < header->attrs; i++) { + struct perf_header_attr *attr = header->attr[i]; + int j; + + for (j = 0; j < attr->ids; j++) { + if (attr->id[j] == id) + return &attr->attr; + } + } + + return NULL; +} + static int process_read_event(event_t *event, unsigned long offset, unsigned long head) { - dprintf("%p [%p]: PERF_EVENT_READ: %d %d %Lu\n", + struct perf_counter_attr *attr = perf_header__find_attr(event->read.id); + + dprintf("%p [%p]: PERF_EVENT_READ: %d %d %s %Lu\n", (void *)(offset + head), (void *)(long)(event->header.size), event->read.pid, event->read.tid, + attr ? __event_name(attr->type, attr->config) + : "FAIL", event->read.value); return 0; @@ -1743,8 +1768,6 @@ process_event(event_t *event, unsigned long offset, unsigned long head) return 0; } -static struct perf_header *header; - static u64 perf_header__sample_type(void) { u64 sample_type = 0; diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 7bdad8d..f77407b 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -223,9 +223,15 @@ char *event_name(int counter) { u64 config = attrs[counter].config; int type = attrs[counter].type; + + return __event_name(type, config); +} + +char *__event_name(int type, u64 config) +{ static char buf[32]; - if (attrs[counter].type == PERF_TYPE_RAW) { + if (type == PERF_TYPE_RAW) { sprintf(buf, "raw 0x%llx", config); return buf; } diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index 1ea5d09..192a962 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -10,6 +10,7 @@ extern int nr_counters; extern struct perf_counter_attr attrs[MAX_COUNTERS]; extern char *event_name(int ctr); +extern char *__event_name(int type, u64 config); extern int parse_events(const struct option *opt, const char *str, int unset); -- cgit v0.10.2 From 94cb9e385d5b4d55a5ae389baa10ad2835ea39bb Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 6 Aug 2009 14:43:17 -0300 Subject: perf report: Add debug help for the finding of symbol bugs - show the symtab origin (DSO, build-id, kernel, etc) Used with perf report --verbose: [acme@doppio linux-2.6-tip]$ perf report -v | head -16 5.17% firefox /usr/lib64/xulrunner-1.9.1/libxul.so 0x00000000005d8eee f [.] imgContainer::DrawFrameTo(gfxIImageFrame*, gfxIImageFrame*, nsRect&) 2.56% firefox /lib64/libpthread-2.10.1.so 0x0000000000008e02 d [.] __pthread_mutex_lock_internal 1.94% firefox /usr/lib64/xulrunner-1.9.1/libxul.so 0x0000000000d0af8f f [.] SearchTable 1.75% firefox [kernel] 0xffffffffff60013b k [.] vread_hpet 1.63% firefox /lib64/libpthread-2.10.1.so 0x000000000000a404 d [.] __pthread_mutex_unlock 1.47% firefox /usr/lib64/xulrunner-1.9.1/libmozjs.so 0x00000000000482ea f [.] js_Interpret 1.42% firefox /usr/lib64/xulrunner-1.9.1/libmozjs.so 0x000000000003eda3 f [.] JS_CallTracer 1.24% firefox [kernel] 0xffffffff8102ca4a k [k] read_hpet 1.16% firefox [kernel] 0xffffffff810f3dd4 k [k] fget_light 1.11% firefox /usr/lib64/xulrunner-1.9.1/libmozjs.so 0x00000000000567ff f [.] js_TraceObject 0.98% firefox /usr/lib64/firefox-3.5.2/firefox 0x000000000000dd23 b [.] arena_ralloc [acme@doppio linux-2.6-tip]$ The new field is just after the symbol address. To help in figuring out symbol resolution bugs. Signed-off-by: Arnaldo Carvalho de Melo Acked-by: Peter Zijlstra Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 8420546..a5e2f8d 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -700,7 +700,8 @@ sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used) size_t ret = 0; if (verbose) - ret += repsep_fprintf(fp, "%#018llx ", (u64)self->ip); + ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip, + dso__symtab_origin(self->dso)); ret += repsep_fprintf(fp, "[%c] ", self->level); if (self->sym) { diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 16ddca2..f1dcede 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -24,6 +24,16 @@ const char *sym_hist_filter; #define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ #endif +enum dso_origin { + DSO__ORIG_KERNEL = 0, + DSO__ORIG_JAVA_JIT, + DSO__ORIG_FEDORA, + DSO__ORIG_UBUNTU, + DSO__ORIG_BUILDID, + DSO__ORIG_DSO, + DSO__ORIG_NOT_FOUND, +}; + static struct symbol *symbol__new(u64 start, u64 len, const char *name, unsigned int priv_size, u64 obj_start, int verbose) @@ -81,6 +91,7 @@ struct dso *dso__new(const char *name, unsigned int sym_priv_size) self->sym_priv_size = sym_priv_size; self->find_symbol = dso__find_symbol; self->slen_calculated = 0; + self->origin = DSO__ORIG_NOT_FOUND; } return self; @@ -710,7 +721,7 @@ static char *dso__read_build_id(struct dso *self, int verbose) ++raw; bid += 2; } - if (verbose) + if (verbose >= 2) printf("%s(%s): %s\n", __func__, self->name, build_id); out_elf_end: elf_end(elf); @@ -720,11 +731,26 @@ out: return build_id; } +char dso__symtab_origin(const struct dso *self) +{ + static const char origin[] = { + [DSO__ORIG_KERNEL] = 'k', + [DSO__ORIG_JAVA_JIT] = 'j', + [DSO__ORIG_FEDORA] = 'f', + [DSO__ORIG_UBUNTU] = 'u', + [DSO__ORIG_BUILDID] = 'b', + [DSO__ORIG_DSO] = 'd', + }; + + if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) + return '!'; + return origin[self->origin]; +} + int dso__load(struct dso *self, symbol_filter_t filter, int verbose) { int size = PATH_MAX; char *name = malloc(size), *build_id = NULL; - int variant = 0; int ret = -1; int fd; @@ -733,19 +759,26 @@ int dso__load(struct dso *self, symbol_filter_t filter, int verbose) self->adjust_symbols = 0; - if (strncmp(self->name, "/tmp/perf-", 10) == 0) - return dso__load_perf_map(self, filter, verbose); + if (strncmp(self->name, "/tmp/perf-", 10) == 0) { + ret = dso__load_perf_map(self, filter, verbose); + self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : + DSO__ORIG_NOT_FOUND; + return ret; + } + + self->origin = DSO__ORIG_FEDORA - 1; more: do { - switch (variant) { - case 0: /* Fedora */ + self->origin++; + switch (self->origin) { + case DSO__ORIG_FEDORA: snprintf(name, size, "/usr/lib/debug%s.debug", self->name); break; - case 1: /* Ubuntu */ + case DSO__ORIG_UBUNTU: snprintf(name, size, "/usr/lib/debug%s", self->name); break; - case 2: + case DSO__ORIG_BUILDID: build_id = dso__read_build_id(self, verbose); if (build_id != NULL) { snprintf(name, size, @@ -754,16 +787,15 @@ more: free(build_id); break; } - variant++; + self->origin++; /* Fall thru */ - case 3: /* Sane people */ + case DSO__ORIG_DSO: snprintf(name, size, "%s", self->name); break; default: goto out; } - variant++; fd = open(name, O_RDONLY); } while (fd < 0); @@ -899,6 +931,9 @@ int dso__load_kernel(struct dso *self, const char *vmlinux, if (err <= 0) err = dso__load_kallsyms(self, filter, verbose); + if (err > 0) + self->origin = DSO__ORIG_KERNEL; + return err; } diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 2f92b21..1e003ec 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -26,6 +26,7 @@ struct dso { unsigned int sym_priv_size; unsigned char adjust_symbols; unsigned char slen_calculated; + unsigned char origin; char name[0]; }; @@ -49,6 +50,7 @@ int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose); int dso__load(struct dso *self, symbol_filter_t filter, int verbose); size_t dso__fprintf(struct dso *self, FILE *fp); +char dso__symtab_origin(const struct dso *self); void symbol__init(void); #endif /* _PERF_SYMBOL_ */ -- cgit v0.10.2 From b26bc5a7f81474937e427b0c855eabee5ad56f89 Mon Sep 17 00:00:00 2001 From: Brice Goglin Date: Fri, 7 Aug 2009 10:18:39 +0200 Subject: perf stat: Fix tool option consistency: rename -S/--scale to -c/--scale We want to use a coherent flag for -S/--stat across all tools, so free up -S in perf stat. Signed-off-by: Brice Goglin Cc: Peter Zijlstra Cc: paulus@samba.org Signed-off-by: Ingo Molnar diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt index 0d74346..484080d 100644 --- a/tools/perf/Documentation/perf-stat.txt +++ b/tools/perf/Documentation/perf-stat.txt @@ -40,7 +40,7 @@ OPTIONS -a:: system-wide collection --S:: +-c:: scale counter values EXAMPLES diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index f9510ee..b4b06c7 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -496,7 +496,7 @@ static const struct option options[] = { "stat events on existing pid"), OPT_BOOLEAN('a', "all-cpus", &system_wide, "system-wide collection from all CPUs"), - OPT_BOOLEAN('S', "scale", &scale, + OPT_BOOLEAN('c', "scale", &scale, "scale/normalize counters"), OPT_BOOLEAN('v', "verbose", &verbose, "be more verbose (show counter open errors, etc)"), -- cgit v0.10.2 From f36a1a133a947973efb8e6a1fbdcc23e4a011437 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 7 Aug 2009 16:59:45 +1000 Subject: perf_counter/powerpc: Fix oops on cpus without perf_counter hardware support If we have the powerpc perf_counter backend compiled in, but the cpu we are running on is one where we don't support the PMU, we currently oops in hw_perf_group_sched_in if we try to use any counters, because ppmu is NULL in that case, and we unconditionally dereference ppmu. This fixes the problem by adding a check if ppmu is NULL at the beginning of hw_perf_group_sched_in, and also at the beginning of the other functions that get called from the perf_counter core, i.e. hw_perf_disable, hw_perf_enable, and hw_perf_counter_setup. Signed-off-by: Paul Mackerras Cc: Peter Zijlstra Cc: benh@kernel.crashing.org Signed-off-by: Ingo Molnar diff --git a/arch/powerpc/kernel/perf_counter.c b/arch/powerpc/kernel/perf_counter.c index 809fdf9..70e1f57 100644 --- a/arch/powerpc/kernel/perf_counter.c +++ b/arch/powerpc/kernel/perf_counter.c @@ -518,6 +518,8 @@ void hw_perf_disable(void) struct cpu_hw_counters *cpuhw; unsigned long flags; + if (!ppmu) + return; local_irq_save(flags); cpuhw = &__get_cpu_var(cpu_hw_counters); @@ -572,6 +574,8 @@ void hw_perf_enable(void) int n_lim; int idx; + if (!ppmu) + return; local_irq_save(flags); cpuhw = &__get_cpu_var(cpu_hw_counters); if (!cpuhw->disabled) { @@ -737,6 +741,8 @@ int hw_perf_group_sched_in(struct perf_counter *group_leader, long i, n, n0; struct perf_counter *sub; + if (!ppmu) + return 0; cpuhw = &__get_cpu_var(cpu_hw_counters); n0 = cpuhw->n_counters; n = collect_events(group_leader, ppmu->n_counter - n0, @@ -1281,6 +1287,8 @@ void hw_perf_counter_setup(int cpu) { struct cpu_hw_counters *cpuhw = &per_cpu(cpu_hw_counters, cpu); + if (!ppmu) + return; memset(cpuhw, 0, sizeof(*cpuhw)); cpuhw->mmcr[0] = MMCR0_FC; } -- cgit v0.10.2 From ae07b63f4b6728e1f98aa5c5416cfc1280f59f51 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 6 Aug 2009 16:48:54 +0200 Subject: perf list: Fix the output to not include tracepoints without an id Stop perf list from displaying tracepoints without an id file, those are special tracepoints that are not interfaced to perfcounters so listing them is erroneous and passing them as events will produce no output. Signed-off-by: Peter Zijlstra Acked-by: Jason Baron Cc: Steven Rostedt Cc: Chris Mason Signed-off-by: Ingo Molnar diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index f77407b..4858d83 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -121,13 +121,29 @@ static unsigned long hw_cache_stat[C(MAX)] = { (strcmp(sys_dirent.d_name, ".")) && \ (strcmp(sys_dirent.d_name, ".."))) +static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir) +{ + char evt_path[MAXPATHLEN]; + int fd; + + snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path, + sys_dir->d_name, evt_dir->d_name); + fd = open(evt_path, O_RDONLY); + if (fd < 0) + return -EINVAL; + close(fd); + + return 0; +} + #define for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next, file, st) \ while (!readdir_r(evt_dir, &evt_dirent, &evt_next) && evt_next) \ if (snprintf(file, MAXPATHLEN, "%s/%s/%s", debugfs_path, \ sys_dirent.d_name, evt_dirent.d_name) && \ (!stat(file, &st)) && (S_ISDIR(st.st_mode)) && \ (strcmp(evt_dirent.d_name, ".")) && \ - (strcmp(evt_dirent.d_name, ".."))) + (strcmp(evt_dirent.d_name, "..")) && \ + (!tp_event_has_id(&sys_dirent, &evt_dirent))) #define MAX_EVENT_LENGTH 30 -- cgit v0.10.2 From 7eac7e9e726c1b136bd7e0ad6671ce315f48bb18 Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Fri, 7 Aug 2009 14:16:00 +0200 Subject: perf util: Fix do_read() to fail on EOF instead of busy-looping While toying with perf, I've noticed that perf record can easily enter a busy loop when doing something as silly as: $ perf record -A ls Yeah, do_read here really wants to read a known size, not being able to should die(), not busy-loop ;) That was the cause for the bug. Signed-off-by: Pierre Habouzit Acked-by: Peter Zijlstra Cc: Paul Mackerras Signed-off-by: Ingo Molnar diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 95a44bc..b92a457 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -185,6 +185,8 @@ static void do_read(int fd, void *buf, size_t size) if (ret < 0) die("failed to read"); + if (ret == 0) + die("failed to read: missing data"); size -= ret; buf += ret; -- cgit v0.10.2 From 266e0e219888420a1a7cafc82e82891cf7b5a979 Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Fri, 7 Aug 2009 14:16:01 +0200 Subject: perf record: Fix the -A UI for empty or non-existent perf.data 1. Ignore the -A argument if there is no perf.data file 2. Treat an empty file like a non existent file. Else, perf will try to read the perf.data header, and fail with an error. Treating an empty file like a non-existent file makes sense, since an interupted (as in SIGKILLed) perf could leave such files around, and you don't want to annoy the user with errors for files with no data in it. Signed-off-by: Pierre Habouzit Acked-by: Peter Zijlstra Cc: Paul Mackerras Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 90c9808..0345aad 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -525,10 +525,14 @@ static int __cmd_record(int argc, const char **argv) signal(SIGCHLD, sig_handler); signal(SIGINT, sig_handler); - if (!stat(output_name, &st) && !force && !append_file) { - fprintf(stderr, "Error, output file %s exists, use -A to append or -f to overwrite.\n", - output_name); - exit(-1); + if (!stat(output_name, &st) && st.st_size) { + if (!force && !append_file) { + fprintf(stderr, "Error, output file %s exists, use -A to append or -f to overwrite.\n", + output_name); + exit(-1); + } + } else { + append_file = 0; } flags = O_CREAT|O_RDWR; -- cgit v0.10.2 From b0efe213f84f7fd5ccfe07053e3d9fb827b7c188 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Sat, 8 Aug 2009 02:16:23 +0200 Subject: perf tools: callchain: Fix spurious 'perf report' warnings: ignore empty callchains When the callchain tree comes to insert an empty backtrace, it raises a spurious warning about the fact we are inserting an empty. This is spurious because the radix tree assumes it did something wrong to reach this state. But it didn't, we just met an empty callchain that has to be ignored. This happens occasionally with certain types of call-chain recordings. If it happens it's a big nuisance as perf report output starts with thousands of warning lines. Reported-by: Ingo Molnar Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Mike Galbraith LKML-Reference: <1249690585-9145-2-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index 98c5627..a8e67aa 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c @@ -336,5 +336,7 @@ __append_chain(struct callchain_node *root, struct ip_callchain *chain, void append_chain(struct callchain_node *root, struct ip_callchain *chain, struct symbol **syms) { + if (!chain->nr) + return; __append_chain_children(root, chain, syms, 0); } -- cgit v0.10.2 From b1a88349c37624755b28ac3b3152b48f52c1f487 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Sat, 8 Aug 2009 02:16:24 +0200 Subject: perf tools: callchain: Fix 'perf report' display to be callchain by default If we recorded with -g option to record the callchain, right now we require a -g option to perf report as well - and people reported this as unnecessary complication: the user already specified -g once, no need to require it a second time. So if the recording includes call-chains, display the callchain by default from perf report. ( The user can override this default using "-g none" option from perf report. ) Reported-by: Ingo Molnar Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Mike Galbraith LKML-Reference: <1249690585-9145-3-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index a5e2f8d..c4a8e10 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -68,7 +68,7 @@ static int callchain; static struct callchain_param callchain_param = { - .mode = CHAIN_GRAPH_ABS, + .mode = CHAIN_GRAPH_REL, .min_percent = 0.5 }; @@ -1836,6 +1836,13 @@ static int __cmd_report(void) " -g?\n"); exit(-1); } + } else if (callchain_param.mode != CHAIN_NONE && !callchain) { + callchain = 1; + if (register_callchain_param(&callchain_param) < 0) { + fprintf(stderr, "Can't register callchain" + " params\n"); + exit(-1); + } } if (load_kernel() < 0) { @@ -1974,6 +1981,13 @@ parse_callchain_opt(const struct option *opt __used, const char *arg, else if (!strncmp(tok, "fractal", strlen(arg))) callchain_param.mode = CHAIN_GRAPH_REL; + else if (!strncmp(tok, "none", strlen(arg))) { + callchain_param.mode = CHAIN_NONE; + callchain = 0; + + return 0; + } + else return -1; diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index b2d128e..a926ae4 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h @@ -7,6 +7,7 @@ #include "symbol.h" enum chain_mode { + CHAIN_NONE, CHAIN_FLAT, CHAIN_GRAPH_ABS, CHAIN_GRAPH_REL -- cgit v0.10.2 From 25446036cbfc2c89faacdb4fb4603943d2197dc6 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Sat, 8 Aug 2009 02:16:25 +0200 Subject: perf tools: callchain: Fix sum of percentages to be 100% by displaying amount of ignored chains in fractal mode When we filter the callchains below a given percentage, we ignore them and the end result only shows entries that have an upper percentage than the filter threshold. It seems to users then that we have an imbalance in the percentage, as if the sum inside a profiled branch doesn't reach 100%. Since in the past there have been real perf report bugs that showed the same sypmtom, it would be nice to assure the user that the data is perfect and trustable and it all sums up to 100.00%. So fix this by displaying the remaining hits that have been filtered but without more detail than their amount in each branches. Example while filtering below 50%: 7.73% [k] delay_tsc | |--98.22%-- __const_udelay | | | |--86.37%-- ath5k_hw_register_timeout | | ath5k_hw_noise_floor_calibration | | ath5k_hw_reset | | ath5k_reset | | ath5k_config | | ieee80211_hw_config | | | | | |--88.53%-- ieee80211_scan_work | | | worker_thread | | | kthread | | | child_rip | | --11.47%-- [...] | --13.63%-- [...] --1.78%-- [...] Reported-by: Ingo Molnar Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Mike Galbraith LKML-Reference: <1249690585-9145-4-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index c4a8e10..99274ce 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -891,6 +891,21 @@ ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, int depth, return ret; } +static struct symbol *rem_sq_bracket; +static struct callchain_list rem_hits; + +static void init_rem_hits(void) +{ + rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6); + if (!rem_sq_bracket) { + fprintf(stderr, "Not enough memory to display remaining hits\n"); + return; + } + + strcpy(rem_sq_bracket->name, "[...]"); + rem_hits.sym = rem_sq_bracket; +} + static size_t callchain__fprintf_graph(FILE *fp, struct callchain_node *self, u64 total_samples, int depth, int depth_mask) @@ -900,6 +915,7 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self, struct callchain_list *chain; int new_depth_mask = depth_mask; u64 new_total; + u64 remaining; size_t ret = 0; int i; @@ -908,17 +924,25 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self, else new_total = total_samples; + remaining = new_total; + node = rb_first(&self->rb_root); while (node) { + u64 cumul; + child = rb_entry(node, struct callchain_node, rb_node); + cumul = cumul_hits(child); + remaining -= cumul; /* * The depth mask manages the output of pipes that show * the depth. We don't want to keep the pipes of the current - * level for the last child of this depth + * level for the last child of this depth. + * Except if we have remaining filtered hits. They will + * supersede the last child */ next = rb_next(node); - if (!next) + if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining)) new_depth_mask &= ~(1 << (depth - 1)); /* @@ -933,7 +957,7 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self, ret += ipchain__fprintf_graph(fp, chain, depth, new_depth_mask, i++, new_total, - cumul_hits(child)); + cumul); } ret += callchain__fprintf_graph(fp, child, new_total, depth + 1, @@ -941,6 +965,19 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self, node = next; } + if (callchain_param.mode == CHAIN_GRAPH_REL && + remaining && remaining != new_total) { + + if (!rem_sq_bracket) + return ret; + + new_depth_mask &= ~(1 << (depth - 1)); + + ret += ipchain__fprintf_graph(fp, &rem_hits, depth, + new_depth_mask, 0, new_total, + remaining); + } + return ret; } @@ -1361,6 +1398,8 @@ static size_t output__fprintf(FILE *fp, u64 total_samples) unsigned int width; char *col_width = col_width_list_str; + init_rem_hits(); + fprintf(fp, "# Samples: %Ld\n", (u64)total_samples); fprintf(fp, "#\n"); @@ -1432,6 +1471,8 @@ print_entries: } fprintf(fp, "\n"); + free(rem_sq_bracket); + return ret; } -- cgit v0.10.2 From 10b8e3066066708f304e0fc5cfe658e05abf943d Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Sat, 8 Aug 2009 04:26:35 +0200 Subject: perf_counter: Work around gcc warning by initializing tracepoint record unconditionally MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Despite that the tracepoint record is always present when the PERF_SAMPLE_TP_RECORD flag is set, gcc raises a warning, thinking it might not be initialized: kernel/perf_counter.c: In function ‘perf_counter_output’: kernel/perf_counter.c:2650: warning: ‘tp’ may be used uninitialized in this function Then, initialize it to NULL and always check if it's not NULL before dereference it. Reported-by: Ingo Molnar Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Mike Galbraith Cc: Paul Mackerras LKML-Reference: <1249698400-5441-2-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c index 615440a..117622c 100644 --- a/kernel/perf_counter.c +++ b/kernel/perf_counter.c @@ -2646,7 +2646,7 @@ static void perf_counter_output(struct perf_counter *counter, int nmi, u64 counter; } group_entry; struct perf_callchain_entry *callchain = NULL; - struct perf_tracepoint_record *tp; + struct perf_tracepoint_record *tp = NULL; int callchain_size = 0; u64 time; struct { @@ -2717,7 +2717,8 @@ static void perf_counter_output(struct perf_counter *counter, int nmi, if (sample_type & PERF_SAMPLE_TP_RECORD) { tp = data->private; - header.size += tp->size; + if (tp) + header.size += tp->size; } ret = perf_output_begin(&handle, counter, header.size, nmi, 1); @@ -2783,7 +2784,7 @@ static void perf_counter_output(struct perf_counter *counter, int nmi, } } - if (sample_type & PERF_SAMPLE_TP_RECORD) + if ((sample_type & PERF_SAMPLE_TP_RECORD) && tp) perf_output_copy(&handle, tp->record, tp->size); perf_output_end(&handle); -- cgit v0.10.2 From 3a43ce68ae1758fa6a839386025ef45acb6baa22 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Sat, 8 Aug 2009 04:26:37 +0200 Subject: perf_counter: Fix tracepoint sampling to be part of generic sampling Based on Peter's comments, make tracepoint sampling generic just like all the other sampling bits are. This is a rename with no code changes: - PERF_SAMPLE_TP_RECORD to PERF_SAMPLE_RAW - struct perf_tracepoint_record to perf_raw_record We want the system in place that transport tracepoints raw samples events into the perf ring buffer to be generalized and usable by any type of counter. Reported-by; Peter Zijlstra Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Mike Galbraith Cc: Paul Mackerras LKML-Reference: <1249698400-5441-4-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar diff --git a/include/linux/perf_counter.h b/include/linux/perf_counter.h index a67dd5c..2aabe43 100644 --- a/include/linux/perf_counter.h +++ b/include/linux/perf_counter.h @@ -121,7 +121,7 @@ enum perf_counter_sample_format { PERF_SAMPLE_CPU = 1U << 7, PERF_SAMPLE_PERIOD = 1U << 8, PERF_SAMPLE_STREAM_ID = 1U << 9, - PERF_SAMPLE_TP_RECORD = 1U << 10, + PERF_SAMPLE_RAW = 1U << 10, PERF_SAMPLE_MAX = 1U << 11, /* non-ABI */ }; @@ -414,9 +414,9 @@ struct perf_callchain_entry { __u64 ip[PERF_MAX_STACK_DEPTH]; }; -struct perf_tracepoint_record { - int size; - char *record; +struct perf_raw_record { + u32 size; + void *data; }; struct task_struct; @@ -687,7 +687,7 @@ struct perf_sample_data { struct pt_regs *regs; u64 addr; u64 period; - void *private; + struct perf_raw_record *raw; }; extern int perf_counter_overflow(struct perf_counter *counter, int nmi, diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c index 117622c..0023105 100644 --- a/kernel/perf_counter.c +++ b/kernel/perf_counter.c @@ -2646,7 +2646,7 @@ static void perf_counter_output(struct perf_counter *counter, int nmi, u64 counter; } group_entry; struct perf_callchain_entry *callchain = NULL; - struct perf_tracepoint_record *tp = NULL; + struct perf_raw_record *raw = NULL; int callchain_size = 0; u64 time; struct { @@ -2715,10 +2715,10 @@ static void perf_counter_output(struct perf_counter *counter, int nmi, header.size += sizeof(u64); } - if (sample_type & PERF_SAMPLE_TP_RECORD) { - tp = data->private; - if (tp) - header.size += tp->size; + if (sample_type & PERF_SAMPLE_RAW) { + raw = data->raw; + if (raw) + header.size += raw->size; } ret = perf_output_begin(&handle, counter, header.size, nmi, 1); @@ -2784,8 +2784,8 @@ static void perf_counter_output(struct perf_counter *counter, int nmi, } } - if ((sample_type & PERF_SAMPLE_TP_RECORD) && tp) - perf_output_copy(&handle, tp->record, tp->size); + if ((sample_type & PERF_SAMPLE_RAW) && raw) + perf_output_copy(&handle, raw->data, raw->size); perf_output_end(&handle); } @@ -3740,15 +3740,15 @@ static const struct pmu perf_ops_task_clock = { void perf_tpcounter_event(int event_id, u64 addr, u64 count, void *record, int entry_size) { - struct perf_tracepoint_record tp = { + struct perf_raw_record raw = { .size = entry_size, - .record = record, + .data = record, }; struct perf_sample_data data = { .regs = get_irq_regs(), .addr = addr, - .private = &tp, + .raw = &raw, }; if (!data.regs) -- cgit v0.10.2 From 3a80b4a3539696f4b0574876326860323035a302 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 7 Aug 2009 19:49:01 +0200 Subject: perf_counter: Fix a race on perf_counter_ctx While extending perfcounters with BTS hw-tracing, Markus Metzger managed to trigger this warning: [ 995.557128] WARNING: at kernel/perf_counter.c:1191 __perf_counter_task_sched_out+0x48/0x6b() triggers because commit 9f498cc5be7e013d8d6e4c616980ed0ffc8680d2 (perf_counter: Full task tracing) removed clearing of tsk->perf_counter_ctxp out from under ctx->lock which introduced a race (against perf_lock_task_context). Move it back and deal with the exit notification by explicitly passing along the former task context. Reported-by: Markus T Metzger Signed-off-by: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1249667341.17467.5.camel@twins> Signed-off-by: Ingo Molnar diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c index 0023105..546e62d 100644 --- a/kernel/perf_counter.c +++ b/kernel/perf_counter.c @@ -2850,7 +2850,8 @@ perf_counter_read_event(struct perf_counter *counter, */ struct perf_task_event { - struct task_struct *task; + struct task_struct *task; + struct perf_counter_context *task_ctx; struct { struct perf_event_header header; @@ -2910,24 +2911,23 @@ static void perf_counter_task_ctx(struct perf_counter_context *ctx, static void perf_counter_task_event(struct perf_task_event *task_event) { struct perf_cpu_context *cpuctx; - struct perf_counter_context *ctx; + struct perf_counter_context *ctx = task_event->task_ctx; cpuctx = &get_cpu_var(perf_cpu_context); perf_counter_task_ctx(&cpuctx->ctx, task_event); put_cpu_var(perf_cpu_context); rcu_read_lock(); - /* - * doesn't really matter which of the child contexts the - * events ends up in. - */ - ctx = rcu_dereference(current->perf_counter_ctxp); + if (!ctx) + ctx = rcu_dereference(task_event->task->perf_counter_ctxp); if (ctx) perf_counter_task_ctx(ctx, task_event); rcu_read_unlock(); } -static void perf_counter_task(struct task_struct *task, int new) +static void perf_counter_task(struct task_struct *task, + struct perf_counter_context *task_ctx, + int new) { struct perf_task_event task_event; @@ -2937,8 +2937,9 @@ static void perf_counter_task(struct task_struct *task, int new) return; task_event = (struct perf_task_event){ - .task = task, - .event = { + .task = task, + .task_ctx = task_ctx, + .event = { .header = { .type = new ? PERF_EVENT_FORK : PERF_EVENT_EXIT, .misc = 0, @@ -2956,7 +2957,7 @@ static void perf_counter_task(struct task_struct *task, int new) void perf_counter_fork(struct task_struct *task) { - perf_counter_task(task, 1); + perf_counter_task(task, NULL, 1); } /* @@ -4310,7 +4311,7 @@ void perf_counter_exit_task(struct task_struct *child) unsigned long flags; if (likely(!child->perf_counter_ctxp)) { - perf_counter_task(child, 0); + perf_counter_task(child, NULL, 0); return; } @@ -4330,6 +4331,7 @@ void perf_counter_exit_task(struct task_struct *child) * incremented the context's refcount before we do put_ctx below. */ spin_lock(&child_ctx->lock); + child->perf_counter_ctxp = NULL; /* * If this context is a clone; unclone it so it can't get * swapped to another process while we're removing all @@ -4343,9 +4345,7 @@ void perf_counter_exit_task(struct task_struct *child) * won't get any samples after PERF_EVENT_EXIT. We can however still * get a few PERF_EVENT_READ events. */ - perf_counter_task(child, 0); - - child->perf_counter_ctxp = NULL; + perf_counter_task(child, child_ctx, 0); /* * We can recurse on the same lock type through: -- cgit v0.10.2 From c24b513337f06712b8c81eb4f1413d44591dfee7 Mon Sep 17 00:00:00 2001 From: "Carlos R. Mafra" Date: Wed, 5 Aug 2009 20:53:34 +0200 Subject: perf: "Longum est iter per praecepta, breve et efficax per exempla" A few examples of how 'perf' can be used, from an e-mail by Ingo Molnar http://lkml.org/lkml/2009/8/4/346. Signed-off-by: Carlos R. Mafra Cc: Peter Zijlstra Cc: Valdis.Kletnieks@vt.edu LKML-Reference: <20090805185334.GA4535@Pilar.aei.mpg.de> Signed-off-by: Ingo Molnar diff --git a/tools/perf/Documentation/perf-examples.txt b/tools/perf/Documentation/perf-examples.txt new file mode 100644 index 0000000..8eb6c48 --- /dev/null +++ b/tools/perf/Documentation/perf-examples.txt @@ -0,0 +1,225 @@ + + ------------------------------ + ****** perf by examples ****** + ------------------------------ + +[ From an e-mail by Ingo Molnar, http://lkml.org/lkml/2009/8/4/346 ] + + +First, discovery/enumeration of available counters can be done via +'perf list': + +titan:~> perf list + [...] + kmem:kmalloc [Tracepoint event] + kmem:kmem_cache_alloc [Tracepoint event] + kmem:kmalloc_node [Tracepoint event] + kmem:kmem_cache_alloc_node [Tracepoint event] + kmem:kfree [Tracepoint event] + kmem:kmem_cache_free [Tracepoint event] + kmem:mm_page_free_direct [Tracepoint event] + kmem:mm_pagevec_free [Tracepoint event] + kmem:mm_page_alloc [Tracepoint event] + kmem:mm_page_alloc_zone_locked [Tracepoint event] + kmem:mm_page_pcpu_drain [Tracepoint event] + kmem:mm_page_alloc_extfrag [Tracepoint event] + +Then any (or all) of the above event sources can be activated and +measured. For example the page alloc/free properties of a 'hackbench +run' are: + + titan:~> perf stat -e kmem:mm_page_pcpu_drain -e kmem:mm_page_alloc + -e kmem:mm_pagevec_free -e kmem:mm_page_free_direct ./hackbench 10 + Time: 0.575 + + Performance counter stats for './hackbench 10': + + 13857 kmem:mm_page_pcpu_drain + 27576 kmem:mm_page_alloc + 6025 kmem:mm_pagevec_free + 20934 kmem:mm_page_free_direct + + 0.613972165 seconds time elapsed + +You can observe the statistical properties as well, by using the +'repeat the workload N times' feature of perf stat: + + titan:~> perf stat --repeat 5 -e kmem:mm_page_pcpu_drain -e + kmem:mm_page_alloc -e kmem:mm_pagevec_free -e + kmem:mm_page_free_direct ./hackbench 10 + Time: 0.627 + Time: 0.644 + Time: 0.564 + Time: 0.559 + Time: 0.626 + + Performance counter stats for './hackbench 10' (5 runs): + + 12920 kmem:mm_page_pcpu_drain ( +- 3.359% ) + 25035 kmem:mm_page_alloc ( +- 3.783% ) + 6104 kmem:mm_pagevec_free ( +- 0.934% ) + 18376 kmem:mm_page_free_direct ( +- 4.941% ) + + 0.643954516 seconds time elapsed ( +- 2.363% ) + +Furthermore, these tracepoints can be used to sample the workload as +well. For example the page allocations done by a 'git gc' can be +captured the following way: + + titan:~/git> perf record -f -e kmem:mm_page_alloc -c 1 ./git gc + Counting objects: 1148, done. + Delta compression using up to 2 threads. + Compressing objects: 100% (450/450), done. + Writing objects: 100% (1148/1148), done. + Total 1148 (delta 690), reused 1148 (delta 690) + [ perf record: Captured and wrote 0.267 MB perf.data (~11679 samples) ] + +To check which functions generated page allocations: + + titan:~/git> perf report + # Samples: 10646 + # + # Overhead Command Shared Object + # ........ ............... .......................... + # + 23.57% git-repack /lib64/libc-2.5.so + 21.81% git /lib64/libc-2.5.so + 14.59% git ./git + 11.79% git-repack ./git + 7.12% git /lib64/ld-2.5.so + 3.16% git-repack /lib64/libpthread-2.5.so + 2.09% git-repack /bin/bash + 1.97% rm /lib64/libc-2.5.so + 1.39% mv /lib64/ld-2.5.so + 1.37% mv /lib64/libc-2.5.so + 1.12% git-repack /lib64/ld-2.5.so + 0.95% rm /lib64/ld-2.5.so + 0.90% git-update-serv /lib64/libc-2.5.so + 0.73% git-update-serv /lib64/ld-2.5.so + 0.68% perf /lib64/libpthread-2.5.so + 0.64% git-repack /usr/lib64/libz.so.1.2.3 + +Or to see it on a more finegrained level: + +titan:~/git> perf report --sort comm,dso,symbol +# Samples: 10646 +# +# Overhead Command Shared Object Symbol +# ........ ............... .......................... ...... +# + 9.35% git-repack ./git [.] insert_obj_hash + 9.12% git ./git [.] insert_obj_hash + 7.31% git /lib64/libc-2.5.so [.] memcpy + 6.34% git-repack /lib64/libc-2.5.so [.] _int_malloc + 6.24% git-repack /lib64/libc-2.5.so [.] memcpy + 5.82% git-repack /lib64/libc-2.5.so [.] __GI___fork + 5.47% git /lib64/libc-2.5.so [.] _int_malloc + 2.99% git /lib64/libc-2.5.so [.] memset + +Furthermore, call-graph sampling can be done too, of page +allocations - to see precisely what kind of page allocations there +are: + + titan:~/git> perf record -f -g -e kmem:mm_page_alloc -c 1 ./git gc + Counting objects: 1148, done. + Delta compression using up to 2 threads. + Compressing objects: 100% (450/450), done. + Writing objects: 100% (1148/1148), done. + Total 1148 (delta 690), reused 1148 (delta 690) + [ perf record: Captured and wrote 0.963 MB perf.data (~42069 samples) ] + + titan:~/git> perf report -g + # Samples: 10686 + # + # Overhead Command Shared Object + # ........ ............... .......................... + # + 23.25% git-repack /lib64/libc-2.5.so + | + |--50.00%-- _int_free + | + |--37.50%-- __GI___fork + | make_child + | + |--12.50%-- ptmalloc_unlock_all2 + | make_child + | + --6.25%-- __GI_strcpy + 21.61% git /lib64/libc-2.5.so + | + |--30.00%-- __GI_read + | | + | --83.33%-- git_config_from_file + | git_config + | | + [...] + +Or you can observe the whole system's page allocations for 10 +seconds: + +titan:~/git> perf stat -a -e kmem:mm_page_pcpu_drain -e +kmem:mm_page_alloc -e kmem:mm_pagevec_free -e +kmem:mm_page_free_direct sleep 10 + + Performance counter stats for 'sleep 10': + + 171585 kmem:mm_page_pcpu_drain + 322114 kmem:mm_page_alloc + 73623 kmem:mm_pagevec_free + 254115 kmem:mm_page_free_direct + + 10.000591410 seconds time elapsed + +Or observe how fluctuating the page allocations are, via statistical +analysis done over ten 1-second intervals: + + titan:~/git> perf stat --repeat 10 -a -e kmem:mm_page_pcpu_drain -e + kmem:mm_page_alloc -e kmem:mm_pagevec_free -e + kmem:mm_page_free_direct sleep 1 + + Performance counter stats for 'sleep 1' (10 runs): + + 17254 kmem:mm_page_pcpu_drain ( +- 3.709% ) + 34394 kmem:mm_page_alloc ( +- 4.617% ) + 7509 kmem:mm_pagevec_free ( +- 4.820% ) + 25653 kmem:mm_page_free_direct ( +- 3.672% ) + + 1.058135029 seconds time elapsed ( +- 3.089% ) + +Or you can annotate the recorded 'git gc' run on a per symbol basis +and check which instructions/source-code generated page allocations: + + titan:~/git> perf annotate __GI___fork + ------------------------------------------------ + Percent | Source code & Disassembly of libc-2.5.so + ------------------------------------------------ + : + : + : Disassembly of section .plt: + : Disassembly of section .text: + : + : 00000031a2e95560 <__fork>: + [...] + 0.00 : 31a2e95602: b8 38 00 00 00 mov $0x38,%eax + 0.00 : 31a2e95607: 0f 05 syscall + 83.42 : 31a2e95609: 48 3d 00 f0 ff ff cmp $0xfffffffffffff000,%rax + 0.00 : 31a2e9560f: 0f 87 4d 01 00 00 ja 31a2e95762 <__fork+0x202> + 0.00 : 31a2e95615: 85 c0 test %eax,%eax + +( this shows that 83.42% of __GI___fork's page allocations come from + the 0x38 system call it performs. ) + +etc. etc. - a lot more is possible. I could list a dozen of +other different usecases straight away - neither of which is +possible via /proc/vmstat. + +/proc/vmstat is not in the same league really, in terms of +expressive power of system analysis and performance +analysis. + +All that the above results needed were those new tracepoints +in include/tracing/events/kmem.h. + + Ingo + + -- cgit v0.10.2 From 183f3b0887083d36c8a25cd5e3518906415d1889 Mon Sep 17 00:00:00 2001 From: Mike Galbraith Date: Sat, 8 Aug 2009 14:14:15 +0200 Subject: perf_counter tools: Fix libbfd detection for systems with libz dependency Due to a libz dependency in some distro's binutils package, C++ demangle support isn't compiled in despite the necessary libraries being available. Fix this by adding a -lz link test to the dependency detection rules. Signed-off-by: Mike Galbraith Acked-by: Peter Zijlstra LKML-Reference: <1249733655.6929.5.camel@marge.simson.net> Signed-off-by: Ingo Molnar diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 1916e44..60411e9 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -387,10 +387,14 @@ else has_bfd_iberty := $(shell sh -c "(echo '\#include '; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) -lbfd -liberty > /dev/null 2>&1 && echo y") + has_bfd_iberty_z := $(shell sh -c "(echo '\#include '; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) -lbfd -liberty -lz > /dev/null 2>&1 && echo y") + ifeq ($(has_bfd),y) EXTLIBS += -lbfd else ifeq ($(has_bfd_iberty),y) EXTLIBS += -lbfd -liberty + else ifeq ($(has_bfd_iberty_z),y) + EXTLIBS += -lbfd -liberty -lz else msg := $(warning No bfd.h/libbfd found, install binutils-dev[el] to gain symbol demangling) BASIC_CFLAGS += -DNO_DEMANGLE -- cgit v0.10.2 From c0a8865e32c8d1a562db38e06ef31ef23282f646 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Sun, 9 Aug 2009 04:19:15 +0200 Subject: perf tools: callchain: Fix bad rounding of minimum rate Sometimes we get callchain branches that have a rate under the limit given by the user. Say you launched: perf record -f -g -a ./hackbench 10 perf report -g fractal,10.0 And you got: 2.33% hackbench [kernel] [k] _spin_lock_irqsave | |--78.57%-- remove_wait_queue | poll_freewait | do_sys_poll | sys_poll | sysenter_dispatch | 0xf7ffa430 | 0x1ffadea3c | |--7.14%-- __up_read | up_read | do_page_fault | page_fault | 0xf7ffa430 | 0xa0df710000000a ... It is abnormal to get a 7.14% branch whereas we passed a 10% filter. The problem is that we round down the minimum threshold. This happens mostly when we have very low number of events. If the total amount of your branch is 4 and you have a subranch of 3 events, filtering to 90% will be computed like follows: limit = 4 * 0.9; The result is about 3.6, but the cast to integer will round down to 3. It means that our filter is actually of 75% We must then explicitly round up the minimum threshold. Reported-by: Ingo Molnar Signed-off-by: Frederic Weisbecker Cc: acme@redhat.com Cc: peterz@infradead.org Cc: efault@gmx.de LKML-Reference: <20090809024235.GA10146@nowhere> Signed-off-by: Ingo Molnar diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index a8e67aa..0114734 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "callchain.h" @@ -112,7 +113,7 @@ static void __sort_chain_graph_rel(struct callchain_node *node, u64 min_hit; node->rb_root = RB_ROOT; - min_hit = node->children_hit * min_percent / 100.0; + min_hit = ceil(node->children_hit * min_percent); chain_for_each_child(child, node) { __sort_chain_graph_rel(child, min_percent); @@ -126,7 +127,7 @@ static void sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_node *chain_root, u64 min_hit __used, struct callchain_param *param) { - __sort_chain_graph_rel(chain_root, param->min_percent); + __sort_chain_graph_rel(chain_root, param->min_percent / 100.0); rb_root->rb_node = chain_root->rb_root.rb_node; } -- cgit v0.10.2 From b2f2e8fee3d62f621e795f25b2fc0f51bbdb4af9 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 10 Aug 2009 16:36:38 +1000 Subject: powerpc/dma: pci_set_dma_mask() shouldn't fail if mask fits in RAM On an iMac G5, the b43 driver is failing to initialise because trying to set the dma mask to 30-bit fails. Even though there's only 512MiB of RAM in the machine anyway: https://bugzilla.redhat.com/show_bug.cgi?id=514787 We should probably let it succeed if the available RAM in the system doesn't exceed the requested limit. Signed-off-by: David Woodhouse Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/dma.c b/arch/powerpc/kernel/dma.c index 20a60d6..ccf129d 100644 --- a/arch/powerpc/kernel/dma.c +++ b/arch/powerpc/kernel/dma.c @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -90,11 +91,10 @@ static void dma_direct_unmap_sg(struct device *dev, struct scatterlist *sg, static int dma_direct_dma_supported(struct device *dev, u64 mask) { #ifdef CONFIG_PPC64 - /* Could be improved to check for memory though it better be - * done via some global so platforms can set the limit in case + /* Could be improved so platforms can set the limit in case * they have limited DMA windows */ - return mask >= DMA_BIT_MASK(32); + return mask >= (lmb_end_of_DRAM() - 1); #else return 1; #endif -- cgit v0.10.2 From a044560c3a1f0ad75ce685c1ed7604820b9ed319 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 10 Aug 2009 11:16:52 +0200 Subject: perf_counter: Correct PERF_SAMPLE_RAW output PERF_SAMPLE_* output switches should unconditionally output the correct format, as they are the only way to unambiguously parse the PERF_EVENT_SAMPLE data. Signed-off-by: Peter Zijlstra Acked-by: Frederic Weisbecker Cc: Arnaldo Carvalho de Melo Cc: Mike Galbraith Cc: Paul Mackerras LKML-Reference: <1249896447.17467.74.camel@twins> Signed-off-by: Ingo Molnar diff --git a/include/linux/perf_counter.h b/include/linux/perf_counter.h index 2aabe43..a9d823a 100644 --- a/include/linux/perf_counter.h +++ b/include/linux/perf_counter.h @@ -369,6 +369,8 @@ enum perf_event_type { * * { u64 nr, * u64 ips[nr]; } && PERF_SAMPLE_CALLCHAIN + * { u32 size; + * char data[size];}&& PERF_SAMPLE_RAW * }; */ PERF_EVENT_SAMPLE = 9, diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index 7fb16d9..7167b9b 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h @@ -685,7 +685,8 @@ static void ftrace_profile_##call(proto) \ pc = preempt_count(); \ \ __data_size = ftrace_get_offsets_##call(&__data_offsets, args); \ - __entry_size = ALIGN(__data_size + sizeof(*entry), sizeof(u64));\ + __entry_size = ALIGN(__data_size + sizeof(*entry) + sizeof(u32),\ + sizeof(u64)); \ \ do { \ char raw_data[__entry_size]; \ diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c index 546e62d..5229d16 100644 --- a/kernel/perf_counter.c +++ b/kernel/perf_counter.c @@ -2646,7 +2646,6 @@ static void perf_counter_output(struct perf_counter *counter, int nmi, u64 counter; } group_entry; struct perf_callchain_entry *callchain = NULL; - struct perf_raw_record *raw = NULL; int callchain_size = 0; u64 time; struct { @@ -2716,9 +2715,15 @@ static void perf_counter_output(struct perf_counter *counter, int nmi, } if (sample_type & PERF_SAMPLE_RAW) { - raw = data->raw; - if (raw) - header.size += raw->size; + int size = sizeof(u32); + + if (data->raw) + size += data->raw->size; + else + size += sizeof(u32); + + WARN_ON_ONCE(size & (sizeof(u64)-1)); + header.size += size; } ret = perf_output_begin(&handle, counter, header.size, nmi, 1); @@ -2784,8 +2789,21 @@ static void perf_counter_output(struct perf_counter *counter, int nmi, } } - if ((sample_type & PERF_SAMPLE_RAW) && raw) - perf_output_copy(&handle, raw->data, raw->size); + if (sample_type & PERF_SAMPLE_RAW) { + if (data->raw) { + perf_output_put(&handle, data->raw->size); + perf_output_copy(&handle, data->raw->data, data->raw->size); + } else { + struct { + u32 size; + u32 data; + } raw = { + .size = sizeof(u32), + .data = 0, + }; + perf_output_put(&handle, raw); + } + } perf_output_end(&handle); } -- cgit v0.10.2 From a4e95fc2cbb31d70a65beffeaf8773f881328c34 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 10 Aug 2009 11:20:12 +0200 Subject: perf_counter: Require CAP_SYS_ADMIN for raw tracepoint data Raw tracepoint data contains various kernel internals and data from other users, so restrict this to CAP_SYS_ADMIN. Signed-off-by: Peter Zijlstra Acked-by: Frederic Weisbecker Cc: Arnaldo Carvalho de Melo Cc: Mike Galbraith Cc: Paul Mackerras LKML-Reference: <1249896452.17467.75.camel@twins> Signed-off-by: Ingo Molnar diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c index 5229d16..b0b20a0 100644 --- a/kernel/perf_counter.c +++ b/kernel/perf_counter.c @@ -3787,6 +3787,14 @@ static void tp_perf_counter_destroy(struct perf_counter *counter) static const struct pmu *tp_perf_counter_init(struct perf_counter *counter) { + /* + * Raw tracepoint data is a severe data leak, only allow root to + * have these. + */ + if ((counter->attr.sample_type & PERF_SAMPLE_RAW) && + !capable(CAP_SYS_ADMIN)) + return ERR_PTR(-EPERM); + if (ftrace_profile_enable(counter->attr.config)) return NULL; -- cgit v0.10.2 From 13f0feafa6b8aead57a2a328e2fca6a5828bf286 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Tue, 23 Jun 2009 21:25:32 +0200 Subject: mm_for_maps: simplify, use ptrace_may_access() It would be nice to kill __ptrace_may_access(). It requires task_lock(), but this lock is only needed to read mm->flags in the middle. Convert mm_for_maps() to use ptrace_may_access(), this also simplifies the code a little bit. Also, we do not need to take ->mmap_sem in advance. In fact I think mm_for_maps() should not play with ->mmap_sem at all, the caller should take this lock. With or without this patch, without ->cred_guard_mutex held we can race with exec() and get the new ->mm but check old creds. Signed-off-by: Oleg Nesterov Reviewed-by: Serge Hallyn Signed-off-by: James Morris diff --git a/fs/proc/base.c b/fs/proc/base.c index 3ce5ae9e..917f338 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -237,20 +237,19 @@ struct mm_struct *mm_for_maps(struct task_struct *task) struct mm_struct *mm = get_task_mm(task); if (!mm) return NULL; + if (mm != current->mm) { + /* + * task->mm can be changed before security check, + * in that case we must notice the change after. + */ + if (!ptrace_may_access(task, PTRACE_MODE_READ) || + mm != task->mm) { + mmput(mm); + return NULL; + } + } down_read(&mm->mmap_sem); - task_lock(task); - if (task->mm != mm) - goto out; - if (task->mm != current->mm && - __ptrace_may_access(task, PTRACE_MODE_READ) < 0) - goto out; - task_unlock(task); return mm; -out: - task_unlock(task); - up_read(&mm->mmap_sem); - mmput(mm); - return NULL; } static int proc_pid_cmdline(struct task_struct *task, char * buffer) -- cgit v0.10.2 From 00f89d218523b9bf6b522349c039d5ac80aa536d Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Fri, 10 Jul 2009 03:27:38 +0200 Subject: mm_for_maps: shift down_read(mmap_sem) to the caller mm_for_maps() takes ->mmap_sem after security checks, this looks strange and obfuscates the locking rules. Move this lock to its single caller, m_start(). Signed-off-by: Oleg Nesterov Acked-by: Serge Hallyn Signed-off-by: James Morris diff --git a/fs/proc/base.c b/fs/proc/base.c index 917f338..f3c2e40 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -235,9 +235,8 @@ static int check_mem_permission(struct task_struct *task) struct mm_struct *mm_for_maps(struct task_struct *task) { struct mm_struct *mm = get_task_mm(task); - if (!mm) - return NULL; - if (mm != current->mm) { + + if (mm && mm != current->mm) { /* * task->mm can be changed before security check, * in that case we must notice the change after. @@ -245,10 +244,9 @@ struct mm_struct *mm_for_maps(struct task_struct *task) if (!ptrace_may_access(task, PTRACE_MODE_READ) || mm != task->mm) { mmput(mm); - return NULL; + mm = NULL; } } - down_read(&mm->mmap_sem); return mm; } diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 6f61b7c..9bd8be1 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -119,6 +119,7 @@ static void *m_start(struct seq_file *m, loff_t *pos) mm = mm_for_maps(priv->task); if (!mm) return NULL; + down_read(&mm->mmap_sem); tail_vma = get_gate_vma(priv->task); priv->tail_vma = tail_vma; diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c index 64a72e2..8f5c05d 100644 --- a/fs/proc/task_nommu.c +++ b/fs/proc/task_nommu.c @@ -189,6 +189,7 @@ static void *m_start(struct seq_file *m, loff_t *pos) priv->task = NULL; return NULL; } + down_read(&mm->mmap_sem); /* start from the Nth VMA */ for (p = rb_first(&mm->mm_rb); p; p = rb_next(p)) -- cgit v0.10.2 From 704b836cbf19e885f8366bccb2e4b0474346c02d Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Fri, 10 Jul 2009 03:27:40 +0200 Subject: mm_for_maps: take ->cred_guard_mutex to fix the race with exec The problem is minor, but without ->cred_guard_mutex held we can race with exec() and get the new ->mm but check old creds. Now we do not need to re-check task->mm after ptrace_may_access(), it can't be changed to the new mm under us. Strictly speaking, this also fixes another very minor problem. Unless security check fails or the task exits mm_for_maps() should never return NULL, the caller should get either old or new ->mm. Signed-off-by: Oleg Nesterov Acked-by: Serge Hallyn Signed-off-by: James Morris diff --git a/fs/proc/base.c b/fs/proc/base.c index f3c2e40..175db25 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -234,19 +234,19 @@ static int check_mem_permission(struct task_struct *task) struct mm_struct *mm_for_maps(struct task_struct *task) { - struct mm_struct *mm = get_task_mm(task); + struct mm_struct *mm; - if (mm && mm != current->mm) { - /* - * task->mm can be changed before security check, - * in that case we must notice the change after. - */ - if (!ptrace_may_access(task, PTRACE_MODE_READ) || - mm != task->mm) { - mmput(mm); - mm = NULL; - } + if (mutex_lock_killable(&task->cred_guard_mutex)) + return NULL; + + mm = get_task_mm(task); + if (mm && mm != current->mm && + !ptrace_may_access(task, PTRACE_MODE_READ)) { + mmput(mm); + mm = NULL; } + mutex_unlock(&task->cred_guard_mutex); + return mm; } -- cgit v0.10.2 From 304703aba31a87903b8c0db8f5e6890cac2d596d Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Mon, 10 Aug 2009 16:11:32 +0200 Subject: perf_counter: Subtract the buffer size field from the event record size We compute the perf raw sample size by aligning the raw ftrace event size plus the buffer size field itself. We do that instead of aligning only the perf raw sample size, so that we might economize some in some cases. But this buffer size field is not stored in the perf raw sample, we must then substract its size from the buffer once we computed the alignment unless we may get a useless u32 field in the buffer. Signed-off-by: Frederic Weisbecker Acked-by: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Mike Galbraith Cc: Paul Mackerras LKML-Reference: <20090810141129.GA5124@nowhere> Signed-off-by: Ingo Molnar diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index 7167b9b..a05524f 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h @@ -637,7 +637,12 @@ __attribute__((section("_ftrace_events"))) event_##call = { \ * pc = preempt_count(); * * __data_size = ftrace_get_offsets_(&__data_offsets, args); - * __entry_size = __data_size + sizeof(*entry); + * + * // Below we want to get the aligned size by taking into account + * // the u32 field that will later store the buffer size + * __entry_size = ALIGN(__data_size + sizeof(*entry) + sizeof(u32), + * sizeof(u64)); + * __entry_size -= sizeof(u32); * * do { * char raw_data[__entry_size]; <- allocate our sample in the stack @@ -687,6 +692,7 @@ static void ftrace_profile_##call(proto) \ __data_size = ftrace_get_offsets_##call(&__data_offsets, args); \ __entry_size = ALIGN(__data_size + sizeof(*entry) + sizeof(u32),\ sizeof(u64)); \ + __entry_size -= sizeof(u32); \ \ do { \ char raw_data[__entry_size]; \ -- cgit v0.10.2 From 1853db0e02ae4088f102b0d8e59e83dc98f93f03 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Mon, 10 Aug 2009 16:38:36 +0200 Subject: perf_counter: Zero dead bytes from ftrace raw samples size alignment After aligning the ftrace raw samples, there are dead bytes storing random data from the stack. We don't want to leak these to userspace, then zero these out. Before: 0x2de88 [0x50]: event: 9 . . ... raw event: size 80 bytes . 0000: 09 00 00 00 01 00 50 00 d0 c7 00 81 ff ff ff ff ......P........ . 0010: 68 01 00 00 68 01 00 00 2c 00 00 00 00 00 00 00 h...h...,...... . 0020: 2c 00 00 00 2b 00 01 02 68 01 00 00 68 01 00 00 ,...+...h...h.. . 0030: 6b 6f 6e 64 65 6d 61 6e 64 2f 30 00 00 00 00 00 kondemand/0.... . 0040: 68 01 00 00 40 7f 46 81 ff ff ff ff 00 10 1b 7f h...@.F........ ^ ^ ^ ^ Leak After: 0x2d318 [0x50]: event: 9 . . ... raw event: size 80 bytes . 0000: 09 00 00 00 01 00 50 00 d0 c7 00 81 ff ff ff ff ......P........ . 0010: 68 01 00 00 68 01 00 00 68 14 00 00 00 00 00 00 h...h...h...... . 0020: 2c 00 00 00 2b 00 01 02 68 01 00 00 68 01 00 00 ,...+...h...h.. . 0030: 6b 6f 6e 64 65 6d 61 6e 64 2f 30 00 00 00 00 00 kondemand/0.... . 0040: 68 01 00 00 a0 80 46 81 ff ff ff ff 00 00 00 00 h.....F........ ^ ^ ^ ^ Fixed Reported-by: Peter Zijlstra Signed-off-by: Frederic Weisbecker Cc: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Mike Galbraith LKML-Reference: <1249915116-5210-1-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Mike Galbraith diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index a05524f..f64fbaa 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h @@ -648,6 +648,9 @@ __attribute__((section("_ftrace_events"))) event_##call = { \ * char raw_data[__entry_size]; <- allocate our sample in the stack * struct trace_entry *ent; * + * zero dead bytes from alignment to avoid stack leak to userspace: + * + * *(u64 *)(&raw_data[__entry_size - sizeof(u64)]) = 0ULL; * entry = (struct ftrace_raw_ *)raw_data; * ent = &entry->ent; * tracing_generic_entry_update(ent, irq_flags, pc); @@ -698,6 +701,7 @@ static void ftrace_profile_##call(proto) \ char raw_data[__entry_size]; \ struct trace_entry *ent; \ \ + *(u64 *)(&raw_data[__entry_size - sizeof(u64)]) = 0ULL; \ entry = (struct ftrace_raw_##call *)raw_data; \ ent = &entry->ent; \ tracing_generic_entry_update(ent, irq_flags, pc); \ -- cgit v0.10.2 From 1392e3b33319fd1a2527bebfc56631c2f2d3c7c5 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Sat, 8 Aug 2009 17:52:50 +0900 Subject: documentation: register ioctl entry of nilfs2 This will register the ioctl range used by nilfs2 file system to the table listed in Documentation/ioctl/ioctl-number.txt. Signed-off-by: Ryusuke Konishi Signed-off-by: Linus Torvalds diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt index 7bb0d93..dbea4f9 100644 --- a/Documentation/ioctl/ioctl-number.txt +++ b/Documentation/ioctl/ioctl-number.txt @@ -139,6 +139,7 @@ Code Seq# Include File Comments 'm' all linux/synclink.h conflict! 'm' 00-1F net/irda/irmod.h conflict! 'n' 00-7F linux/ncp_fs.h +'n' 80-8F linux/nilfs2_fs.h NILFS2 'n' E0-FF video/matrox.h matroxfb 'o' 00-1F fs/ocfs2/ocfs2_fs.h OCFS2 'o' 00-03 include/mtd/ubi-user.h conflict! (OCFS2 and UBI overlaps) -- cgit v0.10.2 From 5e2f89b5d5d87a7c3ba19fc85ba0c29adb65f639 Mon Sep 17 00:00:00 2001 From: "Figo.zhang" Date: Sat, 8 Aug 2009 21:01:22 +0800 Subject: mempool.c: clean up type-casting clean up type-casting twice. "size_t" is typedef as "unsigned long" in 64-bit system, and "unsigned int" in 32-bit system, and the intermediate cast to 'long' is pointless. Signed-off-by: Figo.zhang Signed-off-by: Linus Torvalds diff --git a/mm/mempool.c b/mm/mempool.c index a46eb1b..32e75d4 100644 --- a/mm/mempool.c +++ b/mm/mempool.c @@ -303,14 +303,14 @@ EXPORT_SYMBOL(mempool_free_slab); */ void *mempool_kmalloc(gfp_t gfp_mask, void *pool_data) { - size_t size = (size_t)(long)pool_data; + size_t size = (size_t)pool_data; return kmalloc(size, gfp_mask); } EXPORT_SYMBOL(mempool_kmalloc); void *mempool_kzalloc(gfp_t gfp_mask, void *pool_data) { - size_t size = (size_t) pool_data; + size_t size = (size_t)pool_data; return kzalloc(size, gfp_mask); } EXPORT_SYMBOL(mempool_kzalloc); -- cgit v0.10.2 From 04e35357e2e3ff4e0cabd6468354cf3dbfeb4f27 Mon Sep 17 00:00:00 2001 From: Jaswinder Singh Rajput Date: Mon, 10 Aug 2009 16:45:42 +0100 Subject: MN10300: includecheck fix: mn10300, pci.h Fix the following 'make includecheck' warning: arch/mn10300/include/asm/pci.h: linux/mm.h is included more than once. Signed-off-by: Jaswinder Singh Rajput Signed-off-by: David Howells Signed-off-by: Linus Torvalds diff --git a/arch/mn10300/include/asm/pci.h b/arch/mn10300/include/asm/pci.h index 35d2ed6..19aecc9 100644 --- a/arch/mn10300/include/asm/pci.h +++ b/arch/mn10300/include/asm/pci.h @@ -59,7 +59,6 @@ void pcibios_penalize_isa_irq(int irq); #include #include #include -#include #include struct pci_dev; -- cgit v0.10.2 From b6e61eef4f9f94714ac3ee4a5c96862d9bcd1836 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 31 Jul 2009 12:45:41 -0700 Subject: x86: Fix serialization in pit_expect_msb() Wei Chong Tan reported a fast-PIT-calibration corner-case: | pit_expect_msb() is vulnerable to SMI disturbance corner case | in some platforms which causes /proc/cpuinfo to show wrong | CPU MHz value when quick_pit_calibrate() jumps to success | section. I think that the real issue isn't even an SMI - but the fact that in the very last iteration of the loop, there's no serializing instruction _after_ the last 'rdtsc'. So even in the absense of SMI's, we do have a situation where the cycle counter was read without proper serialization. The last check should be done outside the outer loop, since _inside_ the outer loop, we'll be testing that the PIT has the right MSB value has the right value in the next iteration. So only the _last_ iteration is special, because that's the one that will not check the PIT MSB value any more, and because the final 'get_cycles()' isn't serialized. In other words: - I'd like to move the PIT MSB check to after the last iteration, rather than in every iteration - I think we should comment on the fact that it's also a serializing instruction and so 'fences in' the TSC read. Here's a suggested replacement. Signed-off-by: Linus Torvalds Reported-by: "Tan, Wei Chong" Tested-by: "Tan, Wei Chong" LKML-Reference: Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index 6e1a368..71f4368 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -275,15 +275,20 @@ static unsigned long pit_calibrate_tsc(u32 latch, unsigned long ms, int loopmin) * use the TSC value at the transitions to calculate a pretty * good value for the TSC frequencty. */ +static inline int pit_verify_msb(unsigned char val) +{ + /* Ignore LSB */ + inb(0x42); + return inb(0x42) == val; +} + static inline int pit_expect_msb(unsigned char val, u64 *tscp, unsigned long *deltap) { int count; u64 tsc = 0; for (count = 0; count < 50000; count++) { - /* Ignore LSB */ - inb(0x42); - if (inb(0x42) != val) + if (!pit_verify_msb(val)) break; tsc = get_cycles(); } @@ -336,8 +341,7 @@ static unsigned long quick_pit_calibrate(void) * to do that is to just read back the 16-bit counter * once from the PIT. */ - inb(0x42); - inb(0x42); + pit_verify_msb(0); if (pit_expect_msb(0xff, &tsc, &d1)) { for (i = 1; i <= MAX_QUICK_PIT_ITERATIONS; i++) { @@ -348,8 +352,19 @@ static unsigned long quick_pit_calibrate(void) * Iterate until the error is less than 500 ppm */ delta -= tsc; - if (d1+d2 < delta >> 11) - goto success; + if (d1+d2 >= delta >> 11) + continue; + + /* + * Check the PIT one more time to verify that + * all TSC reads were stable wrt the PIT. + * + * This also guarantees serialization of the + * last cycle read ('d2') in pit_expect_msb. + */ + if (!pit_verify_msb(0xfe - i)) + break; + goto success; } } printk("Fast TSC calibration failed\n"); -- cgit v0.10.2 From 85dfd81dc57e8183a277ddd7a56aa65c96f3f487 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 10 Aug 2009 13:21:19 -0700 Subject: pty: fix data loss when stopped (^S/^Q) Commit d945cb9cc ("pty: Rework the pty layer to use the normal buffering logic") dropped the test for 'tty->stopped' in pty_write_room(), which then causes the n_tty line discipline thing to not throttle the data properly when the tty is stopped. So instead of pausing the write due to the tty being stopped, the ldisc layer would go ahead and push it down to the pty. The pty write() routine would then refuse to take the data (because it _did_ check 'stopped'), and the data wouldn't actually be written. This whole stopped test should eventually be moved into the tty ldisc layer rather than have low-level tty drivers care about these things, but right now the fix is to just re-instate the missing pty 'stopped' handling. Reported-and-tested-by: Artur Skawina Cc: Alan Cox Signed-off-by: Linus Torvalds diff --git a/drivers/char/pty.c b/drivers/char/pty.c index 6e6942c..d083c73 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c @@ -144,6 +144,8 @@ static int pty_write(struct tty_struct *tty, const unsigned char *buf, static int pty_write_room(struct tty_struct *tty) { + if (tty->stopped) + return 0; return pty_space(tty->link); } -- cgit v0.10.2