From 0093380c18a4bfc5526577da576335d08bdea2e5 Mon Sep 17 00:00:00 2001 From: Gerhard Sittig Date: Mon, 11 Nov 2013 10:42:36 +0100 Subject: regmap: trivial comment fix (copy'n'paste error) fix a trivial copy'n'paste error in the regmap kerneldoc, s/write/read/ for the regmap_read(), regmap_raw_read() and regmap_bulk_read() routines Signed-off-by: Gerhard Sittig Signed-off-by: Mark Brown --- drivers/base/regmap/regmap.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 9c021d9cace0..f441084bbc8d 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -1743,7 +1743,7 @@ static int _regmap_read(struct regmap *map, unsigned int reg, /** * regmap_read(): Read a value from a single register * - * @map: Register map to write to + * @map: Register map to read from * @reg: Register to be read from * @val: Pointer to store read value * @@ -1770,7 +1770,7 @@ EXPORT_SYMBOL_GPL(regmap_read); /** * regmap_raw_read(): Read raw data from the device * - * @map: Register map to write to + * @map: Register map to read from * @reg: First register to be read from * @val: Pointer to store read value * @val_len: Size of data to read @@ -1882,7 +1882,7 @@ EXPORT_SYMBOL_GPL(regmap_fields_read); /** * regmap_bulk_read(): Read multiple registers from the device * - * @map: Register map to write to + * @map: Register map to read from * @reg: First register to be read from * @val: Pointer to store read value, in native register size for device * @val_count: Number of registers to read -- cgit v1.2.3 From 5dd8c4c3f18b2ebf3f5303c7c273396441db6c6c Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 8 Nov 2013 10:20:06 -0800 Subject: drm/i915/bdw: Add BDW to ULT macro For what we care about ULT and ULX are interchangeable. We know of 3 types of pciids for these cases. I am not sure if at some point we will need to distinguish ULT and ULX. Cc: Paulo Zanoni Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 8600c315b4c4..51951ef7e71d 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1755,8 +1755,13 @@ struct drm_i915_file_private { #define IS_MOBILE(dev) (INTEL_INFO(dev)->is_mobile) #define IS_HSW_EARLY_SDV(dev) (IS_HASWELL(dev) && \ ((dev)->pdev->device & 0xFF00) == 0x0C00) -#define IS_ULT(dev) (IS_HASWELL(dev) && \ +#define IS_BDW_ULT(dev) (IS_BROADWELL(dev) && \ + (((dev)->pdev->device & 0xf) == 0x2 || \ + ((dev)->pdev->device & 0xf) == 0x6 || \ + ((dev)->pdev->device & 0xf) == 0xe)) +#define IS_HSW_ULT(dev) (IS_HASWELL(dev) && \ ((dev)->pdev->device & 0xFF00) == 0x0A00) +#define IS_ULT(dev) (IS_HSW_ULT(dev) || IS_BDW_ULT(dev)) #define IS_HSW_GT3(dev) (IS_HASWELL(dev) && \ ((dev)->pdev->device & 0x00F0) == 0x0020) #define IS_PRELIMINARY_HW(intel_info) ((intel_info)->is_preliminary) -- cgit v1.2.3 From f8e100621b072384ec1180563d933e86e2f7e2d5 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Mon, 11 Nov 2013 11:12:57 +0200 Subject: drm/i915/bdw: GEN8 backlight support Prior to Haswell the CPU control register for backlight (BLC_PWM_CPU_CTL) toggled the PCH baclight pin for us. This made some sense as there was no pin on the CPU. With Haswell came the introduction of a CPU backlight pin, but the interface was still controlled by software with the same mechnism. Behind the scenes, hardware did all the dirty work for us. Broadwell no longer provides this for free. If we want to use the PCH backlight pin [1] then we have to set the override bit BLC_PWM_PCH_CTL1 and program BLC_PWM_PCH_CTL2 for the PWM values. This patch implements that. This patch is compile tested only, and given that I rarely if ever touch this code, careful review is welcome. [1] According to Art, we know of no devices that exist which use the CPU pin (and remember it has existed already on HSW). If such a device does exist, we'll have to handle it properly - this is left as TODO until then. v2: Drop the abstraction prep patch, as a bigger backlight overhaul is in the works, and do just the mimimal bdw enabling now. (by Jani) CC: Art Runyan Signed-off-by: Ben Widawsky Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_panel.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index f161ac02c4f6..e6f782d1c669 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -451,7 +451,9 @@ static u32 intel_panel_get_backlight(struct drm_device *dev, spin_lock_irqsave(&dev_priv->backlight.lock, flags); - if (HAS_PCH_SPLIT(dev)) { + if (IS_BROADWELL(dev)) { + val = I915_READ(BLC_PWM_PCH_CTL2) & BACKLIGHT_DUTY_CYCLE_MASK; + } else if (HAS_PCH_SPLIT(dev)) { val = I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; } else { if (IS_VALLEYVIEW(dev)) @@ -479,6 +481,13 @@ static u32 intel_panel_get_backlight(struct drm_device *dev, return val; } +static void intel_bdw_panel_set_backlight(struct drm_device *dev, u32 level) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 val = I915_READ(BLC_PWM_PCH_CTL2) & ~BACKLIGHT_DUTY_CYCLE_MASK; + I915_WRITE(BLC_PWM_PCH_CTL2, val | level); +} + static void intel_pch_panel_set_backlight(struct drm_device *dev, u32 level) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -496,7 +505,9 @@ static void intel_panel_actually_set_backlight(struct drm_device *dev, DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level); level = intel_panel_compute_brightness(dev, pipe, level); - if (HAS_PCH_SPLIT(dev)) + if (IS_BROADWELL(dev)) + return intel_bdw_panel_set_backlight(dev, level); + else if (HAS_PCH_SPLIT(dev)) return intel_pch_panel_set_backlight(dev, level); if (is_backlight_combination_mode(dev)) { @@ -666,7 +677,16 @@ void intel_panel_enable_backlight(struct intel_connector *connector) POSTING_READ(reg); I915_WRITE(reg, tmp | BLM_PWM_ENABLE); - if (HAS_PCH_SPLIT(dev) && + if (IS_BROADWELL(dev)) { + /* + * Broadwell requires PCH override to drive the PCH + * backlight pin. The above will configure the CPU + * backlight pin, which we don't plan to use. + */ + tmp = I915_READ(BLC_PWM_PCH_CTL1); + tmp |= BLM_PCH_OVERRIDE_ENABLE | BLM_PCH_PWM_ENABLE; + I915_WRITE(BLC_PWM_PCH_CTL1, tmp); + } else if (HAS_PCH_SPLIT(dev) && !(dev_priv->quirks & QUIRK_NO_PCH_PWM_ENABLE)) { tmp = I915_READ(BLC_PWM_PCH_CTL1); tmp |= BLM_PCH_PWM_ENABLE; -- cgit v1.2.3 From 935e8de97564a1ea22c3bb30ca2b20b12af7cbfb Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 7 Nov 2013 21:40:47 -0800 Subject: drm/i915/bdw: Do gen6 style reset for gen8 This patch existed before, but was lost over time. Note that reset is still somewhat problematic in my limited testing (ie. module_reload will not pass) but it can be disabled with a module parameter, and support should be considered preliminary anyway. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_uncore.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index f9883ceff946..6a4f9b615de1 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -782,6 +782,7 @@ static int gen6_do_reset(struct drm_device *dev) int intel_gpu_reset(struct drm_device *dev) { switch (INTEL_INFO(dev)->gen) { + case 8: case 7: case 6: return gen6_do_reset(dev); case 5: return ironlake_do_reset(dev); -- cgit v1.2.3 From 230f955f73074ec5b1b4389f3f26152eebf54404 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 7 Nov 2013 21:40:48 -0800 Subject: drm/i915/bdw: Free correct number of ppgtt pages I am unclear how this got messed up in the shuffle, but it did. Cc: Imre Deak Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 3620a1b0a73c..5a3cc3189f1f 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -335,8 +335,8 @@ static void gen8_ppgtt_cleanup(struct i915_address_space *vm) kfree(ppgtt->gen8_pt_dma_addr[i]); } - __free_pages(ppgtt->gen8_pt_pages, ppgtt->num_pt_pages << PAGE_SHIFT); - __free_pages(ppgtt->pd_pages, ppgtt->num_pd_pages << PAGE_SHIFT); + __free_pages(ppgtt->gen8_pt_pages, get_order(ppgtt->num_pt_pages << PAGE_SHIFT)); + __free_pages(ppgtt->pd_pages, get_order(ppgtt->num_pd_pages << PAGE_SHIFT)); } /** -- cgit v1.2.3 From eb0d4b75d506050cb369df467b93b92360f5acaf Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 7 Nov 2013 21:40:50 -0800 Subject: drm/i915/bdw: Add comment about gen8 HWS PGA This confused me some many times that I think it is appropriate to add a small comment to instruct the reader of the code that it is indeed doing what it is supposed to do. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index b620337e6d67..c2f09d456300 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -965,6 +965,7 @@ void intel_ring_setup_status_page(struct intel_ring_buffer *ring) } else if (IS_GEN6(ring->dev)) { mmio = RING_HWS_PGA_GEN6(ring->mmio_base); } else { + /* XXX: gen8 returns to sanity */ mmio = RING_HWS_PGA(ring->mmio_base); } -- cgit v1.2.3 From 3a2ffb65eec6dbda2fd8151894f51c18b42c8d41 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 7 Nov 2013 21:40:51 -0800 Subject: drm/i915/bdw: Limit GTT to 2GB Because of the way in which we're allocating the pages for the Aliasing PPGTT, we cannot actually successfully alloc enough space for anything greater than 2GB. Instead of a quick hack to fix this, we should defer until we have the real solution in place (allocating much less contiguous space). This wasn't found sooner because we didn't not have any systems supporting more than a 2GB GTT. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 5a3cc3189f1f..f69bdc741b80 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1239,6 +1239,11 @@ static inline unsigned int gen8_get_total_gtt_size(u16 bdw_gmch_ctl) bdw_gmch_ctl &= BDW_GMCH_GGMS_MASK; if (bdw_gmch_ctl) bdw_gmch_ctl = 1 << bdw_gmch_ctl; + if (bdw_gmch_ctl > 4) { + WARN_ON(!i915_preliminary_hw_support); + return 4<<20; + } + return bdw_gmch_ctl << 20; } -- cgit v1.2.3 From 596cc11e7a4a89bf6c45f955402d0bd0c7d51f13 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Mon, 11 Nov 2013 14:46:28 -0800 Subject: drm/i915/bdw: PIPE_[BC] I[ME]R moved to powerwell The pipe B and pipe C interrupt mask and enable registers are now part of the pipe, so disabling the pipe power wells will lost the contests of the registers. Art totally debugged this one! v2: Use the irq_lock to clarify code, and prevent future bugs (Daniel) Cc: Art Runyan Cc: Paulo Zanoni Signed-off-by: Ben Widawsky [danvet: Make sparse happy.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 0a07d7c9cafc..33a8dbe64039 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5684,6 +5684,7 @@ static void __intel_set_power_well(struct drm_device *dev, bool enable) { struct drm_i915_private *dev_priv = dev->dev_private; bool is_enabled, enable_requested; + unsigned long irqflags; uint32_t tmp; tmp = I915_READ(HSW_PWR_WELL_DRIVER); @@ -5701,9 +5702,24 @@ static void __intel_set_power_well(struct drm_device *dev, bool enable) HSW_PWR_WELL_STATE_ENABLED), 20)) DRM_ERROR("Timeout enabling power well\n"); } + + if (IS_BROADWELL(dev)) { + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + I915_WRITE(GEN8_DE_PIPE_IMR(PIPE_B), + dev_priv->de_irq_mask[PIPE_B]); + I915_WRITE(GEN8_DE_PIPE_IER(PIPE_B), + ~dev_priv->de_irq_mask[PIPE_B] | + GEN8_PIPE_VBLANK); + I915_WRITE(GEN8_DE_PIPE_IMR(PIPE_C), + dev_priv->de_irq_mask[PIPE_C]); + I915_WRITE(GEN8_DE_PIPE_IER(PIPE_C), + ~dev_priv->de_irq_mask[PIPE_C] | + GEN8_PIPE_VBLANK); + POSTING_READ(GEN8_DE_PIPE_IER(PIPE_C)); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); + } } else { if (enable_requested) { - unsigned long irqflags; enum pipe p; I915_WRITE(HSW_PWR_WELL_DRIVER, 0); -- cgit v1.2.3 From 718822c1c112dc99e0c72c8968ee1db9d9d910f0 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Fri, 15 Nov 2013 16:12:20 -0500 Subject: dm delay: fix a possible deadlock due to shared workqueue The dm-delay target uses a shared workqueue for multiple instances. This can cause deadlock if two or more dm-delay targets are stacked on the top of each other. This patch changes dm-delay to use a per-instance workqueue. Cc: stable@vger.kernel.org # 2.6.22+ Signed-off-by: Mikulas Patocka Signed-off-by: Mike Snitzer --- drivers/md/dm-delay.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-delay.c b/drivers/md/dm-delay.c index 496d5f3646a5..2f91d6d4a2cc 100644 --- a/drivers/md/dm-delay.c +++ b/drivers/md/dm-delay.c @@ -20,6 +20,7 @@ struct delay_c { struct timer_list delay_timer; struct mutex timer_lock; + struct workqueue_struct *kdelayd_wq; struct work_struct flush_expired_bios; struct list_head delayed_bios; atomic_t may_delay; @@ -45,14 +46,13 @@ struct dm_delay_info { static DEFINE_MUTEX(delayed_bios_lock); -static struct workqueue_struct *kdelayd_wq; static struct kmem_cache *delayed_cache; static void handle_delayed_timer(unsigned long data) { struct delay_c *dc = (struct delay_c *)data; - queue_work(kdelayd_wq, &dc->flush_expired_bios); + queue_work(dc->kdelayd_wq, &dc->flush_expired_bios); } static void queue_timeout(struct delay_c *dc, unsigned long expires) @@ -191,6 +191,12 @@ out: goto bad_dev_write; } + dc->kdelayd_wq = alloc_workqueue("kdelayd", WQ_MEM_RECLAIM, 0); + if (!dc->kdelayd_wq) { + DMERR("Couldn't start kdelayd"); + goto bad_queue; + } + setup_timer(&dc->delay_timer, handle_delayed_timer, (unsigned long)dc); INIT_WORK(&dc->flush_expired_bios, flush_expired_bios); @@ -203,6 +209,8 @@ out: ti->private = dc; return 0; +bad_queue: + mempool_destroy(dc->delayed_pool); bad_dev_write: if (dc->dev_write) dm_put_device(ti, dc->dev_write); @@ -217,7 +225,7 @@ static void delay_dtr(struct dm_target *ti) { struct delay_c *dc = ti->private; - flush_workqueue(kdelayd_wq); + destroy_workqueue(dc->kdelayd_wq); dm_put_device(ti, dc->dev_read); @@ -350,12 +358,6 @@ static int __init dm_delay_init(void) { int r = -ENOMEM; - kdelayd_wq = alloc_workqueue("kdelayd", WQ_MEM_RECLAIM, 0); - if (!kdelayd_wq) { - DMERR("Couldn't start kdelayd"); - goto bad_queue; - } - delayed_cache = KMEM_CACHE(dm_delay_info, 0); if (!delayed_cache) { DMERR("Couldn't create delayed bio cache."); @@ -373,8 +375,6 @@ static int __init dm_delay_init(void) bad_register: kmem_cache_destroy(delayed_cache); bad_memcache: - destroy_workqueue(kdelayd_wq); -bad_queue: return r; } @@ -382,7 +382,6 @@ static void __exit dm_delay_exit(void) { dm_unregister_target(&delay_target); kmem_cache_destroy(delayed_cache); - destroy_workqueue(kdelayd_wq); } /* Module hooks */ -- cgit v1.2.3 From 73f080fde50de1be7ab1e62fd93287edaf0861db Mon Sep 17 00:00:00 2001 From: Courtney Cavin Date: Wed, 20 Nov 2013 15:27:09 -0800 Subject: regmap: make sure we unlock on failure in regmap_bulk_write Signed-off-by: Courtney Cavin Signed-off-by: Mark Brown --- drivers/base/regmap/regmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 9c021d9cace0..d1a914116f66 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -1549,7 +1549,7 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, val + (i * val_bytes), val_bytes); if (ret != 0) - return ret; + goto out; } } else { ret = _regmap_raw_write(map, reg, wval, val_bytes * val_count); -- cgit v1.2.3 From 76bb80ed3027fc51af24a378a5986672dc01398f Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 15 Nov 2013 15:29:57 +0200 Subject: drm/i915/ddi: set sink to power down mode on dp disable Similar to commit fdbc3b1f639bb2cbfb32c612b2699e0ba373317d Author: Jani Nikula Date: Tue Nov 12 17:10:13 2013 +0200 drm/i915/dp: set sink to power down mode on dp disable but for DDI, where we've never done this. Signed-off-by: Jani Nikula Reviewed-by: Paulo Zanoni Tested-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 330077bcd0bd..333fff367e5e 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1158,9 +1158,10 @@ static void intel_ddi_post_disable(struct intel_encoder *intel_encoder) if (wait) intel_wait_ddi_buf_idle(dev_priv, port); - if (type == INTEL_OUTPUT_EDP) { + if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); ironlake_edp_panel_vdd_on(intel_dp); + intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF); ironlake_edp_panel_off(intel_dp); } -- cgit v1.2.3 From 34af1ab4a2cc97721a00fce19d9fbafd9ff4b300 Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Fri, 8 Nov 2013 12:15:55 +0530 Subject: gpio: davinci: fix check for unbanked gpio This patch fixes a check for offset in gpio_to_irq_unbanked() and also assigns gpio_irq, gpio_unbanked of chips[0] to appropriate values which is used in gpio_to_irq_unbanked() function. Without this patch, unbanked IRQ handling is broken. Reported-by: Grygorii Strashko Acked-by: Grygorii Strashko Acked-by: Linus Walleij Signed-off-by: Lad, Prabhakar Signed-off-by: Sekhar Nori --- drivers/gpio/gpio-davinci.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index 8847adf392b7..84be70157ad6 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -327,7 +327,7 @@ static int gpio_to_irq_unbanked(struct gpio_chip *chip, unsigned offset) * NOTE: we assume for now that only irqs in the first gpio_chip * can provide direct-mapped IRQs to AINTC (up to 32 GPIOs). */ - if (offset < d->irq_base) + if (offset < d->gpio_unbanked) return d->gpio_irq + offset; else return -ENODEV; @@ -419,6 +419,8 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) /* pass "bank 0" GPIO IRQs to AINTC */ chips[0].chip.to_irq = gpio_to_irq_unbanked; + chips[0].gpio_irq = bank_irq; + chips[0].gpio_unbanked = pdata->gpio_unbanked; binten = BIT(0); /* AINTC handles mask/unmask; GPIO handles triggering */ -- cgit v1.2.3 From e55bc55867585e6628359fd5496316576fe58a2f Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 9 Nov 2013 13:18:01 +0100 Subject: irqchip: renesas-intc-irqpin: Fix register bitfield shift calculation The SENSE register bitfield position is incorrectly computed for SoCs that use 2-bit IRQ sense fields. Fix it. This has been tested on the Marzen (H1) and Bockw (M1) boards. This bug has been present since the renesas-intc-irqpin driver was introduced by 443580486e3b9657 ("irqchip: Renesas INTC External IRQ pin driver") in v3.10-rc1. Signed-off-by: Laurent Pinchart Acked-by: Magnus Damm Tested-by: Simon Horman Signed-off-by: Simon Horman --- drivers/irqchip/irq-renesas-intc-irqpin.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-renesas-intc-irqpin.c b/drivers/irqchip/irq-renesas-intc-irqpin.c index 82cec63a9011..3ee78f02e5d7 100644 --- a/drivers/irqchip/irq-renesas-intc-irqpin.c +++ b/drivers/irqchip/irq-renesas-intc-irqpin.c @@ -149,8 +149,9 @@ static void intc_irqpin_read_modify_write(struct intc_irqpin_priv *p, static void intc_irqpin_mask_unmask_prio(struct intc_irqpin_priv *p, int irq, int do_mask) { - int bitfield_width = 4; /* PRIO assumed to have fixed bitfield width */ - int shift = (7 - irq) * bitfield_width; /* PRIO assumed to be 32-bit */ + /* The PRIO register is assumed to be 32-bit with fixed 4-bit fields. */ + int bitfield_width = 4; + int shift = 32 - (irq + 1) * bitfield_width; intc_irqpin_read_modify_write(p, INTC_IRQPIN_REG_PRIO, shift, bitfield_width, @@ -159,8 +160,9 @@ static void intc_irqpin_mask_unmask_prio(struct intc_irqpin_priv *p, static int intc_irqpin_set_sense(struct intc_irqpin_priv *p, int irq, int value) { + /* The SENSE register is assumed to be 32-bit. */ int bitfield_width = p->config.sense_bitfield_width; - int shift = (7 - irq) * bitfield_width; /* SENSE assumed to be 32-bit */ + int shift = 32 - (irq + 1) * bitfield_width; dev_dbg(&p->pdev->dev, "sense irq = %d, mode = %d\n", irq, value); -- cgit v1.2.3 From c51e9701c4ad68d87baecefad6c58d051574f848 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 22 Nov 2013 10:37:53 +0000 Subject: drm/i915: Prefer setting PTE cache age to 3 We have conflicting benchmark data that suggest either age 0 or age 3 is better. However, the earlier benchmark on which we based the switch to age 0 (commit 0d8ff15e9a15f2b393e53337a107b7a1e5919b6d Author: Ben Widawsky Date: Thu Jul 4 11:02:03 2013 -0700 drm/i915/hsw: Set correct Haswell PTE encodings) actually seems to prefer the default PTE encoding as age 3. Presumably, this is in part due to the use of MOCS to override the PTE encodings when appropriate. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=69870 Tested-by: mengmeng.meng@intel.com Signed-off-by: Chris Wilson Acked-by: Jesse Barnes Reviewed-by: Eric Anholt --- drivers/gpu/drm/i915/i915_gem_gtt.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 3620a1b0a73c..38cb8d44a013 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -57,7 +57,9 @@ typedef gen8_gtt_pte_t gen8_ppgtt_pde_t; #define HSW_WB_LLC_AGE3 HSW_CACHEABILITY_CONTROL(0x2) #define HSW_WB_LLC_AGE0 HSW_CACHEABILITY_CONTROL(0x3) #define HSW_WB_ELLC_LLC_AGE0 HSW_CACHEABILITY_CONTROL(0xb) +#define HSW_WB_ELLC_LLC_AGE3 HSW_CACHEABILITY_CONTROL(0x8) #define HSW_WT_ELLC_LLC_AGE0 HSW_CACHEABILITY_CONTROL(0x6) +#define HSW_WT_ELLC_LLC_AGE3 HSW_CACHEABILITY_CONTROL(0x7) #define GEN8_PTES_PER_PAGE (PAGE_SIZE / sizeof(gen8_gtt_pte_t)) #define GEN8_PDES_PER_PAGE (PAGE_SIZE / sizeof(gen8_ppgtt_pde_t)) @@ -185,10 +187,10 @@ static gen6_gtt_pte_t iris_pte_encode(dma_addr_t addr, case I915_CACHE_NONE: break; case I915_CACHE_WT: - pte |= HSW_WT_ELLC_LLC_AGE0; + pte |= HSW_WT_ELLC_LLC_AGE3; break; default: - pte |= HSW_WB_ELLC_LLC_AGE0; + pte |= HSW_WB_ELLC_LLC_AGE3; break; } -- cgit v1.2.3 From 76a56eb3b0fe82f77b1fb604dbf4a408e6ad7ba2 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sat, 2 Nov 2013 15:57:36 +0200 Subject: mac80211_hwsim: Fix radiotap header for ACK frames The earlier addition of rt_tsft to struct hwsim_radiotap_hdr updated only mac80211_hwsim_monitor_tx() to fill in the new field. mac80211_hwsim_monitor_ack() did not set the rt_tsft field and as such, leaked eight bytes of kernel memory to user space. In addition, the resulting radiotap header is invalid since the field offsets do not match. Fix these issues by defining a separate radiotap header structure for the ACK frame case which does not use all the fields. Signed-off-by: Jouni Malinen Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 9df7bc91a26f..3df400c593a1 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -383,6 +383,14 @@ struct hwsim_radiotap_hdr { __le16 rt_chbitmask; } __packed; +struct hwsim_radiotap_ack_hdr { + struct ieee80211_radiotap_header hdr; + u8 rt_flags; + u8 pad; + __le16 rt_channel; + __le16 rt_chbitmask; +} __packed; + /* MAC80211_HWSIM netlinf family */ static struct genl_family hwsim_genl_family = { .id = GENL_ID_GENERATE, @@ -500,7 +508,7 @@ static void mac80211_hwsim_monitor_ack(struct ieee80211_channel *chan, const u8 *addr) { struct sk_buff *skb; - struct hwsim_radiotap_hdr *hdr; + struct hwsim_radiotap_ack_hdr *hdr; u16 flags; struct ieee80211_hdr *hdr11; @@ -511,14 +519,14 @@ static void mac80211_hwsim_monitor_ack(struct ieee80211_channel *chan, if (skb == NULL) return; - hdr = (struct hwsim_radiotap_hdr *) skb_put(skb, sizeof(*hdr)); + hdr = (struct hwsim_radiotap_ack_hdr *) skb_put(skb, sizeof(*hdr)); hdr->hdr.it_version = PKTHDR_RADIOTAP_VERSION; hdr->hdr.it_pad = 0; hdr->hdr.it_len = cpu_to_le16(sizeof(*hdr)); hdr->hdr.it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | (1 << IEEE80211_RADIOTAP_CHANNEL)); hdr->rt_flags = 0; - hdr->rt_rate = 0; + hdr->pad = 0; hdr->rt_channel = cpu_to_le16(chan->center_freq); flags = IEEE80211_CHAN_2GHZ; hdr->rt_chbitmask = cpu_to_le16(flags); -- cgit v1.2.3 From cdb1b8057a44bbda67d403000a26be00de1d2326 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Wed, 6 Nov 2013 12:06:30 +0200 Subject: mac80211_hwsim: Fix bcn_en_iter to use atomic iteration 'mac80211_hwsim: Fix tracking of beaconing for multi-vif' introduced an iteration of active interfaces into the bss_info_changed handler. However, it used a wrong type of iteration and could result in a dead lock since iflist_mtx can already be held. Fix this by using the atomic version of the iteration function. Signed-off-by: Jouni Malinen Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 3df400c593a1..c72438bb2faf 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -1238,7 +1238,7 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw, HRTIMER_MODE_REL); } else if (!info->enable_beacon) { unsigned int count = 0; - ieee80211_iterate_active_interfaces( + ieee80211_iterate_active_interfaces_atomic( data->hw, IEEE80211_IFACE_ITER_NORMAL, mac80211_hwsim_bcn_en_iter, &count); wiphy_debug(hw->wiphy, " beaconing vifs remaining: %u", -- cgit v1.2.3 From 39189c98d161c292e7f80fe50da00d33193362b9 Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Sun, 10 Nov 2013 19:37:37 +0100 Subject: usb: phy: remove dead code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit [4d175f34: usb: phy: nop: Defer clock prepare until PHY init] removed a goto reaching behind a “return ret” at the end of the function thus removing the only possible way that statement could be reached, and so rendering it a dead code. This commit cleans it up by removing said dead code. Signed-off-by: Michal Nazarewicz Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-am335x.c | 2 -- drivers/usb/phy/phy-generic.c | 2 -- 2 files changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/phy/phy-am335x.c b/drivers/usb/phy/phy-am335x.c index 6370e50649d7..48d41abd1b6b 100644 --- a/drivers/usb/phy/phy-am335x.c +++ b/drivers/usb/phy/phy-am335x.c @@ -66,8 +66,6 @@ static int am335x_phy_probe(struct platform_device *pdev) platform_set_drvdata(pdev, am_phy); return 0; - - return ret; } static int am335x_phy_remove(struct platform_device *pdev) diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c index fce3a9e9bb5d..db4fc22e4aa6 100644 --- a/drivers/usb/phy/phy-generic.c +++ b/drivers/usb/phy/phy-generic.c @@ -271,8 +271,6 @@ static int usb_phy_gen_xceiv_probe(struct platform_device *pdev) platform_set_drvdata(pdev, nop); return 0; - - return err; } static int usb_phy_gen_xceiv_remove(struct platform_device *pdev) -- cgit v1.2.3 From af9f51c5512f9d55972603dd5dd90d0fa300b200 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 24 Oct 2013 09:45:29 -0500 Subject: usb: phy: generic: fix how we find out about our resources instead of having each user of generic phy find out about its own resources and pass it to the core layer, have th core layer itself figure that out. It's as simple as moving a piece of code around. This fixes a big regression caused during the merge window where am335x-based platforms wouldn't be able to probe their PHY driver. Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-am335x.c | 3 +-- drivers/usb/phy/phy-generic.c | 61 +++++++++++++++++++++---------------------- drivers/usb/phy/phy-generic.h | 4 ++- 3 files changed, 34 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/phy/phy-am335x.c b/drivers/usb/phy/phy-am335x.c index 48d41abd1b6b..0e3c60cb669a 100644 --- a/drivers/usb/phy/phy-am335x.c +++ b/drivers/usb/phy/phy-am335x.c @@ -52,8 +52,7 @@ static int am335x_phy_probe(struct platform_device *pdev) return am_phy->id; } - ret = usb_phy_gen_create_phy(dev, &am_phy->usb_phy_gen, - USB_PHY_TYPE_USB2, 0, false); + ret = usb_phy_gen_create_phy(dev, &am_phy->usb_phy_gen, NULL); if (ret) return ret; diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c index db4fc22e4aa6..0c3b24124063 100644 --- a/drivers/usb/phy/phy-generic.c +++ b/drivers/usb/phy/phy-generic.c @@ -150,10 +150,38 @@ static int nop_set_host(struct usb_otg *otg, struct usb_bus *host) } int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop, - enum usb_phy_type type, u32 clk_rate, bool needs_vcc) + struct usb_phy_gen_xceiv_platform_data *pdata) { + enum usb_phy_type type = USB_PHY_TYPE_USB2; int err; + u32 clk_rate = 0; + bool needs_vcc = false; + + nop->reset_active_low = true; /* default behaviour */ + + if (dev->of_node) { + struct device_node *node = dev->of_node; + enum of_gpio_flags flags; + + if (of_property_read_u32(node, "clock-frequency", &clk_rate)) + clk_rate = 0; + + needs_vcc = of_property_read_bool(node, "vcc-supply"); + nop->gpio_reset = of_get_named_gpio_flags(node, "reset-gpios", + 0, &flags); + if (nop->gpio_reset == -EPROBE_DEFER) + return -EPROBE_DEFER; + + nop->reset_active_low = flags & OF_GPIO_ACTIVE_LOW; + + } else if (pdata) { + type = pdata->type; + clk_rate = pdata->clk_rate; + needs_vcc = pdata->needs_vcc; + nop->gpio_reset = pdata->gpio_reset; + } + nop->phy.otg = devm_kzalloc(dev, sizeof(*nop->phy.otg), GFP_KERNEL); if (!nop->phy.otg) @@ -218,43 +246,14 @@ EXPORT_SYMBOL_GPL(usb_phy_gen_create_phy); static int usb_phy_gen_xceiv_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct usb_phy_gen_xceiv_platform_data *pdata = - dev_get_platdata(&pdev->dev); struct usb_phy_gen_xceiv *nop; - enum usb_phy_type type = USB_PHY_TYPE_USB2; int err; - u32 clk_rate = 0; - bool needs_vcc = false; nop = devm_kzalloc(dev, sizeof(*nop), GFP_KERNEL); if (!nop) return -ENOMEM; - nop->reset_active_low = true; /* default behaviour */ - - if (dev->of_node) { - struct device_node *node = dev->of_node; - enum of_gpio_flags flags; - - if (of_property_read_u32(node, "clock-frequency", &clk_rate)) - clk_rate = 0; - - needs_vcc = of_property_read_bool(node, "vcc-supply"); - nop->gpio_reset = of_get_named_gpio_flags(node, "reset-gpios", - 0, &flags); - if (nop->gpio_reset == -EPROBE_DEFER) - return -EPROBE_DEFER; - - nop->reset_active_low = flags & OF_GPIO_ACTIVE_LOW; - - } else if (pdata) { - type = pdata->type; - clk_rate = pdata->clk_rate; - needs_vcc = pdata->needs_vcc; - nop->gpio_reset = pdata->gpio_reset; - } - - err = usb_phy_gen_create_phy(dev, nop, type, clk_rate, needs_vcc); + err = usb_phy_gen_create_phy(dev, nop, dev_get_platdata(&pdev->dev)); if (err) return err; diff --git a/drivers/usb/phy/phy-generic.h b/drivers/usb/phy/phy-generic.h index d2a220d81734..38a81f307b82 100644 --- a/drivers/usb/phy/phy-generic.h +++ b/drivers/usb/phy/phy-generic.h @@ -1,6 +1,8 @@ #ifndef _PHY_GENERIC_H_ #define _PHY_GENERIC_H_ +#include + struct usb_phy_gen_xceiv { struct usb_phy phy; struct device *dev; @@ -14,6 +16,6 @@ int usb_gen_phy_init(struct usb_phy *phy); void usb_gen_phy_shutdown(struct usb_phy *phy); int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop, - enum usb_phy_type type, u32 clk_rate, bool needs_vcc); + struct usb_phy_gen_xceiv_platform_data *pdata); #endif -- cgit v1.2.3 From 93f599f279ab56b1761c76e53f9753b26aeefe9e Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Thu, 21 Nov 2013 13:49:17 +0100 Subject: usb: gadget: s3c-hsotg: fix spinlock locking This patch adds missing spinlock locking in s3c_hsotg_complete_setup function, and unlocking for gadget setup call. Signed-off-by: Robert Baldyga Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- drivers/usb/gadget/s3c-hsotg.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index 9875d9c0823f..56fad76baa53 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -1245,7 +1245,9 @@ static void s3c_hsotg_process_control(struct s3c_hsotg *hsotg, /* as a fallback, try delivering it to the driver to deal with */ if (ret == 0 && hsotg->driver) { + spin_unlock(&hsotg->lock); ret = hsotg->driver->setup(&hsotg->gadget, ctrl); + spin_lock(&hsotg->lock); if (ret < 0) dev_dbg(hsotg->dev, "driver->setup() ret %d\n", ret); } @@ -1308,10 +1310,12 @@ static void s3c_hsotg_complete_setup(struct usb_ep *ep, return; } + spin_lock(&hsotg->lock); if (req->actual == 0) s3c_hsotg_enqueue_setup(hsotg); else s3c_hsotg_process_control(hsotg, req->buf); + spin_unlock(&hsotg->lock); } /** -- cgit v1.2.3 From d18f7116a5ddb8263fe62b05ad63e5ceb5875791 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Thu, 21 Nov 2013 13:49:18 +0100 Subject: usb: gadget: s3c-hsotg: fix disconnect handling This patch moves s3c_hsotg_disconnect function call from USBSusp interrupt handler to SET_ADDRESS request handler. It's because disconnected state can't be detected directly, because this hardware doesn't support Disconnected interrupt for device mode. For both Suspend and Disconnect events there is one interrupt USBSusp, but calling s3c_hsotg_disconnect from this interrupt handler causes config reset in composite layer, which is not undesirable for Suspended state. For this reason s3c_hsotg_disconnect is called from SET_ADDRESS request handler, which occurs always after disconnection, so we do disconnect immediately before we are connected again. It's probably only way we can do handle disconnection correctly. Signed-off-by: Robert Baldyga Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- drivers/usb/gadget/s3c-hsotg.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index 56fad76baa53..e20bc109fdd7 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -1180,6 +1180,7 @@ static int s3c_hsotg_process_req_feature(struct s3c_hsotg *hsotg, } static void s3c_hsotg_enqueue_setup(struct s3c_hsotg *hsotg); +static void s3c_hsotg_disconnect(struct s3c_hsotg *hsotg); /** * s3c_hsotg_process_control - process a control request @@ -1221,6 +1222,7 @@ static void s3c_hsotg_process_control(struct s3c_hsotg *hsotg, if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { switch (ctrl->bRequest) { case USB_REQ_SET_ADDRESS: + s3c_hsotg_disconnect(hsotg); dcfg = readl(hsotg->regs + DCFG); dcfg &= ~DCFG_DevAddr_MASK; dcfg |= ctrl->wValue << DCFG_DevAddr_SHIFT; @@ -2537,7 +2539,6 @@ irq_retry: writel(GINTSTS_USBSusp, hsotg->regs + GINTSTS); call_gadget(hsotg, suspend); - s3c_hsotg_disconnect(hsotg); } if (gintsts & GINTSTS_WkUpInt) { -- cgit v1.2.3 From b144e4ab1ef130e8bf30bcd3e529b7f35112c503 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 18 Nov 2013 11:37:20 +0100 Subject: usb: gadget: fix pxa25x compilation problems In commit 88f718e3fa4d67f3a8dbe79a2f97d722323e4051 "ARM: pxa: delete the custom GPIO header" we removed the implicit inclusion of from . The pxa25x_udc was not using that, but it was relying on to implictly include which in turn implicitly included , which was needed for the driver to compile. Fix this up by explicitly including the necessary header. Reported-by: Russell King Signed-off-by: Linus Walleij Signed-off-by: Felipe Balbi --- drivers/usb/gadget/pxa25x_udc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c index 0ac6064aa3b8..409a3c45a36a 100644 --- a/drivers/usb/gadget/pxa25x_udc.c +++ b/drivers/usb/gadget/pxa25x_udc.c @@ -54,6 +54,7 @@ */ #ifdef CONFIG_ARCH_PXA #include +#include #endif #ifdef CONFIG_ARCH_LUBBOCK -- cgit v1.2.3 From fd3923a9904f34d5472134358d87f454a288fc45 Mon Sep 17 00:00:00 2001 From: Apelete Seketeli Date: Tue, 19 Nov 2013 23:18:20 +0100 Subject: usb: fix musb gadget to enable OTG mode conditionally The musb driver is usable in host, gadget or dual role mode depending on the kernel configuration. However, the musb gadget part of the driver is enabling OTG mode whether the driver is built for dual role or gadget only mode. This induces a bug for gadget only USB device controllers where the kernel tries to use Host Negotiation Protocol with such controllers, which causes a panic. This behaviour is now fixed by enabling OTG mode only when musb driver is built for dual role mode. Signed-off-by: Apelete Seketeli Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_gadget.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index d2d3a173b315..32fb057c03f5 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1796,7 +1796,11 @@ int musb_gadget_setup(struct musb *musb) /* this "gadget" abstracts/virtualizes the controller */ musb->g.name = musb_driver_name; +#if IS_ENABLED(CONFIG_USB_MUSB_DUAL_ROLE) musb->g.is_otg = 1; +#elif IS_ENABLED(CONFIG_USB_MUSB_GADGET) + musb->g.is_otg = 0; +#endif musb_g_init_endpoints(musb); -- cgit v1.2.3 From dc52c57411ccad276af6b4f35a670773110b35c5 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Fri, 15 Nov 2013 21:38:50 +0200 Subject: usb: phy-generic: fix nop xceiv probe Commit bd27fa44e13830d2baa278d5702e766380659cb3 (usb: phy: generic: Don't use regulator framework for RESET line) introduced regression: All users of usb_nop_xceiv_register() will fail because there is no platform data and the default reset GPIO is 0 which is a valid GPIO. Fix that. Signed-off-by: Aaro Koskinen Acked-by: Roger Quadros Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-generic.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c index 0c3b24124063..8ee37f403553 100644 --- a/drivers/usb/phy/phy-generic.c +++ b/drivers/usb/phy/phy-generic.c @@ -180,6 +180,8 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop, clk_rate = pdata->clk_rate; needs_vcc = pdata->needs_vcc; nop->gpio_reset = pdata->gpio_reset; + } else { + nop->gpio_reset = -1; } nop->phy.otg = devm_kzalloc(dev, sizeof(*nop->phy.otg), -- cgit v1.2.3 From 37cfbc42887fbd4ff0f4c520c9f3fdea9e6f2a82 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Fri, 15 Nov 2013 10:35:12 +0200 Subject: usb: phy: generic: fix a compiler warning Just because it annoys me. Signed-off-by: Heikki Krogerus Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-generic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c index 8ee37f403553..2d135b09c051 100644 --- a/drivers/usb/phy/phy-generic.c +++ b/drivers/usb/phy/phy-generic.c @@ -162,7 +162,7 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop, if (dev->of_node) { struct device_node *node = dev->of_node; - enum of_gpio_flags flags; + enum of_gpio_flags flags = 0; if (of_property_read_u32(node, "clock-frequency", &clk_rate)) clk_rate = 0; -- cgit v1.2.3 From 6f6485463aada1ec6a0f3db6a03eb8e393d6bb55 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Sat, 9 Nov 2013 12:38:09 +0100 Subject: USB: serial: fix race in generic write Fix race in generic write implementation, which could lead to temporarily degraded throughput. The current generic write implementation introduced by commit 27c7acf22047 ("USB: serial: reimplement generic fifo-based writes") has always had this bug, although it's fairly hard to trigger and the consequences are not likely to be noticed. Specifically, a write() on one CPU while the completion handler is running on another could result in only one of the two write urbs being utilised to empty the remainder of the write fifo (unless there is a second write() that doesn't race during that time). Cc: stable # 2.6.35 Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/generic.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 2b01ec8651c2..e36b25a2fa02 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -173,16 +173,8 @@ retry: clear_bit_unlock(USB_SERIAL_WRITE_BUSY, &port->flags); return result; } - /* - * Try sending off another urb, unless called from completion handler - * (in which case there will be no free urb or no data). - */ - if (mem_flags != GFP_ATOMIC) - goto retry; - clear_bit_unlock(USB_SERIAL_WRITE_BUSY, &port->flags); - - return 0; + goto retry; /* try sending off another urb */ } EXPORT_SYMBOL_GPL(usb_serial_generic_write_start); -- cgit v1.2.3 From 043e3f834530e15e89c58c1b7af59cc646700134 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Sat, 9 Nov 2013 12:38:10 +0100 Subject: USB: serial: fix write memory-allocation flag Fix regression introduced by commit 818f60365a29 ("USB: serial: add memory flags to usb_serial_generic_write_start"), which incorrectly used GFP_KERNEL in write(), which must not not sleep. Reported-by: Dave Jones Tested-by: Dave Jones Cc: Dave Jones Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/generic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index e36b25a2fa02..b63ce023f96f 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -200,7 +200,7 @@ int usb_serial_generic_write(struct tty_struct *tty, return 0; count = kfifo_in_locked(&port->write_fifo, buf, count, &port->lock); - result = usb_serial_generic_write_start(port, GFP_KERNEL); + result = usb_serial_generic_write_start(port, GFP_ATOMIC); if (result) return result; -- cgit v1.2.3 From d373a8534d5e1e7a350e40d3c11961a7cd8d530b Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Tue, 12 Nov 2013 16:37:46 +0100 Subject: usb: musb: musb_cppi41: factor most of cppi41_dma_callback() into cppi41_trans_done() This patch moves most of the logic in cppi41_dma_callback() into cppi41_trans_done() where it can be called from another function. Instead of computing "transferred" (the number of bytes transferred in the last transaction) in cppi41_trans_done() the member "cppi41_channel->prog_len" is now set to 0 if the transfer as a whole can be considered as done. If it is != 0 then the next iteration is assumed. This is a preparation for a workaround. Cc: stable@vger.kernel.org Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_cppi41.c | 59 ++++++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/musb/musb_cppi41.c b/drivers/usb/musb/musb_cppi41.c index ff9d6de2b746..83a8a1d125ac 100644 --- a/drivers/usb/musb/musb_cppi41.c +++ b/drivers/usb/musb/musb_cppi41.c @@ -96,31 +96,15 @@ static void update_rx_toggle(struct cppi41_dma_channel *cppi41_channel) cppi41_channel->usb_toggle = toggle; } -static void cppi41_dma_callback(void *private_data) +static void cppi41_dma_callback(void *private_data); + +static void cppi41_trans_done(struct dma_channel *channel) { - struct dma_channel *channel = private_data; struct cppi41_dma_channel *cppi41_channel = channel->private_data; struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep; struct musb *musb = hw_ep->musb; - unsigned long flags; - struct dma_tx_state txstate; - u32 transferred; - spin_lock_irqsave(&musb->lock, flags); - - dmaengine_tx_status(cppi41_channel->dc, cppi41_channel->cookie, - &txstate); - transferred = cppi41_channel->prog_len - txstate.residue; - cppi41_channel->transferred += transferred; - - dev_dbg(musb->controller, "DMA transfer done on hw_ep=%d bytes=%d/%d\n", - hw_ep->epnum, cppi41_channel->transferred, - cppi41_channel->total_len); - - update_rx_toggle(cppi41_channel); - - if (cppi41_channel->transferred == cppi41_channel->total_len || - transferred < cppi41_channel->packet_sz) { + if (!cppi41_channel->prog_len) { /* done, complete */ cppi41_channel->channel.actual_len = @@ -150,10 +134,8 @@ static void cppi41_dma_callback(void *private_data) remain_bytes, direction, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (WARN_ON(!dma_desc)) { - spin_unlock_irqrestore(&musb->lock, flags); + if (WARN_ON(!dma_desc)) return; - } dma_desc->callback = cppi41_dma_callback; dma_desc->callback_param = channel; @@ -166,6 +148,37 @@ static void cppi41_dma_callback(void *private_data) musb_writew(epio, MUSB_RXCSR, csr); } } +} + +static void cppi41_dma_callback(void *private_data) +{ + struct dma_channel *channel = private_data; + struct cppi41_dma_channel *cppi41_channel = channel->private_data; + struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep; + struct musb *musb = hw_ep->musb; + unsigned long flags; + struct dma_tx_state txstate; + u32 transferred; + + spin_lock_irqsave(&musb->lock, flags); + + dmaengine_tx_status(cppi41_channel->dc, cppi41_channel->cookie, + &txstate); + transferred = cppi41_channel->prog_len - txstate.residue; + cppi41_channel->transferred += transferred; + + dev_dbg(musb->controller, "DMA transfer done on hw_ep=%d bytes=%d/%d\n", + hw_ep->epnum, cppi41_channel->transferred, + cppi41_channel->total_len); + + update_rx_toggle(cppi41_channel); + + if (cppi41_channel->transferred == cppi41_channel->total_len || + transferred < cppi41_channel->packet_sz) + cppi41_channel->prog_len = 0; + + cppi41_trans_done(channel); + spin_unlock_irqrestore(&musb->lock, flags); } -- cgit v1.2.3 From a655f481d83d6d37bec0a2ddfdd24c30ff8f541f Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Tue, 12 Nov 2013 16:37:47 +0100 Subject: usb: musb: musb_cppi41: handle pre-mature TX complete interrupt The TX-complete interrupt of the CPPI41 on AM335x fires too early. Adding a loop and counting how long it takes until the MUSB_TXCSR_TXPKTRDY bit is cleared I see FS: |musb-hdrc musb-hdrc.0.auto: configure ep1/80 packet_sz=64, mode=0, dma_addr=0xadc54002, len=1514 is_tx=1 |cppi41_dma_callback() 74 loops |musb-hdrc musb-hdrc.0.auto: configure ep1/80 packet_sz=64, mode=0, dma_addr=0xadcd8802, len=1514 is_tx=1 |cppi41_dma_callback() 66 loops |musb-hdrc musb-hdrc.0.auto: configure ep1/80 packet_sz=64, mode=0, dma_addr=0xadcd8002, len=1514 is_tx=1 |cppi41_dma_callback() 136 loops |musb-hdrc musb-hdrc.0.auto: configure ep1/80 packet_sz=64, mode=0, dma_addr=0xadf55802, len=1514 is_tx=1 |cppi41_dma_callback() 136 loops avg: 110 - 150us HS: |musb-hdrc musb-hdrc.0.auto: configure ep1/80 packet_sz=512, mode=0, dma_addr=0xaca6f002, len=1514 is_tx=1 |cppi41_dma_callback() 0 loops |musb-hdrc musb-hdrc.0.auto: configure ep1/80 packet_sz=512, mode=0, dma_addr=0xadd6f802, len=1514 is_tx=1 |cppi41_dma_callback() 2 loops |musb-hdrc musb-hdrc.0.auto: configure ep1/80 packet_sz=512, mode=0, dma_addr=0xadd6f002, len=1514 is_tx=1 |cppi41_dma_callback() 13 loops avg: 2us for the same test case. One loop means a udelay(1). The delay seems to depend on the packet size. On HS the bit is always cleared for small packet sizes while on FS it is never the case, it mostly around 110us. This testing has been performed with g_ether (musb as device) and using BULK transfers. INTR transfers are way more fun: during init the gadget sends a INT packet to the host and cppi41 says "transfer done" shortly after. The MUSB_TXCSR_TXPKTRDY bit is set even seconds later. The reason is that the host did not try to receive it, it does so after the interface (on host side) has been configured. Until this happens, that packet remains in musb's FIFO. To fix this, two things are done: - No DMA transfers for INT based endpoints. These transfer are usually very small and rare so it is likely better to skip the DMA engine and stuff the four bytes directly into the FIFO - on HS we poll up to 25us and hope that bit goes away. If not we setup a hrtimer to poll for it. The 140us delay is a rule of thumb. In FS the command | ping 10.10.10.10 -c1 -s65130 creates about 44 1514bytes transfers. About 19 of them need a second timer to complete. Reported-by: Bin Liu Cc: stable@vger.kernel.org Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_cppi41.c | 113 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 108 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/musb/musb_cppi41.c b/drivers/usb/musb/musb_cppi41.c index 83a8a1d125ac..a12bd30401e0 100644 --- a/drivers/usb/musb/musb_cppi41.c +++ b/drivers/usb/musb/musb_cppi41.c @@ -38,6 +38,7 @@ struct cppi41_dma_channel { u32 prog_len; u32 transferred; u32 packet_sz; + struct list_head tx_check; }; #define MUSB_DMA_NUM_CHANNELS 15 @@ -47,6 +48,8 @@ struct cppi41_dma_controller { struct cppi41_dma_channel rx_channel[MUSB_DMA_NUM_CHANNELS]; struct cppi41_dma_channel tx_channel[MUSB_DMA_NUM_CHANNELS]; struct musb *musb; + struct hrtimer early_tx; + struct list_head early_tx_list; u32 rx_mode; u32 tx_mode; u32 auto_req; @@ -96,11 +99,23 @@ static void update_rx_toggle(struct cppi41_dma_channel *cppi41_channel) cppi41_channel->usb_toggle = toggle; } +static bool musb_is_tx_fifo_empty(struct musb_hw_ep *hw_ep) +{ + u8 epnum = hw_ep->epnum; + struct musb *musb = hw_ep->musb; + void __iomem *epio = musb->endpoints[epnum].regs; + u16 csr; + + csr = musb_readw(epio, MUSB_TXCSR); + if (csr & MUSB_TXCSR_TXPKTRDY) + return false; + return true; +} + static void cppi41_dma_callback(void *private_data); -static void cppi41_trans_done(struct dma_channel *channel) +static void cppi41_trans_done(struct cppi41_dma_channel *cppi41_channel) { - struct cppi41_dma_channel *cppi41_channel = channel->private_data; struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep; struct musb *musb = hw_ep->musb; @@ -138,7 +153,7 @@ static void cppi41_trans_done(struct dma_channel *channel) return; dma_desc->callback = cppi41_dma_callback; - dma_desc->callback_param = channel; + dma_desc->callback_param = &cppi41_channel->channel; cppi41_channel->cookie = dma_desc->tx_submit(dma_desc); dma_async_issue_pending(dc); @@ -150,6 +165,41 @@ static void cppi41_trans_done(struct dma_channel *channel) } } +static enum hrtimer_restart cppi41_recheck_tx_req(struct hrtimer *timer) +{ + struct cppi41_dma_controller *controller; + struct cppi41_dma_channel *cppi41_channel, *n; + struct musb *musb; + unsigned long flags; + enum hrtimer_restart ret = HRTIMER_NORESTART; + + controller = container_of(timer, struct cppi41_dma_controller, + early_tx); + musb = controller->musb; + + spin_lock_irqsave(&musb->lock, flags); + list_for_each_entry_safe(cppi41_channel, n, &controller->early_tx_list, + tx_check) { + bool empty; + struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep; + + empty = musb_is_tx_fifo_empty(hw_ep); + if (empty) { + list_del_init(&cppi41_channel->tx_check); + cppi41_trans_done(cppi41_channel); + } + } + + if (!list_empty(&controller->early_tx_list)) { + ret = HRTIMER_RESTART; + hrtimer_forward_now(&controller->early_tx, + ktime_set(0, 150 * NSEC_PER_USEC)); + } + + spin_unlock_irqrestore(&musb->lock, flags); + return ret; +} + static void cppi41_dma_callback(void *private_data) { struct dma_channel *channel = private_data; @@ -159,6 +209,7 @@ static void cppi41_dma_callback(void *private_data) unsigned long flags; struct dma_tx_state txstate; u32 transferred; + bool empty; spin_lock_irqsave(&musb->lock, flags); @@ -177,8 +228,52 @@ static void cppi41_dma_callback(void *private_data) transferred < cppi41_channel->packet_sz) cppi41_channel->prog_len = 0; - cppi41_trans_done(channel); - + empty = musb_is_tx_fifo_empty(hw_ep); + if (empty) { + cppi41_trans_done(cppi41_channel); + } else { + struct cppi41_dma_controller *controller; + /* + * On AM335x it has been observed that the TX interrupt fires + * too early that means the TXFIFO is not yet empty but the DMA + * engine says that it is done with the transfer. We don't + * receive a FIFO empty interrupt so the only thing we can do is + * to poll for the bit. On HS it usually takes 2us, on FS around + * 110us - 150us depending on the transfer size. + * We spin on HS (no longer than than 25us and setup a timer on + * FS to check for the bit and complete the transfer. + */ + controller = cppi41_channel->controller; + + if (musb->g.speed == USB_SPEED_HIGH) { + unsigned wait = 25; + + do { + empty = musb_is_tx_fifo_empty(hw_ep); + if (empty) + break; + wait--; + if (!wait) + break; + udelay(1); + } while (1); + + empty = musb_is_tx_fifo_empty(hw_ep); + if (empty) { + cppi41_trans_done(cppi41_channel); + goto out; + } + } + list_add_tail(&cppi41_channel->tx_check, + &controller->early_tx_list); + if (!hrtimer_active(&controller->early_tx)) { + hrtimer_start_range_ns(&controller->early_tx, + ktime_set(0, 140 * NSEC_PER_USEC), + 40 * NSEC_PER_USEC, + HRTIMER_MODE_REL); + } + } +out: spin_unlock_irqrestore(&musb->lock, flags); } @@ -377,6 +472,8 @@ static int cppi41_is_compatible(struct dma_channel *channel, u16 maxpacket, WARN_ON(1); return 1; } + if (cppi41_channel->hw_ep->ep_in.type != USB_ENDPOINT_XFER_BULK) + return 0; if (cppi41_channel->is_tx) return 1; /* AM335x Advisory 1.0.13. No workaround for device RX mode */ @@ -401,6 +498,7 @@ static int cppi41_dma_channel_abort(struct dma_channel *channel) if (cppi41_channel->channel.status == MUSB_DMA_STATUS_FREE) return 0; + list_del_init(&cppi41_channel->tx_check); if (is_tx) { csr = musb_readw(epio, MUSB_TXCSR); csr &= ~MUSB_TXCSR_DMAENAB; @@ -508,6 +606,7 @@ static int cppi41_dma_controller_start(struct cppi41_dma_controller *controller) cppi41_channel->controller = controller; cppi41_channel->port_num = port; cppi41_channel->is_tx = is_tx; + INIT_LIST_HEAD(&cppi41_channel->tx_check); musb_dma = &cppi41_channel->channel; musb_dma->private_data = cppi41_channel; @@ -533,6 +632,7 @@ void dma_controller_destroy(struct dma_controller *c) struct cppi41_dma_controller *controller = container_of(c, struct cppi41_dma_controller, controller); + hrtimer_cancel(&controller->early_tx); cppi41_dma_controller_stop(controller); kfree(controller); } @@ -552,6 +652,9 @@ struct dma_controller *dma_controller_create(struct musb *musb, if (!controller) goto kzalloc_fail; + hrtimer_init(&controller->early_tx, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + controller->early_tx.function = cppi41_recheck_tx_req; + INIT_LIST_HEAD(&controller->early_tx_list); controller->musb = musb; controller->controller.channel_alloc = cppi41_dma_channel_allocate; -- cgit v1.2.3 From 2bac51a1827a18821150ed8c9f9752c02f9c2b02 Mon Sep 17 00:00:00 2001 From: Michael Grzeschik Date: Mon, 11 Nov 2013 23:43:32 +0100 Subject: usb: gadget: composite: reset delayed_status on reset_config The delayed_status value is used to keep track of status response packets on ep0. It needs to be reset or the set_config function would still delay the answer, if the usb device got unplugged while waiting for setup_continue to be called. Cc: stable@vger.kernel.org Signed-off-by: Michael Grzeschik Signed-off-by: Felipe Balbi --- drivers/usb/gadget/composite.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 3e7ae707f691..2018ba1a2172 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -593,6 +593,7 @@ static void reset_config(struct usb_composite_dev *cdev) bitmap_zero(f->endpoints, 32); } cdev->config = NULL; + cdev->delayed_status = 0; } static int set_config(struct usb_composite_dev *cdev, -- cgit v1.2.3 From 66fadea5b79c07154126bb0db375be915f611246 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Wed, 6 Nov 2013 09:25:27 +0100 Subject: usb: musb: only cancel work if it is initialized Since commit c5340bd14 ("usb: musb: cancel work on removal") the workqueue is cancelled but then if we bail out before the workqueue is setup we get this: |INFO: trying to register non-static key. |the code is fine but needs lockdep annotation. |turning off the locking correctness validator. |CPU: 0 PID: 708 Comm: modprobe Not tainted 3.12.0+ #435 |[] (lock_acquire+0xf0/0x108) from [] (flush_work+0x38/0x2ec) |[] (flush_work+0x38/0x2ec) from [] (__cancel_work_timer+0xa0/0x134) |[] (__cancel_work_timer+0xa0/0x134) from [] (musb_free+0x40/0x60 [musb_hdrc]) |[] (musb_free+0x40/0x60 [musb_hdrc]) from [] (musb_probe+0x678/0xb78 [musb_hdrc]) |[] (musb_probe+0x678/0xb78 [musb_hdrc]) from [] (platform_drv_probe+0x1c/0x24) |[] (platform_drv_probe+0x1c/0x24) from [] (driver_probe_device+0x90/0x224) |[] (driver_probe_device+0x90/0x224) from [] (bus_for_each_drv+0x60/0x8c) |[] (bus_for_each_drv+0x60/0x8c) from [] (device_attach+0x80/0xa4) |[] (device_attach+0x80/0xa4) from [] (bus_probe_device+0x88/0xac) |[] (bus_probe_device+0x88/0xac) from [] (device_add+0x388/0x6c8) |[] (device_add+0x388/0x6c8) from [] (platform_device_add+0x188/0x22c) |[] (platform_device_add+0x188/0x22c) from [] (dsps_probe+0x294/0x394 [musb_dsps]) |[] (dsps_probe+0x294/0x394 [musb_dsps]) from [] (platform_drv_probe+0x1c/0x24) |platform musb-hdrc.1.auto: Driver musb-hdrc requests probe deferral |musb-hdrc musb-hdrc.1.auto: musb_init_controller failed with status -517 This patch moves the init part to earlier part so it can be cleaned as part of the fail3 label because now it is surrounded by the fail4 label. Step two is to remove it from musb_free() and add it to the two cleanup paths (error path and device removal) separately. Cc: stable@vger.kernel.org Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_core.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 0a43329569d1..4d4499b80449 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1809,7 +1809,6 @@ static void musb_free(struct musb *musb) disable_irq_wake(musb->nIrq); free_irq(musb->nIrq, musb); } - cancel_work_sync(&musb->irq_work); musb_host_free(musb); } @@ -1896,6 +1895,9 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) musb_platform_disable(musb); musb_generic_disable(musb); + /* Init IRQ workqueue before request_irq */ + INIT_WORK(&musb->irq_work, musb_irq_work); + /* setup musb parts of the core (especially endpoints) */ status = musb_core_init(plat->config->multipoint ? MUSB_CONTROLLER_MHDRC @@ -